816 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			816 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Copyright © 2014 Canonical Ltd
 | |
|  *
 | |
|  * This library is free software; you can redistribute it and/or
 | |
|  * modify it under the terms of the GNU Lesser General Public License
 | |
|  * as published by the Free Software Foundation; either version 2 of
 | |
|  * the License, or (at your option) any later version.
 | |
|  *
 | |
|  * This library is distributed in the hope that it will be useful, but
 | |
|  * WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
|  * Lesser General Public License for more details.
 | |
|  *
 | |
|  * You should have received a copy of the GNU Lesser General Public
 | |
|  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 | |
|  */
 | |
| 
 | |
| #include "config.h"
 | |
| 
 | |
| #include "gdkinternals.h"
 | |
| #include "gdkdisplayprivate.h"
 | |
| #include "gdkmir.h"
 | |
| #include "gdkmir-private.h"
 | |
| 
 | |
| #define NANO_TO_MILLI(x) ((x) / 1000000)
 | |
| 
 | |
| struct _GdkMirWindowReference {
 | |
|   GdkMirEventSource *source;
 | |
|   GdkWindow         *window;
 | |
|   gint               ref_count;
 | |
| };
 | |
| 
 | |
| typedef struct {
 | |
|   GdkMirWindowReference *window_ref;
 | |
|   const MirEvent        *event;
 | |
| } GdkMirQueuedEvent;
 | |
| 
 | |
| struct _GdkMirEventSource
 | |
| {
 | |
|   GSource parent_instance;
 | |
| 
 | |
|   GMutex mir_event_lock;
 | |
|   GQueue mir_events;
 | |
|   gboolean log_events;
 | |
| 
 | |
|   GdkDisplay *display;
 | |
| };
 | |
| 
 | |
| static void
 | |
| send_event (GdkWindow *window, GdkDevice *device, GdkEvent *event)
 | |
| {
 | |
|   GdkDisplay *display;
 | |
|   GList *node;
 | |
| 
 | |
|   gdk_event_set_device (event, device);
 | |
|   gdk_event_set_source_device (event, device);
 | |
|   gdk_event_set_screen (event, gdk_display_get_default_screen (gdk_window_get_display (window)));
 | |
|   event->any.window = g_object_ref (window);
 | |
| 
 | |
|   display = gdk_window_get_display (window);
 | |
|   node = _gdk_event_queue_append (display, event);
 | |
|   _gdk_windowing_got_event (display, node, event, _gdk_display_get_next_serial (display));
 | |
| }
 | |
| 
 | |
| static void
 | |
| set_key_event_string (GdkEventKey *event)
 | |
| {
 | |
|   gunichar c = 0;
 | |
| 
 | |
|   if (event->keyval != GDK_KEY_VoidSymbol)
 | |
|     c = gdk_keyval_to_unicode (event->keyval);
 | |
| 
 | |
|   if (c)
 | |
|     {
 | |
|       gchar buf[7];
 | |
|       gint len;
 | |
|       gsize bytes_written;
 | |
| 
 | |
|       /* Apply the control key - Taken from Xlib
 | |
|        */
 | |
|       if (event->state & GDK_CONTROL_MASK)
 | |
|         {
 | |
|           if ((c >= '@' && c < '\177') || c == ' ') c &= 0x1F;
 | |
|           else if (c == '2')
 | |
|             {
 | |
|               event->string = g_memdup ("\0\0", 2);
 | |
|               event->length = 1;
 | |
|               buf[0] = '\0';
 | |
|               return;
 | |
|             }
 | |
|           else if (c >= '3' && c <= '7') c -= ('3' - '\033');
 | |
|           else if (c == '8') c = '\177';
 | |
|           else if (c == '/') c = '_' & 0x1F;
 | |
|         }
 | |
| 
 | |
|       len = g_unichar_to_utf8 (c, buf);
 | |
|       buf[len] = '\0';
 | |
| 
 | |
|       event->string = g_locale_from_utf8 (buf, len,
 | |
|                                           NULL, &bytes_written,
 | |
|                                           NULL);
 | |
|       if (event->string)
 | |
|         event->length = bytes_written;
 | |
|     }
 | |
|   else if (event->keyval == GDK_KEY_Escape)
 | |
|     {
 | |
|       event->length = 1;
 | |
|       event->string = g_strdup ("\033");
 | |
|     }
 | |
|   else if (event->keyval == GDK_KEY_Return ||
 | |
|            event->keyval == GDK_KEY_KP_Enter)
 | |
|     {
 | |
|       event->length = 1;
 | |
|       event->string = g_strdup ("\r");
 | |
|     }
 | |
| 
 | |
|   if (!event->string)
 | |
|     {
 | |
|       event->length = 0;
 | |
|       event->string = g_strdup ("");
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| generate_key_event (GdkWindow *window, GdkEventType type, guint state, guint keyval, guint16 keycode, gboolean is_modifier, guint32 event_time)
 | |
| {
 | |
|   GdkEvent *event;
 | |
|   GdkDisplay *display;
 | |
|   GdkSeat *seat;
 | |
|   GdkDevice *keyboard;
 | |
| 
 | |
|   event = gdk_event_new (type);
 | |
|   event->key.state = state;
 | |
|   event->key.keyval = keyval;
 | |
|   event->key.hardware_keycode = keycode + 8;
 | |
|   event->key.is_modifier = is_modifier;
 | |
|   event->key.time = event_time;
 | |
|   set_key_event_string (&event->key);
 | |
| 
 | |
|   display = gdk_window_get_display (window);
 | |
|   seat = gdk_display_get_default_seat (display);
 | |
|   keyboard = gdk_seat_get_keyboard (seat);
 | |
| 
 | |
|   send_event (window, keyboard, event);
 | |
| }
 | |
| 
 | |
| static GdkDevice *
 | |
| get_pointer (GdkWindow *window)
 | |
| {
 | |
|   GdkDisplay *display;
 | |
|   GdkSeat *seat;
 | |
|   GdkDevice *pointer;
 | |
| 
 | |
|   display = gdk_window_get_display (window);
 | |
|   seat = gdk_display_get_default_seat (display);
 | |
|   pointer = gdk_seat_get_pointer (seat);
 | |
| 
 | |
|   return pointer;
 | |
| }
 | |
| 
 | |
| static void
 | |
| generate_button_event (GdkWindow *window, GdkEventType type, gdouble x, gdouble y, guint button, guint state, guint32 event_time)
 | |
| {
 | |
|   GdkEvent *event;
 | |
| 
 | |
|   event = gdk_event_new (type);
 | |
|   event->button.x = x;
 | |
|   event->button.y = y;
 | |
|   event->button.state = state;
 | |
|   event->button.button = button;
 | |
|   event->button.time = event_time;
 | |
| 
 | |
|   send_event (window, get_pointer (window), event);
 | |
| }
 | |
| 
 | |
| static void
 | |
| generate_scroll_event (GdkWindow *window, gdouble x, gdouble y, gdouble delta_x, gdouble delta_y, guint state, guint32 event_time)
 | |
| {
 | |
|   GdkEvent *event;
 | |
| 
 | |
|   event = gdk_event_new (GDK_SCROLL);
 | |
|   event->scroll.x = x;
 | |
|   event->scroll.y = y;
 | |
|   event->scroll.state = state;
 | |
|   event->scroll.time = event_time;
 | |
| 
 | |
|   if (ABS (delta_x) == 1 && delta_y == 0)
 | |
|     {
 | |
|       event->scroll.direction = (delta_x < 0) ? GDK_SCROLL_LEFT : GDK_SCROLL_RIGHT;
 | |
|     }
 | |
|   else if (ABS (delta_y) == 1 && delta_x == 0)
 | |
|     {
 | |
|       event->scroll.direction = (delta_y < 0) ? GDK_SCROLL_DOWN : GDK_SCROLL_UP;
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       event->scroll.direction = GDK_SCROLL_SMOOTH;
 | |
|       event->scroll.delta_x = -delta_x;
 | |
|       event->scroll.delta_y = -delta_y;
 | |
|     }
 | |
| 
 | |
|   send_event (window, get_pointer (window), event);
 | |
| }
 | |
| 
 | |
| static void
 | |
| generate_motion_event (GdkWindow *window, gdouble x, gdouble y, guint state, guint32 event_time)
 | |
| {
 | |
|   GdkEvent *event;
 | |
| 
 | |
|   event = gdk_event_new (GDK_MOTION_NOTIFY);
 | |
|   event->motion.x = x;
 | |
|   event->motion.y = y;
 | |
|   event->motion.state = state;
 | |
|   event->motion.is_hint = FALSE;
 | |
|   event->motion.time = event_time;
 | |
| 
 | |
|   send_event (window, get_pointer (window), event);
 | |
| }
 | |
| 
 | |
| static void
 | |
| generate_crossing_event (GdkWindow *window, GdkEventType type, gdouble x, gdouble y, guint32 event_time)
 | |
| {
 | |
|   GdkEvent *event;
 | |
| 
 | |
|   event = gdk_event_new (type);
 | |
|   event->crossing.x = x;
 | |
|   event->crossing.y = y;
 | |
|   event->crossing.mode = GDK_CROSSING_NORMAL;
 | |
|   event->crossing.detail = GDK_NOTIFY_ANCESTOR;
 | |
|   event->crossing.focus = TRUE;
 | |
|   event->crossing.time = event_time;
 | |
| 
 | |
|   send_event (window, get_pointer (window), event);
 | |
| }
 | |
| 
 | |
| static void
 | |
| generate_focus_event (GdkWindow *window, gboolean focused)
 | |
| {
 | |
|   GdkEvent *event;
 | |
| 
 | |
|   if (focused)
 | |
|     gdk_synthesize_window_state (window, 0, GDK_WINDOW_STATE_FOCUSED);
 | |
|   else
 | |
|     gdk_synthesize_window_state (window, GDK_WINDOW_STATE_FOCUSED, 0);
 | |
| 
 | |
|   event = gdk_event_new (GDK_FOCUS_CHANGE);
 | |
|   event->focus_change.send_event = FALSE;
 | |
|   event->focus_change.in = focused;
 | |
| 
 | |
|   send_event (window, get_pointer (window), event);
 | |
| }
 | |
| 
 | |
| static guint
 | |
| get_modifier_state (unsigned int modifiers, guint button_state)
 | |
| {
 | |
|   guint modifier_state = button_state;
 | |
| 
 | |
|   if ((modifiers & (mir_input_event_modifier_alt |
 | |
|                     mir_input_event_modifier_alt_left |
 | |
|                     mir_input_event_modifier_alt_right)) != 0)
 | |
|     modifier_state |= GDK_MOD1_MASK;
 | |
|   if ((modifiers & (mir_input_event_modifier_shift |
 | |
|                     mir_input_event_modifier_shift_left |
 | |
|                     mir_input_event_modifier_shift_right)) != 0)
 | |
|     modifier_state |= GDK_SHIFT_MASK;
 | |
|   if ((modifiers & (mir_input_event_modifier_ctrl |
 | |
|                     mir_input_event_modifier_ctrl_left |
 | |
|                     mir_input_event_modifier_ctrl_right)) != 0)
 | |
|     modifier_state |= GDK_CONTROL_MASK;
 | |
|   if ((modifiers & (mir_input_event_modifier_meta |
 | |
|                     mir_input_event_modifier_meta_left |
 | |
|                     mir_input_event_modifier_meta_right)) != 0)
 | |
|     modifier_state |= GDK_META_MASK;
 | |
|   if ((modifiers & mir_input_event_modifier_caps_lock) != 0)
 | |
|     modifier_state |= GDK_LOCK_MASK;
 | |
| 
 | |
|   return modifier_state;
 | |
| }
 | |
| 
 | |
| static void
 | |
| handle_key_event (GdkWindow *window, const MirInputEvent *event)
 | |
| {
 | |
|   const MirKeyboardEvent *keyboard_event = mir_input_event_get_keyboard_event (event);
 | |
|   GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
 | |
|   GdkKeymap *keymap;
 | |
|   guint modifier_state;
 | |
|   guint button_state;
 | |
| 
 | |
|   if (!keyboard_event)
 | |
|     return;
 | |
| 
 | |
|   switch (mir_keyboard_event_action (keyboard_event))
 | |
|     {
 | |
|     case mir_keyboard_action_up:
 | |
|     case mir_keyboard_action_down:
 | |
|       // FIXME: Convert keycode
 | |
|       _gdk_mir_window_impl_get_cursor_state (impl, NULL, NULL, NULL, &button_state);
 | |
|       modifier_state = get_modifier_state (mir_keyboard_event_modifiers (keyboard_event), button_state);
 | |
|       keymap = gdk_keymap_get_for_display (gdk_window_get_display (window));
 | |
| 
 | |
|       generate_key_event (window,
 | |
|                           mir_keyboard_event_action (keyboard_event) == mir_keyboard_action_down ? GDK_KEY_PRESS : GDK_KEY_RELEASE,
 | |
|                           modifier_state,
 | |
|                           mir_keyboard_event_key_code (keyboard_event),
 | |
|                           mir_keyboard_event_scan_code (keyboard_event),
 | |
|                           _gdk_mir_keymap_key_is_modifier (keymap, mir_keyboard_event_key_code (keyboard_event)),
 | |
|                           NANO_TO_MILLI (mir_input_event_get_event_time (event)));
 | |
|       break;
 | |
|     default:
 | |
|     //case mir_key_action_multiple:
 | |
|       // FIXME
 | |
|       break;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| handle_touch_event (GdkWindow           *window,
 | |
|                     const MirTouchEvent *mir_touch_event)
 | |
| {
 | |
|   const MirInputEvent *mir_input_event = mir_touch_event_input_event (mir_touch_event);
 | |
|   guint n = mir_touch_event_point_count (mir_touch_event);
 | |
|   GdkEvent *gdk_event;
 | |
|   guint i;
 | |
| 
 | |
|   for (i = 0; i < n; i++)
 | |
|     {
 | |
|       switch (mir_touch_event_action (mir_touch_event, i))
 | |
|         {
 | |
|         case mir_touch_action_up:
 | |
|           gdk_event = gdk_event_new (GDK_TOUCH_END);
 | |
|           break;
 | |
|         case mir_touch_action_down:
 | |
|           gdk_event = gdk_event_new (GDK_TOUCH_BEGIN);
 | |
|           break;
 | |
|         case mir_touch_action_change:
 | |
|           gdk_event = gdk_event_new (GDK_TOUCH_UPDATE);
 | |
|           break;
 | |
|         }
 | |
| 
 | |
|       gdk_event->touch.window = window;
 | |
|       gdk_event->touch.sequence = GINT_TO_POINTER (mir_touch_event_id (mir_touch_event, i));
 | |
|       gdk_event->touch.time = mir_input_event_get_event_time (mir_input_event);
 | |
|       gdk_event->touch.state = get_modifier_state (mir_touch_event_modifiers (mir_touch_event), 0);
 | |
|       gdk_event->touch.x = mir_touch_event_axis_value (mir_touch_event, i, mir_touch_axis_x);
 | |
|       gdk_event->touch.y = mir_touch_event_axis_value (mir_touch_event, i, mir_touch_axis_y);
 | |
|       gdk_event->touch.x_root = mir_touch_event_axis_value (mir_touch_event, i, mir_touch_axis_x);
 | |
|       gdk_event->touch.y_root = mir_touch_event_axis_value (mir_touch_event, i, mir_touch_axis_y);
 | |
|       gdk_event->touch.emulating_pointer = TRUE;
 | |
|       _gdk_event_set_pointer_emulated (gdk_event, TRUE);
 | |
| 
 | |
|       send_event (window, get_pointer (window), gdk_event);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static guint
 | |
| get_button_state (const MirPointerEvent *event)
 | |
| {
 | |
|   guint state = 0;
 | |
| 
 | |
|   if (mir_pointer_event_button_state (event, mir_pointer_button_primary)) /* left */
 | |
|     state |= GDK_BUTTON1_MASK;
 | |
|   if (mir_pointer_event_button_state (event, mir_pointer_button_secondary)) /* right */
 | |
|     state |= GDK_BUTTON3_MASK;
 | |
|   if (mir_pointer_event_button_state (event, mir_pointer_button_tertiary)) /* middle */
 | |
|     state |= GDK_BUTTON2_MASK;
 | |
| 
 | |
|   return state;
 | |
| }
 | |
| 
 | |
| static void
 | |
| handle_motion_event (GdkWindow *window, const MirInputEvent *event)
 | |
| {
 | |
|   const MirPointerEvent *pointer_event = mir_input_event_get_pointer_event (event);
 | |
|   GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
 | |
|   gdouble x, y;
 | |
|   gboolean cursor_inside;
 | |
|   guint button_state;
 | |
|   guint new_button_state;
 | |
|   guint modifier_state;
 | |
|   guint32 event_time;
 | |
|   GdkEventType event_type;
 | |
|   guint changed_button_state;
 | |
| 
 | |
|   if (!pointer_event)
 | |
|     return;
 | |
| 
 | |
|   _gdk_mir_window_impl_get_cursor_state (impl, &x, &y, &cursor_inside, &button_state);
 | |
|   new_button_state = get_button_state (pointer_event);
 | |
|   modifier_state = get_modifier_state (mir_pointer_event_modifiers (pointer_event), new_button_state);
 | |
|   event_time = NANO_TO_MILLI (mir_input_event_get_event_time (event));
 | |
| 
 | |
|   if (window)
 | |
|     {
 | |
|       gdouble new_x;
 | |
|       gdouble new_y;
 | |
|       gdouble hscroll;
 | |
|       gdouble vscroll;
 | |
| 
 | |
|       /* Update which window has focus */
 | |
|       _gdk_mir_pointer_set_location (get_pointer (window), x, y, window, modifier_state);
 | |
|       switch (mir_pointer_event_action (pointer_event))
 | |
|         {
 | |
|         case mir_pointer_action_button_up:
 | |
|         case mir_pointer_action_button_down:
 | |
|           event_type = mir_pointer_event_action (pointer_event) == mir_pointer_action_button_down ? GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE;
 | |
|           changed_button_state = button_state ^ new_button_state;
 | |
|           if (changed_button_state == 0 || (changed_button_state & GDK_BUTTON1_MASK) != 0)
 | |
|             generate_button_event (window, event_type, x, y, GDK_BUTTON_PRIMARY, modifier_state, event_time);
 | |
|           if ((changed_button_state & GDK_BUTTON2_MASK) != 0)
 | |
|             generate_button_event (window, event_type, x, y, GDK_BUTTON_MIDDLE, modifier_state, event_time);
 | |
|           if ((changed_button_state & GDK_BUTTON3_MASK) != 0)
 | |
|             generate_button_event (window, event_type, x, y, GDK_BUTTON_SECONDARY, modifier_state, event_time);
 | |
|           button_state = new_button_state;
 | |
|           break;
 | |
|         case mir_pointer_action_motion:
 | |
|           new_x = mir_pointer_event_axis_value (pointer_event, mir_pointer_axis_x);
 | |
|           new_y = mir_pointer_event_axis_value (pointer_event, mir_pointer_axis_y);
 | |
|           hscroll = mir_pointer_event_axis_value (pointer_event, mir_pointer_axis_hscroll);
 | |
|           vscroll = mir_pointer_event_axis_value (pointer_event, mir_pointer_axis_vscroll);
 | |
| 
 | |
|           if (ABS (hscroll) > 0.5 || ABS (vscroll) > 0.5)
 | |
|             generate_scroll_event (window, x, y, hscroll, vscroll, modifier_state, event_time);
 | |
|           if (ABS (new_x - x) > 0.5 || ABS (new_y - y) > 0.5)
 | |
|             {
 | |
|               generate_motion_event (window, new_x, new_y, modifier_state, event_time);
 | |
|               x = new_x;
 | |
|               y = new_y;
 | |
|             }
 | |
| 
 | |
|           break;
 | |
|         case mir_pointer_action_enter:
 | |
|           if (!cursor_inside)
 | |
|             {
 | |
|               cursor_inside = TRUE;
 | |
|               generate_crossing_event (window, GDK_ENTER_NOTIFY, x, y, event_time);
 | |
|             }
 | |
|           break;
 | |
|         case mir_pointer_action_leave:
 | |
|           if (cursor_inside)
 | |
|             {
 | |
|               cursor_inside = FALSE;
 | |
|               generate_crossing_event (window, GDK_LEAVE_NOTIFY, x, y, event_time);
 | |
|             }
 | |
|           break;
 | |
|         default:
 | |
|           break;
 | |
|         }
 | |
| 
 | |
|       _gdk_mir_window_impl_set_cursor_state (impl, x, y, cursor_inside, button_state);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| handle_surface_event (GdkWindow *window, const MirSurfaceEvent *event)
 | |
| {
 | |
|   GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
 | |
|   MirSurfaceState state;
 | |
| 
 | |
|   switch (mir_surface_event_get_attribute (event))
 | |
|     {
 | |
|     case mir_surface_attrib_type:
 | |
|       _gdk_mir_window_impl_set_surface_type (impl, mir_surface_event_get_attribute_value (event));
 | |
|       break;
 | |
|     case mir_surface_attrib_state:
 | |
|       state = mir_surface_event_get_attribute_value (event);
 | |
|       _gdk_mir_window_impl_set_surface_state (impl, state);
 | |
| 
 | |
|       switch (state)
 | |
|         {
 | |
|         case mir_surface_state_restored:
 | |
|         case mir_surface_state_hidden:
 | |
|           gdk_synthesize_window_state (window,
 | |
|                                        GDK_WINDOW_STATE_ICONIFIED |
 | |
|                                        GDK_WINDOW_STATE_MAXIMIZED |
 | |
|                                        GDK_WINDOW_STATE_FULLSCREEN,
 | |
|                                        0);
 | |
|           break;
 | |
|         case mir_surface_state_minimized:
 | |
|           gdk_synthesize_window_state (window,
 | |
|                                        GDK_WINDOW_STATE_MAXIMIZED |
 | |
|                                        GDK_WINDOW_STATE_FULLSCREEN,
 | |
|                                        GDK_WINDOW_STATE_ICONIFIED);
 | |
|           break;
 | |
|         case mir_surface_state_maximized:
 | |
|         case mir_surface_state_vertmaximized:
 | |
|         case mir_surface_state_horizmaximized:
 | |
|           gdk_synthesize_window_state (window,
 | |
|                                        GDK_WINDOW_STATE_ICONIFIED |
 | |
|                                        GDK_WINDOW_STATE_FULLSCREEN,
 | |
|                                        GDK_WINDOW_STATE_MAXIMIZED);
 | |
|           break;
 | |
|         case mir_surface_state_fullscreen:
 | |
|           gdk_synthesize_window_state (window,
 | |
|                                        GDK_WINDOW_STATE_ICONIFIED |
 | |
|                                        GDK_WINDOW_STATE_MAXIMIZED,
 | |
|                                        GDK_WINDOW_STATE_FULLSCREEN);
 | |
|           break;
 | |
|         default:
 | |
|           break;
 | |
|         }
 | |
| 
 | |
|       break;
 | |
|     case mir_surface_attrib_swapinterval:
 | |
|       break;
 | |
|     case mir_surface_attrib_focus:
 | |
|       generate_focus_event (window, mir_surface_event_get_attribute_value (event) != 0);
 | |
|       break;
 | |
|     default:
 | |
|       break;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| generate_configure_event (GdkWindow *window,
 | |
|                           gint       width,
 | |
|                           gint       height)
 | |
| {
 | |
|   GdkEvent *event;
 | |
| 
 | |
|   event = gdk_event_new (GDK_CONFIGURE);
 | |
|   event->configure.send_event = FALSE;
 | |
|   event->configure.width = width;
 | |
|   event->configure.height = height;
 | |
| 
 | |
|   send_event (window, get_pointer (window), event);
 | |
| }
 | |
| 
 | |
| static void
 | |
| handle_resize_event (GdkWindow            *window,
 | |
|                      const MirResizeEvent *event)
 | |
| {
 | |
|   window->width = mir_resize_event_get_width (event);
 | |
|   window->height = mir_resize_event_get_height (event);
 | |
|   _gdk_window_update_size (window);
 | |
| 
 | |
|   generate_configure_event (window, mir_resize_event_get_width (event), mir_resize_event_get_height (event));
 | |
| }
 | |
| 
 | |
| static void
 | |
| handle_close_event (GdkWindow *window)
 | |
| {
 | |
|   send_event (window, get_pointer (window), gdk_event_new (GDK_DESTROY));
 | |
|   gdk_window_destroy_notify (window);
 | |
| }
 | |
| 
 | |
| typedef struct
 | |
| {
 | |
|   GdkWindow *window;
 | |
|   MirEvent *event;
 | |
| } EventData;
 | |
| 
 | |
| static void
 | |
| gdk_mir_event_source_queue_event (GdkDisplay     *display,
 | |
|                                   GdkWindow      *window,
 | |
|                                   const MirEvent *event)
 | |
| {
 | |
|   const MirInputEvent *input_event;
 | |
| 
 | |
|   // FIXME: Only generate events if the window wanted them?
 | |
|   switch (mir_event_get_type (event))
 | |
|     {
 | |
|     case mir_event_type_input:
 | |
|       input_event = mir_event_get_input_event (event);
 | |
| 
 | |
|       switch (mir_input_event_get_type (input_event))
 | |
|         {
 | |
|         case mir_input_event_type_key:
 | |
|           handle_key_event (window, input_event);
 | |
|           break;
 | |
|         case mir_input_event_type_touch:
 | |
|           handle_touch_event (window, mir_input_event_get_touch_event (input_event));
 | |
|           break;
 | |
|         case mir_input_event_type_pointer:
 | |
|           handle_motion_event (window, input_event);
 | |
|           break;
 | |
|         }
 | |
| 
 | |
|       break;
 | |
|     case mir_event_type_key:
 | |
|       handle_key_event (window, mir_event_get_input_event (event));
 | |
|       break;
 | |
|     case mir_event_type_motion:
 | |
|       handle_motion_event (window, mir_event_get_input_event (event));
 | |
|       break;
 | |
|     case mir_event_type_surface:
 | |
|       handle_surface_event (window, mir_event_get_surface_event (event));
 | |
|       break;
 | |
|     case mir_event_type_resize:
 | |
|       handle_resize_event (window, mir_event_get_resize_event (event));
 | |
|       break;
 | |
|     case mir_event_type_prompt_session_state_change:
 | |
|       // FIXME?
 | |
|       break;
 | |
|     case mir_event_type_orientation:
 | |
|       // FIXME?
 | |
|       break;
 | |
|     case mir_event_type_close_surface:
 | |
|       handle_close_event (window);
 | |
|       break;
 | |
|     default:
 | |
|       g_warning ("Ignoring unknown Mir event %d", mir_event_get_type (event));
 | |
|       // FIXME?
 | |
|       break;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static GdkMirQueuedEvent *
 | |
| gdk_mir_event_source_take_queued_event (GdkMirEventSource *source)
 | |
| {
 | |
|   GdkMirQueuedEvent *queued_event;
 | |
| 
 | |
|   g_mutex_lock (&source->mir_event_lock);
 | |
|   queued_event = g_queue_pop_head (&source->mir_events);
 | |
|   g_mutex_unlock (&source->mir_event_lock);
 | |
| 
 | |
|   return queued_event;
 | |
| }
 | |
| 
 | |
| static void
 | |
| gdk_mir_queued_event_free (GdkMirQueuedEvent *event)
 | |
| {
 | |
|   _gdk_mir_window_reference_unref (event->window_ref);
 | |
|   mir_event_unref (event->event);
 | |
|   g_slice_free (GdkMirQueuedEvent, event);
 | |
| }
 | |
| 
 | |
| static void
 | |
| gdk_mir_event_source_convert_events (GdkMirEventSource *source)
 | |
| {
 | |
|   GdkMirQueuedEvent *event;
 | |
| 
 | |
|   while ((event = gdk_mir_event_source_take_queued_event (source)))
 | |
|     {
 | |
|       GdkWindow *window = event->window_ref->window;
 | |
| 
 | |
|       /* The window may have been destroyed in the main thread while the
 | |
|        * event was being dispatched...
 | |
|        */
 | |
|       if (window != NULL)
 | |
|         {
 | |
|           if (source->log_events)
 | |
|             _gdk_mir_print_event (event->event);
 | |
| 
 | |
|           gdk_mir_event_source_queue_event (source->display, window, event->event);
 | |
|         }
 | |
|       else
 | |
|         g_warning ("window was destroyed before event arrived...");
 | |
| 
 | |
|       gdk_mir_queued_event_free (event);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| gdk_mir_event_source_prepare (GSource *g_source,
 | |
|                               gint    *timeout)
 | |
| {
 | |
|   GdkMirEventSource *source = (GdkMirEventSource *) g_source;
 | |
|   gboolean mir_events_in_queue;
 | |
| 
 | |
|   if (_gdk_event_queue_find_first (source->display))
 | |
|    return TRUE;
 | |
| 
 | |
|   g_mutex_lock (&source->mir_event_lock);
 | |
|   mir_events_in_queue = g_queue_get_length (&source->mir_events) > 0;
 | |
|   g_mutex_unlock (&source->mir_event_lock);
 | |
| 
 | |
|   return mir_events_in_queue;
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| gdk_mir_event_source_check (GSource *g_source)
 | |
| {
 | |
|   return gdk_mir_event_source_prepare (g_source, NULL);
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| gdk_mir_event_source_dispatch (GSource     *g_source,
 | |
|                                GSourceFunc  callback,
 | |
|                                gpointer     user_data)
 | |
| {
 | |
|   GdkMirEventSource *source = (GdkMirEventSource *) g_source;
 | |
|   GdkEvent *event;
 | |
| 
 | |
|   /* First, run the queue of events from the thread */
 | |
|   gdk_mir_event_source_convert_events (source);
 | |
| 
 | |
|   /* Next, dispatch one single event from the display's queue.
 | |
|    *
 | |
|    * If there is more than one event then we will soon find ourselves
 | |
|    * back here again.
 | |
|    */
 | |
| 
 | |
|   gdk_threads_enter ();
 | |
| 
 | |
|   event = gdk_display_get_event (source->display);
 | |
| 
 | |
|   if (event)
 | |
|     {
 | |
|       _gdk_event_emit (event);
 | |
| 
 | |
|       gdk_event_free (event);
 | |
|     }
 | |
| 
 | |
|   gdk_threads_leave ();
 | |
| 
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| static void
 | |
| gdk_mir_event_source_finalize (GSource *g_source)
 | |
| {
 | |
|   GdkMirEventSource *source = (GdkMirEventSource *) g_source;
 | |
|   GdkMirQueuedEvent *event;
 | |
| 
 | |
|   while ((event = gdk_mir_event_source_take_queued_event (source)))
 | |
|     gdk_mir_queued_event_free (event);
 | |
| 
 | |
|   g_mutex_clear (&source->mir_event_lock);
 | |
| }
 | |
| 
 | |
| static GSourceFuncs gdk_mir_event_source_funcs = {
 | |
|   gdk_mir_event_source_prepare,
 | |
|   gdk_mir_event_source_check,
 | |
|   gdk_mir_event_source_dispatch,
 | |
|   gdk_mir_event_source_finalize
 | |
| };
 | |
| 
 | |
| GdkMirEventSource *
 | |
| _gdk_mir_event_source_new (GdkDisplay *display)
 | |
| {
 | |
|   GdkMirEventSource *source;
 | |
|   GSource *g_source;
 | |
| 
 | |
|   g_source = g_source_new (&gdk_mir_event_source_funcs, sizeof (GdkMirEventSource));
 | |
|   g_source_attach (g_source, NULL);
 | |
| 
 | |
|   source = (GdkMirEventSource *) g_source;
 | |
|   g_mutex_init (&source->mir_event_lock);
 | |
|   source->display = display;
 | |
|   source->log_events = (g_getenv ("GDK_MIR_LOG_EVENTS") != NULL);
 | |
| 
 | |
|   return source;
 | |
| }
 | |
| 
 | |
| GdkMirWindowReference *
 | |
| _gdk_mir_event_source_get_window_reference (GdkWindow *window)
 | |
| {
 | |
|   static GQuark win_ref_quark;
 | |
|   GdkMirWindowReference *ref;
 | |
| 
 | |
|   if G_UNLIKELY (!win_ref_quark)
 | |
|     win_ref_quark = g_quark_from_string ("GdkMirEventSource window reference");
 | |
| 
 | |
|   ref = g_object_get_qdata (G_OBJECT (window), win_ref_quark);
 | |
| 
 | |
|   if (!ref)
 | |
|     {
 | |
|       GdkMirEventSource *source;
 | |
| 
 | |
|       source = _gdk_mir_display_get_event_source (gdk_window_get_display (window));
 | |
|       g_source_ref ((GSource *) source);
 | |
| 
 | |
|       ref = g_slice_new (GdkMirWindowReference);
 | |
|       ref->window = window;
 | |
|       ref->source = source;
 | |
|       ref->ref_count = 0;
 | |
|       g_object_add_weak_pointer (G_OBJECT (window), (gpointer *) &ref->window);
 | |
| 
 | |
|       g_object_set_qdata_full (G_OBJECT (window), win_ref_quark,
 | |
|                                ref, (GDestroyNotify) _gdk_mir_window_reference_unref);
 | |
|     }
 | |
| 
 | |
|   g_atomic_int_inc (&ref->ref_count);
 | |
| 
 | |
|   return ref;
 | |
| }
 | |
| 
 | |
| void
 | |
| _gdk_mir_window_reference_unref (GdkMirWindowReference *ref)
 | |
| {
 | |
|   if (g_atomic_int_dec_and_test (&ref->ref_count))
 | |
|     {
 | |
|       if (ref->window)
 | |
|         g_object_remove_weak_pointer (G_OBJECT (ref->window), (gpointer *) &ref->window);
 | |
| 
 | |
|       g_source_unref ((GSource *) ref->source);
 | |
| 
 | |
|       g_slice_free (GdkMirWindowReference, ref);
 | |
|     }
 | |
| }
 | |
| 
 | |
| void
 | |
| _gdk_mir_event_source_queue (GdkMirWindowReference *window_ref,
 | |
|                              const MirEvent        *event)
 | |
| {
 | |
|   GdkMirEventSource *source = window_ref->source;
 | |
|   GdkMirQueuedEvent *queued_event;
 | |
| 
 | |
|   /* We are in the wrong thread right now.  We absolutely cannot touch
 | |
|    * the window.
 | |
|    *
 | |
|    * We can do pretty much anything we want with the source, though...
 | |
|    */
 | |
| 
 | |
|   queued_event = g_slice_new (GdkMirQueuedEvent);
 | |
|   g_atomic_int_inc (&window_ref->ref_count);
 | |
|   queued_event->window_ref = window_ref;
 | |
|   queued_event->event = mir_event_ref (event);
 | |
| 
 | |
|   g_mutex_lock (&source->mir_event_lock);
 | |
|   g_queue_push_tail (&source->mir_events, queued_event);
 | |
|   g_mutex_unlock (&source->mir_event_lock);
 | |
| 
 | |
|   g_main_context_wakeup (NULL);
 | |
| }
 | 
