1 /*
2  * panel-xutils.c: X related utility methods.
3  *
4  * Copyright (C) 2003 Sun Microsystems, Inc.
5  * Copyright (C) 2012-2021 MATE Developers
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2 of the
10  * License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20  * 02110-1301, USA.
21  *
22  * Authors:
23  *    Mark McLoughlin <mark@skynet.ie>
24  */
25 
26 #include <config.h>
27 
28 #ifndef HAVE_X11
29 #error file should only be built when HAVE_X11 is enabled
30 #endif
31 
32 #include "panel-xutils.h"
33 
34 #include <glib.h>
35 #include <gdk/gdk.h>
36 #include <gdk/gdkx.h>
37 #include <X11/Xlib.h>
38 #include <X11/Xatom.h>
39 
40 static Atom net_wm_strut              = None;
41 static Atom net_wm_strut_partial      = None;
42 
43 enum {
44     STRUT_LEFT = 0,
45     STRUT_RIGHT = 1,
46     STRUT_TOP = 2,
47     STRUT_BOTTOM = 3,
48     STRUT_LEFT_START = 4,
49     STRUT_LEFT_END = 5,
50     STRUT_RIGHT_START = 6,
51     STRUT_RIGHT_END = 7,
52     STRUT_TOP_START = 8,
53     STRUT_TOP_END = 9,
54     STRUT_BOTTOM_START = 10,
55     STRUT_BOTTOM_END = 11
56 };
57 
58 void
panel_xutils_set_strut(GdkWindow * gdk_window,PanelOrientation orientation,guint32 strut,guint32 strut_start,guint32 strut_end)59 panel_xutils_set_strut (GdkWindow        *gdk_window,
60                         PanelOrientation  orientation,
61                         guint32           strut,
62                         guint32           strut_start,
63                         guint32           strut_end)
64  {
65     Display *xdisplay;
66     Window   window;
67     gulong   struts [12] = { 0, };
68     GdkDisplay *display;
69 
70     g_return_if_fail (GDK_IS_WINDOW (gdk_window));
71     g_return_if_fail (GDK_IS_X11_DISPLAY (gdk_window_get_display (gdk_window)));
72 
73     xdisplay = GDK_WINDOW_XDISPLAY (gdk_window);
74     window = GDK_WINDOW_XID (gdk_window);
75 
76     if (net_wm_strut == None)
77         net_wm_strut = XInternAtom (xdisplay, "_NET_WM_STRUT", False);
78     if (net_wm_strut_partial == None)
79         net_wm_strut_partial = XInternAtom (xdisplay, "_NET_WM_STRUT_PARTIAL", False);
80 
81     switch (orientation) {
82     case PANEL_ORIENTATION_LEFT:
83         struts [STRUT_LEFT] = strut;
84         struts [STRUT_LEFT_START] = strut_start;
85         struts [STRUT_LEFT_END] = strut_end;
86         break;
87     case PANEL_ORIENTATION_RIGHT:
88         struts [STRUT_RIGHT] = strut;
89         struts [STRUT_RIGHT_START] = strut_start;
90         struts [STRUT_RIGHT_END] = strut_end;
91         break;
92     case PANEL_ORIENTATION_TOP:
93         struts [STRUT_TOP] = strut;
94         struts [STRUT_TOP_START] = strut_start;
95         struts [STRUT_TOP_END] = strut_end;
96         break;
97     case PANEL_ORIENTATION_BOTTOM:
98         struts [STRUT_BOTTOM] = strut;
99         struts [STRUT_BOTTOM_START] = strut_start;
100         struts [STRUT_BOTTOM_END] = strut_end;
101         break;
102     }
103 
104     display = gdk_window_get_display (gdk_window);
105     gdk_x11_display_error_trap_push (display);
106     XChangeProperty (xdisplay, window, net_wm_strut,
107                      XA_CARDINAL, 32, PropModeReplace,
108                      (guchar *) &struts, 4);
109     XChangeProperty (xdisplay, window, net_wm_strut_partial,
110                      XA_CARDINAL, 32, PropModeReplace,
111                      (guchar *) &struts, 12);
112     gdk_x11_display_error_trap_pop_ignored (display);
113 }
114 
115 void
panel_xutils_unset_strut(GdkWindow * gdk_window)116 panel_xutils_unset_strut (GdkWindow *gdk_window)
117 {
118     GdkDisplay *display;
119     Display *xdisplay;
120     Window xwindow;
121 
122     display = gdk_window_get_display (gdk_window);
123     xdisplay = gdk_x11_display_get_xdisplay (display);
124     xwindow = gdk_x11_window_get_xid (gdk_window);
125 
126     if (net_wm_strut == None)
127         net_wm_strut = XInternAtom (xdisplay, "_NET_WM_STRUT", False);
128     if (net_wm_strut_partial == None)
129         net_wm_strut_partial = XInternAtom (xdisplay, "_NET_WM_STRUT_PARTIAL", False);
130 
131     gdk_x11_display_error_trap_push (display);
132 
133     XDeleteProperty (xdisplay, xwindow, net_wm_strut);
134     XDeleteProperty (xdisplay, xwindow, net_wm_strut_partial);
135 
136     gdk_x11_display_error_trap_pop_ignored (display);
137 }
138 
139 void
panel_warp_pointer(GdkWindow * gdk_window,int x,int y)140 panel_warp_pointer (GdkWindow *gdk_window,
141                     int        x,
142                     int        y)
143 {
144     Display *xdisplay;
145     Window   window;
146     GdkDisplay *display;
147 
148     g_return_if_fail (GDK_IS_WINDOW (gdk_window));
149     g_return_if_fail (GDK_IS_X11_DISPLAY (gdk_window_get_display (gdk_window)));
150 
151     xdisplay = GDK_WINDOW_XDISPLAY (gdk_window);
152     window = GDK_WINDOW_XID (gdk_window);
153 
154     display = gdk_window_get_display (gdk_window);
155     gdk_x11_display_error_trap_push (display);
156     XWarpPointer (xdisplay, None, window, 0, 0, 0, 0, x, y);
157     gdk_x11_display_error_trap_pop_ignored (display);
158 }
159 
160 guint
panel_get_real_modifier_mask(guint mask)161 panel_get_real_modifier_mask (guint mask)
162 {
163     guint real_mask;
164     Display *display;
165     int i, min_keycode, max_keycode, keysyms_per_keycode;
166     int max_keycodes_per_modifier;
167     KeySym *keysyms_for_keycodes;
168     XModifierKeymap *modifier_keymap;
169 
170     real_mask = mask & ((Mod5Mask << 1) - 1);
171 
172     /* Already real */
173     if (mask == real_mask) {
174         return mask;
175     }
176 
177     g_return_val_if_fail (GDK_IS_X11_DISPLAY (gdk_display_get_default ()), mask);
178     display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
179 
180     XDisplayKeycodes (display, &min_keycode, &max_keycode);
181     keysyms_for_keycodes = XGetKeyboardMapping (display,
182                                                 min_keycode,
183                                                 max_keycode - min_keycode + 1,
184                                                 &keysyms_per_keycode);
185 
186     modifier_keymap = XGetModifierMapping (display);
187     max_keycodes_per_modifier = modifier_keymap->max_keypermod;
188 
189     /* Loop through all the modifiers and find out which "real"
190      * (Mod2..Mod5) modifiers Super, Hyper, and Meta are mapped to.
191      * Note, Mod1 is used by the Alt modifier */
192     for (i = Mod2MapIndex * max_keycodes_per_modifier;
193          i < (Mod5MapIndex + 1) * max_keycodes_per_modifier;
194          i++) {
195             int keycode;
196             int j;
197             KeySym *keysyms_for_keycode;
198             int map_index;
199             int map_mask;
200 
201             keycode = modifier_keymap->modifiermap[i];
202 
203             /* The array is sparse, there may be some
204              * empty entries.  Filter those out
205              * (along with any invalid entries) */
206             if (keycode < min_keycode || keycode > max_keycode)
207                 continue;
208 
209             keysyms_for_keycode = keysyms_for_keycodes +
210                 (keycode - min_keycode) * keysyms_per_keycode;
211 
212             map_index = i / max_keycodes_per_modifier;
213 
214             g_assert (map_index <= Mod5MapIndex);
215 
216             map_mask = 1 << map_index;
217 
218             for (j = 0; j < keysyms_per_keycode; j++) {
219                 switch (keysyms_for_keycode[j]) {
220                     case XK_Super_L:
221                     case XK_Super_R:
222                         if (mask & GDK_SUPER_MASK)
223                             real_mask |= map_mask;
224                         break;
225                     case XK_Hyper_L:
226                     case XK_Hyper_R:
227                         if (mask & GDK_HYPER_MASK)
228                             real_mask |= map_mask;
229                         break;
230                     case XK_Meta_L:
231                     case XK_Meta_R:
232                         if (mask & GDK_META_MASK)
233                             real_mask |= map_mask;
234                         break;
235                     default:
236                         break;
237                 }
238             }
239         }
240 
241     XFreeModifiermap (modifier_keymap);
242     XFree (keysyms_for_keycodes);
243 
244     return real_mask;
245 }
246