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