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 "gdkx11devicemanager-core.h"
23 #include "gdkdevicemanagerprivate-core.h"
24 #include "gdkx11device-core.h"
26 #include "gdkdeviceprivate.h"
27 #include "gdkdisplayprivate.h"
28 #include "gdkeventtranslator.h"
29 #include "gdkprivate-x11.h"
30 #include "gdkkeysyms.h"
33 #define HAS_FOCUS(toplevel) \
34 ((toplevel)->has_focus || (toplevel)->has_pointer_focus)
36 static void gdk_x11_device_manager_core_finalize (GObject *object);
37 static void gdk_x11_device_manager_core_constructed (GObject *object);
39 static GList * gdk_x11_device_manager_core_list_devices (GdkDeviceManager *device_manager,
41 static GdkDevice * gdk_x11_device_manager_core_get_client_pointer (GdkDeviceManager *device_manager);
43 static void gdk_x11_device_manager_event_translator_init (GdkEventTranslatorIface *iface);
45 static gboolean gdk_x11_device_manager_core_translate_event (GdkEventTranslator *translator,
51 G_DEFINE_TYPE_WITH_CODE (GdkX11DeviceManagerCore, gdk_x11_device_manager_core, GDK_TYPE_DEVICE_MANAGER,
52 G_IMPLEMENT_INTERFACE (GDK_TYPE_EVENT_TRANSLATOR,
53 gdk_x11_device_manager_event_translator_init))
56 gdk_x11_device_manager_core_class_init (GdkX11DeviceManagerCoreClass *klass)
58 GdkDeviceManagerClass *device_manager_class = GDK_DEVICE_MANAGER_CLASS (klass);
59 GObjectClass *object_class = G_OBJECT_CLASS (klass);
61 object_class->finalize = gdk_x11_device_manager_core_finalize;
62 object_class->constructed = gdk_x11_device_manager_core_constructed;
63 device_manager_class->list_devices = gdk_x11_device_manager_core_list_devices;
64 device_manager_class->get_client_pointer = gdk_x11_device_manager_core_get_client_pointer;
68 gdk_x11_device_manager_event_translator_init (GdkEventTranslatorIface *iface)
70 iface->translate_event = gdk_x11_device_manager_core_translate_event;
74 create_core_pointer (GdkDeviceManager *device_manager,
77 return g_object_new (GDK_TYPE_X11_DEVICE_CORE,
78 "name", "Core Pointer",
79 "type", GDK_DEVICE_TYPE_MASTER,
80 "input-source", GDK_SOURCE_MOUSE,
81 "input-mode", GDK_MODE_SCREEN,
84 "device-manager", device_manager,
89 create_core_keyboard (GdkDeviceManager *device_manager,
92 return g_object_new (GDK_TYPE_X11_DEVICE_CORE,
93 "name", "Core Keyboard",
94 "type", GDK_DEVICE_TYPE_MASTER,
95 "input-source", GDK_SOURCE_KEYBOARD,
96 "input-mode", GDK_MODE_SCREEN,
99 "device-manager", device_manager,
104 gdk_x11_device_manager_core_init (GdkX11DeviceManagerCore *device_manager)
109 gdk_x11_device_manager_core_finalize (GObject *object)
111 GdkX11DeviceManagerCore *device_manager_core;
113 device_manager_core = GDK_X11_DEVICE_MANAGER_CORE (object);
115 g_object_unref (device_manager_core->core_pointer);
116 g_object_unref (device_manager_core->core_keyboard);
118 G_OBJECT_CLASS (gdk_x11_device_manager_core_parent_class)->finalize (object);
122 gdk_x11_device_manager_core_constructed (GObject *object)
124 GdkX11DeviceManagerCore *device_manager;
127 device_manager = GDK_X11_DEVICE_MANAGER_CORE (object);
128 display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (object));
129 device_manager->core_pointer = create_core_pointer (GDK_DEVICE_MANAGER (device_manager), display);
130 device_manager->core_keyboard = create_core_keyboard (GDK_DEVICE_MANAGER (device_manager), display);
132 _gdk_device_set_associated_device (device_manager->core_pointer, device_manager->core_keyboard);
133 _gdk_device_set_associated_device (device_manager->core_keyboard, device_manager->core_pointer);
137 translate_key_event (GdkDisplay *display,
138 GdkX11DeviceManagerCore *device_manager,
142 GdkKeymap *keymap = gdk_keymap_get_for_display (display);
143 GdkModifierType consumed, state;
145 event->key.type = xevent->xany.type == KeyPress ? GDK_KEY_PRESS : GDK_KEY_RELEASE;
146 event->key.time = xevent->xkey.time;
147 gdk_event_set_device (event, device_manager->core_keyboard);
149 event->key.state = (GdkModifierType) xevent->xkey.state;
150 event->key.group = _gdk_x11_get_group_for_state (display, xevent->xkey.state);
151 event->key.hardware_keycode = xevent->xkey.keycode;
153 event->key.keyval = GDK_KEY_VoidSymbol;
155 gdk_keymap_translate_keyboard_state (keymap,
156 event->key.hardware_keycode,
160 NULL, NULL, &consumed);
162 state = event->key.state & ~consumed;
163 _gdk_x11_keymap_add_virt_mods (keymap, &state);
164 event->key.state |= state;
166 event->key.is_modifier = _gdk_x11_keymap_key_is_modifier (keymap, event->key.hardware_keycode);
168 _gdk_x11_event_translate_keyboard_string (&event->key);
170 #ifdef G_ENABLE_DEBUG
171 if (_gdk_debug_flags & GDK_DEBUG_EVENTS)
173 g_message ("%s:\t\twindow: %ld key: %12s %d",
174 event->type == GDK_KEY_PRESS ? "key press " : "key release",
176 event->key.keyval ? gdk_keyval_name (event->key.keyval) : "(none)",
179 if (event->key.length > 0)
180 g_message ("\t\tlength: %4d string: \"%s\"",
181 event->key.length, event->key.string);
183 #endif /* G_ENABLE_DEBUG */
187 #ifdef G_ENABLE_DEBUG
188 static const char notify_modes[][19] = {
195 static const char notify_details[][23] = {
200 "NotifyNonlinearVirtual",
208 set_user_time (GdkWindow *window,
211 g_return_if_fail (event != NULL);
213 window = gdk_window_get_toplevel (event->any.window);
214 g_return_if_fail (GDK_IS_WINDOW (window));
216 /* If an event doesn't have a valid timestamp, we shouldn't use it
217 * to update the latest user interaction time.
219 if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
220 gdk_x11_window_set_user_time (gdk_window_get_toplevel (window),
221 gdk_event_get_time (event));
225 set_screen_from_root (GdkDisplay *display,
231 screen = _gdk_x11_display_screen_for_xrootwin (display, xrootwin);
235 gdk_event_set_screen (event, screen);
243 static GdkCrossingMode
244 translate_crossing_mode (int mode)
249 return GDK_CROSSING_NORMAL;
251 return GDK_CROSSING_GRAB;
253 return GDK_CROSSING_UNGRAB;
255 g_assert_not_reached ();
260 translate_notify_type (int detail)
265 return GDK_NOTIFY_INFERIOR;
267 return GDK_NOTIFY_ANCESTOR;
269 return GDK_NOTIFY_VIRTUAL;
270 case NotifyNonlinear:
271 return GDK_NOTIFY_NONLINEAR;
272 case NotifyNonlinearVirtual:
273 return GDK_NOTIFY_NONLINEAR_VIRTUAL;
275 g_assert_not_reached ();
280 is_parent_of (GdkWindow *parent,
291 w = gdk_window_get_parent (w);
298 get_event_window (GdkEventTranslator *translator,
301 GdkDeviceManager *device_manager;
305 device_manager = GDK_DEVICE_MANAGER (translator);
306 display = gdk_device_manager_get_display (device_manager);
307 window = gdk_x11_window_lookup_for_display (display, xevent->xany.window);
309 /* Apply keyboard grabs to non-native windows */
310 if (xevent->type == KeyPress || xevent->type == KeyRelease)
312 GdkDeviceGrabInfo *info;
315 serial = _gdk_display_get_next_serial (display);
316 info = _gdk_display_has_device_grab (display,
317 GDK_X11_DEVICE_MANAGER_CORE (device_manager)->core_keyboard,
320 (!is_parent_of (info->window, window) ||
321 !info->owner_events))
323 /* Report key event against grab window */
324 window = info->window;
332 gdk_x11_device_manager_core_translate_event (GdkEventTranslator *translator,
337 GdkX11DeviceManagerCore *device_manager;
340 GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
342 device_manager = GDK_X11_DEVICE_MANAGER_CORE (translator);
345 window = get_event_window (translator, xevent);
349 if (GDK_WINDOW_DESTROYED (window) || !GDK_IS_WINDOW (window))
352 g_object_ref (window);
355 event->any.window = window;
356 event->any.send_event = xevent->xany.send_event ? TRUE : FALSE;
358 if (window && GDK_WINDOW_DESTROYED (window))
360 if (xevent->type != DestroyNotify)
368 (xevent->type == MotionNotify ||
369 xevent->type == ButtonRelease))
371 if (_gdk_x11_moveresize_handle_event (xevent))
378 /* We do a "manual" conversion of the XEvent to a
379 * GdkEvent. The structures are mostly the same so
380 * the conversion is fairly straightforward. We also
381 * optionally print debugging info regarding events
387 switch (xevent->type)
395 translate_key_event (display, device_manager, event, xevent);
396 set_user_time (window, event);
406 /* Emulate detectable auto-repeat by checking to see
407 * if the next event is a key press with the same
408 * keycode and timestamp, and if so, ignoring the event.
411 if (!display_x11->have_xkb_autorepeat && XPending (xevent->xkey.display))
415 XPeekEvent (xevent->xkey.display, &next_event);
417 if (next_event.type == KeyPress &&
418 next_event.xkey.keycode == xevent->xkey.keycode &&
419 next_event.xkey.time == xevent->xkey.time)
426 translate_key_event (display, device_manager, event, xevent);
431 g_message ("button press:\t\twindow: %ld x,y: %d %d button: %d",
432 xevent->xbutton.window,
433 xevent->xbutton.x, xevent->xbutton.y,
434 xevent->xbutton.button));
442 /* If we get a ButtonPress event where the button is 4 or 5,
443 it's a Scroll event */
444 switch (xevent->xbutton.button)
450 event->scroll.type = GDK_SCROLL;
452 if (xevent->xbutton.button == 4)
453 event->scroll.direction = GDK_SCROLL_UP;
454 else if (xevent->xbutton.button == 5)
455 event->scroll.direction = GDK_SCROLL_DOWN;
456 else if (xevent->xbutton.button == 6)
457 event->scroll.direction = GDK_SCROLL_LEFT;
459 event->scroll.direction = GDK_SCROLL_RIGHT;
461 event->scroll.window = window;
462 event->scroll.time = xevent->xbutton.time;
463 event->scroll.x = (gdouble) xevent->xbutton.x;
464 event->scroll.y = (gdouble) xevent->xbutton.y;
465 event->scroll.x_root = (gdouble) xevent->xbutton.x_root;
466 event->scroll.y_root = (gdouble) xevent->xbutton.y_root;
467 event->scroll.state = (GdkModifierType) xevent->xbutton.state;
468 event->scroll.device = device_manager->core_pointer;
470 if (!set_screen_from_root (display, event, xevent->xbutton.root))
479 event->button.type = GDK_BUTTON_PRESS;
480 event->button.window = window;
481 event->button.time = xevent->xbutton.time;
482 event->button.x = (gdouble) xevent->xbutton.x;
483 event->button.y = (gdouble) xevent->xbutton.y;
484 event->button.x_root = (gdouble) xevent->xbutton.x_root;
485 event->button.y_root = (gdouble) xevent->xbutton.y_root;
486 event->button.axes = NULL;
487 event->button.state = (GdkModifierType) xevent->xbutton.state;
488 event->button.button = xevent->xbutton.button;
489 event->button.device = device_manager->core_pointer;
491 if (!set_screen_from_root (display, event, xevent->xbutton.root))
497 set_user_time (window, event);
503 g_message ("button release:\twindow: %ld x,y: %d %d button: %d",
504 xevent->xbutton.window,
505 xevent->xbutton.x, xevent->xbutton.y,
506 xevent->xbutton.button));
514 /* We treat button presses as scroll wheel events, so ignore the release */
515 if (xevent->xbutton.button == 4 || xevent->xbutton.button == 5 ||
516 xevent->xbutton.button == 6 || xevent->xbutton.button == 7)
522 event->button.type = GDK_BUTTON_RELEASE;
523 event->button.window = window;
524 event->button.time = xevent->xbutton.time;
525 event->button.x = (gdouble) xevent->xbutton.x;
526 event->button.y = (gdouble) xevent->xbutton.y;
527 event->button.x_root = (gdouble) xevent->xbutton.x_root;
528 event->button.y_root = (gdouble) xevent->xbutton.y_root;
529 event->button.axes = NULL;
530 event->button.state = (GdkModifierType) xevent->xbutton.state;
531 event->button.button = xevent->xbutton.button;
532 event->button.device = device_manager->core_pointer;
534 if (!set_screen_from_root (display, event, xevent->xbutton.root))
541 g_message ("motion notify:\t\twindow: %ld x,y: %d %d hint: %s",
542 xevent->xmotion.window,
543 xevent->xmotion.x, xevent->xmotion.y,
544 (xevent->xmotion.is_hint) ? "true" : "false"));
552 event->motion.type = GDK_MOTION_NOTIFY;
553 event->motion.window = window;
554 event->motion.time = xevent->xmotion.time;
555 event->motion.x = (gdouble) xevent->xmotion.x;
556 event->motion.y = (gdouble) xevent->xmotion.y;
557 event->motion.x_root = (gdouble) xevent->xmotion.x_root;
558 event->motion.y_root = (gdouble) xevent->xmotion.y_root;
559 event->motion.axes = NULL;
560 event->motion.state = (GdkModifierType) xevent->xmotion.state;
561 event->motion.is_hint = xevent->xmotion.is_hint;
562 event->motion.device = device_manager->core_pointer;
564 if (!set_screen_from_root (display, event, xevent->xbutton.root))
574 g_message ("enter notify:\t\twindow: %ld detail: %d subwin: %ld",
575 xevent->xcrossing.window,
576 xevent->xcrossing.detail,
577 xevent->xcrossing.subwindow));
585 if (!set_screen_from_root (display, event, xevent->xbutton.root))
591 event->crossing.type = GDK_ENTER_NOTIFY;
592 event->crossing.window = window;
593 gdk_event_set_device (event, device_manager->core_pointer);
595 /* If the subwindow field of the XEvent is non-NULL, then
596 * lookup the corresponding GdkWindow.
598 if (xevent->xcrossing.subwindow != None)
599 event->crossing.subwindow = gdk_x11_window_lookup_for_display (display, xevent->xcrossing.subwindow);
601 event->crossing.subwindow = NULL;
603 event->crossing.time = xevent->xcrossing.time;
604 event->crossing.x = (gdouble) xevent->xcrossing.x;
605 event->crossing.y = (gdouble) xevent->xcrossing.y;
606 event->crossing.x_root = (gdouble) xevent->xcrossing.x_root;
607 event->crossing.y_root = (gdouble) xevent->xcrossing.y_root;
609 event->crossing.mode = translate_crossing_mode (xevent->xcrossing.mode);
610 event->crossing.detail = translate_notify_type (xevent->xcrossing.detail);
612 event->crossing.focus = xevent->xcrossing.focus;
613 event->crossing.state = xevent->xcrossing.state;
619 g_message ("leave notify:\t\twindow: %ld detail: %d subwin: %ld",
620 xevent->xcrossing.window,
621 xevent->xcrossing.detail, xevent->xcrossing.subwindow));
629 if (!set_screen_from_root (display, event, xevent->xbutton.root))
635 event->crossing.type = GDK_LEAVE_NOTIFY;
636 event->crossing.window = window;
637 gdk_event_set_device (event, device_manager->core_pointer);
639 /* If the subwindow field of the XEvent is non-NULL, then
640 * lookup the corresponding GdkWindow.
642 if (xevent->xcrossing.subwindow != None)
643 event->crossing.subwindow = gdk_x11_window_lookup_for_display (display, xevent->xcrossing.subwindow);
645 event->crossing.subwindow = NULL;
647 event->crossing.time = xevent->xcrossing.time;
648 event->crossing.x = (gdouble) xevent->xcrossing.x;
649 event->crossing.y = (gdouble) xevent->xcrossing.y;
650 event->crossing.x_root = (gdouble) xevent->xcrossing.x_root;
651 event->crossing.y_root = (gdouble) xevent->xcrossing.y_root;
653 event->crossing.mode = translate_crossing_mode (xevent->xcrossing.mode);
654 event->crossing.detail = translate_notify_type (xevent->xcrossing.detail);
656 event->crossing.focus = xevent->xcrossing.focus;
657 event->crossing.state = xevent->xcrossing.state;
664 _gdk_device_manager_core_handle_focus (window,
665 device_manager->core_keyboard,
667 xevent->type == FocusIn,
668 xevent->xfocus.detail,
669 xevent->xfocus.mode);
680 if (event->any.window)
681 g_object_ref (event->any.window);
683 if (((event->any.type == GDK_ENTER_NOTIFY) ||
684 (event->any.type == GDK_LEAVE_NOTIFY)) &&
685 (event->crossing.subwindow != NULL))
686 g_object_ref (event->crossing.subwindow);
690 /* Mark this event as having no resources to be freed */
691 event->any.window = NULL;
692 event->any.type = GDK_NOTHING;
696 g_object_unref (window);
702 gdk_x11_device_manager_core_list_devices (GdkDeviceManager *device_manager,
705 GdkX11DeviceManagerCore *device_manager_core;
706 GList *devices = NULL;
708 if (type == GDK_DEVICE_TYPE_MASTER)
710 device_manager_core = (GdkX11DeviceManagerCore *) device_manager;
711 devices = g_list_prepend (devices, device_manager_core->core_keyboard);
712 devices = g_list_prepend (devices, device_manager_core->core_pointer);
719 gdk_x11_device_manager_core_get_client_pointer (GdkDeviceManager *device_manager)
721 GdkX11DeviceManagerCore *device_manager_core;
723 device_manager_core = (GdkX11DeviceManagerCore *) device_manager;
724 return device_manager_core->core_pointer;
728 _gdk_x11_event_translate_keyboard_string (GdkEventKey *event)
733 /* Fill in event->string crudely, since various programs
736 event->string = NULL;
738 if (event->keyval != GDK_KEY_VoidSymbol)
739 c = gdk_keyval_to_unicode (event->keyval);
746 /* Apply the control key - Taken from Xlib
748 if (event->state & GDK_CONTROL_MASK)
750 if ((c >= '@' && c < '\177') || c == ' ') c &= 0x1F;
753 event->string = g_memdup ("\0\0", 2);
758 else if (c >= '3' && c <= '7') c -= ('3' - '\033');
759 else if (c == '8') c = '\177';
760 else if (c == '/') c = '_' & 0x1F;
763 len = g_unichar_to_utf8 (c, buf);
766 event->string = g_locale_from_utf8 (buf, len,
767 NULL, &bytes_written,
770 event->length = bytes_written;
772 else if (event->keyval == GDK_KEY_Escape)
775 event->string = g_strdup ("\033");
777 else if (event->keyval == GDK_KEY_Return ||
778 event->keyval == GDK_KEY_KP_Enter)
781 event->string = g_strdup ("\r");
787 event->string = g_strdup ("");
791 /* We only care about focus events that indicate that _this_
792 * window (not a ancestor or child) got or lost the focus
795 _gdk_device_manager_core_handle_focus (GdkWindow *window,
797 GdkDevice *source_device,
802 GdkToplevelX11 *toplevel;
805 g_return_if_fail (GDK_IS_WINDOW (window));
806 g_return_if_fail (GDK_IS_DEVICE (device));
807 g_return_if_fail (source_device == NULL || GDK_IS_DEVICE (source_device));
810 g_message ("focus out:\t\twindow: %ld, detail: %s, mode: %s",
811 GDK_WINDOW_XID (window),
812 notify_details[detail],
813 notify_modes[mode]));
815 toplevel = _gdk_x11_window_get_toplevel (window);
820 had_focus = HAS_FOCUS (toplevel);
826 /* When the focus moves from an ancestor of the window to
827 * the window or a descendent of the window, *and* the
828 * pointer is inside the window, then we were previously
829 * receiving keystroke events in the has_pointer_focus
830 * case and are now receiving them in the
831 * has_focus_window case.
833 if (toplevel->has_pointer &&
834 mode != NotifyGrab &&
835 mode != NotifyUngrab)
836 toplevel->has_pointer_focus = (focus_in) ? FALSE : TRUE;
839 case NotifyNonlinear:
840 case NotifyNonlinearVirtual:
841 if (mode != NotifyGrab &&
842 mode != NotifyUngrab)
843 toplevel->has_focus_window = (focus_in) ? TRUE : FALSE;
844 /* We pretend that the focus moves to the grab
845 * window, so we pay attention to NotifyGrab
846 * NotifyUngrab, and ignore NotifyWhileGrabbed
848 if (mode != NotifyWhileGrabbed)
849 toplevel->has_focus = (focus_in) ? TRUE : FALSE;
852 /* The X server sends NotifyPointer/NotifyGrab,
853 * but the pointer focus is ignored while a
856 if (mode != NotifyGrab &&
857 mode != NotifyUngrab)
858 toplevel->has_pointer_focus = (focus_in) ? TRUE : FALSE;
861 case NotifyPointerRoot:
862 case NotifyDetailNone:
867 if (HAS_FOCUS (toplevel) != had_focus)
871 event = gdk_event_new (GDK_FOCUS_CHANGE);
872 event->focus_change.window = g_object_ref (window);
873 event->focus_change.send_event = FALSE;
874 event->focus_change.in = focus_in;
875 gdk_event_set_device (event, device);
877 gdk_event_set_source_device (event, source_device);
879 gdk_event_put (event);
880 gdk_event_free (event);