1 /* GDK - The GIMP Drawing Kit
2 * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
22 #include "gdkx11device-core.h"
23 #include "gdkdeviceprivate.h"
25 #include "gdkinternals.h"
26 #include "gdkwindow.h"
27 #include "gdkprivate-x11.h"
30 struct _GdkX11DeviceCore
32 GdkDevice parent_instance;
35 struct _GdkX11DeviceCoreClass
37 GdkDeviceClass parent_class;
40 static gboolean gdk_x11_device_core_get_history (GdkDevice *device,
44 GdkTimeCoord ***events,
46 static void gdk_x11_device_core_get_state (GdkDevice *device,
49 GdkModifierType *mask);
50 static void gdk_x11_device_core_set_window_cursor (GdkDevice *device,
53 static void gdk_x11_device_core_warp (GdkDevice *device,
57 static gboolean gdk_x11_device_core_query_state (GdkDevice *device,
59 GdkWindow **root_window,
60 GdkWindow **child_window,
65 GdkModifierType *mask);
66 static GdkGrabStatus gdk_x11_device_core_grab (GdkDevice *device,
68 gboolean owner_events,
69 GdkEventMask event_mask,
70 GdkWindow *confine_to,
73 static void gdk_x11_device_core_ungrab (GdkDevice *device,
75 static GdkWindow * gdk_x11_device_core_window_at_position (GdkDevice *device,
78 GdkModifierType *mask,
79 gboolean get_toplevel);
80 static void gdk_x11_device_core_select_window_events (GdkDevice *device,
82 GdkEventMask event_mask);
84 G_DEFINE_TYPE (GdkX11DeviceCore, gdk_x11_device_core, GDK_TYPE_DEVICE)
87 gdk_x11_device_core_class_init (GdkX11DeviceCoreClass *klass)
89 GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass);
91 device_class->get_history = gdk_x11_device_core_get_history;
92 device_class->get_state = gdk_x11_device_core_get_state;
93 device_class->set_window_cursor = gdk_x11_device_core_set_window_cursor;
94 device_class->warp = gdk_x11_device_core_warp;
95 device_class->query_state = gdk_x11_device_core_query_state;
96 device_class->grab = gdk_x11_device_core_grab;
97 device_class->ungrab = gdk_x11_device_core_ungrab;
98 device_class->window_at_position = gdk_x11_device_core_window_at_position;
99 device_class->select_window_events = gdk_x11_device_core_select_window_events;
103 gdk_x11_device_core_init (GdkX11DeviceCore *device_core)
107 device = GDK_DEVICE (device_core);
109 _gdk_device_add_axis (device, GDK_NONE, GDK_AXIS_X, 0, 0, 1);
110 _gdk_device_add_axis (device, GDK_NONE, GDK_AXIS_Y, 0, 0, 1);
114 impl_coord_in_window (GdkWindow *window,
118 if (impl_x < window->abs_x ||
119 impl_x >= window->abs_x + window->width)
122 if (impl_y < window->abs_y ||
123 impl_y >= window->abs_y + window->height)
130 gdk_x11_device_core_get_history (GdkDevice *device,
134 GdkTimeCoord ***events,
138 GdkTimeCoord **coords;
139 GdkWindow *impl_window;
143 impl_window = _gdk_window_get_impl_window (window);
144 xcoords = XGetMotionEvents (GDK_WINDOW_XDISPLAY (window),
145 GDK_WINDOW_XID (impl_window),
146 start, stop, &tmp_n_events);
150 coords = _gdk_device_allocate_history (device, tmp_n_events);
152 for (i = 0, j = 0; i < tmp_n_events; i++)
154 if (impl_coord_in_window (window, xcoords[i].x, xcoords[i].y))
156 coords[j]->time = xcoords[i].time;
157 coords[j]->axes[0] = xcoords[i].x - window->abs_x;
158 coords[j]->axes[1] = xcoords[i].y - window->abs_y;
165 /* free the events we allocated too much */
166 for (i = j; i < tmp_n_events; i++)
174 if (tmp_n_events == 0)
176 gdk_device_free_history (coords, tmp_n_events);
181 *n_events = tmp_n_events;
186 gdk_device_free_history (coords, tmp_n_events);
192 gdk_x11_device_core_get_state (GdkDevice *device,
195 GdkModifierType *mask)
199 gdk_window_get_pointer (window, &x_int, &y_int, mask);
209 gdk_x11_device_core_set_window_cursor (GdkDevice *device,
218 xcursor = gdk_x11_cursor_get_xcursor (cursor);
220 XDefineCursor (GDK_WINDOW_XDISPLAY (window),
221 GDK_WINDOW_XID (window),
226 gdk_x11_device_core_warp (GdkDevice *device,
234 xdisplay = GDK_DISPLAY_XDISPLAY (gdk_device_get_display (device));
235 dest = GDK_WINDOW_XID (gdk_screen_get_root_window (screen));
237 XWarpPointer (xdisplay, None, dest, 0, 0, 0, 0, x, y);
241 gdk_x11_device_core_query_state (GdkDevice *device,
243 GdkWindow **root_window,
244 GdkWindow **child_window,
249 GdkModifierType *mask)
252 GdkScreen *default_screen;
253 Window xroot_window, xchild_window;
254 int xroot_x, xroot_y, xwin_x, xwin_y;
257 display = gdk_window_get_display (window);
258 default_screen = gdk_display_get_default_screen (display);
260 if (G_LIKELY (GDK_X11_DISPLAY (display)->trusted_client))
262 if (!XQueryPointer (GDK_WINDOW_XDISPLAY (window),
263 GDK_WINDOW_XID (window),
273 XSetWindowAttributes attributes;
277 /* FIXME: untrusted clients not multidevice-safe */
278 xdisplay = GDK_SCREEN_XDISPLAY (default_screen);
279 xwindow = GDK_SCREEN_XROOTWIN (default_screen);
281 w = XCreateWindow (xdisplay, xwindow, 0, 0, 1, 1, 0,
282 CopyFromParent, InputOnly, CopyFromParent,
284 XQueryPointer (xdisplay, w,
290 XDestroyWindow (xdisplay, w);
294 *root_window = gdk_x11_window_lookup_for_display (display, xroot_window);
297 *child_window = gdk_x11_window_lookup_for_display (display, xchild_window);
318 gdk_x11_device_core_grab (GdkDevice *device,
320 gboolean owner_events,
321 GdkEventMask event_mask,
322 GdkWindow *confine_to,
327 Window xwindow, xconfine_to;
330 display = gdk_device_get_display (device);
332 xwindow = GDK_WINDOW_XID (window);
335 confine_to = _gdk_window_get_impl_window (confine_to);
337 if (!confine_to || GDK_WINDOW_DESTROYED (confine_to))
340 xconfine_to = GDK_WINDOW_XID (confine_to);
342 #ifdef G_ENABLE_DEBUG
343 if (_gdk_debug_flags & GDK_DEBUG_NOGRABS)
344 status = GrabSuccess;
347 if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
349 /* Device is a keyboard */
350 status = XGrabKeyboard (GDK_DISPLAY_XDISPLAY (display),
353 GrabModeAsync, GrabModeAsync,
362 /* Device is a pointer */
367 _gdk_x11_cursor_update_theme (cursor);
368 xcursor = gdk_x11_cursor_get_xcursor (cursor);
373 for (i = 0; i < _gdk_x11_event_mask_table_size; i++)
375 if (event_mask & (1 << (i + 1)))
376 xevent_mask |= _gdk_x11_event_mask_table[i];
379 /* We don't want to set a native motion hint mask, as we're emulating motion
380 * hints. If we set a native one we just wouldn't get any events.
382 xevent_mask &= ~PointerMotionHintMask;
384 status = XGrabPointer (GDK_DISPLAY_XDISPLAY (display),
388 GrabModeAsync, GrabModeAsync,
394 _gdk_x11_display_update_grab_info (display, device, status);
396 return _gdk_x11_convert_grab_status (status);
400 gdk_x11_device_core_ungrab (GdkDevice *device,
406 display = gdk_device_get_display (device);
407 serial = NextRequest (GDK_DISPLAY_XDISPLAY (display));
409 if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
410 XUngrabKeyboard (GDK_DISPLAY_XDISPLAY (display), time_);
412 XUngrabPointer (GDK_DISPLAY_XDISPLAY (display), time_);
414 _gdk_x11_display_update_grab_info_ungrab (display, device, time_, serial);
418 gdk_x11_device_core_window_at_position (GdkDevice *device,
421 GdkModifierType *mask,
422 gboolean get_toplevel)
428 Window xwindow, root, child, last;
429 int xroot_x, xroot_y, xwin_x, xwin_y;
433 display = gdk_device_get_display (device);
434 screen = gdk_display_get_default_screen (display);
436 /* This function really only works if the mouse pointer is held still
437 * during its operation. If it moves from one leaf window to another
438 * than we'll end up with inaccurate values for win_x, win_y
441 gdk_x11_display_grab (display);
443 xdisplay = GDK_SCREEN_XDISPLAY (screen);
444 xwindow = GDK_SCREEN_XROOTWIN (screen);
446 if (G_LIKELY (GDK_X11_DISPLAY (display)->trusted_client))
448 XQueryPointer (xdisplay, xwindow,
461 gint i, screens, width, height;
462 GList *toplevels, *list;
463 Window pointer_window, root, child;
464 int rootx = -1, rooty = -1;
468 /* FIXME: untrusted clients case not multidevice-safe */
469 pointer_window = None;
470 screens = gdk_display_get_n_screens (display);
472 for (i = 0; i < screens; ++i)
474 screen = gdk_display_get_screen (display, i);
475 toplevels = gdk_screen_get_toplevel_windows (screen);
476 for (list = toplevels; list != NULL; list = g_list_next (list))
478 window = GDK_WINDOW (list->data);
479 xwindow = GDK_WINDOW_XID (window);
480 gdk_x11_display_error_trap_push (display);
481 XQueryPointer (xdisplay, xwindow,
486 if (gdk_x11_display_error_trap_pop (display))
490 pointer_window = child;
493 gdk_window_get_geometry (window, NULL, NULL, &width, &height);
494 if (winx >= 0 && winy >= 0 && winx < width && winy < height)
496 /* A childless toplevel, or below another window? */
497 XSetWindowAttributes attributes;
500 w = XCreateWindow (xdisplay, xwindow, winx, winy, 1, 1, 0,
501 CopyFromParent, InputOnly, CopyFromParent,
503 XMapWindow (xdisplay, w);
504 XQueryPointer (xdisplay, xwindow,
509 XDestroyWindow (xdisplay, w);
512 pointer_window = xwindow;
518 g_list_free (toplevels);
519 if (pointer_window != None)
523 xwindow = pointer_window;
529 gdk_x11_display_error_trap_push (display);
530 XQueryPointer (xdisplay, xwindow,
535 if (gdk_x11_display_error_trap_pop (display))
538 if (get_toplevel && last != root &&
539 (window = gdk_x11_window_lookup_for_display (display, last)) != NULL &&
540 window->window_type != GDK_WINDOW_FOREIGN)
547 gdk_x11_display_ungrab (display);
549 window = gdk_x11_window_lookup_for_display (display, last);
552 *win_x = (window) ? xwin_x : -1;
555 *win_y = (window) ? xwin_y : -1;
564 gdk_x11_device_core_select_window_events (GdkDevice *device,
566 GdkEventMask event_mask)
568 GdkEventMask filter_mask, window_mask;
572 window_mask = gdk_window_get_events (window);
573 filter_mask = (GDK_POINTER_MOTION_MASK &
574 GDK_POINTER_MOTION_HINT_MASK &
575 GDK_BUTTON_MOTION_MASK &
576 GDK_BUTTON1_MOTION_MASK &
577 GDK_BUTTON2_MOTION_MASK &
578 GDK_BUTTON3_MOTION_MASK &
579 GDK_BUTTON_PRESS_MASK &
580 GDK_BUTTON_RELEASE_MASK &
582 GDK_KEY_RELEASE_MASK &
583 GDK_ENTER_NOTIFY_MASK &
584 GDK_LEAVE_NOTIFY_MASK &
585 GDK_FOCUS_CHANGE_MASK &
586 GDK_PROXIMITY_IN_MASK &
587 GDK_PROXIMITY_OUT_MASK &
590 /* Filter out non-device events */
591 event_mask &= filter_mask;
593 /* Unset device events on window mask */
594 window_mask &= ~(filter_mask);
597 event_mask |= window_mask;
599 for (i = 0; i < _gdk_x11_event_mask_table_size; i++)
601 if (event_mask & (1 << (i + 1)))
602 xmask |= _gdk_x11_event_mask_table[i];
605 if (GDK_WINDOW_XID (window) != GDK_WINDOW_XROOTWIN (window))
606 xmask |= StructureNotifyMask | PropertyChangeMask;
608 XSelectInput (GDK_WINDOW_XDISPLAY (window),
609 GDK_WINDOW_XID (window),