New panel layout and many changes
[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>
48
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 {
244 qDebug() << "Cannot obtain pixmap info from the window";
245 return false;
246 }
247
248 QImage img (data[0], data[1], QImage::Format_ARGB32);
249 for (int i=0; i<img.byteCount()/4; ++i)
250 ((uint*)img.bits())[i] = data[i+2];
251
252 _pixreturn = QPixmap::fromImage(img);
253 XFree(data);
254
255 return true;
256}
257
258
259
260/**
261 * @brief destructor
262 */
263XfitMan::~XfitMan()
264{
265}
266/**
267 * @brief returns a windowname and sets _nameSource to the finally used Atom
268 */
269
270//i got the idea for this from taskbar-plugin of LXPanel - so credits fly out :)
8dcae6df 271QString XfitMan::getWindowTitle(Window _wid) const
4ef6cee9 272{
273 QString name = "";
274 //first try the modern net-wm ones
275 unsigned long length;
276 unsigned char *data = NULL;
277 Atom utf8Atom = atom("UTF8_STRING");
278
279 if (getWindowProperty(_wid, atom("_NET_WM_VISIBLE_NAME"), utf8Atom, &length, &data))
280 {
281 name = QString::fromUtf8((char*) data);
282 XFree(data);
283
284 }
285
286 if (name.isEmpty())
287 if (getWindowProperty(_wid, atom("_NET_WM_NAME"), utf8Atom, &length, &data))
288 {
289 name = QString::fromUtf8((char*) data);
290 XFree(data);
291 }
292
293 if (name.isEmpty())
294 if (getWindowProperty(_wid, atom("XA_WM_NAME"), XA_STRING, &length, &data))
295 {
296 name = (char*) data;
297 XFree(data);
298 }
299
300 if (name.isEmpty())
301 {
302 Status ok = XFetchName(QX11Info::display(), _wid, (char**) &data);
303 name = QString((char*) data);
304 if (0 != ok) XFree(data);
305 }
306
307 return name;
308}
309
8dcae6df
PV
310QString XfitMan::getApplicationName(Window _wid) const
311{
312 XClassHint hint;
313 QString ret;
314
315 if (XGetClassHint(QX11Info::display(), _wid, &hint))
316 {
317 if (hint.res_name)
318 {
319 ret = hint.res_name;
320 XFree(hint.res_name);
321 }
322 if (hint.res_class)
323 {
324 XFree(hint.res_class);
325 }
326 }
327
328 return ret;
329}
4ef6cee9 330
4ef6cee9 331/**
332 * @brief sends a clientmessage to a window
333 */
334int XfitMan::clientMessage(Window _wid, Atom _msg,
335 unsigned long data0,
336 unsigned long data1,
337 unsigned long data2,
338 unsigned long data3,
339 unsigned long data4) const
340{
341 XClientMessageEvent msg;
342 msg.window = _wid;
343 msg.type = ClientMessage;
344 msg.message_type = _msg;
345 msg.send_event = true;
346 msg.display = QX11Info::display();
347 msg.format = 32;
348 msg.data.l[0] = data0;
349 msg.data.l[1] = data1;
350 msg.data.l[2] = data2;
351 msg.data.l[3] = data3;
352 msg.data.l[4] = data4;
353 if (XSendEvent(QX11Info::display(), root, FALSE, (SubstructureRedirectMask | SubstructureNotifyMask) , (XEvent *) &msg) == Success)
354 return EXIT_SUCCESS;
355 else
356 return EXIT_FAILURE;
357}
358
4ef6cee9 359
360/***********************************************
361
362 ***********************************************/
363WindowAllowedActions XfitMan::getAllowedActions(Window window) const
364{
365 WindowAllowedActions actions = { };
366
367 unsigned long len;
368 unsigned long *data;
369 if (getWindowProperty(window, atom("_NET_WM_ALLOWED_ACTIONS"), XA_ATOM, &len, (unsigned char**) &data))
370 {
371 for (unsigned long i=0; i<len; ++i)
372 {
373 if (data[i] == atom("_NET_WM_ACTION_MOVE")) actions.Move = true; else
374 if (data[i] == atom("_NET_WM_ACTION_RESIZE")) actions.Resize = true; else
375 if (data[i] == atom("_NET_WM_ACTION_MINIMIZE")) actions.Minimize = true; else
376 if (data[i] == atom("_NET_WM_ACTION_SHADE")) actions.Shade = true; else
377 if (data[i] == atom("_NET_WM_ACTION_STICK")) actions.Stick = true; else
378 if (data[i] == atom("_NET_WM_ACTION_MAXIMIZE_HORZ")) actions.MaximizeHoriz = true; else
379 if (data[i] == atom("_NET_WM_ACTION_MAXIMIZE_VERT")) actions.MaximizeVert = true; else
380 if (data[i] == atom("_NET_WM_ACTION_FULLSCREEN")) actions.FullScreen = true; else
381 if (data[i] == atom("_NET_WM_ACTION_CHANGE_DESKTOP")) actions.ChangeDesktop = true; else
382 if (data[i] == atom("_NET_WM_ACTION_CLOSE")) actions.Close = true; else
383 if (data[i] == atom("_NET_WM_ACTION_ABOVE")) actions.AboveLayer = true; else
384 if (data[i] == atom("_NET_WM_ACTION_BELOW")) actions.BelowLayer = true;
385 }
386 XFree(data);
387 }
388
389 return actions;
390}
391
392
393WindowState XfitMan::getWindowState(Window window) const
394{
395 WindowState state = { };
396
397 unsigned long len;
398 unsigned long *data;
399 if (getWindowProperty(window, atom("_NET_WM_STATE"), XA_ATOM, &len, (unsigned char**) &data))
400 {
401 for (unsigned long i=0; i<len; ++i)
402 {
403 if (data[i] == atom("_NET_WM_STATE_MODAL")) state.Modal = true; else
404 if (data[i] == atom("_NET_WM_STATE_STICKY")) state.Sticky = true; else
405 if (data[i] == atom("_NET_WM_STATE_MAXIMIZED_VERT")) state.MaximizedVert = true; else
406 if (data[i] == atom("_NET_WM_STATE_MAXIMIZED_HORZ")) state.MaximizedHoriz = true; else
407 if (data[i] == atom("_NET_WM_STATE_SHADED")) state.Shaded = true; else
408 if (data[i] == atom("_NET_WM_STATE_SKIP_TASKBAR")) state.SkipTaskBar = true; else
409 if (data[i] == atom("_NET_WM_STATE_SKIP_PAGER")) state.SkipPager = true; else
410 if (data[i] == atom("_NET_WM_STATE_HIDDEN")) state.Hidden = true; else
411 if (data[i] == atom("_NET_WM_STATE_FULLSCREEN")) state.FullScreen = true; else
412 if (data[i] == atom("_NET_WM_STATE_ABOVE")) state.AboveLayer = true; else
413 if (data[i] == atom("_NET_WM_STATE_BELOW")) state.BelowLayer = true; else
414 if (data[i] == atom("_NET_WM_STATE_DEMANDS_ATTENTION")) state.Attention = true;
415 }
416 XFree(data);
417 }
418
419 return state;
420
421}
422
423
424
425/**
426 * @brief returns true if a window has its hidden_flag set
427 */
428
429bool XfitMan::isHidden(Window _wid) const
430{
431 return getWindowState(_wid).Hidden;
432}
433
4ef6cee9 434Atom XfitMan::atom(const char* atomName)
435{
436 static QHash<QString, Atom> hash;
437
438 if (hash.contains(atomName))
439 return hash.value(atomName);
440
441 Atom atom = XInternAtom(QX11Info::display(), atomName, false);
442 hash[atomName] = atom;
443 return atom;
444}
445
4ef6cee9 446AtomList XfitMan::getWindowType(Window window) const
447{
448 AtomList result;
449
450 unsigned long length, *data;
451 length=0;
452 if (!getWindowProperty(window, atom("_NET_WM_WINDOW_TYPE"), (Atom)AnyPropertyType, &length, (unsigned char**) &data))
453 return result;
454
455 for (unsigned int i = 0; i < length; i++)
456 result.append(data[i]);
457
458 XFree(data);
459 return result;
460}
461
462
463/**
464 * @brief rejects a window from beeing listed
465 */
466bool XfitMan::acceptWindow(Window window) const
467{
468 {
469 AtomList types = getWindowType(window);
470 AtomList ignoreList;
471 ignoreList << atom("_NET_WM_WINDOW_TYPE_DESKTOP")
472 << atom("_NET_WM_WINDOW_TYPE_DOCK")
473 << atom("_NET_WM_WINDOW_TYPE_SPLASH")
474 << atom("_NET_WM_WINDOW_TYPE_TOOLBAR")
475 << atom("_NET_WM_WINDOW_TYPE_MENU")
d201be97
PV
476 // for qlipper - using qpopup as a main window
477 << atom("_NET_WM_WINDOW_TYPE_POPUP_MENU");
478 // issue #284: qmmp its not registered in window list panel
479 // qmmp has _KDE_NET_WM_WINDOW_TYPE_OVERRIDE in its
480 // _NET_WM_WINDOW_TYPE(ATOM) = _KDE_NET_WM_WINDOW_TYPE_OVERRIDE, _NET_WM_WINDOW_TYPE_NORMAL
481 // Let's expect that _KDE_NET_WM_WINDOW_TYPE_OVERRIDE can be set for
482 // regular windows too. If it should be hidden we should expect
483 // one of atoms listed above.
484// << atom("_KDE_NET_WM_WINDOW_TYPE_OVERRIDE");
485
4ef6cee9 486 foreach (Atom i, ignoreList)
487 {
488 if (types.contains(i))
489 return false;
490 }
491
492 WindowState state = getWindowState(window);
493 if (state.SkipTaskBar) return false;
494 }
495
496 Window transFor = None;
497 // WM_TRANSIENT_FOR hint not set - normal window
498 if (!XGetTransientForHint(QX11Info::display(), window, &transFor))
499 return true;
500
501 if (transFor == 0) return true;
502 if (transFor == window) return true;
503 if (transFor == root) return true;
504
505 AtomList transForTypes = getWindowType(transFor);
506 return !transForTypes.contains(atom("_NET_WM_WINDOW_TYPE_NORMAL"));
507}
508
509
510
511/**
512 * @brief gets a client list
513 */
d201be97 514WindowList XfitMan::getClientList() const
4ef6cee9 515{
516 //initialize the parameters for the XGetWindowProperty call
517 unsigned long length, *data;
518 length=0;
519
520 /**
521 * @todo maybe support multiple desktops here!
522 */
523 QList<Window> output;
524
525 if (getRootWindowProperty(atom("_NET_CLIENT_LIST"), (Atom)AnyPropertyType, &length, (unsigned char**) &data))
526 {
527 for (unsigned int i = 0; i < length; i ++)
528 output.append(data[i]);
529 XFree(data);
530 }
531
532 return output;
533}
534
535
536/**
537 * @brief returns the current desktop
538 */
539int XfitMan::getActiveDesktop() const
540{
541 int res = -2;
542 unsigned long length, *data;
543 if (getRootWindowProperty(atom("_NET_CURRENT_DESKTOP"), XA_CARDINAL, &length, (unsigned char**) &data))
544 {
545 if (data)
546 {
547 res = data[0];
548 XFree(data);
549 }
550 }
551
552 return res;
553}
554
555
556/**
557 * @brief gets the desktop of the windows _wid
558 */
559int XfitMan::getWindowDesktop(Window _wid) const
560{
561 int res = -1;
562 unsigned long length, *data;
563 // so we try to use net_wm_desktop first, but if the
564 // system does not use net_wm standard we use win_workspace!
565 if (getWindowProperty(_wid, atom("_NET_WM_DESKTOP"), XA_CARDINAL, &length, (unsigned char**) &data))
566 {
567 if (!data)
568 return res;
569 res = data[0];
570 XFree(data);
571 }
572 else
573 {
574 if (getWindowProperty(_wid, atom("_WIN_WORKSPACE"), XA_CARDINAL, &length, (unsigned char**) &data))
575 {
576 if (!data)
577 return res;
578 res = data[0];
579 XFree(data);
580 }
581 }
582
583 return res;
584}
585
586
587/**
588 * @brief moves a window to a specified desktop
589 */
590
591void XfitMan::moveWindowToDesktop(Window _wid, int _display) const
592{
593 clientMessage(_wid, atom("_NET_WM_DESKTOP"), (unsigned long) _display,0,0,0,0);
594}
595
596
597/**
598 * @brief raises windows _wid
599 */
600void XfitMan::raiseWindow(Window _wid) const
601{
602 clientMessage(_wid, atom("_NET_ACTIVE_WINDOW"),
603 SOURCE_PAGER);
604}
605
606
607/************************************************
608
609 ************************************************/
610void XfitMan::minimizeWindow(Window _wid) const
611{
612 clientMessage(_wid, atom("WM_CHANGE_STATE"),
613 IconicState);
614}
615
616
617/************************************************
618
619 ************************************************/
620void XfitMan::maximizeWindow(Window _wid, MaximizeDirection direction) const
621{
622 Atom atom1 = 0, atom2= 0;
623 switch (direction)
624 {
625 case MaximizeHoriz:
626 atom1 = atom("_NET_WM_STATE_MAXIMIZED_HORZ");
627 break;
628
629 case MaximizeVert:
630 atom1 = atom("_NET_WM_STATE_MAXIMIZED_VERT");
631 break;
632
633 case MaximizeBoth:
634 atom1 = atom("_NET_WM_STATE_MAXIMIZED_VERT");
635 atom2 = atom("_NET_WM_STATE_MAXIMIZED_HORZ");
636 break;
637
638 }
639
640 clientMessage(_wid, atom("_NET_WM_STATE"),
641 _NET_WM_STATE_ADD,
642 atom1, atom2,
643 SOURCE_PAGER);
644 raiseWindow(_wid);
645}
646
647
648/************************************************
649
650 ************************************************/
651void XfitMan::deMaximizeWindow(Window _wid) const
652{
653 clientMessage(_wid, atom("_NET_WM_STATE"),
654 _NET_WM_STATE_REMOVE,
655 atom("_NET_WM_STATE_MAXIMIZED_VERT"),
656 atom("_NET_WM_STATE_MAXIMIZED_HORZ"),
657 SOURCE_PAGER);
658}
659
660/************************************************
661
662 ************************************************/
663void XfitMan::shadeWindow(Window _wid, bool shade) const
664{
665 clientMessage(_wid, atom("_NET_WM_STATE"),
666 shade ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE,
667 atom("_NET_WM_STATE_SHADED"),
668 0,
669 SOURCE_PAGER);
670}
671
672
673/************************************************
674
675 ************************************************/
676void XfitMan::closeWindow(Window _wid) const
677{
678 clientMessage(_wid, atom("_NET_CLOSE_WINDOW"),
679 0, // Timestamp
680 SOURCE_PAGER);
681}
682
683
684/************************************************
685
686 ************************************************/
687void XfitMan::setWindowLayer(Window _wid, XfitMan::Layer layer) const
688{
689 ulong aboveAction = (layer == LayerAbove) ?
690 _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
691
692 ulong belowAction = (layer == LayerBelow) ?
693 _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
694
695 clientMessage(_wid, atom("_NET_WM_STATE"),
696 aboveAction,
697 atom("_NET_WM_STATE_ABOVE"),
698 0,
699 SOURCE_PAGER);
700
701 clientMessage(_wid, atom("_NET_WM_STATE"),
702 belowAction,
703 atom("_NET_WM_STATE_BELOW"),
704 0,
705 SOURCE_PAGER);
706}
707
708/**
709 * @brief changes active desktop to _desktop
710 */
711void XfitMan::setActiveDesktop(int _desktop) const
712{
713 clientMessage(root, atom("_NET_CURRENT_DESKTOP"), (unsigned long) _desktop,0,0,0,0);
714}
715
4ef6cee9 716/**
717 * @brief sets net_wm_strut_partial = our reserved panelspace for the mainbar!
718 */
719void XfitMan::setStrut(Window _wid,
720 int left, int right,
721 int top, int bottom,
722
723 int leftStartY, int leftEndY,
724 int rightStartY, int rightEndY,
725 int topStartX, int topEndX,
726 int bottomStartX, int bottomEndX
727 ) const
728{
729 //qDebug() << "XfitMan: Trying to set STRUT_PARTIAL for panel!";
aedd12d4 730 unsigned long desstrut[12];
4ef6cee9 731 memset(desstrut,0,sizeof(desstrut));
732 //prepare the array
733 //it has format:
734 /*
735 * left, right, top, bottom, left_start_y, left_end_y,
736 * right_start_y, right_end_y, top_start_x, top_end_x, bottom_start_x,
737 * bottom_end_x
738 *
739 */
740
741 //so we take our panelsize from the bottom up
742 desstrut[0] = left; desstrut[1] = right;
743 desstrut[2] = top; desstrut[3] = bottom;
744
745 desstrut[4] = leftStartY; desstrut[5] = leftEndY;
746 desstrut[6] = rightStartY; desstrut[7] = rightEndY;
747 desstrut[8] = topStartX; desstrut[9] = topEndX;
748 desstrut[10] = bottomStartX; desstrut[11] = bottomEndX;
749
750 //now we can change that property right
751 XChangeProperty(QX11Info::display(), _wid , atom("_NET_WM_STRUT_PARTIAL"),
752 XA_CARDINAL, 32, PropModeReplace, (unsigned char *) desstrut, 12 );
753
754 //now some wm do not support net_wm_strut_partial but only net_wm_strut, so we also
755 // send that one too xdg-std says: if you get a strut_partial ignore all following
756 // struts! so if this msg is recognized its ok if not, we dont care either
757
758 XChangeProperty(QX11Info::display(), _wid, atom("_NET_WM_STRUT"),
759 XA_CARDINAL, 32, PropModeReplace, (unsigned char*) desstrut, 4);
760}
761
4ef6cee9 762
763#ifdef DEBUG
764/************************************************
765
766 ************************************************/
767QString XfitMan::debugWindow(Window wnd)
768{
769 if (!wnd)
770 return QString("[%1]").arg(wnd,8, 16);
771
772 QString typeStr;
773 int format;
774 unsigned long type, length, rest, *data;
775 length=0;
776 if (XGetWindowProperty(QX11Info::display(), wnd, XInternAtom(QX11Info::display(), "_NET_WM_WINDOW_TYPE", False),
777 0, 4096, FALSE, AnyPropertyType, &type, &format,
778 &length, &rest,(unsigned char**) &data) == Success)
779 {
780 for (unsigned int i = 0; i < length; i++)
781 {
782 char* aname = XGetAtomName(QX11Info::display(), data[i]);
783 typeStr = typeStr + " " + aname;
784 XFree(aname);
785 }
786 }
787 else
788 typeStr ="ERROR";
789
8dcae6df 790 return QString("[%1] %2 %3").arg(wnd,8, 16).arg(xfitMan().getWindowTitle(wnd)).arg(typeStr);
4ef6cee9 791}
792#endif
793
794
795/************************************************
796
797 ************************************************/
798const QRect XfitMan::availableGeometry(int screen) const
799{
800 QDesktopWidget *d = QApplication::desktop();
801
802 if (screen < 0 || screen >= d->screenCount())
803 screen = d->primaryScreen();
804
805 QRect available = d->screenGeometry(screen);
806
807 // Iterate over all the client windows and subtract from the available
808 // area the space they reserved on the edges (struts).
809 // Note: _NET_WORKAREA is not reliable as it exposes only one
810 // rectangular area spanning all screens.
811 Display *display = QX11Info::display();
812 int x11Screen = d->isVirtualDesktop() ? DefaultScreen(display) : screen;
813
814 Atom ret;
815 int format, status;
816 uchar* data = 0;
817 ulong nitems, after;
818
819 status = XGetWindowProperty(display, QX11Info::appRootWindow(x11Screen),
820 atom("_NET_CLIENT_LIST"), 0L, ~0L, False, XA_WINDOW,
821 &ret, &format, &nitems, &after, &data);
822
823 if (status == Success && ret == XA_WINDOW && format == 32 && nitems)
824 {
825 const QRect desktopGeometry = d->rect();
826
827 Window* xids = (Window*) data;
828 for (quint32 i = 0; i < nitems; ++i)
829 {
830 ulong nitems2;
831 uchar* data2 = 0;
832 status = XGetWindowProperty(display, xids[i],
833 atom("_NET_WM_STRUT_PARTIAL"), 0, 12, False, XA_CARDINAL,
834 &ret, &format, &nitems2, &after, &data2);
835
836 if (status == Success && ret == XA_CARDINAL && format == 32 && nitems2 == 12)
837 {
838 ulong* struts = (ulong*) data2;
839
840 QRect left(desktopGeometry.x(),
841 desktopGeometry.y() + struts[4],
842 struts[0],
843 struts[5] - struts[4]);
844 if (available.intersects(left))
845 available.setX(left.width());
846
847 QRect right(desktopGeometry.x() + desktopGeometry.width() - struts[1],
848 desktopGeometry.y() + struts[6],
849 struts[1],
850 struts[7] - struts[6]);
851 if (available.intersects(right))
852 available.setWidth(right.x() - available.x());
853
854 QRect top(desktopGeometry.x() + struts[8],
855 desktopGeometry.y(),
856 struts[9] - struts[8],
857 struts[2]);
858 if (available.intersects(top))
859 available.setY(top.height());
860
861 QRect bottom(desktopGeometry.x() + struts[10],
862 desktopGeometry.y() + desktopGeometry.height() - struts[3],
863 struts[11] - struts[10],
864 struts[3]);
865 if (available.intersects(bottom))
866 available.setHeight(bottom.y() - available.y());
867 }
868 if (data2)
869 XFree(data2);
870 }
871 }
872 if (data)
873 XFree(data);
874
875 return available;
876}
877
878
879/************************************************
880
881 ************************************************/
882const QRect XfitMan::availableGeometry(const QWidget *widget) const
883{
884 if (!widget)
885 {
886 qWarning("XfitMan::availableGeometry(): Attempt "
887 "to get the available geometry of a null widget");
888 return QRect();
889 }
890
891 return availableGeometry(QApplication::desktop()->screenNumber(widget));
892}
893
894
895/************************************************
896
897 ************************************************/
898const QRect XfitMan::availableGeometry(const QPoint &point) const
899{
900 return availableGeometry(QApplication::desktop()->screenNumber(point));
901}
902
903
904/************************************************
905 The Window Manager MUST set this property on the root window to be the ID of a child
906 window created by himself, to indicate that a compliant window manager is active.
907
908 http://standards.freedesktop.org/wm-spec/wm-spec-latest.html#id2550836
909 ************************************************/
910bool XfitMan::isWindowManagerActive() const
911{
912 //Window *wins;
913
914 //getRootWindowProperty(atom("_NET_SUPPORTING_WM_CHECK"), XA_WINDOW, &length, (unsigned char**) &wins);
915
916 Atom type;
917 unsigned long length;
918 Window *wins;
919 int format;
920 unsigned long after;
921
922 XGetWindowProperty(QX11Info::display(), root, atom("_NET_SUPPORTING_WM_CHECK"),
923 0, LONG_MAX,
924 false, XA_WINDOW, &type, &format, &length,
925 &after, (unsigned char **)&wins);
926
927 if ( type == XA_WINDOW && length > 0 && wins[0] != None )
928 {
929 XFree(wins);
930 return true;
931 }
932 return false;
933}