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