You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
lxqt-panel-packaging/plugin-tray/xfitman.cpp

335 lines
8.6 KiB

/* BEGIN_COMMON_COPYRIGHT_HEADER
* (c)LGPL2+
*
* LXQt - a lightweight, Qt based, desktop toolset
* http://razor-qt.org
*
* Copyright: 2010-2011 Razor team
* Authors:
* Christopher "VdoP" Regali
* Alexander Sokoloff <sokoloff.a@gmail.com>
*
* This program or library is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* END_COMMON_COPYRIGHT_HEADER */
#include <QDebug>
// #include <stdint.h>
// #include <stdio.h>
// #include <stdlib.h>
// #include <assert.h>
#include <QX11Info>
#include <QIcon>
#include "xfitman.h"
#include <X11/Xatom.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
/**
* @file xfitman.cpp
* @brief implements class Xfitman
* @author Christopher "VdoP" Regali
*/
/*
S ome requests from Cli*ents include type of the Client, for example the _NET_ACTIVE_WINDOW
message. Currently the types can be 1 for normal applications, and 2 for pagers.
See http://standards.freedesktop.org/wm-spec/latest/ar01s09.html#sourceindication
*/
#define SOURCE_NORMAL 1
#define SOURCE_PAGER 2
const XfitMan& xfitMan()
{
static XfitMan instance;
return instance;
}
/**
* @brief constructor: gets Display vars and registers us
*/
XfitMan::XfitMan()
{
root = (Window)QX11Info::appRootWindow();
}
Atom XfitMan::atom(const char* atomName)
{
static QHash<QString, Atom> hash;
if (hash.contains(atomName))
return hash.value(atomName);
Atom atom = XInternAtom(QX11Info::display(), atomName, false);
hash[atomName] = atom;
return atom;
}
/**
* @brief moves a window to a new position
*/
void XfitMan::moveWindow(Window _win, int _x, int _y) const
{
XMoveWindow(QX11Info::display(), _win, _x, _y);
}
/************************************************
************************************************/
bool XfitMan::getWindowProperty(Window window,
Atom atom, // property
Atom reqType, // req_type
unsigned long* resultLen,// nitems_return
unsigned char** result // prop_return
) const
{
int format;
unsigned long type, rest;
return XGetWindowProperty(QX11Info::display(), window, atom, 0, 4096, false,
reqType, &type, &format, resultLen, &rest,
result) == Success;
}
/************************************************
************************************************/
bool XfitMan::getRootWindowProperty(Atom atom, // property
Atom reqType, // req_type
unsigned long* resultLen,// nitems_return
unsigned char** result // prop_return
) const
{
return getWindowProperty(root, atom, reqType, resultLen, result);
}
/**
* @brief resizes a window to the given dimensions
*/
void XfitMan::resizeWindow(Window _wid, int _width, int _height) const
{
XResizeWindow(QX11Info::display(), _wid, _width, _height);
}
/**
* @brief gets a windowpixmap from a window
*/
bool XfitMan::getClientIcon(Window _wid, QPixmap& _pixreturn) const
{
int format;
ulong type, nitems, extra;
ulong* data = 0;
XGetWindowProperty(QX11Info::display(), _wid, atom("_NET_WM_ICON"),
0, LONG_MAX, False, AnyPropertyType,
&type, &format, &nitems, &extra,
(uchar**)&data);
if (!data)
{
return false;
}
QImage img (data[0], data[1], QImage::Format_ARGB32);
for (int i=0; i<img.byteCount()/4; ++i)
((uint*)img.bits())[i] = data[i+2];
_pixreturn = QPixmap::fromImage(img);
XFree(data);
return true;
}
bool XfitMan::getClientIcon(Window _wid, QIcon *icon) const
{
int format;
ulong type, nitems, extra;
ulong* data = 0;
XGetWindowProperty(QX11Info::display(), _wid, atom("_NET_WM_ICON"),
0, LONG_MAX, False, AnyPropertyType,
&type, &format, &nitems, &extra,
(uchar**)&data);
if (!data)
{
return false;
}
ulong* d = data;
while (d < data + nitems)
{
QImage img (d[0], d[1], QImage::Format_ARGB32);
d+=2;
for (int i=0; i<img.byteCount()/4; ++i, ++d)
((uint*)img.bits())[i] = *d;
icon->addPixmap(QPixmap::fromImage(img));
}
XFree(data);
return true;
}
/**
* @brief destructor
*/
XfitMan::~XfitMan()
{
}
/**
* @brief returns a windowname and sets _nameSource to the finally used Atom
*/
// i got the idea for this from taskbar-plugin of LXPanel - so credits fly out :)
QString XfitMan::getWindowTitle(Window _wid) const
{
QString name = "";
//first try the modern net-wm ones
unsigned long length;
unsigned char *data = NULL;
Atom utf8Atom = atom("UTF8_STRING");
if (getWindowProperty(_wid, atom("_NET_WM_VISIBLE_NAME"), utf8Atom, &length, &data))
{
name = QString::fromUtf8((char*) data);
XFree(data);
}
if (name.isEmpty())
{
if (getWindowProperty(_wid, atom("_NET_WM_NAME"), utf8Atom, &length, &data))
{
name = QString::fromUtf8((char*) data);
XFree(data);
}
}
if (name.isEmpty())
{
if (getWindowProperty(_wid, atom("XA_WM_NAME"), XA_STRING, &length, &data))
{
name = (char*) data;
XFree(data);
}
}
if (name.isEmpty())
{
Status ok = XFetchName(QX11Info::display(), _wid, (char**) &data);
name = QString((char*) data);
if (0 != ok) XFree(data);
}
if (name.isEmpty())
{
XTextProperty prop;
if (XGetWMName(QX11Info::display(), _wid, &prop))
{
name = QString::fromUtf8((char*) prop.value);
XFree(prop.value);
}
}
return name;
}
QString XfitMan::getApplicationName(Window _wid) const
{
XClassHint hint;
QString ret;
if (XGetClassHint(QX11Info::display(), _wid, &hint))
{
if (hint.res_name)
{
ret = hint.res_name;
XFree(hint.res_name);
}
if (hint.res_class)
{
XFree(hint.res_class);
}
}
return ret;
}
/**
* @brief sends a clientmessage to a window
*/
int XfitMan::clientMessage(Window _wid, Atom _msg,
unsigned long data0,
unsigned long data1,
unsigned long data2,
unsigned long data3,
unsigned long data4) const
{
XClientMessageEvent msg;
msg.window = _wid;
msg.type = ClientMessage;
msg.message_type = _msg;
msg.send_event = true;
msg.display = QX11Info::display();
msg.format = 32;
msg.data.l[0] = data0;
msg.data.l[1] = data1;
msg.data.l[2] = data2;
msg.data.l[3] = data3;
msg.data.l[4] = data4;
if (XSendEvent(QX11Info::display(), root, false, (SubstructureRedirectMask | SubstructureNotifyMask) , (XEvent *) &msg) == Success)
return EXIT_SUCCESS;
else
return EXIT_FAILURE;
}
/**
* @brief raises windows _wid
*/
void XfitMan::raiseWindow(Window _wid) const
{
clientMessage(_wid, atom("_NET_ACTIVE_WINDOW"),
SOURCE_PAGER);
}
/************************************************
************************************************/
void XfitMan::closeWindow(Window _wid) const
{
clientMessage(_wid, atom("_NET_CLOSE_WINDOW"),
0, // Timestamp
SOURCE_PAGER);
}
void XfitMan::setIconGeometry(Window _wid, QRect* rect) const
{
Atom net_wm_icon_geometry = atom("_NET_WM_ICON_GEOMETRY");
if(!rect)
XDeleteProperty(QX11Info::display(), _wid, net_wm_icon_geometry);
else
{
long data[4];
data[0] = rect->x();
data[1] = rect->y();
data[2] = rect->width();
data[3] = rect->height();
XChangeProperty(QX11Info::display(), _wid, net_wm_icon_geometry,
XA_CARDINAL, 32, PropModeReplace, (unsigned char*)data, 4);
}
}