RazorAutostartEntry => LxQt::AutostartEntry
[lxde/liblxqt.git] / xfitman.cpp
CommitLineData
4ef6cee9 1/* BEGIN_COMMON_COPYRIGHT_HEADER
29dd5476 2 * (c)LGPL2+
4ef6cee9 3 *
4 * Razor - a lightweight, Qt based, desktop toolset
5 * http://razor-qt.org
6 *
7 * Copyright: 2010-2011 Razor team
8 * Authors:
9 * Christopher "VdoP" Regali
626f1f31 10 * Alexander Sokoloff <sokoloff.a@gmail.com>
4ef6cee9 11 *
c6357562 12 * This program or library is free software; you can redistribute it
13 * and/or modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
29dd5476 15 * version 2.1 of the License, or (at your option) any later version.
4ef6cee9 16 *
c6357562 17 * This library is distributed in the hope that it will be useful,
4ef6cee9 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
c6357562 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
29dd5476 21
c6357562 22 * You should have received a copy of the GNU Lesser General
23 * Public License along with this library; if not, write to the
24 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25 * Boston, MA 02110-1301 USA
4ef6cee9 26 *
4ef6cee9 27 * END_COMMON_COPYRIGHT_HEADER */
28
29
30
31#include <QtGui/QX11Info>
32#include <QtCore/QList>
33#include <QtGui/QApplication>
34#include <QtCore/QDebug>
35#include <QtGui/QDesktopWidget>
36
37#include <stdint.h>
38#include "xfitman.h"
39
40#include <stdio.h>
41#include <stdlib.h>
42#include <X11/Xutil.h>
43#include <assert.h>
44#include <X11/Xatom.h>
45#include <X11/Xlib.h>
46
47#include <QtGui/QWidget>
ca1b12f4 48#include <QtGui/QIcon>
4ef6cee9 49/**
50 * @file xfitman.cpp
51 * @brief implements class Xfitman
52 * @author Christopher "VdoP" Regali
53 */
54
55/*
56 Some requests from Clients include type of the Client, for example the _NET_ACTIVE_WINDOW
57 message. Currently the types can be 1 for normal applications, and 2 for pagers.
58 See http://standards.freedesktop.org/wm-spec/latest/ar01s09.html#sourceindication
59 */
60#define SOURCE_NORMAL 1
61#define SOURCE_PAGER 2
62
63/*
64 _NET_WM_STATE actions
65 */
66#define _NET_WM_STATE_REMOVE 0 // remove/unset property
67#define _NET_WM_STATE_ADD 1 // add/set property
68#define _NET_WM_STATE_TOGGLE 2 // toggle property
69
70
71const XfitMan& xfitMan()
72{
73 static XfitMan instance;
74 return instance;
75}
76
77/**
78 * @brief constructor: gets Display vars and registers us
79 */
80XfitMan::XfitMan()
81{
4ef6cee9 82 root = QX11Info::appRootWindow();
4ef6cee9 83}
84
85/**
86 * @brief moves a window to a new position
87 */
88
89void XfitMan::moveWindow(Window _win, int _x, int _y) const
90{
91 XMoveWindow(QX11Info::display(), _win, _x, _y);
92}
93
94/************************************************
95
96 ************************************************/
97bool XfitMan::getWindowProperty(Window window,
98 Atom atom, // property
99 Atom reqType, // req_type
100 unsigned long* resultLen,// nitems_return
101 unsigned char** result // prop_return
102 ) const
103{
104 int format;
105 unsigned long type, rest;
106 return XGetWindowProperty(QX11Info::display(), window, atom, 0, 4096, false,
107 reqType, &type, &format, resultLen, &rest,
108 result) == Success;
109}
110
111
112/************************************************
113
114 ************************************************/
115bool XfitMan::getRootWindowProperty(Atom atom, // property
116 Atom reqType, // req_type
117 unsigned long* resultLen,// nitems_return
118 unsigned char** result // prop_return
119 ) const
120{
121 return getWindowProperty(root, atom, reqType, resultLen, result);
122}
123
124
125/**
126 * @brief this one gets the active application window.
127 */
128Window XfitMan::getActiveAppWindow() const
129{
130 Window window = getActiveWindow();
131 if (window == 0)
132 return 0;
133
134 if (acceptWindow(window))
135 return window;
136
137 Window transFor = None;
138 if (XGetTransientForHint(QX11Info::display(), window, &transFor))
139 return transFor;
140
141 return 0;
142}
143
4ef6cee9 144/**
145 * @brief returns the window that currently has inputfocus
146 */
147Window XfitMan::getActiveWindow() const
148{
149 unsigned long len;
150 unsigned long *data;
151 if (!getWindowProperty(root, atom("_NET_ACTIVE_WINDOW"), XA_WINDOW,
152 &len, (unsigned char**) &data)
153 )
154 return 0;
155
156 Window result = 0;
157 if (len)
158 result = data[0];
159
160 XFree(data);
161 return result;
162}
163
164
165/**
166 * @brief Get the number of desktops
167 */
168
169int XfitMan::getNumDesktop() const
170{
171 unsigned long length, *data;
172 getRootWindowProperty(atom("_NET_NUMBER_OF_DESKTOPS"), XA_CARDINAL, &length, (unsigned char**) &data);
173 if (data)
174 {
175 int res = data[0];
176 XFree(data);
177 return res;
178 }
179 return 0;
180}
181
182QStringList XfitMan::getDesktopNames() const
183{
184 QStringList ret;
185 unsigned long length;
186 unsigned char *data = 0;
187
188 if (getRootWindowProperty(atom("_NET_DESKTOP_NAMES"), atom("UTF8_STRING"), &length, &data))
189 {
190 if (data)
191 {
192 char* c = (char*)data;
193 char* end = (char*)data + length;
194 while (c < end)
195 {
196 ret << QString::fromUtf8(c);
197 c += strlen(c) + 1; // for trailing \0
198 }
199
200 XFree(data);
201 }
202 }
203
204
205 return ret;
206}
207
208
209QString XfitMan::getDesktopName(int desktopNum, const QString &defaultName) const
210{
211 QStringList names = getDesktopNames();
212 if (desktopNum<0 || desktopNum>names.count()-1)
213 return defaultName;
214
215 return names.at(desktopNum);
216}
217
218/**
219 * @brief resizes a window to the given dimensions
220 */
221void XfitMan::resizeWindow(Window _wid, int _width, int _height) const
222{
223 XResizeWindow(QX11Info::display(), _wid, _width, _height);
224}
225
226
227
228/**
229 * @brief gets a windowpixmap from a window
230 */
231
232bool XfitMan::getClientIcon(Window _wid, QPixmap& _pixreturn) const
233{
234 int format;
235 ulong type, nitems, extra;
236 ulong* data = 0;
237
238 XGetWindowProperty(QX11Info::display(), _wid, atom("_NET_WM_ICON"),
239 0, LONG_MAX, False, AnyPropertyType,
240 &type, &format, &nitems, &extra,
241 (uchar**)&data);
242 if (!data)
243 {
4ef6cee9 244 return false;
245 }
246
247 QImage img (data[0], data[1], QImage::Format_ARGB32);
248 for (int i=0; i<img.byteCount()/4; ++i)
249 ((uint*)img.bits())[i] = data[i+2];
250
251 _pixreturn = QPixmap::fromImage(img);
252 XFree(data);
253
254 return true;
255}
256
ca1b12f4
AS
257bool XfitMan::getClientIcon(Window _wid, QIcon *icon) const
258{
259 int format;
260 ulong type, nitems, extra;
261 ulong* data = 0;
262
263 XGetWindowProperty(QX11Info::display(), _wid, atom("_NET_WM_ICON"),
264 0, LONG_MAX, False, AnyPropertyType,
265 &type, &format, &nitems, &extra,
266 (uchar**)&data);
267 if (!data)
268 {
269 return false;
270 }
271
272 ulong* d = data;
273 while (d < data + nitems)
274 {
275 QImage img (d[0], d[1], QImage::Format_ARGB32);
276 d+=2;
277 for (int i=0; i<img.byteCount()/4; ++i, ++d)
278 ((uint*)img.bits())[i] = *d;
279
280 icon->addPixmap(QPixmap::fromImage(img));
281 }
282
283 XFree(data);
284 return true;
285}
286
4ef6cee9 287
288
289/**
290 * @brief destructor
291 */
292XfitMan::~XfitMan()
293{
294}
295/**
296 * @brief returns a windowname and sets _nameSource to the finally used Atom
297 */
298
299//i got the idea for this from taskbar-plugin of LXPanel - so credits fly out :)
8dcae6df 300QString XfitMan::getWindowTitle(Window _wid) const
4ef6cee9 301{
302 QString name = "";
303 //first try the modern net-wm ones
304 unsigned long length;
305 unsigned char *data = NULL;
306 Atom utf8Atom = atom("UTF8_STRING");
307
308 if (getWindowProperty(_wid, atom("_NET_WM_VISIBLE_NAME"), utf8Atom, &length, &data))
309 {
310 name = QString::fromUtf8((char*) data);
311 XFree(data);
312
313 }
314
315 if (name.isEmpty())
295215e2 316 {
4ef6cee9 317 if (getWindowProperty(_wid, atom("_NET_WM_NAME"), utf8Atom, &length, &data))
318 {
319 name = QString::fromUtf8((char*) data);
320 XFree(data);
321 }
295215e2 322 }
4ef6cee9 323
324 if (name.isEmpty())
295215e2 325 {
4ef6cee9 326 if (getWindowProperty(_wid, atom("XA_WM_NAME"), XA_STRING, &length, &data))
327 {
328 name = (char*) data;
329 XFree(data);
330 }
295215e2 331 }
4ef6cee9 332
333 if (name.isEmpty())
334 {
335 Status ok = XFetchName(QX11Info::display(), _wid, (char**) &data);
336 name = QString((char*) data);
337 if (0 != ok) XFree(data);
338 }
339
295215e2
AM
340 if (name.isEmpty())
341 {
342 XTextProperty prop;
343 if (XGetWMName(QX11Info::display(), _wid, &prop))
344 {
345 name = QString::fromUtf8((char*) prop.value);
346 XFree(prop.value);
347 }
348 }
349
4ef6cee9 350 return name;
351}
352
8dcae6df
PV
353QString XfitMan::getApplicationName(Window _wid) const
354{
355 XClassHint hint;
356 QString ret;
357
358 if (XGetClassHint(QX11Info::display(), _wid, &hint))
359 {
360 if (hint.res_name)
361 {
362 ret = hint.res_name;
363 XFree(hint.res_name);
364 }
365 if (hint.res_class)
366 {
367 XFree(hint.res_class);
368 }
369 }
370
371 return ret;
372}
4ef6cee9 373
4ef6cee9 374/**
375 * @brief sends a clientmessage to a window
376 */
377int XfitMan::clientMessage(Window _wid, Atom _msg,
378 unsigned long data0,
379 unsigned long data1,
380 unsigned long data2,
381 unsigned long data3,
382 unsigned long data4) const
383{
384 XClientMessageEvent msg;
385 msg.window = _wid;
386 msg.type = ClientMessage;
387 msg.message_type = _msg;
388 msg.send_event = true;
389 msg.display = QX11Info::display();
390 msg.format = 32;
391 msg.data.l[0] = data0;
392 msg.data.l[1] = data1;
393 msg.data.l[2] = data2;
394 msg.data.l[3] = data3;
395 msg.data.l[4] = data4;
396 if (XSendEvent(QX11Info::display(), root, FALSE, (SubstructureRedirectMask | SubstructureNotifyMask) , (XEvent *) &msg) == Success)
397 return EXIT_SUCCESS;
398 else
399 return EXIT_FAILURE;
400}
401
4ef6cee9 402
403/***********************************************
404
405 ***********************************************/
406WindowAllowedActions XfitMan::getAllowedActions(Window window) const
407{
408 WindowAllowedActions actions = { };
409
410 unsigned long len;
411 unsigned long *data;
412 if (getWindowProperty(window, atom("_NET_WM_ALLOWED_ACTIONS"), XA_ATOM, &len, (unsigned char**) &data))
413 {
414 for (unsigned long i=0; i<len; ++i)
415 {
416 if (data[i] == atom("_NET_WM_ACTION_MOVE")) actions.Move = true; else
417 if (data[i] == atom("_NET_WM_ACTION_RESIZE")) actions.Resize = true; else
418 if (data[i] == atom("_NET_WM_ACTION_MINIMIZE")) actions.Minimize = true; else
419 if (data[i] == atom("_NET_WM_ACTION_SHADE")) actions.Shade = true; else
420 if (data[i] == atom("_NET_WM_ACTION_STICK")) actions.Stick = true; else
421 if (data[i] == atom("_NET_WM_ACTION_MAXIMIZE_HORZ")) actions.MaximizeHoriz = true; else
422 if (data[i] == atom("_NET_WM_ACTION_MAXIMIZE_VERT")) actions.MaximizeVert = true; else
423 if (data[i] == atom("_NET_WM_ACTION_FULLSCREEN")) actions.FullScreen = true; else
424 if (data[i] == atom("_NET_WM_ACTION_CHANGE_DESKTOP")) actions.ChangeDesktop = true; else
425 if (data[i] == atom("_NET_WM_ACTION_CLOSE")) actions.Close = true; else
426 if (data[i] == atom("_NET_WM_ACTION_ABOVE")) actions.AboveLayer = true; else
427 if (data[i] == atom("_NET_WM_ACTION_BELOW")) actions.BelowLayer = true;
428 }
429 XFree(data);
430 }
431
432 return actions;
433}
434
435
436WindowState XfitMan::getWindowState(Window window) const
437{
438 WindowState state = { };
439
440 unsigned long len;
441 unsigned long *data;
442 if (getWindowProperty(window, atom("_NET_WM_STATE"), XA_ATOM, &len, (unsigned char**) &data))
443 {
444 for (unsigned long i=0; i<len; ++i)
445 {
446 if (data[i] == atom("_NET_WM_STATE_MODAL")) state.Modal = true; else
447 if (data[i] == atom("_NET_WM_STATE_STICKY")) state.Sticky = true; else
448 if (data[i] == atom("_NET_WM_STATE_MAXIMIZED_VERT")) state.MaximizedVert = true; else
449 if (data[i] == atom("_NET_WM_STATE_MAXIMIZED_HORZ")) state.MaximizedHoriz = true; else
450 if (data[i] == atom("_NET_WM_STATE_SHADED")) state.Shaded = true; else
451 if (data[i] == atom("_NET_WM_STATE_SKIP_TASKBAR")) state.SkipTaskBar = true; else
452 if (data[i] == atom("_NET_WM_STATE_SKIP_PAGER")) state.SkipPager = true; else
453 if (data[i] == atom("_NET_WM_STATE_HIDDEN")) state.Hidden = true; else
454 if (data[i] == atom("_NET_WM_STATE_FULLSCREEN")) state.FullScreen = true; else
455 if (data[i] == atom("_NET_WM_STATE_ABOVE")) state.AboveLayer = true; else
456 if (data[i] == atom("_NET_WM_STATE_BELOW")) state.BelowLayer = true; else
457 if (data[i] == atom("_NET_WM_STATE_DEMANDS_ATTENTION")) state.Attention = true;
458 }
459 XFree(data);
460 }
461
462 return state;
463
464}
465
466
467
468/**
469 * @brief returns true if a window has its hidden_flag set
470 */
471
472bool XfitMan::isHidden(Window _wid) const
473{
474 return getWindowState(_wid).Hidden;
475}
476
4ef6cee9 477Atom XfitMan::atom(const char* atomName)
478{
479 static QHash<QString, Atom> hash;
480
481 if (hash.contains(atomName))
482 return hash.value(atomName);
483
484 Atom atom = XInternAtom(QX11Info::display(), atomName, false);
485 hash[atomName] = atom;
486 return atom;
487}
488
4ef6cee9 489AtomList XfitMan::getWindowType(Window window) const
490{
491 AtomList result;
492
493 unsigned long length, *data;
494 length=0;
495 if (!getWindowProperty(window, atom("_NET_WM_WINDOW_TYPE"), (Atom)AnyPropertyType, &length, (unsigned char**) &data))
496 return result;
497
498 for (unsigned int i = 0; i < length; i++)
499 result.append(data[i]);
500
501 XFree(data);
502 return result;
503}
504
505
506/**
507 * @brief rejects a window from beeing listed
508 */
509bool XfitMan::acceptWindow(Window window) const
510{
511 {
512 AtomList types = getWindowType(window);
513 AtomList ignoreList;
514 ignoreList << atom("_NET_WM_WINDOW_TYPE_DESKTOP")
515 << atom("_NET_WM_WINDOW_TYPE_DOCK")
516 << atom("_NET_WM_WINDOW_TYPE_SPLASH")
517 << atom("_NET_WM_WINDOW_TYPE_TOOLBAR")
518 << atom("_NET_WM_WINDOW_TYPE_MENU")
d201be97
PV
519 // for qlipper - using qpopup as a main window
520 << atom("_NET_WM_WINDOW_TYPE_POPUP_MENU");
521 // issue #284: qmmp its not registered in window list panel
522 // qmmp has _KDE_NET_WM_WINDOW_TYPE_OVERRIDE in its
523 // _NET_WM_WINDOW_TYPE(ATOM) = _KDE_NET_WM_WINDOW_TYPE_OVERRIDE, _NET_WM_WINDOW_TYPE_NORMAL
524 // Let's expect that _KDE_NET_WM_WINDOW_TYPE_OVERRIDE can be set for
525 // regular windows too. If it should be hidden we should expect
526 // one of atoms listed above.
527// << atom("_KDE_NET_WM_WINDOW_TYPE_OVERRIDE");
528
4ef6cee9 529 foreach (Atom i, ignoreList)
530 {
531 if (types.contains(i))
532 return false;
533 }
534
535 WindowState state = getWindowState(window);
536 if (state.SkipTaskBar) return false;
537 }
538
539 Window transFor = None;
540 // WM_TRANSIENT_FOR hint not set - normal window
541 if (!XGetTransientForHint(QX11Info::display(), window, &transFor))
542 return true;
543
544 if (transFor == 0) return true;
545 if (transFor == window) return true;
546 if (transFor == root) return true;
547
548 AtomList transForTypes = getWindowType(transFor);
549 return !transForTypes.contains(atom("_NET_WM_WINDOW_TYPE_NORMAL"));
550}
551
552
553
554/**
555 * @brief gets a client list
556 */
d201be97 557WindowList XfitMan::getClientList() const
4ef6cee9 558{
559 //initialize the parameters for the XGetWindowProperty call
560 unsigned long length, *data;
561 length=0;
562
563 /**
564 * @todo maybe support multiple desktops here!
565 */
566 QList<Window> output;
567
568 if (getRootWindowProperty(atom("_NET_CLIENT_LIST"), (Atom)AnyPropertyType, &length, (unsigned char**) &data))
569 {
570 for (unsigned int i = 0; i < length; i ++)
571 output.append(data[i]);
572 XFree(data);
573 }
574
575 return output;
576}
577
578
579/**
580 * @brief returns the current desktop
581 */
582int XfitMan::getActiveDesktop() const
583{
584 int res = -2;
585 unsigned long length, *data;
586 if (getRootWindowProperty(atom("_NET_CURRENT_DESKTOP"), XA_CARDINAL, &length, (unsigned char**) &data))
587 {
588 if (data)
589 {
590 res = data[0];
591 XFree(data);
592 }
593 }
594
595 return res;
596}
597
598
599/**
600 * @brief gets the desktop of the windows _wid
601 */
602int XfitMan::getWindowDesktop(Window _wid) const
603{
604 int res = -1;
605 unsigned long length, *data;
606 // so we try to use net_wm_desktop first, but if the
607 // system does not use net_wm standard we use win_workspace!
608 if (getWindowProperty(_wid, atom("_NET_WM_DESKTOP"), XA_CARDINAL, &length, (unsigned char**) &data))
609 {
610 if (!data)
611 return res;
612 res = data[0];
613 XFree(data);
614 }
615 else
616 {
617 if (getWindowProperty(_wid, atom("_WIN_WORKSPACE"), XA_CARDINAL, &length, (unsigned char**) &data))
618 {
619 if (!data)
620 return res;
621 res = data[0];
622 XFree(data);
623 }
624 }
625
626 return res;
627}
628
629
630/**
631 * @brief moves a window to a specified desktop
632 */
633
634void XfitMan::moveWindowToDesktop(Window _wid, int _display) const
635{
636 clientMessage(_wid, atom("_NET_WM_DESKTOP"), (unsigned long) _display,0,0,0,0);
637}
638
639
640/**
641 * @brief raises windows _wid
642 */
643void XfitMan::raiseWindow(Window _wid) const
644{
645 clientMessage(_wid, atom("_NET_ACTIVE_WINDOW"),
646 SOURCE_PAGER);
647}
648
649
650/************************************************
651
652 ************************************************/
653void XfitMan::minimizeWindow(Window _wid) const
654{
655 clientMessage(_wid, atom("WM_CHANGE_STATE"),
656 IconicState);
657}
658
659
660/************************************************
661
662 ************************************************/
663void XfitMan::maximizeWindow(Window _wid, MaximizeDirection direction) const
664{
665 Atom atom1 = 0, atom2= 0;
666 switch (direction)
667 {
668 case MaximizeHoriz:
669 atom1 = atom("_NET_WM_STATE_MAXIMIZED_HORZ");
670 break;
671
672 case MaximizeVert:
673 atom1 = atom("_NET_WM_STATE_MAXIMIZED_VERT");
674 break;
675
676 case MaximizeBoth:
677 atom1 = atom("_NET_WM_STATE_MAXIMIZED_VERT");
678 atom2 = atom("_NET_WM_STATE_MAXIMIZED_HORZ");
679 break;
680
681 }
682
683 clientMessage(_wid, atom("_NET_WM_STATE"),
684 _NET_WM_STATE_ADD,
685 atom1, atom2,
686 SOURCE_PAGER);
687 raiseWindow(_wid);
688}
689
690
691/************************************************
692
693 ************************************************/
694void XfitMan::deMaximizeWindow(Window _wid) const
695{
696 clientMessage(_wid, atom("_NET_WM_STATE"),
697 _NET_WM_STATE_REMOVE,
698 atom("_NET_WM_STATE_MAXIMIZED_VERT"),
699 atom("_NET_WM_STATE_MAXIMIZED_HORZ"),
700 SOURCE_PAGER);
701}
702
703/************************************************
704
705 ************************************************/
706void XfitMan::shadeWindow(Window _wid, bool shade) const
707{
708 clientMessage(_wid, atom("_NET_WM_STATE"),
709 shade ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE,
710 atom("_NET_WM_STATE_SHADED"),
711 0,
712 SOURCE_PAGER);
713}
714
715
716/************************************************
717
718 ************************************************/
719void XfitMan::closeWindow(Window _wid) const
720{
721 clientMessage(_wid, atom("_NET_CLOSE_WINDOW"),
722 0, // Timestamp
723 SOURCE_PAGER);
724}
725
726
727/************************************************
728
729 ************************************************/
730void XfitMan::setWindowLayer(Window _wid, XfitMan::Layer layer) const
731{
732 ulong aboveAction = (layer == LayerAbove) ?
733 _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
734
735 ulong belowAction = (layer == LayerBelow) ?
736 _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
737
738 clientMessage(_wid, atom("_NET_WM_STATE"),
739 aboveAction,
740 atom("_NET_WM_STATE_ABOVE"),
741 0,
742 SOURCE_PAGER);
743
744 clientMessage(_wid, atom("_NET_WM_STATE"),
745 belowAction,
746 atom("_NET_WM_STATE_BELOW"),
747 0,
748 SOURCE_PAGER);
749}
750
751/**
752 * @brief changes active desktop to _desktop
753 */
754void XfitMan::setActiveDesktop(int _desktop) const
755{
756 clientMessage(root, atom("_NET_CURRENT_DESKTOP"), (unsigned long) _desktop,0,0,0,0);
757}
758
4ef6cee9 759/**
760 * @brief sets net_wm_strut_partial = our reserved panelspace for the mainbar!
761 */
762void XfitMan::setStrut(Window _wid,
763 int left, int right,
764 int top, int bottom,
765
766 int leftStartY, int leftEndY,
767 int rightStartY, int rightEndY,
768 int topStartX, int topEndX,
769 int bottomStartX, int bottomEndX
770 ) const
771{
772 //qDebug() << "XfitMan: Trying to set STRUT_PARTIAL for panel!";
aedd12d4 773 unsigned long desstrut[12];
4ef6cee9 774 memset(desstrut,0,sizeof(desstrut));
775 //prepare the array
776 //it has format:
777 /*
778 * left, right, top, bottom, left_start_y, left_end_y,
779 * right_start_y, right_end_y, top_start_x, top_end_x, bottom_start_x,
780 * bottom_end_x
781 *
782 */
783
784 //so we take our panelsize from the bottom up
785 desstrut[0] = left; desstrut[1] = right;
786 desstrut[2] = top; desstrut[3] = bottom;
787
788 desstrut[4] = leftStartY; desstrut[5] = leftEndY;
789 desstrut[6] = rightStartY; desstrut[7] = rightEndY;
790 desstrut[8] = topStartX; desstrut[9] = topEndX;
791 desstrut[10] = bottomStartX; desstrut[11] = bottomEndX;
792
793 //now we can change that property right
794 XChangeProperty(QX11Info::display(), _wid , atom("_NET_WM_STRUT_PARTIAL"),
795 XA_CARDINAL, 32, PropModeReplace, (unsigned char *) desstrut, 12 );
796
797 //now some wm do not support net_wm_strut_partial but only net_wm_strut, so we also
798 // send that one too xdg-std says: if you get a strut_partial ignore all following
799 // struts! so if this msg is recognized its ok if not, we dont care either
800
801 XChangeProperty(QX11Info::display(), _wid, atom("_NET_WM_STRUT"),
802 XA_CARDINAL, 32, PropModeReplace, (unsigned char*) desstrut, 4);
803}
804
4ef6cee9 805
806#ifdef DEBUG
807/************************************************
808
809 ************************************************/
810QString XfitMan::debugWindow(Window wnd)
811{
812 if (!wnd)
813 return QString("[%1]").arg(wnd,8, 16);
814
815 QString typeStr;
816 int format;
817 unsigned long type, length, rest, *data;
818 length=0;
819 if (XGetWindowProperty(QX11Info::display(), wnd, XInternAtom(QX11Info::display(), "_NET_WM_WINDOW_TYPE", False),
820 0, 4096, FALSE, AnyPropertyType, &type, &format,
821 &length, &rest,(unsigned char**) &data) == Success)
822 {
823 for (unsigned int i = 0; i < length; i++)
824 {
825 char* aname = XGetAtomName(QX11Info::display(), data[i]);
826 typeStr = typeStr + " " + aname;
827 XFree(aname);
828 }
829 }
830 else
831 typeStr ="ERROR";
832
8dcae6df 833 return QString("[%1] %2 %3").arg(wnd,8, 16).arg(xfitMan().getWindowTitle(wnd)).arg(typeStr);
4ef6cee9 834}
835#endif
836
837
838/************************************************
839
840 ************************************************/
841const QRect XfitMan::availableGeometry(int screen) const
842{
843 QDesktopWidget *d = QApplication::desktop();
844
845 if (screen < 0 || screen >= d->screenCount())
846 screen = d->primaryScreen();
847
848 QRect available = d->screenGeometry(screen);
849
850 // Iterate over all the client windows and subtract from the available
851 // area the space they reserved on the edges (struts).
852 // Note: _NET_WORKAREA is not reliable as it exposes only one
853 // rectangular area spanning all screens.
854 Display *display = QX11Info::display();
855 int x11Screen = d->isVirtualDesktop() ? DefaultScreen(display) : screen;
856
857 Atom ret;
858 int format, status;
859 uchar* data = 0;
860 ulong nitems, after;
861
862 status = XGetWindowProperty(display, QX11Info::appRootWindow(x11Screen),
863 atom("_NET_CLIENT_LIST"), 0L, ~0L, False, XA_WINDOW,
864 &ret, &format, &nitems, &after, &data);
865
866 if (status == Success && ret == XA_WINDOW && format == 32 && nitems)
867 {
868 const QRect desktopGeometry = d->rect();
869
870 Window* xids = (Window*) data;
871 for (quint32 i = 0; i < nitems; ++i)
872 {
873 ulong nitems2;
874 uchar* data2 = 0;
875 status = XGetWindowProperty(display, xids[i],
876 atom("_NET_WM_STRUT_PARTIAL"), 0, 12, False, XA_CARDINAL,
877 &ret, &format, &nitems2, &after, &data2);
878
879 if (status == Success && ret == XA_CARDINAL && format == 32 && nitems2 == 12)
880 {
881 ulong* struts = (ulong*) data2;
882
883 QRect left(desktopGeometry.x(),
884 desktopGeometry.y() + struts[4],
885 struts[0],
886 struts[5] - struts[4]);
887 if (available.intersects(left))
888 available.setX(left.width());
889
890 QRect right(desktopGeometry.x() + desktopGeometry.width() - struts[1],
891 desktopGeometry.y() + struts[6],
892 struts[1],
893 struts[7] - struts[6]);
894 if (available.intersects(right))
895 available.setWidth(right.x() - available.x());
896
897 QRect top(desktopGeometry.x() + struts[8],
898 desktopGeometry.y(),
899 struts[9] - struts[8],
900 struts[2]);
901 if (available.intersects(top))
902 available.setY(top.height());
903
904 QRect bottom(desktopGeometry.x() + struts[10],
905 desktopGeometry.y() + desktopGeometry.height() - struts[3],
906 struts[11] - struts[10],
907 struts[3]);
908 if (available.intersects(bottom))
909 available.setHeight(bottom.y() - available.y());
910 }
911 if (data2)
912 XFree(data2);
913 }
914 }
915 if (data)
916 XFree(data);
917
918 return available;
919}
920
921
922/************************************************
923
924 ************************************************/
925const QRect XfitMan::availableGeometry(const QWidget *widget) const
926{
927 if (!widget)
928 {
929 qWarning("XfitMan::availableGeometry(): Attempt "
930 "to get the available geometry of a null widget");
931 return QRect();
932 }
933
934 return availableGeometry(QApplication::desktop()->screenNumber(widget));
935}
936
937
938/************************************************
939
940 ************************************************/
941const QRect XfitMan::availableGeometry(const QPoint &point) const
942{
943 return availableGeometry(QApplication::desktop()->screenNumber(point));
944}
945
946
947/************************************************
948 The Window Manager MUST set this property on the root window to be the ID of a child
949 window created by himself, to indicate that a compliant window manager is active.
950
951 http://standards.freedesktop.org/wm-spec/wm-spec-latest.html#id2550836
952 ************************************************/
953bool XfitMan::isWindowManagerActive() const
954{
955 //Window *wins;
956
957 //getRootWindowProperty(atom("_NET_SUPPORTING_WM_CHECK"), XA_WINDOW, &length, (unsigned char**) &wins);
958
959 Atom type;
960 unsigned long length;
961 Window *wins;
962 int format;
963 unsigned long after;
964
965 XGetWindowProperty(QX11Info::display(), root, atom("_NET_SUPPORTING_WM_CHECK"),
966 0, LONG_MAX,
967 false, XA_WINDOW, &type, &format, &length,
968 &after, (unsigned char **)&wins);
969
970 if ( type == XA_WINDOW && length > 0 && wins[0] != None )
971 {
972 XFree(wins);
973 return true;
974 }
975 return false;
976}