1
/***************************************************************************
2
* Copyright (C) 2010 by Dmitry 'Krasu' Baryshev *
3
* ksquirrel.iv@gmail.com *
5
* This program is free software; you can redistribute it and/or modify *
6
* it under the terms of the GNU General Public License as published by *
7
* the Free Software Foundation; either version 3 of the License, or *
8
* (at your option) any later version. *
10
* This program is distributed in the hope that it will be useful, *
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13
* GNU General Public License for more details. *
15
* You should have received a copy of the GNU General Public License *
16
* along with this program; if not, write to the *
17
* Free Software Foundation, Inc., *
18
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19
***************************************************************************/
32
#include <X11/Xutil.h>
35
#include <X11/extensions/Xcomposite.h>
40
#define DBG(...) //fprintf(stderr, ##__VA_ARGS__)
42
Atom NETWM::UTF8_STRING = 0;
43
Atom NETWM::XROOTPMAP_ID = 0;
45
Atom NETWM::WM_STATE = 0;
46
Atom NETWM::WM_CLASS = 0;
47
Atom NETWM::WM_NAME = 0;
48
Atom NETWM::WM_DELETE_WINDOW = 0;
49
Atom NETWM::WM_PROTOCOLS = 0;
50
Atom NETWM::WM_CHANGE_STATE = 0;
51
Atom NETWM::WM_WINDOW_ROLE = 0;
53
Atom NETWM::NET_WORKAREA = 0;
54
Atom NETWM::NET_CLIENT_LIST = 0;
55
Atom NETWM::NET_CLIENT_LIST_STACKING = 0;
56
Atom NETWM::NET_NUMBER_OF_DESKTOPS = 0;
57
Atom NETWM::NET_CURRENT_DESKTOP = 0;
58
Atom NETWM::NET_DESKTOP_NAMES = 0;
59
Atom NETWM::NET_ACTIVE_WINDOW = 0;
60
Atom NETWM::NET_CLOSE_WINDOW = 0;
61
Atom NETWM::NET_SUPPORTED = 0;
62
Atom NETWM::NET_WM_DESKTOP = 0;
63
Atom NETWM::NET_SHOWING_DESKTOP = 0;
65
Atom NETWM::NET_WM_STATE = 0;
66
Atom NETWM::NET_WM_STATE_MODAL = 0;
67
Atom NETWM::NET_WM_STATE_STICKY = 0;
68
Atom NETWM::NET_WM_STATE_MAXIMIZED_VERT = 0;
69
Atom NETWM::NET_WM_STATE_MAXIMIZED_HORZ = 0;
70
Atom NETWM::NET_WM_STATE_SHADED = 0;
71
Atom NETWM::NET_WM_STATE_SKIP_TASKBAR = 0;
72
Atom NETWM::NET_WM_STATE_SKIP_PAGER = 0;
73
Atom NETWM::NET_WM_STATE_HIDDEN = 0;
74
Atom NETWM::NET_WM_STATE_FULLSCREEN = 0;
75
Atom NETWM::NET_WM_STATE_ABOVE = 0;
76
Atom NETWM::NET_WM_STATE_BELOW = 0;
77
Atom NETWM::NET_WM_STATE_STAYS_ON_TOP = 0;
78
Atom NETWM::NET_WM_STATE_STAYS_ON_BOTTOM = 0;
79
Atom NETWM::NET_WM_STATE_DEMANDS_ATTENTION = 0;
81
Atom NETWM::NET_WM_WINDOW_TYPE = 0;
82
Atom NETWM::NET_WM_WINDOW_TYPE_DESKTOP = 0;
83
Atom NETWM::NET_WM_WINDOW_TYPE_DOCK = 0;
84
Atom NETWM::MODERRO_WINDOW_TYPE_DOCK = 0;
85
Atom NETWM::NET_WM_WINDOW_TYPE_TOOLBAR = 0;
86
Atom NETWM::NET_WM_WINDOW_TYPE_MENU = 0;
87
Atom NETWM::NET_WM_WINDOW_TYPE_UTILITY = 0;
88
Atom NETWM::NET_WM_WINDOW_TYPE_SPLASH = 0;
89
Atom NETWM::NET_WM_WINDOW_TYPE_DIALOG = 0;
90
Atom NETWM::NET_WM_WINDOW_TYPE_DROPDOWN_MENU = 0;
91
Atom NETWM::NET_WM_WINDOW_TYPE_POPUP_MENU = 0;
92
Atom NETWM::NET_WM_WINDOW_TYPE_TOOLTIP = 0;
93
Atom NETWM::NET_WM_WINDOW_TYPE_NOTIFICATION = 0;
94
Atom NETWM::NET_WM_WINDOW_TYPE_COMBO = 0;
95
Atom NETWM::NET_WM_WINDOW_TYPE_DND = 0;
96
Atom NETWM::NET_WM_WINDOW_TYPE_NORMAL = 0;
97
Atom NETWM::NET_WM_WINDOW_OPACITY = 0;
98
Atom NETWM::NET_WM_NAME = 0;
99
Atom NETWM::NET_WM_VISIBLE_NAME = 0;
100
Atom NETWM::NET_WM_STRUT = 0;
101
Atom NETWM::NET_WM_STRUT_PARTIAL = 0;
102
Atom NETWM::NET_WM_ICON = 0;
103
Atom NETWM::NET_WM_PID = 0;
105
NETWM::net_wm_state::net_wm_state()
106
: modal(0), sticky(0), maximized_vert(0),
107
maximized_horz(0), shaded(0), skip_taskbar(0),
108
skip_pager(0), hidden(0), fullscreen(0),
109
above(0), below(0), stays_on_top(0), stays_on_bottom(0),
110
demands_attention(0), valid(false)
113
NETWM::net_wm_window_type::net_wm_window_type()
114
: desktop(0), dock(0), toolbar(0),
115
menu(0), utility(0), splash(0), dialog(0),
116
dropdown(0), popup(0), tooltip(0), notification(0),
117
combo(0), dnd(0), normal(0), valid(false)
120
/**********************************************************/
124
Display *dpy = QX11Info::display();
126
UTF8_STRING = XInternAtom(dpy, "UTF8_STRING", False);
127
XROOTPMAP_ID = XInternAtom(dpy, "_XROOTPMAP_ID", False);
128
WM_STATE = XInternAtom(dpy, "WM_STATE", False);
129
WM_CLASS = XInternAtom(dpy, "WM_CLASS", False);
130
WM_NAME = XInternAtom(dpy, "WM_NAME", False);
131
WM_DELETE_WINDOW = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
132
WM_CHANGE_STATE = XInternAtom(dpy, "WM_CHANGE_STATE", False);
133
WM_WINDOW_ROLE = XInternAtom(dpy, "WM_WINDOW_ROLE", False);
135
WM_PROTOCOLS = XInternAtom(dpy, "WM_PROTOCOLS", False);
136
NET_WORKAREA = XInternAtom(dpy, "_NET_WORKAREA", False);
137
NET_CLIENT_LIST = XInternAtom(dpy, "_NET_CLIENT_LIST", False);
138
NET_CLIENT_LIST_STACKING = XInternAtom(dpy, "_NET_CLIENT_LIST_STACKING", False);
139
NET_NUMBER_OF_DESKTOPS = XInternAtom(dpy, "_NET_NUMBER_OF_DESKTOPS", False);
140
NET_CURRENT_DESKTOP = XInternAtom(dpy, "_NET_CURRENT_DESKTOP", False);
141
NET_DESKTOP_NAMES = XInternAtom(dpy, "_NET_DESKTOP_NAMES", False);
142
NET_ACTIVE_WINDOW = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False);
143
NET_CLOSE_WINDOW = XInternAtom(dpy, "_NET_CLOSE_WINDOW", False);
144
NET_SUPPORTED = XInternAtom(dpy, "_NET_SUPPORTED", False);
145
NET_WM_DESKTOP = XInternAtom(dpy, "_NET_WM_DESKTOP", False);
146
NET_SHOWING_DESKTOP = XInternAtom(dpy, "_NET_SHOWING_DESKTOP", False);
148
NET_WM_STATE = XInternAtom(dpy, "_NET_WM_STATE", False);
149
NET_WM_STATE_MODAL = XInternAtom(dpy, "_NET_WM_STATE_MODAL", False);
150
NET_WM_STATE_STICKY = XInternAtom(dpy, "_NET_WM_STATE_STICKY", False);
151
NET_WM_STATE_MAXIMIZED_VERT = XInternAtom(dpy, "_NET_WM_STATE_MAXIMIZED_VERT", False);
152
NET_WM_STATE_MAXIMIZED_HORZ = XInternAtom(dpy, "_NET_WM_STATE_MAXIMIZED_HORZ", False);
153
NET_WM_STATE_SHADED = XInternAtom(dpy, "_NET_WM_STATE_SHADED", False);
154
NET_WM_STATE_SKIP_TASKBAR = XInternAtom(dpy, "_NET_WM_STATE_SKIP_TASKBAR", False);
155
NET_WM_STATE_SKIP_PAGER = XInternAtom(dpy, "_NET_WM_STATE_SKIP_PAGER", False);
156
NET_WM_STATE_HIDDEN = XInternAtom(dpy, "_NET_WM_STATE_HIDDEN", False);
157
NET_WM_STATE_FULLSCREEN = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
158
NET_WM_STATE_ABOVE = XInternAtom(dpy, "_NET_WM_STATE_ABOVE", False);
159
NET_WM_STATE_BELOW = XInternAtom(dpy, "_NET_WM_STATE_BELOW", False);
160
NET_WM_STATE_STAYS_ON_TOP = XInternAtom(dpy, "_NET_WM_STATE_STAYS_ON_TOP", False);
161
NET_WM_STATE_STAYS_ON_BOTTOM = XInternAtom(dpy, "_NET_WM_STATE_STAYS_ON_BOTTOM", False);
162
NET_WM_STATE_DEMANDS_ATTENTION = XInternAtom(dpy, "_NET_WM_STATE_DEMANDS_ATTENTION", False);
164
NET_WM_WINDOW_TYPE = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
165
NET_WM_WINDOW_TYPE_DESKTOP = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DESKTOP", False);
166
NET_WM_WINDOW_TYPE_DOCK = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DOCK", False);
167
MODERRO_WINDOW_TYPE_DOCK = XInternAtom(dpy, "_MODERRO_WINDOW_TYPE_DOCK", False);
168
NET_WM_WINDOW_TYPE_TOOLBAR = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_TOOLBAR", False);
169
NET_WM_WINDOW_TYPE_MENU = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_MENU", False);
170
NET_WM_WINDOW_TYPE_UTILITY = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_UTILITY", False);
171
NET_WM_WINDOW_TYPE_SPLASH = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_SPLASH", False);
172
NET_WM_WINDOW_TYPE_DIALOG = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
173
NET_WM_WINDOW_TYPE_DROPDOWN_MENU = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU", False);
174
NET_WM_WINDOW_TYPE_POPUP_MENU = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_POPUP_MENU", False);
175
NET_WM_WINDOW_TYPE_TOOLTIP = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_TOOLTIP", False);
176
NET_WM_WINDOW_TYPE_NOTIFICATION = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_NOTIFICATION", False);
177
NET_WM_WINDOW_TYPE_COMBO = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_COMBO", False);
178
NET_WM_WINDOW_TYPE_DND = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DND", False);
179
NET_WM_WINDOW_TYPE_NORMAL = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_NORMAL", False);
181
NET_WM_WINDOW_OPACITY = XInternAtom(dpy, "_NET_WM_WINDOW_OPACITY", False);
182
NET_WM_NAME = XInternAtom(dpy, "_NET_WM_NAME", False);
183
NET_WM_VISIBLE_NAME = XInternAtom(dpy, "_NET_WM_VISIBLE_NAME", False);
184
NET_WM_STRUT = XInternAtom(dpy, "_NET_WM_STRUT", False);
185
NET_WM_STRUT_PARTIAL = XInternAtom(dpy, "_NET_WM_STRUT_PARTIAL", False);
186
NET_WM_ICON = XInternAtom(dpy, "_NET_WM_ICON", False);
187
NET_WM_PID = XInternAtom(dpy, "_NET_WM_PID", False);
190
int NETWM::setProperty(Window window, Atom atom, long offset, uchar *data, int nelem)
194
return XChangeProperty(QX11Info::display(), window, atom, offset, 32, PropModeReplace, data, nelem);
197
int NETWM::setPropertySkipTaskbar(Window window)
203
state[0] = NETWM::NET_WM_STATE_SKIP_PAGER;
204
state[1] = NETWM::NET_WM_STATE_SKIP_TASKBAR;
205
state[2] = NETWM::NET_WM_STATE_STICKY;
207
return NETWM::setProperty(window, NETWM::NET_WM_STATE, XA_ATOM, (uchar *)&state, 3);
210
int NETWM::setPropertyOnTop(Window window)
216
state[0] = NETWM::NET_WM_STATE_ABOVE;
217
state[1] = NETWM::NET_WM_STATE_STAYS_ON_TOP;
219
return NETWM::setProperty(window, NETWM::NET_WM_STATE, XA_ATOM, (uchar *)&state, 2);
222
void* NETWM::property(Window win, Atom prop, Atom type, int *nitems, bool *ok)
228
unsigned long items_ret;
229
unsigned long after_ret;
230
unsigned char *prop_data = 0;
232
if(XGetWindowProperty(QX11Info::display(),
243
&prop_data) != Success)
260
bool NETWM::climsg(Window win, long type, long l0, long l1, long l2, long l3, long l4)
264
XClientMessageEvent xev;
266
xev.type = ClientMessage;
268
xev.message_type = type;
276
return (XSendEvent(QX11Info::display(), QX11Info::appRootWindow(), False,
277
(SubstructureNotifyMask | SubstructureRedirectMask),
278
(XEvent *)&xev) == Success);
281
bool NETWM::climsgwm(Window win, Atom type, Atom arg)
285
XClientMessageEvent xev;
287
xev.type = ClientMessage;
289
xev.message_type = type;
292
xev.data.l[1] = CurrentTime;
294
return (XSendEvent(QX11Info::display(), win, False, 0L, (XEvent *)&xev) == Success);
297
uint NETWM::netwmDesktopsNumber()
304
data = (quint32 *)NETWM::property(QX11Info::appRootWindow(), NETWM::NET_NUMBER_OF_DESKTOPS, XA_CARDINAL, 0);
315
uint NETWM::netwmCurrentDesktop()
322
data = (quint32 *)NETWM::property(QX11Info::appRootWindow(), NETWM::NET_CURRENT_DESKTOP, XA_CARDINAL, 0);
333
qint64 NETWM::netwmPid(Window win)
340
data = (ulong *)NETWM::property(win, NETWM::NET_WM_PID, XA_CARDINAL, 0);
351
bool NETWM::netwmActivateWindow(Window win)
355
return NETWM::climsg(win, NETWM::NET_ACTIVE_WINDOW, 2, CurrentTime);
358
QList<Window> NETWM::netwmWindowList()
365
Window *win = reinterpret_cast<Window *>(NETWM::property(QX11Info::appRootWindow(), NETWM::NET_CLIENT_LIST, XA_WINDOW, &num));
369
qDebug("NETWM: Cannot get window list");
373
for(int i = 0;i < num;i++)
381
int NETWM::netwmDesktop(Window win)
388
data = (ulong *)NETWM::property(win, NETWM::NET_WM_DESKTOP, XA_CARDINAL, 0);
399
NETWM::net_wm_state NETWM::netwmState(Window win)
407
if(!(state = (Atom *)NETWM::property(win, NETWM::NET_WM_STATE, XA_ATOM, &num3)))
412
if(state[num3] == NETWM::NET_WM_STATE_MODAL)
414
DBG("NET_WM_STATE_MODAL\n");
417
else if(state[num3] == NETWM::NET_WM_STATE_STICKY)
419
DBG("NET_WM_STATE_STICKY\n");
422
else if(state[num3] == NETWM::NET_WM_STATE_MAXIMIZED_VERT)
424
DBG("NET_WM_STATE_MAXIMIZED_VERT\n");
425
nws.maximized_vert = 1;
427
else if(state[num3] == NETWM::NET_WM_STATE_MAXIMIZED_HORZ)
429
DBG("NET_WM_STATE_MAXIMIZED_HORZ\n");
430
nws.maximized_horz = 1;
432
else if(state[num3] == NETWM::NET_WM_STATE_SHADED)
434
DBG("NET_WM_STATE_SHADED\n");
437
else if(state[num3] == NETWM::NET_WM_STATE_SKIP_TASKBAR)
439
DBG("NET_WM_STATE_SKIP_TASKBAR\n");
440
nws.skip_taskbar = 1;
442
else if(state[num3] == NETWM::NET_WM_STATE_SKIP_PAGER)
444
DBG("NET_WM_STATE_SKIP_PAGER\n");
447
else if(state[num3] == NETWM::NET_WM_STATE_HIDDEN)
449
DBG("NET_WM_STATE_HIDDEN\n");
452
else if(state[num3] == NETWM::NET_WM_STATE_FULLSCREEN)
454
DBG("NET_WM_STATE_FULLSCREEN\n");
457
else if(state[num3] == NETWM::NET_WM_STATE_ABOVE)
459
DBG("NET_WM_STATE_ABOVE\n");
462
else if(state[num3] == NETWM::NET_WM_STATE_BELOW)
464
DBG("NET_WM_STATE_BELOW\n");
467
else if(state[num3] == NETWM::NET_WM_STATE_STAYS_ON_TOP)
469
DBG("NET_WM_STATE_STAYS_ON_TOP\n");
470
nws.stays_on_top = 1;
472
else if(state[num3] == NETWM::NET_WM_STATE_STAYS_ON_BOTTOM)
474
DBG("NET_WM_STATE_STAYS_ON_BOTTOM\n");
475
nws.stays_on_bottom = 1;
477
else if(state[num3] == NETWM::NET_WM_STATE_DEMANDS_ATTENTION)
479
DBG("NET_WM_STATE_DEMANDS_ATTENTION\n");
480
nws.demands_attention = 1;
491
NETWM::net_wm_window_type NETWM::netwmWindowType(Window win)
495
net_wm_window_type nwwt;
501
if(!(state = (Atom *)NETWM::property(win, NETWM::NET_WM_WINDOW_TYPE, XA_ATOM, &num3, &ok)))
516
if(state[num3] == NETWM::NET_WM_WINDOW_TYPE_DESKTOP)
518
DBG("NET_WM_WINDOW_TYPE_DESKTOP\n");
521
else if(state[num3] == NETWM::NET_WM_WINDOW_TYPE_DOCK)
523
DBG("NET_WM_WINDOW_TYPE_DOCK\n");
526
else if(state[num3] == NETWM::NET_WM_WINDOW_TYPE_TOOLBAR)
528
DBG("NET_WM_WINDOW_TYPE_TOOLBAR\n");
531
else if(state[num3] == NETWM::NET_WM_WINDOW_TYPE_MENU)
533
DBG("NET_WM_WINDOW_TYPE_MENU\n");
536
else if(state[num3] == NETWM::NET_WM_WINDOW_TYPE_UTILITY)
538
DBG("NET_WM_WINDOW_TYPE_UTILITY\n");
541
else if(state[num3] == NETWM::NET_WM_WINDOW_TYPE_SPLASH)
543
DBG("NET_WM_WINDOW_TYPE_SPLASH\n");
546
else if(state[num3] == NETWM::NET_WM_WINDOW_TYPE_DIALOG)
548
DBG("NET_WM_WINDOW_TYPE_DIALOG\n");
551
else if(state[num3] == NETWM::NET_WM_WINDOW_TYPE_DROPDOWN_MENU)
553
DBG("NET_WM_WINDOW_TYPE_DROPDOWN_MENU\n");
556
else if(state[num3] == NETWM::NET_WM_WINDOW_TYPE_POPUP_MENU)
558
DBG("NET_WM_WINDOW_TYPE_POPUP_MENU\n");
561
else if(state[num3] == NETWM::NET_WM_WINDOW_TYPE_TOOLTIP)
563
DBG("NET_WM_WINDOW_TYPE_TOOLTIP\n");
566
else if(state[num3] == NETWM::NET_WM_WINDOW_TYPE_NOTIFICATION)
568
DBG("NET_WM_WINDOW_TYPE_NOTIFICATION\n");
569
nwwt.notification = 1;
571
else if(state[num3] == NETWM::NET_WM_WINDOW_TYPE_COMBO)
573
DBG("NET_WM_WINDOW_TYPE_COMBO\n");
576
else if(state[num3] == NETWM::NET_WM_WINDOW_TYPE_DND)
578
DBG("NET_WM_WINDOW_TYPE_DND\n");
581
else if(state[num3] == NETWM::NET_WM_WINDOW_TYPE_NORMAL)
583
DBG("NET_WM_WINDOW_TYPE_NORMAL\n");
593
QString NETWM::icccmString(Window win, Atom atom)
600
if(!(data = (char *)NETWM::property(win, atom, XA_STRING)))
603
s = QString::fromUtf8(data);
610
QString NETWM::icccmUtf8String(Window win, Atom atom)
624
result = XGetWindowProperty(QX11Info::display(), win, atom, 0, LONG_MAX, False,
625
NETWM::UTF8_STRING, &type, &format, &nitems,
628
if(result != Success || type == None || !tmp)
631
if(type == NETWM::UTF8_STRING && format == 8 && nitems != 0)
632
val = QString::fromUtf8(reinterpret_cast<char *>(tmp));
639
QString NETWM::icccmWindowRole(Window win)
643
return NETWM::icccmString(win, NETWM::WM_WINDOW_ROLE);
646
QStringList NETWM::icccmClass(Window win)
653
if(!(data = (char *)NETWM::property(win, NETWM::WM_CLASS, XA_STRING)))
656
l.append(QString::fromUtf8(data));
657
l.append(QString::fromUtf8(data+strlen(data)+1));
664
QString NETWM::icccmName(Window win)
668
return NETWM::icccmString(win, NETWM::WM_NAME);
671
QStringList NETWM::icccmCommand(Window win)
679
if(!XGetCommand(QX11Info::display(), win, &argv, &argc))
682
for(int i = 0;i < argc;i++)
683
list.append(argv[i]);
685
XFreeStringList(argv);
690
#define MO_NETWM_OPAQUE 0xffffffff
692
void NETWM::transset(Window window, double d)
696
Display *dpy = QX11Info::display();
698
uint opacity = (uint)(d * MO_NETWM_OPAQUE);
700
if(opacity == MO_NETWM_OPAQUE)
701
XDeleteProperty(dpy, window, NETWM::NET_WM_WINDOW_OPACITY);
703
XChangeProperty(dpy, window, NETWM::NET_WM_WINDOW_OPACITY,
704
XA_CARDINAL, 32, PropModeReplace, (uchar *)&opacity, 1L);
710
bool NETWM::isComposite()
712
int event_base, error_base;
714
Display *dpy = QX11Info::display();
716
// extension is not supported
717
if(!XCompositeQueryExtension(dpy, &event_base, &error_base))
719
qDebug("NETWM: Composite extension is not supported");
723
// NETWM-compliant composite manager MUST set selection owner
725
Window owner = XGetSelectionOwner(dpy, XInternAtom(dpy, "_NET_WM_CM_S0", False));
727
return (owner != None);
731
void NETWM::checkInit()