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 <gdk/gdktypes.h>
23 #include <gdk/gdkdevicemanager.h>
24 #include "gdkdevicemanager-core.h"
25 #include "gdkeventtranslator.h"
26 #include "gdkdevice-core.h"
27 #include "gdkkeysyms.h"
28 #include "gdkprivate-x11.h"
32 #include <X11/XKBlib.h>
36 #define HAS_FOCUS(toplevel) \
37 ((toplevel)->has_focus || (toplevel)->has_pointer_focus)
39 static void gdk_device_manager_core_finalize (GObject *object);
40 static void gdk_device_manager_core_constructed (GObject *object);
42 static GList * gdk_device_manager_core_list_devices (GdkDeviceManager *device_manager,
44 static GdkDevice * gdk_device_manager_core_get_client_pointer (GdkDeviceManager *device_manager);
46 static void gdk_device_manager_event_translator_init (GdkEventTranslatorIface *iface);
48 static gboolean gdk_device_manager_core_translate_event (GdkEventTranslator *translator,
54 G_DEFINE_TYPE_WITH_CODE (GdkDeviceManagerCore, gdk_device_manager_core, GDK_TYPE_DEVICE_MANAGER,
55 G_IMPLEMENT_INTERFACE (GDK_TYPE_EVENT_TRANSLATOR,
56 gdk_device_manager_event_translator_init))
59 gdk_device_manager_core_class_init (GdkDeviceManagerCoreClass *klass)
61 GdkDeviceManagerClass *device_manager_class = GDK_DEVICE_MANAGER_CLASS (klass);
62 GObjectClass *object_class = G_OBJECT_CLASS (klass);
64 object_class->finalize = gdk_device_manager_core_finalize;
65 object_class->constructed = gdk_device_manager_core_constructed;
66 device_manager_class->list_devices = gdk_device_manager_core_list_devices;
67 device_manager_class->get_client_pointer = gdk_device_manager_core_get_client_pointer;
71 gdk_device_manager_event_translator_init (GdkEventTranslatorIface *iface)
73 iface->translate_event = gdk_device_manager_core_translate_event;
77 create_core_pointer (GdkDeviceManager *device_manager,
80 return g_object_new (GDK_TYPE_DEVICE_CORE,
81 "name", "Core Pointer",
82 "type", GDK_DEVICE_TYPE_MASTER,
83 "input-source", GDK_SOURCE_MOUSE,
84 "input-mode", GDK_MODE_SCREEN,
87 "device-manager", device_manager,
92 create_core_keyboard (GdkDeviceManager *device_manager,
95 return g_object_new (GDK_TYPE_DEVICE_CORE,
96 "name", "Core Keyboard",
97 "type", GDK_DEVICE_TYPE_MASTER,
98 "input-source", GDK_SOURCE_KEYBOARD,
99 "input-mode", GDK_MODE_SCREEN,
102 "device-manager", device_manager,
107 gdk_device_manager_core_init (GdkDeviceManagerCore *device_manager)
112 gdk_device_manager_core_finalize (GObject *object)
114 GdkDeviceManagerCore *device_manager_core;
116 device_manager_core = GDK_DEVICE_MANAGER_CORE (object);
118 g_object_unref (device_manager_core->core_pointer);
119 g_object_unref (device_manager_core->core_keyboard);
121 G_OBJECT_CLASS (gdk_device_manager_core_parent_class)->finalize (object);
125 gdk_device_manager_core_constructed (GObject *object)
127 GdkDeviceManagerCore *device_manager;
130 device_manager = GDK_DEVICE_MANAGER_CORE (object);
131 display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (object));
132 device_manager->core_pointer = create_core_pointer (GDK_DEVICE_MANAGER (device_manager), display);
133 device_manager->core_keyboard = create_core_keyboard (GDK_DEVICE_MANAGER (device_manager), display);
135 _gdk_device_set_associated_device (device_manager->core_pointer, device_manager->core_keyboard);
136 _gdk_device_set_associated_device (device_manager->core_keyboard, device_manager->core_pointer);
140 translate_key_event (GdkDisplay *display,
141 GdkDeviceManagerCore *device_manager,
145 GdkKeymap *keymap = gdk_keymap_get_for_display (display);
146 GdkModifierType consumed, state;
150 event->key.type = xevent->xany.type == KeyPress ? GDK_KEY_PRESS : GDK_KEY_RELEASE;
151 event->key.time = xevent->xkey.time;
152 gdk_event_set_device (event, device_manager->core_keyboard);
154 event->key.state = (GdkModifierType) xevent->xkey.state;
155 event->key.group = _gdk_x11_get_group_for_state (display, xevent->xkey.state);
156 event->key.hardware_keycode = xevent->xkey.keycode;
158 event->key.keyval = GDK_KEY_VoidSymbol;
160 gdk_keymap_translate_keyboard_state (keymap,
161 event->key.hardware_keycode,
165 NULL, NULL, &consumed);
167 state = event->key.state & ~consumed;
168 _gdk_keymap_add_virtual_modifiers_compat (keymap, &state);
169 event->key.state |= state;
171 event->key.is_modifier = _gdk_keymap_key_is_modifier (keymap, event->key.hardware_keycode);
173 /* Fill in event->string crudely, since various programs
176 event->key.string = NULL;
178 if (event->key.keyval != GDK_KEY_VoidSymbol)
179 c = gdk_keyval_to_unicode (event->key.keyval);
186 /* Apply the control key - Taken from Xlib
188 if (event->key.state & GDK_CONTROL_MASK)
190 if ((c >= '@' && c < '\177') || c == ' ') c &= 0x1F;
193 event->key.string = g_memdup ("\0\0", 2);
194 event->key.length = 1;
198 else if (c >= '3' && c <= '7') c -= ('3' - '\033');
199 else if (c == '8') c = '\177';
200 else if (c == '/') c = '_' & 0x1F;
203 len = g_unichar_to_utf8 (c, buf);
206 event->key.string = g_locale_from_utf8 (buf, len,
207 NULL, &bytes_written,
209 if (event->key.string)
210 event->key.length = bytes_written;
212 else if (event->key.keyval == GDK_KEY_Escape)
214 event->key.length = 1;
215 event->key.string = g_strdup ("\033");
217 else if (event->key.keyval == GDK_KEY_Return ||
218 event->key.keyval == GDK_KEY_KP_Enter)
220 event->key.length = 1;
221 event->key.string = g_strdup ("\r");
224 if (!event->key.string)
226 event->key.length = 0;
227 event->key.string = g_strdup ("");
231 #ifdef G_ENABLE_DEBUG
232 if (_gdk_debug_flags & GDK_DEBUG_EVENTS)
234 g_message ("%s:\t\twindow: %ld key: %12s %d",
235 event->type == GDK_KEY_PRESS ? "key press " : "key release",
237 event->key.keyval ? gdk_keyval_name (event->key.keyval) : "(none)",
240 if (event->key.length > 0)
241 g_message ("\t\tlength: %4d string: \"%s\"",
242 event->key.length, buf);
244 #endif /* G_ENABLE_DEBUG */
248 #ifdef G_ENABLE_DEBUG
249 static const char notify_modes[][19] = {
256 static const char notify_details[][23] = {
261 "NotifyNonlinearVirtual",
269 set_user_time (GdkWindow *window,
272 g_return_if_fail (event != NULL);
274 window = gdk_window_get_toplevel (event->client.window);
275 g_return_if_fail (GDK_IS_WINDOW (window));
277 /* If an event doesn't have a valid timestamp, we shouldn't use it
278 * to update the latest user interaction time.
280 if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
281 gdk_x11_window_set_user_time (gdk_window_get_toplevel (window),
282 gdk_event_get_time (event));
286 generate_focus_event (GdkDeviceManagerCore *device_manager,
292 event = gdk_event_new (GDK_FOCUS_CHANGE);
293 event->focus_change.window = g_object_ref (window);
294 event->focus_change.send_event = FALSE;
295 event->focus_change.in = in;
296 gdk_event_set_device (event, device_manager->core_keyboard);
298 gdk_event_put (event);
299 gdk_event_free (event);
303 set_screen_from_root (GdkDisplay *display,
309 screen = _gdk_x11_display_screen_for_xrootwin (display, xrootwin);
313 gdk_event_set_screen (event, screen);
321 static GdkCrossingMode
322 translate_crossing_mode (int mode)
327 return GDK_CROSSING_NORMAL;
329 return GDK_CROSSING_GRAB;
331 return GDK_CROSSING_UNGRAB;
333 g_assert_not_reached ();
338 translate_notify_type (int detail)
343 return GDK_NOTIFY_INFERIOR;
345 return GDK_NOTIFY_ANCESTOR;
347 return GDK_NOTIFY_VIRTUAL;
348 case NotifyNonlinear:
349 return GDK_NOTIFY_NONLINEAR;
350 case NotifyNonlinearVirtual:
351 return GDK_NOTIFY_NONLINEAR_VIRTUAL;
353 g_assert_not_reached ();
358 is_parent_of (GdkWindow *parent,
369 w = gdk_window_get_parent (w);
376 get_event_window (GdkEventTranslator *translator,
379 GdkDeviceManager *device_manager;
383 device_manager = GDK_DEVICE_MANAGER (translator);
384 display = gdk_device_manager_get_display (device_manager);
385 window = gdk_window_lookup_for_display (display, xevent->xany.window);
387 /* Apply keyboard grabs to non-native windows */
388 if (xevent->type == KeyPress || xevent->type == KeyRelease)
390 GdkDeviceGrabInfo *info;
393 serial = _gdk_windowing_window_get_next_serial (display);
394 info = _gdk_display_has_device_grab (display,
395 GDK_DEVICE_MANAGER_CORE (device_manager)->core_keyboard,
398 (!is_parent_of (info->window, window) ||
399 !info->owner_events))
401 /* Report key event against grab window */
402 window = info->window;
410 gdk_device_manager_core_translate_event (GdkEventTranslator *translator,
415 GdkDeviceManagerCore *device_manager;
417 GdkWindowObject *window_private;
418 GdkWindowImplX11 *window_impl = NULL;
420 GdkToplevelX11 *toplevel = NULL;
421 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
423 device_manager = GDK_DEVICE_MANAGER_CORE (translator);
426 window = get_event_window (translator, xevent);
427 window_private = (GdkWindowObject *) window;
431 if (GDK_WINDOW_DESTROYED (window) || !GDK_IS_WINDOW (window))
434 toplevel = _gdk_x11_window_get_toplevel (window);
435 window_impl = GDK_WINDOW_IMPL_X11 (window_private->impl);
436 g_object_ref (window);
439 event->any.window = window;
440 event->any.send_event = xevent->xany.send_event ? TRUE : FALSE;
442 if (window_private && GDK_WINDOW_DESTROYED (window))
444 if (xevent->type != DestroyNotify)
452 (xevent->type == MotionNotify ||
453 xevent->type == ButtonRelease))
455 if (_gdk_moveresize_handle_event (xevent))
462 /* We do a "manual" conversion of the XEvent to a
463 * GdkEvent. The structures are mostly the same so
464 * the conversion is fairly straightforward. We also
465 * optionally print debugging info regarding events
471 switch (xevent->type)
474 if (window_private == NULL)
479 translate_key_event (display, device_manager, event, xevent);
480 set_user_time (window, event);
484 if (window_private == NULL)
490 /* Emulate detectable auto-repeat by checking to see
491 * if the next event is a key press with the same
492 * keycode and timestamp, and if so, ignoring the event.
495 if (!display_x11->have_xkb_autorepeat && XPending (xevent->xkey.display))
499 XPeekEvent (xevent->xkey.display, &next_event);
501 if (next_event.type == KeyPress &&
502 next_event.xkey.keycode == xevent->xkey.keycode &&
503 next_event.xkey.time == xevent->xkey.time)
510 translate_key_event (display, device_manager, event, xevent);
515 g_message ("button press:\t\twindow: %ld x,y: %d %d button: %d",
516 xevent->xbutton.window,
517 xevent->xbutton.x, xevent->xbutton.y,
518 xevent->xbutton.button));
520 if (window_private == NULL)
526 /* If we get a ButtonPress event where the button is 4 or 5,
527 it's a Scroll event */
528 switch (xevent->xbutton.button)
534 event->scroll.type = GDK_SCROLL;
536 if (xevent->xbutton.button == 4)
537 event->scroll.direction = GDK_SCROLL_UP;
538 else if (xevent->xbutton.button == 5)
539 event->scroll.direction = GDK_SCROLL_DOWN;
540 else if (xevent->xbutton.button == 6)
541 event->scroll.direction = GDK_SCROLL_LEFT;
543 event->scroll.direction = GDK_SCROLL_RIGHT;
545 event->scroll.window = window;
546 event->scroll.time = xevent->xbutton.time;
547 event->scroll.x = (gdouble) xevent->xbutton.x;
548 event->scroll.y = (gdouble) xevent->xbutton.y;
549 event->scroll.x_root = (gdouble) xevent->xbutton.x_root;
550 event->scroll.y_root = (gdouble) xevent->xbutton.y_root;
551 event->scroll.state = (GdkModifierType) xevent->xbutton.state;
552 event->scroll.device = device_manager->core_pointer;
554 if (!set_screen_from_root (display, event, xevent->xbutton.root))
563 event->button.type = GDK_BUTTON_PRESS;
564 event->button.window = window;
565 event->button.time = xevent->xbutton.time;
566 event->button.x = (gdouble) xevent->xbutton.x;
567 event->button.y = (gdouble) xevent->xbutton.y;
568 event->button.x_root = (gdouble) xevent->xbutton.x_root;
569 event->button.y_root = (gdouble) xevent->xbutton.y_root;
570 event->button.axes = NULL;
571 event->button.state = (GdkModifierType) xevent->xbutton.state;
572 event->button.button = xevent->xbutton.button;
573 event->button.device = device_manager->core_pointer;
575 if (!set_screen_from_root (display, event, xevent->xbutton.root))
581 set_user_time (window, event);
587 g_message ("button release:\twindow: %ld x,y: %d %d button: %d",
588 xevent->xbutton.window,
589 xevent->xbutton.x, xevent->xbutton.y,
590 xevent->xbutton.button));
592 if (window_private == NULL)
598 /* We treat button presses as scroll wheel events, so ignore the release */
599 if (xevent->xbutton.button == 4 || xevent->xbutton.button == 5 ||
600 xevent->xbutton.button == 6 || xevent->xbutton.button == 7)
606 event->button.type = GDK_BUTTON_RELEASE;
607 event->button.window = window;
608 event->button.time = xevent->xbutton.time;
609 event->button.x = (gdouble) xevent->xbutton.x;
610 event->button.y = (gdouble) xevent->xbutton.y;
611 event->button.x_root = (gdouble) xevent->xbutton.x_root;
612 event->button.y_root = (gdouble) xevent->xbutton.y_root;
613 event->button.axes = NULL;
614 event->button.state = (GdkModifierType) xevent->xbutton.state;
615 event->button.button = xevent->xbutton.button;
616 event->button.device = device_manager->core_pointer;
618 if (!set_screen_from_root (display, event, xevent->xbutton.root))
625 g_message ("motion notify:\t\twindow: %ld x,y: %d %d hint: %s",
626 xevent->xmotion.window,
627 xevent->xmotion.x, xevent->xmotion.y,
628 (xevent->xmotion.is_hint) ? "true" : "false"));
630 if (window_private == NULL)
636 event->motion.type = GDK_MOTION_NOTIFY;
637 event->motion.window = window;
638 event->motion.time = xevent->xmotion.time;
639 event->motion.x = (gdouble) xevent->xmotion.x;
640 event->motion.y = (gdouble) xevent->xmotion.y;
641 event->motion.x_root = (gdouble) xevent->xmotion.x_root;
642 event->motion.y_root = (gdouble) xevent->xmotion.y_root;
643 event->motion.axes = NULL;
644 event->motion.state = (GdkModifierType) xevent->xmotion.state;
645 event->motion.is_hint = xevent->xmotion.is_hint;
646 event->motion.device = device_manager->core_pointer;
648 if (!set_screen_from_root (display, event, xevent->xbutton.root))
658 g_message ("enter notify:\t\twindow: %ld detail: %d subwin: %ld",
659 xevent->xcrossing.window,
660 xevent->xcrossing.detail,
661 xevent->xcrossing.subwindow));
663 if (window_private == NULL)
669 if (!set_screen_from_root (display, event, xevent->xbutton.root))
675 event->crossing.type = GDK_ENTER_NOTIFY;
676 event->crossing.window = window;
677 gdk_event_set_device (event, device_manager->core_pointer);
679 /* If the subwindow field of the XEvent is non-NULL, then
680 * lookup the corresponding GdkWindow.
682 if (xevent->xcrossing.subwindow != None)
683 event->crossing.subwindow = gdk_window_lookup_for_display (display, xevent->xcrossing.subwindow);
685 event->crossing.subwindow = NULL;
687 event->crossing.time = xevent->xcrossing.time;
688 event->crossing.x = (gdouble) xevent->xcrossing.x;
689 event->crossing.y = (gdouble) xevent->xcrossing.y;
690 event->crossing.x_root = (gdouble) xevent->xcrossing.x_root;
691 event->crossing.y_root = (gdouble) xevent->xcrossing.y_root;
693 event->crossing.mode = translate_crossing_mode (xevent->xcrossing.mode);
694 event->crossing.detail = translate_notify_type (xevent->xcrossing.detail);
696 event->crossing.focus = xevent->xcrossing.focus;
697 event->crossing.state = xevent->xcrossing.state;
703 g_message ("leave notify:\t\twindow: %ld detail: %d subwin: %ld",
704 xevent->xcrossing.window,
705 xevent->xcrossing.detail, xevent->xcrossing.subwindow));
707 if (window_private == NULL)
713 if (!set_screen_from_root (display, event, xevent->xbutton.root))
719 event->crossing.type = GDK_LEAVE_NOTIFY;
720 event->crossing.window = window;
721 gdk_event_set_device (event, device_manager->core_pointer);
723 /* If the subwindow field of the XEvent is non-NULL, then
724 * lookup the corresponding GdkWindow.
726 if (xevent->xcrossing.subwindow != None)
727 event->crossing.subwindow = gdk_window_lookup_for_display (display, xevent->xcrossing.subwindow);
729 event->crossing.subwindow = NULL;
731 event->crossing.time = xevent->xcrossing.time;
732 event->crossing.x = (gdouble) xevent->xcrossing.x;
733 event->crossing.y = (gdouble) xevent->xcrossing.y;
734 event->crossing.x_root = (gdouble) xevent->xcrossing.x_root;
735 event->crossing.y_root = (gdouble) xevent->xcrossing.y_root;
737 event->crossing.mode = translate_crossing_mode (xevent->xcrossing.mode);
738 event->crossing.detail = translate_notify_type (xevent->xcrossing.detail);
740 event->crossing.focus = xevent->xcrossing.focus;
741 event->crossing.state = xevent->xcrossing.state;
745 /* We only care about focus events that indicate that _this_
746 * window (not a ancestor or child) got or lost the focus
750 g_message ("focus in:\t\twindow: %ld, detail: %s, mode: %s",
751 xevent->xfocus.window,
752 notify_details[xevent->xfocus.detail],
753 notify_modes[xevent->xfocus.mode]));
757 gboolean had_focus = HAS_FOCUS (toplevel);
759 switch (xevent->xfocus.detail)
763 /* When the focus moves from an ancestor of the window to
764 * the window or a descendent of the window, *and* the
765 * pointer is inside the window, then we were previously
766 * receiving keystroke events in the has_pointer_focus
767 * case and are now receiving them in the
768 * has_focus_window case.
770 if (toplevel->has_pointer &&
771 xevent->xfocus.mode != NotifyGrab &&
772 xevent->xfocus.mode != NotifyUngrab)
773 toplevel->has_pointer_focus = FALSE;
776 case NotifyNonlinear:
777 case NotifyNonlinearVirtual:
778 if (xevent->xfocus.mode != NotifyGrab &&
779 xevent->xfocus.mode != NotifyUngrab)
780 toplevel->has_focus_window = TRUE;
781 /* We pretend that the focus moves to the grab
782 * window, so we pay attention to NotifyGrab
783 * NotifyUngrab, and ignore NotifyWhileGrabbed
785 if (xevent->xfocus.mode != NotifyWhileGrabbed)
786 toplevel->has_focus = TRUE;
789 /* The X server sends NotifyPointer/NotifyGrab,
790 * but the pointer focus is ignored while a
793 if (xevent->xfocus.mode != NotifyGrab &&
794 xevent->xfocus.mode != NotifyUngrab)
795 toplevel->has_pointer_focus = TRUE;
798 case NotifyPointerRoot:
799 case NotifyDetailNone:
803 if (HAS_FOCUS (toplevel) != had_focus)
804 generate_focus_event (device_manager, window, TRUE);
809 g_message ("focus out:\t\twindow: %ld, detail: %s, mode: %s",
810 xevent->xfocus.window,
811 notify_details[xevent->xfocus.detail],
812 notify_modes[xevent->xfocus.mode]));
816 gboolean had_focus = HAS_FOCUS (toplevel);
818 switch (xevent->xfocus.detail)
822 /* When the focus moves from the window or a descendent
823 * of the window to an ancestor of the window, *and* the
824 * pointer is inside the window, then we were previously
825 * receiving keystroke events in the has_focus_window
826 * case and are now receiving them in the
827 * has_pointer_focus case.
829 if (toplevel->has_pointer &&
830 xevent->xfocus.mode != NotifyGrab &&
831 xevent->xfocus.mode != NotifyUngrab)
832 toplevel->has_pointer_focus = TRUE;
835 case NotifyNonlinear:
836 case NotifyNonlinearVirtual:
837 if (xevent->xfocus.mode != NotifyGrab &&
838 xevent->xfocus.mode != NotifyUngrab)
839 toplevel->has_focus_window = FALSE;
840 if (xevent->xfocus.mode != NotifyWhileGrabbed)
841 toplevel->has_focus = FALSE;
844 if (xevent->xfocus.mode != NotifyGrab &&
845 xevent->xfocus.mode != NotifyUngrab)
846 toplevel->has_pointer_focus = FALSE;
849 case NotifyPointerRoot:
850 case NotifyDetailNone:
854 if (HAS_FOCUS (toplevel) != had_focus)
855 generate_focus_event (device_manager, window, FALSE);
866 if (event->any.window)
867 g_object_ref (event->any.window);
869 if (((event->any.type == GDK_ENTER_NOTIFY) ||
870 (event->any.type == GDK_LEAVE_NOTIFY)) &&
871 (event->crossing.subwindow != NULL))
872 g_object_ref (event->crossing.subwindow);
876 /* Mark this event as having no resources to be freed */
877 event->any.window = NULL;
878 event->any.type = GDK_NOTHING;
882 g_object_unref (window);
888 gdk_device_manager_core_list_devices (GdkDeviceManager *device_manager,
891 GdkDeviceManagerCore *device_manager_core;
892 GList *devices = NULL;
894 if (type == GDK_DEVICE_TYPE_MASTER)
896 device_manager_core = (GdkDeviceManagerCore *) device_manager;
897 devices = g_list_prepend (devices, device_manager_core->core_keyboard);
898 devices = g_list_prepend (devices, device_manager_core->core_pointer);
905 gdk_device_manager_core_get_client_pointer (GdkDeviceManager *device_manager)
907 GdkDeviceManagerCore *device_manager_core;
909 device_manager_core = (GdkDeviceManagerCore *) device_manager;
910 return device_manager_core->core_pointer;