ignore crossing events while an interactive grab is going on.
[dana/openbox.git] / openbox / grab.c
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
2
3    grab.c for the Openbox window manager
4    Copyright (c) 2006        Mikael Magnusson
5    Copyright (c) 2003        Ben Jansens
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    See the COPYING file for a copy of the GNU General Public License.
18 */
19
20 #include "grab.h"
21 #include "openbox.h"
22 #include "event.h"
23 #include "xerror.h"
24 #include "screen.h"
25
26 #include <glib.h>
27 #include <X11/Xlib.h>
28
29 #define GRAB_PTR_MASK (ButtonPressMask | ButtonReleaseMask | \
30                        PointerMotionMask | EnterWindowMask | LeaveWindowMask)
31 #define GRAB_KEY_MASK (KeyPressMask | KeyReleaseMask)
32
33 #define MASK_LIST_SIZE 8
34
35 /*! A list of all possible combinations of keyboard lock masks */
36 static guint mask_list[MASK_LIST_SIZE];
37 static guint kgrabs = 0;
38 static guint pgrabs = 0;
39 /*! The time at which the last grab was made */
40 static Time  grab_time = CurrentTime;
41
42 static Time ungrab_time()
43 {
44     Time t = event_curtime;
45     if (!(t == CurrentTime || event_time_after(t, grab_time)))
46         /* When the time moves backward on the server, then we can't use
47            the grab time because that will be in the future. So instead we
48            have to use CurrentTime.
49
50            "XUngrabPointer does not release the pointer if the specified time
51            is earlier than the last-pointer-grab time or is later than the
52            current X server time."
53         */
54         t = CurrentTime; /*grab_time;*/
55     return t;
56 }
57
58 gboolean grab_on_keyboard()
59 {
60     return kgrabs > 0;
61 }
62
63 gboolean grab_on_pointer()
64 {
65     return pgrabs > 0;
66 }
67
68 gboolean grab_keyboard(gboolean grab)
69 {
70     gboolean ret = FALSE;
71
72     if (grab) {
73         if (kgrabs++ == 0) {
74             ret = XGrabKeyboard(ob_display, RootWindow(ob_display, ob_screen),
75                                 False, GrabModeAsync, GrabModeAsync,
76                                 event_curtime) == Success;
77             if (!ret)
78                 --kgrabs;
79             else
80                 grab_time = event_curtime;
81         } else
82             ret = TRUE;
83     } else if (kgrabs > 0) {
84         if (--kgrabs == 0) {
85             XUngrabKeyboard(ob_display, ungrab_time());
86         }
87         ret = TRUE;
88     }
89
90     return ret;
91 }
92
93 gboolean grab_pointer(gboolean grab, ObCursor cur)
94 {
95     gboolean ret = FALSE;
96
97     if (grab) {
98         if (pgrabs++ == 0) {
99             ret = XGrabPointer(ob_display, screen_support_win,
100                                True, GRAB_PTR_MASK, GrabModeAsync,
101                                GrabModeAsync, None,
102                                ob_cursor(cur), event_curtime) == Success;
103             if (!ret)
104                 --pgrabs;
105             else
106                 grab_time = event_curtime;
107         } else
108             ret = TRUE;
109     } else if (pgrabs > 0) {
110         if (--pgrabs == 0) {
111             XUngrabPointer(ob_display, ungrab_time());
112         }
113         ret = TRUE;
114     }
115     return ret;
116 }
117
118 gboolean grab_pointer_window(gboolean grab, ObCursor cur, Window win)
119 {
120     gboolean ret = FALSE;
121
122     if (grab) {
123         if (pgrabs++ == 0) {
124             ret = XGrabPointer(ob_display, win, True, GRAB_PTR_MASK,
125                                GrabModeAsync, GrabModeAsync, None,
126                                ob_cursor(cur),
127                                event_curtime) == Success;
128             if (!ret)
129                 --pgrabs;
130             else
131                 grab_time = event_curtime;
132         } else
133             ret = TRUE;
134     } else if (pgrabs > 0) {
135         if (--pgrabs == 0) {
136             XUngrabPointer(ob_display, ungrab_time());
137         }
138         ret = TRUE;
139     }
140     return ret;
141 }
142
143 gint grab_server(gboolean grab)
144 {
145     static guint sgrabs = 0;
146     if (grab) {
147         if (sgrabs++ == 0) {
148             XGrabServer(ob_display);
149             XSync(ob_display, FALSE);
150         }
151     } else if (sgrabs > 0) {
152         if (--sgrabs == 0) {
153             XUngrabServer(ob_display);
154             XFlush(ob_display);
155         }
156     }
157     return sgrabs;
158 }
159
160 void grab_startup(gboolean reconfig)
161 {
162     guint i = 0;
163
164     if (reconfig) return;
165
166     mask_list[i++] = 0;
167     mask_list[i++] = LockMask;
168     mask_list[i++] = NumLockMask;
169     mask_list[i++] = LockMask | NumLockMask;
170     mask_list[i++] = ScrollLockMask;
171     mask_list[i++] = ScrollLockMask | LockMask;
172     mask_list[i++] = ScrollLockMask | NumLockMask;
173     mask_list[i++] = ScrollLockMask | LockMask | NumLockMask;
174     g_assert(i == MASK_LIST_SIZE);
175 }
176
177 void grab_shutdown(gboolean reconfig)
178 {
179     if (reconfig) return;
180
181     while (grab_keyboard(FALSE));
182     while (grab_pointer(FALSE, OB_CURSOR_NONE));
183     while (grab_pointer_window(FALSE, OB_CURSOR_NONE, None));
184     while (grab_server(FALSE));
185 }
186
187 void grab_button_full(guint button, guint state, Window win, guint mask,
188                       gint pointer_mode, ObCursor cur)
189 {
190     guint i;
191
192     xerror_set_ignore(TRUE); /* can get BadAccess' from these */
193     xerror_occured = FALSE;
194     for (i = 0; i < MASK_LIST_SIZE; ++i)
195         XGrabButton(ob_display, button, state | mask_list[i], win, FALSE, mask,
196                     pointer_mode, GrabModeSync, None, ob_cursor(cur));
197     xerror_set_ignore(FALSE);
198     if (xerror_occured)
199         g_warning("failed to grab button %d modifiers %d", button, state);
200 }
201
202 void grab_button(guint button, guint state, Window win, guint mask)
203 {
204     grab_button_full(button, state, win, mask, GrabModeAsync, OB_CURSOR_NONE);
205 }
206
207 void ungrab_button(guint button, guint state, Window win)
208 {
209     guint i;
210
211     for (i = 0; i < MASK_LIST_SIZE; ++i)
212         XUngrabButton(ob_display, button, state | mask_list[i], win);
213 }
214
215 void grab_key(guint keycode, guint state, Window win, gint keyboard_mode)
216 {
217     guint i;
218
219     xerror_set_ignore(TRUE); /* can get BadAccess' from these */
220     xerror_occured = FALSE;
221     for (i = 0; i < MASK_LIST_SIZE; ++i)
222         XGrabKey(ob_display, keycode, state | mask_list[i], win, FALSE,
223                  GrabModeAsync, keyboard_mode);
224     xerror_set_ignore(FALSE);
225     if (xerror_occured)
226         g_warning("failed to grab keycode %d modifiers %d", keycode, state);
227 }
228
229 void ungrab_all_keys(Window win)
230 {
231     XUngrabKey(ob_display, AnyKey, AnyModifier, win);
232 }