1 /************************************************************************
2  *
3  * adapted from:
4  * wmctrl
5  * A command line tool to interact with an EWMH/NetWM compatible X Window Manager.
6  *
7  * Copyright 2003 Tomas Styblo <tripie@cpan.org>
8  * Copyright 2011 Tim Blechmann (tim@klingt.org)
9  * Copyright 2011 Jakob Leben (jakob.leben@gmail.com)
10  *
11  * This file is part of SuperCollider Qt GUI.
12  *
13  * This program is free software: you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation, either version 2 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
25  *
26  ************************************************************************/
27 
28 #include "hacks_x11.hpp"
29 
30 #ifdef Q_WS_X11
31 #    include <stdlib.h>
32 #    include <stdio.h>
33 
34 #    include <X11/Xlib.h>
35 #    include <X11/Xatom.h>
36 
37 #    define MAX_PROPERTY_VALUE_LEN 4096
38 
p_verbose(...)39 static inline void p_verbose(...) {}
40 
41 #    define gchar char
42 #    define gboolean bool
43 #    define g_malloc (char*)malloc
44 #    define g_free free
45 
get_property(Display * disp,Window win,Atom xa_prop_type,const gchar * prop_name,unsigned long * size)46 static gchar* get_property(Display* disp, Window win, Atom xa_prop_type, const gchar* prop_name, unsigned long* size) {
47     Atom xa_prop_name;
48     Atom xa_ret_type;
49     int ret_format;
50     unsigned long ret_nitems;
51     unsigned long ret_bytes_after;
52     unsigned long tmp_size;
53     unsigned char* ret_prop;
54     gchar* ret;
55 
56     xa_prop_name = XInternAtom(disp, prop_name, False);
57 
58     /* MAX_PROPERTY_VALUE_LEN / 4 explanation (XGetWindowProperty manpage):
59      *
60      * long_length = Specifies the length in 32-bit multiples of the
61      *               data to be retrieved.
62      */
63     if (XGetWindowProperty(disp, win, xa_prop_name, 0, MAX_PROPERTY_VALUE_LEN / 4, False, xa_prop_type, &xa_ret_type,
64                            &ret_format, &ret_nitems, &ret_bytes_after, &ret_prop)
65         != Success) {
66         p_verbose("Cannot get %s property.\n", prop_name);
67         return NULL;
68     }
69 
70     if (xa_ret_type != xa_prop_type) {
71         p_verbose("Invalid type of %s property.\n", prop_name);
72         XFree(ret_prop);
73         return NULL;
74     }
75 
76     /* null terminate the result to make string handling easier */
77     tmp_size = (ret_format / 8) * ret_nitems;
78     ret = g_malloc(tmp_size + 1);
79     memcpy(ret, ret_prop, tmp_size);
80     ret[tmp_size] = '\0';
81 
82     if (size) {
83         *size = tmp_size;
84     }
85 
86     XFree(ret_prop);
87     return ret;
88 } /*}}}*/
89 
client_msg(Display * disp,Window win,const char * msg,unsigned long data0,unsigned long data1,unsigned long data2,unsigned long data3,unsigned long data4)90 static int client_msg(Display* disp, Window win, const char* msg, /* {{{ */
91                       unsigned long data0, unsigned long data1, unsigned long data2, unsigned long data3,
92                       unsigned long data4) {
93     XEvent event;
94     long mask = SubstructureRedirectMask | SubstructureNotifyMask;
95 
96     event.xclient.type = ClientMessage;
97     event.xclient.serial = 0;
98     event.xclient.send_event = True;
99     event.xclient.message_type = XInternAtom(disp, msg, False);
100     event.xclient.window = win;
101     event.xclient.format = 32;
102     event.xclient.data.l[0] = data0;
103     event.xclient.data.l[1] = data1;
104     event.xclient.data.l[2] = data2;
105     event.xclient.data.l[3] = data3;
106     event.xclient.data.l[4] = data4;
107 
108     if (XSendEvent(disp, DefaultRootWindow(disp), False, mask, &event)) {
109         return EXIT_SUCCESS;
110     } else {
111         fprintf(stderr, "Cannot send %s event.\n", msg);
112         return EXIT_FAILURE;
113     }
114 } /*}}}*/
115 
activate_window(Display * disp,Window win,gboolean switch_desktop)116 static int activate_window(Display* disp, Window win, /* {{{ */
117                            gboolean switch_desktop) {
118     unsigned long* desktop;
119 
120     /* desktop ID */
121     if ((desktop = (unsigned long*)get_property(disp, win, XA_CARDINAL, "_NET_WM_DESKTOP", NULL)) == NULL) {
122         if ((desktop = (unsigned long*)get_property(disp, win, XA_CARDINAL, "_WIN_WORKSPACE", NULL)) == NULL) {
123             p_verbose("Cannot find desktop ID of the window.\n");
124         }
125     }
126 
127     if (switch_desktop && desktop) {
128         if (client_msg(disp, DefaultRootWindow(disp), "_NET_CURRENT_DESKTOP", *desktop, 0, 0, 0, 0) != EXIT_SUCCESS) {
129             p_verbose("Cannot switch desktop.\n");
130         }
131     }
132     if (desktop)
133         g_free(desktop);
134 
135     client_msg(disp, win, "_NET_ACTIVE_WINDOW", 0, 0, 0, 0, 0);
136     XMapRaised(disp, win);
137 
138     return EXIT_SUCCESS;
139 } /*}}}*/
140 
141 #    undef p_verbose
142 #    undef gchar
143 #    undef gboolean
144 #    undef g_malloc
145 #    undef g_free
146 
raise_window(Display * display,QWidget * win)147 bool raise_window(Display* display, QWidget* win) {
148     Window window = win->winId();
149     int raised_via_xlib_error = XRaiseWindow(display, window);
150     if (raised_via_xlib_error == 0)
151         return true;
152 
153     int raised_via_ewmh_error = activate_window(display, window, true);
154     return raised_via_ewmh_error == 0;
155 }
156 
157 
158 #endif
159