1 /****************************************************************************
2 * *
3 * X11tools *
4 * Copyright (C) 2008-2014 Piotr Dąbrowski ultr@ultr.pl *
5 * Copyright (C) 2011 Przemysław Rudy prudy1@o2.pl *
6 * *
7 * This program is free software: you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation, either version 2 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
19 * *
20 ****************************************************************************/
21
22
23
24
25 #include <list>
26 #include <unistd.h>
27
28 #include <X11/Xatom.h>
29 #include <X11/Xlib.h>
30 #include <X11/Xmd.h>
31 #include <X11/Xresource.h>
32 #include <X11/Xutil.h>
33
34 #include "x11tools.h"
35
36
37
38
X11_getCardinalProperty(Display * display,Window window,const char * propertyName,uint32_t * value,long offset)39 bool X11_getCardinalProperty( Display *display, Window window, const char *propertyName, uint32_t *value, long offset )
40 {
41 Atom property = XInternAtom( display, propertyName, False );
42 if( property == None )
43 return false;
44 uint32_t *data = NULL; Atom realtype; int realformat; unsigned long nitems, left;
45 int result = XGetWindowProperty( display, window, property, offset, 1L, False, XA_CARDINAL, &realtype, &realformat, &nitems, &left, (unsigned char**)&data );
46 if( result == Success )
47 {
48 if( realtype == XA_CARDINAL )
49 {
50 if( nitems > 0 )
51 {
52 *value = data[0];
53 XFree( data );
54 return true;
55 }
56 }
57 XFree( data );
58 }
59 return false;
60 }
61
62
X11_getFirstPropertyAtom(Display * display,Window window,const char * propertyName,Atom * value)63 bool X11_getFirstPropertyAtom( Display *display, Window window, const char *propertyName, Atom *value )
64 {
65 Atom property = XInternAtom( display, propertyName, False );
66 if( property == None )
67 return false;
68 Atom *data = NULL; Atom realtype; int realformat; unsigned long nitems, left;
69 int result = XGetWindowProperty( display, window, property, 0L, 1L, False, XA_ATOM, &realtype, &realformat, &nitems, &left, (unsigned char**)&data );
70 if( result == Success )
71 {
72 if( realtype == XA_ATOM )
73 {
74 if( nitems > 0 )
75 {
76 *value = data[0L];
77 XFree( data );
78 return true;
79 }
80 }
81 XFree( data );
82 }
83 return false;
84 }
85
86
X11_isPropertyAtomSet(Display * display,Window window,const char * propertyName,const char * atomName)87 bool X11_isPropertyAtomSet( Display *display, Window window, const char *propertyName, const char *atomName )
88 {
89 Atom property = XInternAtom( display, propertyName, False );
90 if( property == None )
91 return false;
92 Atom atom = XInternAtom( display, atomName, False );
93 if( atom == None )
94 return false;
95 Atom *atoms = NULL; Atom realtype; int realformat; unsigned long nitems, left;
96 int result = XGetWindowProperty( display, window, property, 0L, 8192L, False, XA_ATOM, &realtype, &realformat, &nitems, &left, (unsigned char**)&atoms );
97 if( result != Success )
98 return false;
99 if( realtype != XA_ATOM )
100 return false;
101 for( unsigned long k = 0; k < nitems; k++ )
102 {
103 if( atoms[k] == atom )
104 {
105 XFree( atoms );
106 return true;
107 }
108 }
109 XFree( atoms );
110 return false;
111 }
112
113
114
115
X11_getResolution(Display * display)116 std::pair<int,int> X11_getResolution( Display *display )
117 {
118 return X11_getWindowSize( display, DefaultRootWindow( display ) );
119 // neither XDisplayWidth/XDisplayHeight nor _NET_WORKAREA work for Gnome :|
120 // they do not get updated after resolution change
121 }
122
123
X11_getDesktopSize(Display * display)124 std::pair<int,int> X11_getDesktopSize( Display *display )
125 {
126 uint32_t width;
127 if( ! X11_getCardinalProperty( display, DefaultRootWindow( display ), "_NET_DESKTOP_GEOMETRY", &width, 0 ) )
128 return std::make_pair( 0, 0 );
129 uint32_t height;
130 if( ! X11_getCardinalProperty( display, DefaultRootWindow( display ), "_NET_DESKTOP_GEOMETRY", &height, 1 ) )
131 return std::make_pair( 0, 0 );
132 return std::make_pair( width, height );
133 }
134
135
136
137
X11_getMousePos(Display * display)138 std::pair<int,int> X11_getMousePos( Display *display )
139 {
140 int x = 0;
141 int y = 0;
142 Window root;
143 Window child;
144 int winx, winy;
145 unsigned int mask;
146 XQueryPointer( display, DefaultRootWindow( display ), &root, &child, &x, &y, &winx, &winy, &mask );
147 return std::make_pair( x, y );
148 }
149
150
151
152
X11_isPointerGrabbed(Display * display)153 bool X11_isPointerGrabbed( Display *display )
154 {
155 int status = XGrabPointer(
156 display,
157 DefaultRootWindow( display ),
158 True,
159 ButtonReleaseMask | ButtonMotionMask | ButtonPressMask,
160 GrabModeAsync,
161 GrabModeAsync,
162 None,
163 None,
164 0xFFFFFFFFL
165 );
166 if( status == AlreadyGrabbed )
167 return true;
168 if( status == GrabInvalidTime )
169 {
170 _x11toolsdebug( "[TIME]" );
171 }
172 if( status == GrabSuccess )
173 {
174 _x11toolsdebug( "[GRAB]" );
175 XUngrabPointer( display, CurrentTime );
176 XFlush( display );
177 }
178 return false;
179 }
180
181
182
183
X11_isFreeDesktopCompatible(Display * display)184 bool X11_isFreeDesktopCompatible( Display *display )
185 {
186 if( X11_getDesktopsCount( display, true ) != 1 ) // _NET multiple desktops, FreeDesktop compatible
187 return true;
188 std::pair<int,int> resolution = X11_getResolution( display );
189 std::pair<int,int> desktopsize = X11_getDesktopSize( display );
190 if( resolution == desktopsize ) // one desktop only, so we don't have to care
191 return true;
192 if (resolution.first == 0)
193 return false;
194 if( ( desktopsize.first % resolution.first != 0 ) || ( desktopsize.second % resolution.second != 0 ) ) // virtual resolution
195 return true;
196 // not FreeDesktop compatible :(
197 return false;
198 }
199
200
201
202
X11_getDesktopsCount(Display * display,bool forceFreeDesktop)203 uint32_t X11_getDesktopsCount( Display *display, bool forceFreeDesktop )
204 {
205 if( ( ! forceFreeDesktop ) && ( ! X11_isFreeDesktopCompatible( display ) ) )
206 {
207 std::pair<int,int> resolution = X11_getResolution( display );
208 std::pair<int,int> desktopsize = X11_getDesktopSize( display );
209 return static_cast<uint32_t>(( desktopsize.second / resolution.second ) * ( desktopsize.first / resolution.first ));
210 }
211 else
212 {
213 uint32_t value;
214 if( ! X11_getCardinalProperty( display, DefaultRootWindow( display ), "_NET_NUMBER_OF_DESKTOPS", &value ) )
215 return 1; // 0 desktops doesn't make sense, even Compiz returns 1 ()
216 return value;
217 }
218 }
219
220
X11_getCurrentDesktop(Display * display,bool forceFreeDesktop)221 uint32_t X11_getCurrentDesktop( Display *display, bool forceFreeDesktop )
222 {
223 if( ( ! forceFreeDesktop ) && ( ! X11_isFreeDesktopCompatible( display ) ) )
224 {
225 uint32_t dx = 0, dy = 0;
226 X11_getCardinalProperty( display, DefaultRootWindow( display ), "_NET_DESKTOP_VIEWPORT", &dx, 0 );
227 X11_getCardinalProperty( display, DefaultRootWindow( display ), "_NET_DESKTOP_VIEWPORT", &dy, 1 );
228 std::pair<int,int> desktopsize = X11_getDesktopSize( display );
229 std::pair<int,int> resolution = X11_getResolution( display );
230 if (resolution.second == 0)
231 return 0;
232 uint32_t desktop = static_cast<uint32_t>(( static_cast<int>(dy) / resolution.second ) * ( desktopsize.first / resolution.first ) + ( static_cast<int>(dx) / resolution.first ));
233 return desktop;
234 }
235 else
236 {
237 uint32_t desktop;
238 if( ! X11_getCardinalProperty( display, DefaultRootWindow( display ), "_NET_CURRENT_DESKTOP", &desktop ) )
239 return X11_NODESKTOP;
240 return desktop;
241 }
242 }
243
244
X11_setCurrentDesktop(Display * display,uint32_t desktop,bool forceFreeDesktop)245 void X11_setCurrentDesktop( Display *display, uint32_t desktop, bool forceFreeDesktop )
246 {
247 if( ( desktop != X11_ALLDESKTOPS ) && ( desktop != X11_NODESKTOP ) && ( desktop != X11_getCurrentDesktop( display, forceFreeDesktop ) ) )
248 {
249 // generate MouseLeave event
250 int rootx, rooty, windowx, windowy;
251 Window window = X11_getWindowUnderCursor( display, &rootx, &rooty, &windowx, &windowy );
252 if( window != None )
253 {
254 XEvent xev;
255 xev.type = LeaveNotify;
256 xev.xcrossing.type = LeaveNotify;
257 xev.xcrossing.serial = 0;
258 xev.xcrossing.send_event = False;
259 xev.xcrossing.display = display;
260 xev.xcrossing.window = window;
261 xev.xcrossing.root = DefaultRootWindow( display );
262 xev.xcrossing.subwindow = None;
263 xev.xcrossing.time = CurrentTime;
264 xev.xcrossing.x = windowx;
265 xev.xcrossing.y = windowy;
266 xev.xcrossing.x_root = rootx;
267 xev.xcrossing.y_root = rooty;
268 xev.xcrossing.mode = NotifyNormal;
269 xev.xcrossing.detail = NotifyNonlinear;
270 xev.xcrossing.same_screen = True;
271 xev.xcrossing.focus = True;
272 xev.xcrossing.state = 0;
273 XSendEvent( display, window, True, LeaveWindowMask, &xev );
274 XFlush( display );
275 }
276 // change desktop
277 if( ( ! forceFreeDesktop ) && ( ! X11_isFreeDesktopCompatible( display ) ) )
278 {
279 std::pair<int,int> desktopsize = X11_getDesktopSize( display );
280 std::pair<int,int> resolution = X11_getResolution( display );
281 uint32_t dx = ( desktop % ( static_cast<uint32_t>(desktopsize.first / resolution.first) ) ) * static_cast<uint32_t>(resolution.first);
282 uint32_t dy = ( desktop / ( static_cast<uint32_t>(desktopsize.first / resolution.first) ) ) * static_cast<uint32_t>(resolution.second);
283 XEvent xev;
284 xev.type = ClientMessage;
285 xev.xclient.type = ClientMessage;
286 xev.xclient.serial = 0;
287 xev.xclient.send_event = True;
288 xev.xclient.display = display;
289 xev.xclient.window = DefaultRootWindow( display );
290 xev.xclient.message_type = XInternAtom( display, "_NET_DESKTOP_VIEWPORT", False );
291 xev.xclient.format = 32;
292 xev.xclient.data.l[0] = dx;
293 xev.xclient.data.l[1] = dy;
294 xev.xclient.data.l[2] = 0;
295 xev.xclient.data.l[3] = 0;
296 xev.xclient.data.l[4] = 0;
297 XSendEvent( display, DefaultRootWindow( display ), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev );
298 XFlush( display );
299 }
300 else
301 {
302 XEvent xev;
303 xev.type = ClientMessage;
304 xev.xclient.type = ClientMessage;
305 xev.xclient.serial = 0;
306 xev.xclient.send_event = True;
307 xev.xclient.display = display;
308 xev.xclient.window = DefaultRootWindow( display );
309 xev.xclient.message_type = XInternAtom( display, "_NET_CURRENT_DESKTOP", False );
310 xev.xclient.format = 32;
311 xev.xclient.data.l[0] = desktop;
312 xev.xclient.data.l[1] = CurrentTime;
313 xev.xclient.data.l[2] = 0;
314 xev.xclient.data.l[3] = 0;
315 xev.xclient.data.l[4] = 0;
316 XSendEvent( display, DefaultRootWindow( display ), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev );
317 }
318 }
319 }
320
321
X11_getDesktopOfWindow(Display * display,Window window,bool forceFreeDesktop,bool windowareadecides)322 uint32_t X11_getDesktopOfWindow( Display *display, Window window, bool forceFreeDesktop, bool windowareadecides )
323 {
324 if( ( ! forceFreeDesktop ) && ( ! X11_isFreeDesktopCompatible( display ) ) )
325 {
326 uint32_t currentdesktop = X11_getCurrentDesktop( display, forceFreeDesktop );
327 std::pair<int,int> pos = X11_getWindowPos( display, window );
328 std::pair<int,int> desktopsize = X11_getDesktopSize( display );
329 std::pair<int,int> resolution = X11_getResolution( display );
330 if( windowareadecides )
331 {
332 std::pair<int,int> size = X11_getWindowSize( display, window );
333 pos.first += size.first / 2;
334 pos.second += size.second / 2;
335 pos.second %= desktopsize.second;
336 }
337 uint32_t desktopofwindow = currentdesktop
338 + static_cast<uint32_t>(( pos.second / resolution.second ) * ( desktopsize.first / resolution.first ) + ( pos.first / resolution.first ));
339 if( pos.first < 0 )
340 desktopofwindow -= 1;
341 if( pos.second < 0 )
342 desktopofwindow -= static_cast<uint32_t>( desktopsize.first / resolution.first );
343 desktopofwindow %= X11_getDesktopsCount( display, forceFreeDesktop );
344 return desktopofwindow;
345 }
346 else
347 {
348 uint32_t desktopofwindow;
349 if( ! X11_getCardinalProperty( display, window, "_NET_WM_DESKTOP", &desktopofwindow ) )
350 return X11_NODESKTOP;
351 return desktopofwindow;
352 }
353 }
354
355
X11_moveWindowToDesktop(Display * display,Window window,uint32_t desktop,bool forceFreeDesktop,bool position,int x,int y)356 void X11_moveWindowToDesktop( Display *display, Window window, uint32_t desktop, bool forceFreeDesktop, bool position, int x, int y )
357 {
358 if( ( ! forceFreeDesktop ) && ( ! X11_isFreeDesktopCompatible( display ) ) )
359 {
360 std::pair<int,int> pos = X11_getWindowPos( display, window );
361 std::pair<int,int> desktopsize = X11_getDesktopSize( display );
362 std::pair<int,int> resolution = X11_getResolution( display );
363 uint32_t desktopofwindow = X11_getDesktopOfWindow( display, window, forceFreeDesktop );
364 uint32_t ddx = ( desktop % static_cast<uint32_t>( desktopsize.first / resolution.first ) ) - ( desktopofwindow % static_cast<uint32_t>( desktopsize.first / resolution.first ) );
365 uint32_t ddy = ( desktop / static_cast<uint32_t>( desktopsize.first / resolution.first ) ) - ( desktopofwindow / static_cast<uint32_t>( desktopsize.first / resolution.first ) );
366 int newx, newy;
367 if( position )
368 {
369 int oldx = pos.first % resolution.first;
370 if( oldx < 0 )
371 oldx += resolution.first;
372 int oldy = pos.second % resolution.second;
373 if( oldy < 0 )
374 oldy += resolution.second;
375 newx = ( pos.first - oldx + x ) + static_cast<int>(ddx) * resolution.first;
376 newy = ( pos.second - oldy + y ) + static_cast<int>(ddy) * resolution.second;
377 }
378 else
379 {
380 newx = pos.first + static_cast<int>(ddx) * resolution.first;
381 newy = pos.second + static_cast<int>(ddy) * resolution.second;
382 }
383 X11_moveWindow( display, window, newx, newy );
384 }
385 else
386 {
387 XEvent xev;
388 xev.type = ClientMessage;
389 xev.xclient.type = ClientMessage;
390 xev.xclient.display = display;
391 xev.xclient.window = window;
392 xev.xclient.message_type = XInternAtom( display, "_NET_WM_DESKTOP", False);
393 xev.xclient.format = 32;
394 xev.xclient.data.l[0] = desktop;
395 xev.xclient.data.l[1] = 2; /* indicate we are messaging from a pager */
396 XSendEvent( display, DefaultRootWindow( display ), False, SubstructureNotifyMask | SubstructureRedirectMask, &xev );
397 XFlush( display );
398 if( position )
399 X11_moveWindow( display, window, x, y );
400 }
401 }
402
403
X11_isWindowOnDesktop(Display * display,Window window,uint32_t desktop,bool forceFreeDesktop)404 bool X11_isWindowOnDesktop( Display *display, Window window, uint32_t desktop, bool forceFreeDesktop )
405 {
406 if( ( ! forceFreeDesktop ) && ( ! X11_isFreeDesktopCompatible( display ) ) )
407 {
408 uint32_t desktopofwindow = X11_getDesktopOfWindow( display, window, forceFreeDesktop );
409 return ( desktopofwindow == desktop );
410 }
411 else
412 {
413 uint32_t desktopofwindow = X11_getDesktopOfWindow( display, window, forceFreeDesktop );
414 if( desktopofwindow == X11_ALLDESKTOPS )
415 return true;
416 return ( desktopofwindow == desktop );
417 }
418 }
419
420
X11_isWholeWindowOnOneDesktop(Display * display,Window window)421 bool X11_isWholeWindowOnOneDesktop( Display *display, Window window )
422 {
423 std::pair<int,int> pos = X11_getWindowPos( display, window );
424 std::pair<int,int> size = X11_getWindowSize( display, window );
425 std::pair<int,int> resolution = X11_getResolution( display );
426 if( ( pos.first < 0 ) && ( pos.first + size.first > 0 ) )
427 return false;
428 if( ( pos.first > 0 ) && ( pos.first + size.first < 0 ) )
429 return false;
430 if( ( pos.second < 0 ) && ( pos.second + size.second > 0 ) )
431 return false;
432 if( ( pos.second > 0 ) && ( pos.second + size.second < 0 ) )
433 return false;
434 if( ( pos.first / resolution.first ) != ( ( pos.first + size.first - 1 ) / resolution.first ) )
435 return false;
436 if( ( pos.second / resolution.second ) != ( ( pos.second + size.second - 1 ) / resolution.second ) )
437 return false;
438 return true;
439 }
440
441
X11_isWindowCovered(Display * display,Window window)442 bool X11_isWindowCovered( Display *display, Window window )
443 {
444 bool notypes = true;
445 Window parent = window;
446 Window root;
447 Window *children = NULL;
448 unsigned int nchildren;
449 while( ( parent != None ) && ( parent != DefaultRootWindow( display ) ) )
450 {
451 window = parent;
452 XQueryTree( display, window, &root, &parent, &children, &nchildren );
453 XFree( children );
454 Atom type = None;
455 if( X11_getFirstPropertyAtom( display, window, "_NET_WM_WINDOW_TYPE", &type ) )
456 notypes = false;
457 }
458 int x, y;
459 unsigned int width, height, border, depth;
460 XGetGeometry( display, window, &root, &x, &y, &width, &height, &border, &depth );
461 int x1 = x;
462 int y1 = y;
463 int x2 = x + static_cast<int>(width);
464 int y2 = y + static_cast<int>(height);
465 XQueryTree( display, DefaultRootWindow( display ), &root, &parent, &children, &nchildren );
466 if( children != NULL )
467 {
468 unsigned int k = 0;
469 while( k < nchildren )
470 {
471 if( children[k] == window )
472 break;
473 k++;
474 }
475 k++;
476 Atom type_dock = XInternAtom( display, "_NET_WM_WINDOW_TYPE_DOCK" , False );
477 Atom type_toolbar = XInternAtom( display, "_NET_WM_WINDOW_TYPE_TOOLBAR" , False );
478 Atom type_menu = XInternAtom( display, "_NET_WM_WINDOW_TYPE_MENU" , False );
479 Atom type_dropdownmenu = XInternAtom( display, "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU", False );
480 Atom type_popupmenu = XInternAtom( display, "_NET_WM_WINDOW_TYPE_POPUP_MENU" , False );
481 Atom type_combo = XInternAtom( display, "_NET_WM_WINDOW_TYPE_COMBO" , False );
482 uint32_t currentdesktop = X11_getCurrentDesktop( display );
483 for( ; k < nchildren ; k++ )
484 {
485 if( children[k] == window )
486 continue;
487 if( ! X11_isWindowOnDesktop( display, children[k], currentdesktop ) )
488 if( X11_getDesktopOfWindow( display, children[k] ) != X11_NODESKTOP )
489 continue;
490 XWindowAttributes attr;
491 XGetWindowAttributes( display, children[k], &attr );
492 if( attr.map_state != IsViewable )
493 continue;
494 std::pair<int,int> pos2 = X11_getWindowPos( display, children[k] );
495 std::pair<int,int> size2 = X11_getWindowSize( display, children[k] );
496 int X1 = pos2.first;
497 int Y1 = pos2.second;
498 int X2 = pos2.first + size2.first;
499 int Y2 = pos2.second + size2.second;
500 if( ( ( x1 <= X1 && X1 <= x2 ) || ( x1 <= X2 && X2 <= x2 ) || ( x1 >= X1 && x2 <= X2 ) )
501 && ( ( y1 <= Y1 && Y1 <= y2 ) || ( y1 <= Y2 && Y2 <= y2 ) || ( y1 >= Y1 && y2 <= Y2 ) )
502 )
503 {
504 Atom type = None;
505 bool hastype = false;
506 std::list<Window> windows;
507 windows.push_back( children[k] );
508 Window *children2 = NULL;
509 unsigned int nchildren2;
510 while( true )
511 {
512 if( windows.empty() )
513 break;
514 Window w = *(windows.begin());
515 windows.pop_front();
516 if( X11_getFirstPropertyAtom( display, w, "_NET_WM_WINDOW_TYPE", &type ) )
517 hastype = true;
518 if( hastype )
519 break;
520 XQueryTree( display, w, &root, &parent, &children2, &nchildren2 );
521 if( ( nchildren2 > 0 ) && ( children2 != NULL ) )
522 {
523 unsigned int k2 = nchildren2;
524 while (k2 > 0)
525 windows.push_back(children2[--k2]);
526
527 XFree( children2 );
528 children2 = NULL;
529 }
530 }
531 windows.clear();
532 if(
533 ( notypes && ( ! hastype ) ) ||
534 ( hastype &&
535 ( type != type_dock ) && ( type != type_toolbar ) && ( type != type_menu ) &&
536 ( type != type_dropdownmenu ) && ( type != type_popupmenu ) && ( type != type_combo )
537 )
538 )
539 {
540 XFree( children );
541 return true;
542 }
543 }
544 }
545 XFree( children );
546 }
547 return false;
548 }
549
550
X11_isWindowShaded(Display * display,Window window)551 bool X11_isWindowShaded( Display *display, Window window )
552 {
553 return X11_isPropertyAtomSet( display, window, "_NET_WM_STATE", "_NET_WM_STATE_SHADED" );
554 }
555
X11_shadeWindow(Display * display,Window window,bool shade)556 void X11_shadeWindow( Display *display, Window window, bool shade )
557 {
558 X11_windowSendXEvent( display, window, "_NET_WM_STATE", "_NET_WM_STATE_SHADED", shade );
559 }
560
X11_isWindowMinimized(Display * display,Window window)561 bool X11_isWindowMinimized( Display *display, Window window )
562 {
563 if (X11_isPropertyAtomSet( display, window, "_NET_WM_STATE", "_NET_WM_STATE_HIDDEN" ))
564 {
565 return true;
566 }
567
568 Atom r_type;
569 int r_format;
570 unsigned long count, after;
571
572 unsigned char *p = nullptr;
573
574 Atom property = XInternAtom(display, "WM_STATE", False);
575 if (property == None)
576 return false;
577 if (!XGetWindowProperty(display, window, property, 0, 2, False, property,
578 &r_type, &r_format, &count, &after, &p))
579 {
580 if (!p)
581 return true;
582 auto ret = (long)*p == 3;
583 XFree(p);
584 return ret;
585 }
586
587 return false;
588 }
589
X11_getWindowPos(Display * display,Window window)590 std::pair<int,int> X11_getWindowPos( Display *display, Window window )
591 {
592 if( window == None )
593 return std::make_pair( 0, 0 );
594 Window parent = window;
595 Window root;
596 Window *children;
597 unsigned int nchildren;
598 if( window != DefaultRootWindow( display ) )
599 {
600 while( ( parent != 0x0 ) && ( parent != DefaultRootWindow( display ) ) )
601 {
602 window = parent;
603 if( XQueryTree( display, window, &root, &parent, &children, &nchildren ) == 0 )
604 return std::make_pair( 0, 0 );
605 XFree( children );
606 }
607 }
608 int x, y;
609 unsigned int width, height, border, depth;
610 if( XGetGeometry( display, window, &root, &x, &y, &width, &height, &border, &depth ) == 0 )
611 return std::make_pair( 0, 0 );
612 return std::make_pair( x, y );
613 }
614
615
X11_getWindowSize(Display * display,Window window)616 std::pair<int,int> X11_getWindowSize( Display *display, Window window )
617 {
618 if( window == None )
619 return std::make_pair( 0, 0 );
620 Window parent = window;
621 Window root;
622 Window *children;
623 unsigned int nchildren;
624 if( window != DefaultRootWindow( display ) )
625 {
626 while( ( parent != 0x0 ) && ( parent != DefaultRootWindow( display ) ) )
627 {
628 window = parent;
629 if( XQueryTree( display, window, &root, &parent, &children, &nchildren ) == 0 )
630 return std::make_pair( 0, 0 );
631 XFree( children );
632 }
633 }
634 int x, y;
635 unsigned int width, height, border, depth;
636 if( XGetGeometry( display, window, &root, &x, &y, &width, &height, &border, &depth ) == 0 )
637 return std::make_pair( 0, 0 );
638 return std::make_pair( width + 2*border, height + 2*border );
639 }
640
641
X11_getWindowFramelessSize(Display * display,Window window)642 std::pair<int,int> X11_getWindowFramelessSize( Display *display, Window window )
643 {
644 Window root;
645 int x, y;
646 unsigned int width, height, border, depth;
647 if( XGetGeometry( display, window, &root, &x, &y, &width, &height, &border, &depth ) == 0 )
648 return std::make_pair( 0, 0 );
649 return std::make_pair( width - 2*border, height - 2*border );
650 }
651
652
X11_moveWindow(Display * display,Window window,int x,int y)653 void X11_moveWindow( Display *display, Window window, int x, int y )
654 {
655 XMoveWindow( display, window, x, y );
656 XFlush( display );
657 }
658
659
X11_centerWindow(Display * display,Window window,uint32_t desktop,bool forceFreeDesktop)660 void X11_centerWindow( Display *display, Window window, uint32_t desktop, bool forceFreeDesktop )
661 {
662 if( desktop == X11_NODESKTOP )
663 desktop = X11_getCurrentDesktop( display, forceFreeDesktop );
664 if( ( ! forceFreeDesktop ) && ( ! X11_isFreeDesktopCompatible( display ) ) )
665 {
666 std::pair<int,int> resolution = X11_getResolution( display );
667 std::pair<int,int> size = X11_getWindowSize( display, window );
668 int cx = ( resolution.first - size.first ) / 2;
669 int cy = ( resolution.second - size.second ) / 2;
670 X11_moveWindowToDesktop( display, window, desktop, false, true, cx, cy );
671 }
672 else
673 {
674 if( X11_getDesktopOfWindow( display, window, true ) != desktop )
675 X11_moveWindowToDesktop( display, window, desktop, true );
676 std::pair<int,int> resolution = X11_getResolution( display );
677 std::pair<int,int> size = X11_getWindowSize( display, window );
678 int cx = ( resolution.first - size.first ) / 2;
679 int cy = ( resolution.second - size.second ) / 2;
680 X11_moveWindow( display, window, cx, cy );
681 }
682 }
683
684
X11_resizeWindow(Display * display,Window window,unsigned int width,unsigned int height)685 void X11_resizeWindow( Display *display, Window window, unsigned int width, unsigned int height )
686 {
687 XResizeWindow( display, window, width, height );
688 XFlush( display );
689 }
690
691
X11_setSizeHintsOfWindow(Display * display,Window window,int minwidth,int minheight,int maxwidth,int maxheight)692 void X11_setSizeHintsOfWindow( Display *display, Window window, int minwidth, int minheight, int maxwidth, int maxheight )
693 {
694 XSizeHints sizehints;
695 long supplied_return;
696 XGetWMNormalHints( display, window, &sizehints, &supplied_return );
697 sizehints.min_width = minwidth;
698 sizehints.min_height = minheight;
699 sizehints.max_width = maxwidth;
700 sizehints.max_height = maxheight;
701 sizehints.flags |= PMinSize | PMaxSize;
702 XSetWMNormalHints( display, window, &sizehints );
703 }
704
705
706
707
X11_getActiveWindow(Display * display)708 Window X11_getActiveWindow( Display *display )
709 {
710 // _NET_ACTIVE_WINDOW
711 Atom net_active_window = XInternAtom( display, "_NET_ACTIVE_WINDOW", False );
712 if( net_active_window != None )
713 {
714 Window *windowptr = NULL; Atom realtype; int realformat; unsigned long nitems, left;
715 int result = XGetWindowProperty( display, XDefaultRootWindow( display ), net_active_window, 0L, sizeof(Window), False, XA_WINDOW, &realtype, &realformat, &nitems, &left, (unsigned char**)&windowptr);
716 if( result == Success )
717 {
718 if( realtype == XA_WINDOW )
719 {
720 if( nitems > 0 )
721 {
722 Window window = *windowptr;
723 XFree( windowptr );
724 return window;
725 }
726 }
727 XFree( windowptr );
728 }
729 }
730 // XGetInputFocus
731 Window window;
732 int revertto;
733 XGetInputFocus( display, &window, &revertto );
734 return window;
735 }
736
737
X11_setActiveWindow(Display * display,Window window)738 void X11_setActiveWindow( Display *display, Window window )
739 {
740 // raise
741 XRaiseWindow( display, window );
742 // NET
743 Atom net_active_window = XInternAtom( display, "_NET_ACTIVE_WINDOW", False );
744 XEvent e;
745 e.xclient.type = ClientMessage;
746 e.xclient.message_type = net_active_window;
747 e.xclient.display = display;
748 e.xclient.window = window;
749 e.xclient.format = 32;
750 e.xclient.data.l[0] = 2l;
751 e.xclient.data.l[1] = CurrentTime;
752 e.xclient.data.l[2] = None;
753 e.xclient.data.l[3] = 0l;
754 e.xclient.data.l[4] = 0l;
755 XSendEvent( display, DefaultRootWindow( display ), False, SubstructureRedirectMask|SubstructureNotifyMask, &e );
756 }
757
758
X11_setActiveWindowCheck(Display * display,Window window,bool forceFreeDesktop)759 void X11_setActiveWindowCheck( Display *display, Window window, bool forceFreeDesktop )
760 {
761 int time = 0;
762 while( time < X11_SETACTIVEWINDOW_TIMEOUT )
763 {
764 if( X11_isWindowOnDesktop( display, window, X11_getCurrentDesktop( display ), forceFreeDesktop ) )
765 break;
766 usleep( X11_SETACTIVEWINDOW_CHECKTIME );
767 time += X11_SETACTIVEWINDOW_CHECKTIME;
768 }
769 if( ! X11_isWindowOnDesktop( display, window, X11_getCurrentDesktop( display ), forceFreeDesktop ) )
770 return;
771 X11_setActiveWindow( display, window );
772 }
773
774
X11_getTopMostWindow(Display * display)775 Window X11_getTopMostWindow( Display *display )
776 {
777 Atom listatom = None;
778 Atom type_return = None;
779 int format_return;
780 unsigned long nitems_return;
781 unsigned long bytesafter_return;
782 Window *windowarray = NULL;
783 // _NET_CLIENT_LIST_STACKING
784 listatom = XInternAtom( display, "_NET_CLIENT_LIST_STACKING", False );
785 if( XGetWindowProperty( display, DefaultRootWindow( display ), listatom, 0L, (~0L), False, XA_WINDOW, &type_return, &format_return, &nitems_return, &bytesafter_return, (unsigned char**)&windowarray ) == Success )
786 {
787 Window window = None;
788 if( (type_return == XA_WINDOW) && (format_return == 32) && (windowarray) && (nitems_return > 0) )
789 {
790 window = windowarray[nitems_return-1];
791 }
792 XFree( windowarray );
793 if( window != None )
794 return window;
795 }
796 // _NET_CLIENT_LIST
797 listatom = XInternAtom( display, "_NET_CLIENT_LIST" , False );
798 if( XGetWindowProperty( display, DefaultRootWindow( display ), listatom, 0L, (~0L), False, XA_WINDOW, &type_return, &format_return, &nitems_return, &bytesafter_return, (unsigned char**)&windowarray ) == Success )
799 {
800 Window window = None;
801 if( (type_return == XA_WINDOW) && (format_return == 32) && (windowarray) && (nitems_return > 0) )
802 {
803 window = windowarray[nitems_return-1];
804 }
805 XFree(windowarray);
806 if( window != None )
807 return window;
808 }
809 return None;
810 }
811
812
X11_getLatestCreatedWindow(Display * display)813 Window X11_getLatestCreatedWindow( Display *display )
814 {
815 Window window = None;
816 Window parent;
817 Window root;
818 Window *children = NULL;
819 unsigned int nchildren;
820 XQueryTree( display, DefaultRootWindow( display ), &root, &parent, &children, &nchildren );
821 if( children != NULL )
822 window = children[nchildren-1];
823 XFree( children );
824 return window;
825 }
826
827
828
829
X11_getWindowUnderCursor(Display * display,int * rootx,int * rooty,int * windowx,int * windowy)830 Window X11_getWindowUnderCursor( Display *display, int *rootx, int *rooty, int *windowx, int *windowy )
831 {
832 Window root = DefaultRootWindow( display );
833 Window window = None;
834 int _rootx, _rooty, _windowx, _windowy;
835 unsigned int mask;
836 XQueryPointer( display, root, &root, &window,
837 ( rootx ? rootx : &_rootx ),
838 ( rooty ? rooty : &_rooty ),
839 ( windowx ? windowx : &_windowx ),
840 ( windowy ? windowy : &_windowy ),
841 &mask
842 );
843 return window;
844 }
845
846
X11_getInnerMostWindowUnderCursor(Display * display,int * rootx,int * rooty,int * windowx,int * windowy)847 Window X11_getInnerMostWindowUnderCursor( Display *display, int *rootx, int *rooty, int *windowx, int *windowy )
848 {
849 Window root = DefaultRootWindow( display );
850 Window child = root;
851 Window window;
852 int _rootx, _rooty, _windowx, _windowy;
853 unsigned int mask;
854 do
855 {
856 window = child;
857 XQueryPointer( display, window, &root, &child,
858 ( rootx ? rootx : &_rootx ),
859 ( rooty ? rooty : &_rooty ),
860 ( windowx ? windowx : &_windowx ),
861 ( windowy ? windowy : &_windowy ),
862 &mask
863 );
864 } while ( ( child != None ) && ( child != window ) );
865 return window;
866 }
867
868
869
870
X11_getWindowClass(Display * display,Window window)871 std::string X11_getWindowClass( Display *display, Window window )
872 {
873 XClassHint classhint;
874 if( XGetClassHint( display, window, &classhint ) == 0 ) // 0 means error
875 return "";
876 std::string classstring;
877 classstring += classhint.res_name;
878 classstring += ' ';
879 classstring += classhint.res_class;
880 XFree( classhint.res_name );
881 XFree( classhint.res_class );
882 return classstring;
883 }
884
885
X11_getWindowRole(Display * display,Window window)886 std::string X11_getWindowRole( Display *display, Window window )
887 {
888 XTextProperty textproperty;
889 std::string s = "";
890 Atom _XA_WM_WINDOW_ROLE = XInternAtom( display, "WM_WINDOW_ROLE", False );
891 if( XGetTextProperty( display, window, &textproperty, _XA_WM_WINDOW_ROLE ) )
892 {
893 if( textproperty.encoding == XA_STRING && textproperty.format == 8 && textproperty.nitems > 0 )
894 s += (char *)textproperty.value;
895 }
896 XFree( textproperty.value );
897 return s;
898 }
899
900
901
902
X11_windowSendXEvent(Display * display,Window window,const char * type,const char * message,bool set)903 void X11_windowSendXEvent( Display *display, Window window, const char *type, const char *message, bool set )
904 {
905 Atom atomtype = XInternAtom( display, type , False );
906 Atom atommessage = XInternAtom( display, message, False );
907 XEvent xev;
908 xev.type = ClientMessage;
909 xev.xclient.type = ClientMessage;
910 xev.xclient.serial = 0;
911 xev.xclient.send_event = True;
912 xev.xclient.window = window;
913 xev.xclient.message_type = atomtype;
914 xev.xclient.format = 32;
915 xev.xclient.data.l[0] = ( set ? 1 : 0 );
916 xev.xclient.data.l[1] = static_cast<long>(atommessage);
917 xev.xclient.data.l[2] = 0;
918 xev.xclient.data.l[3] = 0;
919 xev.xclient.data.l[4] = 0;
920 XSendEvent( display, DefaultRootWindow( display ), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev );
921 XFlush( display );
922 }
923
924
X11_windowChangeProperty(Display * display,Window window,const char * property,const char * value)925 void X11_windowChangeProperty( Display *display, Window window, const char *property, const char *value )
926 {
927 Atom atomproperty = XInternAtom( display, property, False );
928 Atom atomvalue = XInternAtom( display, value , False );
929 XChangeProperty( display, window, atomproperty, XA_ATOM, 32, PropModeReplace, (unsigned char *)&atomvalue, 1 );
930 }
931
932
X11_windowSetDecoration(Display * display,Window window,bool set)933 void X11_windowSetDecoration( Display *display, Window window, bool set )
934 {
935 MotifWMHints hints;
936 Atom atom = XInternAtom( display, "_MOTIF_WM_HINTS", False );
937 if( atom != None)
938 {
939 hints.flags = MWM_HINTS_DECORATIONS;
940 hints.decorations = ( set ? 1 : 0 );
941 XChangeProperty( display, window, atom, atom, 32, PropModeReplace, (unsigned char *)&hints, 5 );
942 }
943 }
944
945
946
947
X11_checkFullScreen(Display * display)948 bool X11_checkFullScreen( Display *display )
949 {
950 _x11toolsdebug( "[A]" );
951 Window wa = X11_getActiveWindow( display );
952 if( wa != None )
953 if( X11_isPropertyAtomSet( display, wa, "_NET_WM_STATE", "_NET_WM_STATE_FULLSCREEN" ) )
954 return true;
955 _x11toolsdebug( "[B]" )
956 Window wt = X11_getTopMostWindow( display );
957 if( wt != None )
958 if( X11_isPropertyAtomSet( display, wt, "_NET_WM_STATE", "_NET_WM_STATE_FULLSCREEN" ) )
959 return true;
960 _x11toolsdebug( "[C]" );
961 std::pair<int,int> resolution = X11_getResolution( display );
962 _x11toolsdebug( "[RES=%dx%d]", resolution.first, resolution.second );
963 _x11toolsdebug( "[wa=%dx%d]", X11_getWindowSize( display, wa ).first, X11_getWindowSize( display, wa ).second );
964 _x11toolsdebug( "[wt=%dx%d]", X11_getWindowSize( display, wt ).first, X11_getWindowSize( display, wt ).second );
965 uint32_t currentdesktop = X11_getCurrentDesktop( display );
966 _x11toolsdebug( "[cD=%d]", currentdesktop );
967 if( X11_isPointerGrabbed( display ) )
968 {
969 _x11toolsdebug( "[D]" );
970 if( wt != None )
971 if( X11_getWindowSize( display, wt ) == resolution )
972 {
973 _x11toolsdebug( "[D2]" );
974 if(
975 X11_isPropertyAtomSet( display, wt, "_NET_WM_STATE", "_NET_WM_STATE_MAXIMIZED_HORZ" ) &&
976 X11_isPropertyAtomSet( display, wt, "_NET_WM_STATE", "_NET_WM_STATE_MAXIMIZED_VERT" ) &&
977 X11_isWindowOnDesktop( display, wt, currentdesktop )
978 )
979 return false;
980 _x11toolsdebug( "[D3]" );
981 _x11toolsdebug( "[wtD=%d]", X11_getDesktopOfWindow( display, wt ) );
982 if( X11_isWindowOnDesktop( display, wt, currentdesktop ) )
983 return true;
984 _x11toolsdebug( "[D4]" );
985 }
986 _x11toolsdebug( "[E]" );
987 Window wl = X11_getLatestCreatedWindow( display );
988 _x11toolsdebug( "[wl=%dx%d]", X11_getWindowSize( display, wl ).first, X11_getWindowSize( display, wl ).second );
989 if( wl != None )
990 if( X11_getWindowSize( display, wl ) == resolution )
991 {
992 _x11toolsdebug( "[E2]" );
993 _x11toolsdebug( "[wlD=%d]", X11_getDesktopOfWindow( display, wl ) );
994 if(
995 X11_isPropertyAtomSet( display, wl, "_NET_WM_STATE", "_NET_WM_STATE_MAXIMIZED_HORZ" ) &&
996 X11_isPropertyAtomSet( display, wl, "_NET_WM_STATE", "_NET_WM_STATE_MAXIMIZED_VERT" ) &&
997 X11_isWindowOnDesktop( display, wl, currentdesktop )
998 )
999 return false;
1000 _x11toolsdebug( "[E3]" );
1001 return true;
1002 }
1003 _x11toolsdebug( "[F]" );
1004 if( wl != None )
1005 {
1006 _x11toolsdebug( "[F2]" );
1007 Atom wl_type = None;
1008 if( X11_getFirstPropertyAtom( display, wl, "_NET_WM_WINDOW_TYPE", &wl_type ) && ( wl_type != None ) )
1009 {
1010 _x11toolsdebug( "[F3]" );
1011 _x11toolsdebug( "[wlT=%d]", wl_type );
1012 Atom type_toolbar = XInternAtom( display, "_NET_WM_WINDOW_TYPE_TOOLBAR" , False );
1013 Atom type_menu = XInternAtom( display, "_NET_WM_WINDOW_TYPE_MENU" , False );
1014 Atom type_dropdownmenu = XInternAtom( display, "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU", False );
1015 Atom type_popupmenu = XInternAtom( display, "_NET_WM_WINDOW_TYPE_POPUP_MENU" , False );
1016 Atom type_combo = XInternAtom( display, "_NET_WM_WINDOW_TYPE_COMBO" , False );
1017 if(
1018 ( wl_type == type_toolbar ) ||
1019 ( wl_type == type_menu ) ||
1020 ( wl_type == type_dropdownmenu ) ||
1021 ( wl_type == type_popupmenu ) ||
1022 ( wl_type == type_combo )
1023 )
1024 {
1025 _x11toolsdebug( "[Ttoolbar=%d]" , type_toolbar );
1026 _x11toolsdebug( "[Tmenu=%d]" , type_menu );
1027 _x11toolsdebug( "[Tdropdownmenu=%d]", type_dropdownmenu );
1028 _x11toolsdebug( "[Tpopupmenu=%d]" , type_popupmenu );
1029 _x11toolsdebug( "[Tcombo=%d]" , type_combo );
1030 return false;
1031 }
1032 _x11toolsdebug( "[F4]" );
1033 }
1034 }
1035 _x11toolsdebug( "[G]" );
1036 if( ( wa != None ) && ( wt == wa ) )
1037 {
1038 _x11toolsdebug( "[G2]" );
1039 if( wl != None )
1040 {
1041 _x11toolsdebug( "[G3]" );
1042 XWindowAttributes attr;
1043 Status status = XGetWindowAttributes( display, wl, &attr );
1044 if( status != 0 )
1045 if( ( attr.all_event_masks & ( ButtonReleaseMask | KeyReleaseMask ) ) == 0 )
1046 return false;
1047 _x11toolsdebug( "[G4]" );
1048 }
1049 _x11toolsdebug( "[G5]" );
1050 return true;
1051 }
1052 _x11toolsdebug( "[I]" );
1053 return false;
1054 }
1055 _x11toolsdebug( "[Z]" );
1056 return false;
1057 }
1058
1059
1060
1061
X11_waitForWindowMapped(Display * display,Window window)1062 void X11_waitForWindowMapped( Display *display, Window window )
1063 {
1064 XEvent event;
1065 do
1066 {
1067 XMaskEvent( display, StructureNotifyMask, &event );
1068 }
1069 while( ( event.type != MapNotify ) || ( event.xmap.event != window ) );
1070 }
1071
1072
1073
1074
X11_isCompositingManagerRunning(Display * display)1075 bool X11_isCompositingManagerRunning( Display *display )
1076 {
1077 Atom netwmcms0 = XInternAtom( display, "_NET_WM_CM_S0", False );
1078 return XGetSelectionOwner( display, netwmcms0 );
1079 }
1080
1081
1082
1083
X11_setBlur(Display * display,Window window,bool enable)1084 void X11_setBlur( Display *display, Window window, bool enable )
1085 {
1086 Atom atom = XInternAtom( display, "_KDE_NET_WM_BLUR_BEHIND_REGION", False );
1087 if( atom == None )
1088 return;
1089 if( enable )
1090 XChangeProperty( display, window, atom, XA_CARDINAL, 32, PropModeReplace, NULL, 0 );
1091 else
1092 XDeleteProperty( display, window, atom );
1093 }
1094