894 lines
25 KiB
C
894 lines
25 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"
|
|
|
|
struct _GdkMirWindowReference {
|
|
GdkMirEventSource *source;
|
|
GdkWindow *window;
|
|
gint ref_count;
|
|
};
|
|
|
|
typedef struct {
|
|
GdkMirWindowReference *window_ref;
|
|
MirEvent event;
|
|
} GdkMirQueuedEvent;
|
|
|
|
struct _GdkMirEventSource
|
|
{
|
|
GSource parent_instance;
|
|
|
|
GMutex mir_event_lock;
|
|
GQueue mir_events;
|
|
|
|
GdkDisplay *display;
|
|
};
|
|
|
|
static void
|
|
print_modifiers (unsigned int modifiers)
|
|
{
|
|
g_printerr (" Modifiers");
|
|
if ((modifiers & mir_key_modifier_alt) != 0)
|
|
g_printerr (" alt");
|
|
if ((modifiers & mir_key_modifier_alt_left) != 0)
|
|
g_printerr (" alt-left");
|
|
if ((modifiers & mir_key_modifier_alt_right) != 0)
|
|
g_printerr (" alt-right");
|
|
if ((modifiers & mir_key_modifier_shift) != 0)
|
|
g_printerr (" shift");
|
|
if ((modifiers & mir_key_modifier_shift_left) != 0)
|
|
g_printerr (" shift-left");
|
|
if ((modifiers & mir_key_modifier_shift_right) != 0)
|
|
g_printerr (" shift-right");
|
|
if ((modifiers & mir_key_modifier_sym) != 0)
|
|
g_printerr (" sym");
|
|
if ((modifiers & mir_key_modifier_function) != 0)
|
|
g_printerr (" function");
|
|
if ((modifiers & mir_key_modifier_ctrl) != 0)
|
|
g_printerr (" ctrl");
|
|
if ((modifiers & mir_key_modifier_ctrl_left) != 0)
|
|
g_printerr (" ctrl-left");
|
|
if ((modifiers & mir_key_modifier_ctrl_right) != 0)
|
|
g_printerr (" ctrl-right");
|
|
if ((modifiers & mir_key_modifier_meta) != 0)
|
|
g_printerr (" meta");
|
|
if ((modifiers & mir_key_modifier_meta_left) != 0)
|
|
g_printerr (" meta-left");
|
|
if ((modifiers & mir_key_modifier_meta_right) != 0)
|
|
g_printerr (" meta-right");
|
|
if ((modifiers & mir_key_modifier_caps_lock) != 0)
|
|
g_printerr (" caps-lock");
|
|
if ((modifiers & mir_key_modifier_num_lock) != 0)
|
|
g_printerr (" num-lock");
|
|
if ((modifiers & mir_key_modifier_scroll_lock) != 0)
|
|
g_printerr (" scroll-lock");
|
|
g_printerr ("\n");
|
|
}
|
|
|
|
static void
|
|
print_key_event (const MirKeyEvent *event)
|
|
{
|
|
g_printerr ("KEY\n");
|
|
g_printerr (" Device %i\n", event->device_id);
|
|
g_printerr (" Source %i\n", event->source_id);
|
|
g_printerr (" Action ");
|
|
switch (event->action)
|
|
{
|
|
case mir_key_action_down:
|
|
g_printerr ("down");
|
|
break;
|
|
case mir_key_action_up:
|
|
g_printerr ("up");
|
|
break;
|
|
case mir_key_action_multiple:
|
|
g_printerr ("multiple");
|
|
break;
|
|
default:
|
|
g_printerr ("%u", event->action);
|
|
break;
|
|
}
|
|
g_printerr ("\n");
|
|
g_printerr (" Flags");
|
|
if ((event->flags & mir_key_flag_woke_here) != 0)
|
|
g_printerr (" woke-here");
|
|
if ((event->flags & mir_key_flag_soft_keyboard) != 0)
|
|
g_printerr (" soft-keyboard");
|
|
if ((event->flags & mir_key_flag_keep_touch_mode) != 0)
|
|
g_printerr (" keep-touch-mode");
|
|
if ((event->flags & mir_key_flag_from_system) != 0)
|
|
g_printerr (" from-system");
|
|
if ((event->flags & mir_key_flag_editor_action) != 0)
|
|
g_printerr (" editor-action");
|
|
if ((event->flags & mir_key_flag_canceled) != 0)
|
|
g_printerr (" canceled");
|
|
if ((event->flags & mir_key_flag_virtual_hard_key) != 0)
|
|
g_printerr (" virtual-hard-key");
|
|
if ((event->flags & mir_key_flag_long_press) != 0)
|
|
g_printerr (" long-press");
|
|
if ((event->flags & mir_key_flag_canceled_long_press) != 0)
|
|
g_printerr (" canceled-long-press");
|
|
if ((event->flags & mir_key_flag_tracking) != 0)
|
|
g_printerr (" tracking");
|
|
if ((event->flags & mir_key_flag_fallback) != 0)
|
|
g_printerr (" fallback");
|
|
g_printerr ("\n");
|
|
print_modifiers (event->modifiers);
|
|
g_printerr (" Key Code %i\n", event->key_code);
|
|
g_printerr (" Scan Code %i\n", event->scan_code);
|
|
g_printerr (" Repeat Count %i\n", event->repeat_count);
|
|
g_printerr (" Down Time %lli\n", (long long int) event->down_time);
|
|
g_printerr (" Event Time %lli\n", (long long int) event->event_time);
|
|
g_printerr (" Is System Key %s\n", event->is_system_key ? "true" : "false");
|
|
}
|
|
|
|
static void
|
|
print_motion_event (const MirMotionEvent *event)
|
|
{
|
|
size_t i;
|
|
|
|
g_printerr ("MOTION\n");
|
|
g_printerr (" Device %i\n", event->device_id);
|
|
g_printerr (" Source %i\n", event->source_id);
|
|
g_printerr (" Action ");
|
|
switch (event->action)
|
|
{
|
|
case mir_motion_action_down:
|
|
g_printerr ("down");
|
|
break;
|
|
case mir_motion_action_up:
|
|
g_printerr ("up");
|
|
break;
|
|
case mir_motion_action_move:
|
|
g_printerr ("move");
|
|
break;
|
|
case mir_motion_action_cancel:
|
|
g_printerr ("cancel");
|
|
break;
|
|
case mir_motion_action_outside:
|
|
g_printerr ("outside");
|
|
break;
|
|
case mir_motion_action_pointer_down:
|
|
g_printerr ("pointer-down");
|
|
break;
|
|
case mir_motion_action_pointer_up:
|
|
g_printerr ("pointer-up");
|
|
break;
|
|
case mir_motion_action_hover_move:
|
|
g_printerr ("hover-move");
|
|
break;
|
|
case mir_motion_action_scroll:
|
|
g_printerr ("scroll");
|
|
break;
|
|
case mir_motion_action_hover_enter:
|
|
g_printerr ("hover-enter");
|
|
break;
|
|
case mir_motion_action_hover_exit:
|
|
g_printerr ("hover-exit");
|
|
break;
|
|
default:
|
|
g_printerr ("%u", event->action);
|
|
}
|
|
g_printerr ("\n");
|
|
g_printerr (" Flags");
|
|
switch (event->flags)
|
|
{
|
|
case mir_motion_flag_window_is_obscured:
|
|
g_printerr (" window-is-obscured");
|
|
break;
|
|
}
|
|
g_printerr ("\n");
|
|
print_modifiers (event->modifiers);
|
|
g_printerr (" Edge Flags %i\n", event->edge_flags);
|
|
g_printerr (" Button State");
|
|
switch (event->button_state)
|
|
{
|
|
case mir_motion_button_primary:
|
|
g_printerr (" primary");
|
|
break;
|
|
case mir_motion_button_secondary:
|
|
g_printerr (" secondary");
|
|
break;
|
|
case mir_motion_button_tertiary:
|
|
g_printerr (" tertiary");
|
|
break;
|
|
case mir_motion_button_back:
|
|
g_printerr (" back");
|
|
break;
|
|
case mir_motion_button_forward:
|
|
g_printerr (" forward");
|
|
break;
|
|
}
|
|
g_printerr ("\n");
|
|
g_printerr (" Offset (%f, %f)\n", event->x_offset, event->y_offset);
|
|
g_printerr (" Precision (%f, %f)\n", event->x_precision, event->y_precision);
|
|
g_printerr (" Down Time %lli\n", (long long int) event->down_time);
|
|
g_printerr (" Event Time %lli\n", (long long int) event->event_time);
|
|
g_printerr (" Pointer Coordinates\n");
|
|
for (i = 0; i < event->pointer_count; i++)
|
|
{
|
|
g_printerr (" ID=%i location=(%f, %f) raw=(%f, %f) touch=(%f, %f) size=%f pressure=%f orientation=%f scroll=(%f, %f) tool=",
|
|
event->pointer_coordinates[i].id,
|
|
event->pointer_coordinates[i].x, event->pointer_coordinates[i].y,
|
|
event->pointer_coordinates[i].raw_x, event->pointer_coordinates[i].raw_y,
|
|
event->pointer_coordinates[i].touch_major, event->pointer_coordinates[i].touch_minor,
|
|
event->pointer_coordinates[i].size,
|
|
event->pointer_coordinates[i].pressure,
|
|
event->pointer_coordinates[i].orientation,
|
|
event->pointer_coordinates[i].hscroll, event->pointer_coordinates[i].vscroll);
|
|
switch (event->pointer_coordinates[i].tool_type)
|
|
{
|
|
case mir_motion_tool_type_unknown:
|
|
g_printerr ("unknown");
|
|
break;
|
|
case mir_motion_tool_type_finger:
|
|
g_printerr ("finger");
|
|
break;
|
|
case mir_motion_tool_type_stylus:
|
|
g_printerr ("stylus");
|
|
break;
|
|
case mir_motion_tool_type_mouse:
|
|
g_printerr ("mouse");
|
|
break;
|
|
case mir_motion_tool_type_eraser:
|
|
g_printerr ("eraser");
|
|
break;
|
|
default:
|
|
g_printerr ("%u", event->pointer_coordinates[i].tool_type);
|
|
break;
|
|
}
|
|
g_printerr ("\n");
|
|
}
|
|
}
|
|
|
|
static void
|
|
print_surface_event (const MirSurfaceEvent *event)
|
|
{
|
|
g_printerr ("SURFACE\n");
|
|
g_printerr (" Surface %i\n", event->id);
|
|
g_printerr (" Attribute ");
|
|
switch (event->attrib)
|
|
{
|
|
case mir_surface_attrib_type:
|
|
g_printerr ("type");
|
|
break;
|
|
case mir_surface_attrib_state:
|
|
g_printerr ("state");
|
|
break;
|
|
case mir_surface_attrib_swapinterval:
|
|
g_printerr ("swapinterval");
|
|
break;
|
|
case mir_surface_attrib_focus:
|
|
g_printerr ("focus");
|
|
break;
|
|
default:
|
|
g_printerr ("%u", event->attrib);
|
|
break;
|
|
}
|
|
g_printerr ("\n");
|
|
g_printerr (" Value %i\n", event->value);
|
|
}
|
|
|
|
static void
|
|
print_resize_event (const MirResizeEvent *event)
|
|
{
|
|
g_printerr ("RESIZE\n");
|
|
g_printerr (" Surface %i\n", event->surface_id);
|
|
g_printerr (" Size (%i, %i)\n", event->width, event->height);
|
|
}
|
|
|
|
static void
|
|
print_event (const MirEvent *event)
|
|
{
|
|
switch (event->type)
|
|
{
|
|
case mir_event_type_key:
|
|
print_key_event (&event->key);
|
|
break;
|
|
case mir_event_type_motion:
|
|
print_motion_event (&event->motion);
|
|
break;
|
|
case mir_event_type_surface:
|
|
print_surface_event (&event->surface);
|
|
break;
|
|
case mir_event_type_resize:
|
|
print_resize_event (&event->resize);
|
|
break;
|
|
default:
|
|
g_printerr ("EVENT %u\n", event->type);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
send_event (GdkWindow *window, GdkDevice *device, GdkEvent *event)
|
|
{
|
|
GdkDisplay *display;
|
|
GList *node;
|
|
|
|
gdk_event_set_device (event, device);
|
|
gdk_event_set_screen (event, gdk_display_get_screen (gdk_window_get_display (window), 0));
|
|
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)
|
|
{
|
|
GdkEvent *event;
|
|
|
|
event = gdk_event_new (type);
|
|
event->key.state = state;
|
|
event->key.keyval = keyval;
|
|
event->key.hardware_keycode = keycode;
|
|
event->key.is_modifier = is_modifier;
|
|
set_key_event_string (&event->key);
|
|
|
|
send_event (window, _gdk_mir_device_manager_get_keyboard (gdk_display_get_device_manager (gdk_window_get_display (window))), event);
|
|
}
|
|
|
|
static GdkDevice *
|
|
get_pointer (GdkWindow *window)
|
|
{
|
|
return gdk_device_manager_get_client_pointer (gdk_display_get_device_manager (gdk_window_get_display (window)));
|
|
}
|
|
|
|
static void
|
|
generate_button_event (GdkWindow *window, GdkEventType type, gdouble x, gdouble y, guint button, guint state)
|
|
{
|
|
GdkEvent *event;
|
|
|
|
event = gdk_event_new (type);
|
|
event->button.x = x;
|
|
event->button.y = y;
|
|
event->button.state = state;
|
|
event->button.button = button;
|
|
|
|
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)
|
|
{
|
|
GdkEvent *event;
|
|
|
|
event = gdk_event_new (GDK_SCROLL);
|
|
event->scroll.x = x;
|
|
event->scroll.y = y;
|
|
event->scroll.state = state;
|
|
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)
|
|
{
|
|
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;
|
|
|
|
send_event (window, get_pointer (window), event);
|
|
}
|
|
|
|
static void
|
|
generate_crossing_event (GdkWindow *window, GdkEventType type, gdouble x, gdouble y)
|
|
{
|
|
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;
|
|
|
|
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, unsigned int button_state)
|
|
{
|
|
guint modifier_state = 0;
|
|
|
|
if ((modifiers & mir_key_modifier_alt) != 0)
|
|
modifier_state |= GDK_MOD1_MASK;
|
|
if ((modifiers & mir_key_modifier_shift) != 0)
|
|
modifier_state |= GDK_SHIFT_MASK;
|
|
if ((modifiers & mir_key_modifier_ctrl) != 0)
|
|
modifier_state |= GDK_CONTROL_MASK;
|
|
if ((modifiers & mir_key_modifier_meta) != 0)
|
|
modifier_state |= GDK_SUPER_MASK;
|
|
if ((modifiers & mir_key_modifier_caps_lock) != 0)
|
|
modifier_state |= GDK_LOCK_MASK;
|
|
if ((button_state & mir_motion_button_primary) != 0)
|
|
modifier_state |= GDK_BUTTON1_MASK;
|
|
if ((button_state & mir_motion_button_secondary) != 0)
|
|
modifier_state |= GDK_BUTTON3_MASK;
|
|
if ((button_state & mir_motion_button_tertiary) != 0)
|
|
modifier_state |= GDK_BUTTON2_MASK;
|
|
|
|
return modifier_state;
|
|
}
|
|
|
|
/*
|
|
GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (event_data->window->impl);
|
|
MirMotionButton changed_button_state;
|
|
GdkEventType event_type;
|
|
gdouble x, y;
|
|
guint modifier_state;
|
|
gboolean is_modifier = FALSE;
|
|
*/
|
|
|
|
static void
|
|
handle_key_event (GdkWindow *window, const MirKeyEvent *event)
|
|
{
|
|
guint modifier_state;
|
|
gboolean is_modifier = FALSE;
|
|
|
|
modifier_state = get_modifier_state (event->modifiers, 0); // FIXME: Need to track button state
|
|
|
|
switch (event->action)
|
|
{
|
|
case mir_key_action_down:
|
|
case mir_key_action_up:
|
|
// FIXME: Convert keycode
|
|
// FIXME: is_modifier
|
|
generate_key_event (window,
|
|
event->action == mir_key_action_down ? GDK_KEY_PRESS : GDK_KEY_RELEASE,
|
|
modifier_state,
|
|
event->key_code,
|
|
event->scan_code,
|
|
is_modifier);
|
|
break;
|
|
default:
|
|
//case mir_key_action_multiple:
|
|
// FIXME
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
handle_motion_event (GdkWindow *window, const MirMotionEvent *event)
|
|
{
|
|
GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
|
|
guint modifier_state;
|
|
GdkEventType event_type;
|
|
MirMotionButton changed_button_state;
|
|
|
|
if (event->pointer_count > 0)
|
|
{
|
|
impl->x = event->pointer_coordinates[0].x;
|
|
impl->y = event->pointer_coordinates[0].y;
|
|
}
|
|
modifier_state = get_modifier_state (event->modifiers, event->button_state);
|
|
|
|
/* The Mir events generate hover-exits even while inside the window so
|
|
counteract this by always generating an enter notify on all other events */
|
|
if (!impl->cursor_inside && event->action != mir_motion_action_hover_exit)
|
|
{
|
|
impl->cursor_inside = TRUE;
|
|
generate_crossing_event (window, GDK_ENTER_NOTIFY, impl->x, impl->y);
|
|
}
|
|
|
|
/* Update which window has focus */
|
|
_gdk_mir_pointer_set_location (get_pointer (window), impl->x, impl->y, window, modifier_state);
|
|
switch (event->action)
|
|
{
|
|
case mir_motion_action_down:
|
|
case mir_motion_action_up:
|
|
event_type = event->action == mir_motion_action_down ? GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE;
|
|
changed_button_state = impl->button_state ^ event->button_state;
|
|
if ((changed_button_state & mir_motion_button_primary) != 0)
|
|
generate_button_event (window, event_type, impl->x, impl->y, GDK_BUTTON_PRIMARY, modifier_state);
|
|
if ((changed_button_state & mir_motion_button_secondary) != 0)
|
|
generate_button_event (window, event_type, impl->x, impl->y, GDK_BUTTON_SECONDARY, modifier_state);
|
|
if ((changed_button_state & mir_motion_button_tertiary) != 0)
|
|
generate_button_event (window, event_type, impl->x, impl->y, GDK_BUTTON_MIDDLE, modifier_state);
|
|
impl->button_state = event->button_state;
|
|
break;
|
|
case mir_motion_action_scroll:
|
|
generate_scroll_event (window, impl->x, impl->y, event->pointer_coordinates[0].hscroll, event->pointer_coordinates[0].vscroll, modifier_state);
|
|
break;
|
|
case mir_motion_action_move: // move with button
|
|
case mir_motion_action_hover_move: // move without button
|
|
generate_motion_event (window, impl->x, impl->y, modifier_state);
|
|
break;
|
|
case mir_motion_action_hover_exit:
|
|
impl->cursor_inside = FALSE;
|
|
generate_crossing_event (window, GDK_LEAVE_NOTIFY, impl->x, impl->y);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
handle_surface_event (GdkWindow *window, const MirSurfaceEvent *event)
|
|
{
|
|
GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
|
|
|
|
switch (event->attrib)
|
|
{
|
|
case mir_surface_attrib_type:
|
|
break;
|
|
case mir_surface_attrib_state:
|
|
impl->surface_state = event->value;
|
|
// FIXME: notify
|
|
break;
|
|
case mir_surface_attrib_swapinterval:
|
|
break;
|
|
case mir_surface_attrib_focus:
|
|
generate_focus_event (window, event->value != 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 = event->width;
|
|
window->height = event->height;
|
|
_gdk_window_update_size (window);
|
|
|
|
generate_configure_event (window, event->width, event->height);
|
|
}
|
|
|
|
typedef struct
|
|
{
|
|
GdkWindow *window;
|
|
MirEvent event;
|
|
} EventData;
|
|
|
|
static void
|
|
gdk_mir_event_source_queue_event (GdkDisplay *display,
|
|
GdkWindow *window,
|
|
const MirEvent *event)
|
|
{
|
|
if (g_getenv ("GDK_MIR_LOG_EVENTS"))
|
|
print_event (event);
|
|
|
|
// FIXME: Only generate events if the window wanted them?
|
|
switch (event->type)
|
|
{
|
|
case mir_event_type_key:
|
|
handle_key_event (window, &event->key);
|
|
break;
|
|
case mir_event_type_motion:
|
|
handle_motion_event (window, &event->motion);
|
|
break;
|
|
case mir_event_type_surface:
|
|
handle_surface_event (window, &event->surface);
|
|
break;
|
|
case mir_event_type_resize:
|
|
handle_resize_event (window, &event->resize);
|
|
break;
|
|
default:
|
|
g_assert_not_reached ();
|
|
// 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);
|
|
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)
|
|
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;
|
|
|
|
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 = *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);
|
|
}
|