use CurrentTime when time gets moved backwards
[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 | PointerMotionMask)
30 #define GRAB_KEY_MASK (KeyPressMask | KeyReleaseMask)
31
32 #define MASK_LIST_SIZE 8
33
34 /*! A list of all possible combinations of keyboard lock masks */
35 static guint mask_list[MASK_LIST_SIZE];
36 static guint kgrabs = 0;
37 static guint pgrabs = 0;
38 /*! The time at which the last grab was made */
39 static Time  grab_time = CurrentTime;
40
41 static Time ungrab_time()
42 {
43     Time t = event_curtime;
44     if (!(t == 0 || event_time_after(t, grab_time)))
45         /* When the time moves backward on the server, then we can't use
46            the grab time because that will be in the future. So instead we
47            have to use CurrentTime.
48
49            "XUngrabPointer does not release the pointer if the specified time
50            is earlier than the last-pointer-grab time or is later than the
51            current X server time."
52         */
53         t = CurrentTime; /*grab_time;*/
54     return t;
55 }
56
57 gboolean grab_on_keyboard()
58 {
59     return kgrabs > 0;
60 }
61
62 gboolean grab_on_pointer()
63 {
64     return pgrabs > 0;
65 }
66
67 gboolean grab_keyboard(gboolean grab)
68 {
69     gboolean ret = FALSE;
70
71     if (grab) {
72         if (kgrabs++ == 0) {
73             ret = XGrabKeyboard(ob_display, RootWindow(ob_display, ob_screen),
74                                 FALSE, GrabModeAsync, GrabModeAsync,
75                                 event_curtime) == Success;
76             if (!ret)
77                 --kgrabs;
78             else
79                 grab_time = event_curtime;
80         } else
81             ret = TRUE;
82     } else if (kgrabs > 0) {
83         if (--kgrabs == 0) {
84             XUngrabKeyboard(ob_display, ungrab_time());
85         }
86         ret = TRUE;
87     }
88
89     return ret;
90 }
91
92 gboolean grab_pointer(gboolean grab, ObCursor cur)
93 {
94     gboolean ret = FALSE;
95
96     if (grab) {
97         if (pgrabs++ == 0) {
98             ret = XGrabPointer(ob_display, screen_support_win,
99                                False, GRAB_PTR_MASK, GrabModeAsync,
100                                GrabModeAsync, None,
101                                ob_cursor(cur), event_curtime) == Success;
102             if (!ret)
103                 --pgrabs;
104             else
105                 grab_time = event_curtime;
106         } else
107             ret = TRUE;
108     } else if (pgrabs > 0) {
109         if (--pgrabs == 0) {
110             XUngrabPointer(ob_display, ungrab_time());
111         }
112         ret = TRUE;
113     }
114     return ret;
115 }
116
117 gboolean grab_pointer_window(gboolean grab, ObCursor cur, Window win)
118 {
119     gboolean ret = FALSE;
120
121     if (grab) {
122         if (pgrabs++ == 0) {
123             ret = XGrabPointer(ob_display, win, False, GRAB_PTR_MASK,
124                                GrabModeAsync, GrabModeAsync, None,
125                                ob_cursor(cur),
126                                event_curtime) == Success;
127             if (!ret)
128                 --pgrabs;
129             else
130                 grab_time = event_curtime;
131         } else
132             ret = TRUE;
133     } else if (pgrabs > 0) {
134         if (--pgrabs == 0) {
135             XUngrabPointer(ob_display, ungrab_time());
136         }
137         ret = TRUE;
138     }
139     return ret;
140 }
141
142 gint grab_server(gboolean grab)
143 {
144     static guint sgrabs = 0;
145     if (grab) {
146         if (sgrabs++ == 0) {
147             XGrabServer(ob_display);
148             XSync(ob_display, FALSE);
149         }
150     } else if (sgrabs > 0) {
151         if (--sgrabs == 0) {
152             XUngrabServer(ob_display);
153             XFlush(ob_display);
154         }
155     }
156     return sgrabs;
157 }
158
159 void grab_startup(gboolean reconfig)
160 {
161     guint i = 0;
162
163     if (reconfig) return;
164
165     mask_list[i++] = 0;
166     mask_list[i++] = LockMask;
167     mask_list[i++] = NumLockMask;
168     mask_list[i++] = LockMask | NumLockMask;
169     mask_list[i++] = ScrollLockMask;
170     mask_list[i++] = ScrollLockMask | LockMask;
171     mask_list[i++] = ScrollLockMask | NumLockMask;
172     mask_list[i++] = ScrollLockMask | LockMask | NumLockMask;
173     g_assert(i == MASK_LIST_SIZE);
174 }
175
176 void grab_shutdown(gboolean reconfig)
177 {
178     if (reconfig) return;
179
180     while (grab_keyboard(FALSE));
181     while (grab_pointer(FALSE, OB_CURSOR_NONE));
182     while (grab_pointer_window(FALSE, OB_CURSOR_NONE, None));
183     while (grab_server(FALSE));
184 }
185
186 void grab_button_full(guint button, guint state, Window win, guint mask,
187                       gint pointer_mode, ObCursor cur)
188 {
189     guint i;
190
191     xerror_set_ignore(TRUE); /* can get BadAccess' from these */
192     xerror_occured = FALSE;
193     for (i = 0; i < MASK_LIST_SIZE; ++i)
194         XGrabButton(ob_display, button, state | mask_list[i], win, FALSE, mask,
195                     pointer_mode, GrabModeSync, None, ob_cursor(cur));
196     xerror_set_ignore(FALSE);
197     if (xerror_occured)
198         g_warning("failed to grab button %d modifiers %d", button, state);
199 }
200
201 void grab_button(guint button, guint state, Window win, guint mask)
202 {
203     grab_button_full(button, state, win, mask, GrabModeAsync, OB_CURSOR_NONE);
204 }
205
206 void ungrab_button(guint button, guint state, Window win)
207 {
208     guint i;
209
210     for (i = 0; i < MASK_LIST_SIZE; ++i)
211         XUngrabButton(ob_display, button, state | mask_list[i], win);
212 }
213
214 void grab_key(guint keycode, guint state, Window win, gint keyboard_mode)
215 {
216     guint i;
217
218     xerror_set_ignore(TRUE); /* can get BadAccess' from these */
219     xerror_occured = FALSE;
220     for (i = 0; i < MASK_LIST_SIZE; ++i)
221         XGrabKey(ob_display, keycode, state | mask_list[i], win, FALSE,
222                  GrabModeAsync, keyboard_mode);
223     xerror_set_ignore(FALSE);
224     if (xerror_occured)
225         g_warning("failed to grab keycode %d modifiers %d", keycode, state);
226 }
227
228 void ungrab_all_keys(Window win)
229 {
230     XUngrabKey(ob_display, AnyKey, AnyModifier, win);
231 }