frames: Clutterify frame event handling

This lets us remove our horrible X11-based, GDK-based hacky frame event
handling in favor of a more sane one in Clutter.
This commit is contained in:
Jasper St. Pierre 2015-01-19 11:27:27 -08:00
parent ce14bde08d
commit d561b3b18f
10 changed files with 105 additions and 326 deletions

View File

@ -85,6 +85,10 @@ typedef enum {
* Events go to windows normally. */ * Events go to windows normally. */
META_EVENT_ROUTE_NORMAL, META_EVENT_ROUTE_NORMAL,
/* In a window operation like moving or resizing. All events
* goes to MetaWindow, but not to the actual client window. */
META_EVENT_ROUTE_WINDOW_OP,
/* In a compositor grab operation. All events go to the /* In a compositor grab operation. All events go to the
* compositor plugin. */ * compositor plugin. */
META_EVENT_ROUTE_COMPOSITOR_GRAB, META_EVENT_ROUTE_COMPOSITOR_GRAB,
@ -93,9 +97,8 @@ typedef enum {
* the Wayland application. */ * the Wayland application. */
META_EVENT_ROUTE_WAYLAND_POPUP, META_EVENT_ROUTE_WAYLAND_POPUP,
/* In a window operation like moving or resizing. All events /* The user is clicking on a window button. */
* goes to MetaWindow, but not to the actual client window. */ META_EVENT_ROUTE_FRAME_BUTTON,
META_EVENT_ROUTE_WINDOW_OP,
} MetaEventRoute; } MetaEventRoute;
typedef gboolean (*MetaAlarmFilter) (MetaDisplay *display, typedef gboolean (*MetaAlarmFilter) (MetaDisplay *display,

View File

@ -1802,6 +1802,9 @@ get_event_route_from_grab_op (MetaGrabOp op)
case META_GRAB_OP_WAYLAND_POPUP: case META_GRAB_OP_WAYLAND_POPUP:
return META_EVENT_ROUTE_WAYLAND_POPUP; return META_EVENT_ROUTE_WAYLAND_POPUP;
case META_GRAB_OP_FRAME_BUTTON:
return META_EVENT_ROUTE_FRAME_BUTTON;
default: default:
g_assert_not_reached (); g_assert_not_reached ();
} }

View File

@ -66,9 +66,10 @@ get_window_for_event (MetaDisplay *display,
else else
return NULL; return NULL;
} }
case META_EVENT_ROUTE_WAYLAND_POPUP:
case META_EVENT_ROUTE_WINDOW_OP: case META_EVENT_ROUTE_WINDOW_OP:
case META_EVENT_ROUTE_COMPOSITOR_GRAB: case META_EVENT_ROUTE_COMPOSITOR_GRAB:
case META_EVENT_ROUTE_WAYLAND_POPUP:
case META_EVENT_ROUTE_FRAME_BUTTON:
return display->grab_window; return display->grab_window;
default: default:
g_assert_not_reached (); g_assert_not_reached ();
@ -261,7 +262,8 @@ meta_display_handle_event (MetaDisplay *display,
* event, and if it doesn't, replay the event to release our * event, and if it doesn't, replay the event to release our
* own sync grab. */ * own sync grab. */
if (display->event_route == META_EVENT_ROUTE_WINDOW_OP) if (display->event_route == META_EVENT_ROUTE_WINDOW_OP ||
display->event_route == META_EVENT_ROUTE_FRAME_BUTTON)
{ {
bypass_clutter = TRUE; bypass_clutter = TRUE;
bypass_wayland = TRUE; bypass_wayland = TRUE;

View File

@ -106,19 +106,6 @@ meta_window_ensure_frame (MetaWindow *window)
XChangeWindowAttributes (window->display->xdisplay, XChangeWindowAttributes (window->display->xdisplay,
frame->xwindow, CWEventMask, &attrs); frame->xwindow, CWEventMask, &attrs);
{
unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 };
XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits };
XISetMask (mask.mask, XI_ButtonPress);
XISetMask (mask.mask, XI_ButtonRelease);
XISetMask (mask.mask, XI_Motion);
XISetMask (mask.mask, XI_Enter);
XISetMask (mask.mask, XI_Leave);
XISelectEvents (window->display->xdisplay, frame->xwindow, &mask, 1);
}
meta_display_register_x_window (window->display, &frame->xwindow, window); meta_display_register_x_window (window->display, &frame->xwindow, window);
meta_error_trap_push (window->display); meta_error_trap_push (window->display);
@ -158,10 +145,23 @@ meta_window_ensure_frame (MetaWindow *window)
MetaBackend *backend = meta_get_backend (); MetaBackend *backend = meta_get_backend ();
if (META_IS_BACKEND_X11 (backend)) if (META_IS_BACKEND_X11 (backend))
{ {
/* Since the backend takes keygrabs on another connection, make sure Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend));
* to sync the GTK+ connection to ensure that the frame window has
* been created on the server at this point. */ /* Since the backend selects for events on another connection,
* make sure to sync the GTK+ connection to ensure that the
* frame window has been created on the server at this point. */
XSync (window->display->xdisplay, False); XSync (window->display->xdisplay, False);
unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 };
XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits };
XISetMask (mask.mask, XI_ButtonPress);
XISetMask (mask.mask, XI_ButtonRelease);
XISetMask (mask.mask, XI_Motion);
XISetMask (mask.mask, XI_Enter);
XISetMask (mask.mask, XI_Leave);
XISelectEvents (xdisplay, frame->xwindow, &mask, 1);
} }
} }

View File

@ -7773,6 +7773,9 @@ meta_window_handle_ungrabbed_event (MetaWindow *window,
gboolean unmodified; gboolean unmodified;
gboolean is_window_grab; gboolean is_window_grab;
if (window->frame && meta_ui_frame_handle_event (window->frame->ui_frame, event))
return;
if (event->type != CLUTTER_BUTTON_PRESS) if (event->type != CLUTTER_BUTTON_PRESS)
return; return;

View File

@ -152,14 +152,17 @@ typedef enum
{ {
META_GRAB_OP_NONE, META_GRAB_OP_NONE,
/* Window grab ops. */
META_GRAB_OP_WINDOW_BASE,
/* Special grab op when the compositor asked for a grab */ /* Special grab op when the compositor asked for a grab */
META_GRAB_OP_COMPOSITOR, META_GRAB_OP_COMPOSITOR,
/* For when a Wayland client takes a popup grab */ /* For when a Wayland client takes a popup grab. */
META_GRAB_OP_WAYLAND_POPUP, META_GRAB_OP_WAYLAND_POPUP,
/* Window grab ops. */ /* For when the user clicks on a frame button. */
META_GRAB_OP_WINDOW_BASE, META_GRAB_OP_FRAME_BUTTON,
META_GRAB_OP_MOVING = META_GRAB_OP_WINDOW_BASE, META_GRAB_OP_MOVING = META_GRAB_OP_WINDOW_BASE,
META_GRAB_OP_RESIZING_NW = META_GRAB_OP_WINDOW_BASE | _WGO_N | _WGO_W, META_GRAB_OP_RESIZING_NW = META_GRAB_OP_WINDOW_BASE | _WGO_N | _WGO_W,

View File

@ -45,18 +45,8 @@ static void meta_frames_destroy (GtkWidget *object);
static void meta_frames_finalize (GObject *object); static void meta_frames_finalize (GObject *object);
static void meta_frames_style_updated (GtkWidget *widget); static void meta_frames_style_updated (GtkWidget *widget);
static gboolean meta_frames_button_press_event (GtkWidget *widget,
GdkEventButton *event);
static gboolean meta_frames_button_release_event (GtkWidget *widget,
GdkEventButton *event);
static gboolean meta_frames_motion_notify_event (GtkWidget *widget,
GdkEventMotion *event);
static gboolean meta_frames_draw (GtkWidget *widget, static gboolean meta_frames_draw (GtkWidget *widget,
cairo_t *cr); cairo_t *cr);
static gboolean meta_frames_enter_notify_event (GtkWidget *widget,
GdkEventCrossing *event);
static gboolean meta_frames_leave_notify_event (GtkWidget *widget,
GdkEventCrossing *event);
static void meta_ui_frame_attach_style (MetaUIFrame *frame); static void meta_ui_frame_attach_style (MetaUIFrame *frame);
@ -69,9 +59,6 @@ static void meta_ui_frame_calc_geometry (MetaUIFrame *frame,
static void meta_ui_frame_update_prelit_control (MetaUIFrame *frame, static void meta_ui_frame_update_prelit_control (MetaUIFrame *frame,
MetaFrameControl control); MetaFrameControl control);
static MetaUIFrame* meta_frames_lookup_window (MetaFrames *frames,
Window xwindow);
static void meta_frames_font_changed (MetaFrames *frames); static void meta_frames_font_changed (MetaFrames *frames);
static void meta_frames_button_layout_changed (MetaFrames *frames); static void meta_frames_button_layout_changed (MetaFrames *frames);
@ -119,11 +106,6 @@ meta_frames_class_init (MetaFramesClass *class)
widget_class->style_updated = meta_frames_style_updated; widget_class->style_updated = meta_frames_style_updated;
widget_class->draw = meta_frames_draw; widget_class->draw = meta_frames_draw;
widget_class->button_press_event = meta_frames_button_press_event;
widget_class->button_release_event = meta_frames_button_release_event;
widget_class->motion_notify_event = meta_frames_motion_notify_event;
widget_class->enter_notify_event = meta_frames_enter_notify_event;
widget_class->leave_notify_event = meta_frames_leave_notify_event;
} }
static gint static gint
@ -790,17 +772,10 @@ redraw_control (MetaUIFrame *frame,
gdk_window_invalidate_rect (frame->window, rect, FALSE); gdk_window_invalidate_rect (frame->window, rect, FALSE);
} }
static MetaUIFrame*
meta_frames_lookup_window (MetaFrames *frames,
Window xwindow)
{
return g_hash_table_lookup (frames->frames, &xwindow);
}
static gboolean static gboolean
meta_frame_titlebar_event (MetaUIFrame *frame, meta_frame_titlebar_event (MetaUIFrame *frame,
GdkEventButton *event, ClutterButtonEvent *event,
int action) int action)
{ {
MetaFrameFlags flags; MetaFrameFlags flags;
Display *display; Display *display;
@ -871,8 +846,8 @@ meta_frame_titlebar_event (MetaUIFrame *frame,
meta_core_show_window_menu (display, meta_core_show_window_menu (display,
frame->xwindow, frame->xwindow,
META_WINDOW_MENU_WM, META_WINDOW_MENU_WM,
event->x_root, event->x,
event->y_root, event->y,
event->time); event->time);
break; break;
} }
@ -881,8 +856,8 @@ meta_frame_titlebar_event (MetaUIFrame *frame,
} }
static gboolean static gboolean
meta_frame_double_click_event (MetaUIFrame *frame, meta_frame_double_click_event (MetaUIFrame *frame,
GdkEventButton *event) ClutterButtonEvent *event)
{ {
int action = meta_prefs_get_action_double_click_titlebar (); int action = meta_prefs_get_action_double_click_titlebar ();
@ -890,8 +865,8 @@ meta_frame_double_click_event (MetaUIFrame *frame,
} }
static gboolean static gboolean
meta_frame_middle_click_event (MetaUIFrame *frame, meta_frame_middle_click_event (MetaUIFrame *frame,
GdkEventButton *event) ClutterButtonEvent *event)
{ {
int action = meta_prefs_get_action_middle_click_titlebar(); int action = meta_prefs_get_action_middle_click_titlebar();
@ -899,8 +874,8 @@ meta_frame_middle_click_event (MetaUIFrame *frame,
} }
static gboolean static gboolean
meta_frame_right_click_event(MetaUIFrame *frame, meta_frame_right_click_event (MetaUIFrame *frame,
GdkEventButton *event) ClutterButtonEvent *event)
{ {
int action = meta_prefs_get_action_right_click_titlebar(); int action = meta_prefs_get_action_right_click_titlebar();
@ -966,25 +941,14 @@ meta_frames_retry_grab_op (MetaFrames *frames,
} }
static gboolean static gboolean
meta_frames_button_press_event (GtkWidget *widget, handle_button_press_event (MetaUIFrame *frame,
GdkEventButton *event) ClutterButtonEvent *event)
{ {
MetaUIFrame *frame;
MetaFrames *frames;
MetaFrameControl control; MetaFrameControl control;
Display *display; Display *display;
frames = META_FRAMES (widget);
display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
/* Remember that the display may have already done something with this event.
* If so there's probably a GrabOp in effect.
*/
frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window));
if (frame == NULL)
return FALSE;
control = get_control (frame, event->x, event->y); control = get_control (frame, event->x, event->y);
/* focus on click, even if click was on client area */ /* focus on click, even if click was on client area */
@ -1008,7 +972,7 @@ meta_frames_button_press_event (GtkWidget *widget,
*/ */
if (control == META_FRAME_CONTROL_TITLE && if (control == META_FRAME_CONTROL_TITLE &&
event->button == 1 && event->button == 1 &&
event->type == GDK_2BUTTON_PRESS) event->click_count == 2)
{ {
meta_core_end_grab_op (display, event->time); meta_core_end_grab_op (display, event->time);
return meta_frame_double_click_event (frame, event); return meta_frame_double_click_event (frame, event);
@ -1033,8 +997,6 @@ meta_frames_button_press_event (GtkWidget *widget,
control == META_FRAME_CONTROL_MENU || control == META_FRAME_CONTROL_MENU ||
control == META_FRAME_CONTROL_APPMENU)) control == META_FRAME_CONTROL_APPMENU))
{ {
frames->grab_xwindow = frame->xwindow;
frame->grab_button = event->button; frame->grab_button = event->button;
frame->button_state = META_BUTTON_STATE_PRESSED; frame->button_state = META_BUTTON_STATE_PRESSED;
frame->prelit_control = control; frame->prelit_control = control;
@ -1053,9 +1015,7 @@ meta_frames_button_press_event (GtkWidget *widget,
rect = control_rect (control, &fgeom); rect = control_rect (control, &fgeom);
/* convert to root coords */ gdk_window_get_position (frame->window, &win_x, &win_y);
win_x = event->x_root - event->x;
win_y = event->y_root - event->y;
root_rect.x = win_x + rect->x; root_rect.x = win_x + rect->x;
root_rect.y = win_y + rect->y; root_rect.y = win_y + rect->y;
@ -1076,6 +1036,12 @@ meta_frames_button_press_event (GtkWidget *widget,
&root_rect, &root_rect,
event->time); event->time);
} }
else
{
meta_frames_try_grab_op (frame, META_GRAB_OP_FRAME_BUTTON,
event->x, event->y,
event->time);
}
} }
else if (event->button == 1 && else if (event->button == 1 &&
(control == META_FRAME_CONTROL_RESIZE_SE || (control == META_FRAME_CONTROL_RESIZE_SE ||
@ -1123,7 +1089,7 @@ meta_frames_button_press_event (GtkWidget *widget,
} }
meta_frames_try_grab_op (frame, op, meta_frames_try_grab_op (frame, op,
event->x_root, event->y_root, event->x, event->y,
event->time); event->time);
} }
else if (control == META_FRAME_CONTROL_TITLE && else if (control == META_FRAME_CONTROL_TITLE &&
@ -1135,7 +1101,7 @@ meta_frames_button_press_event (GtkWidget *widget,
{ {
meta_frames_try_grab_op (frame, meta_frames_try_grab_op (frame,
META_GRAB_OP_MOVING, META_GRAB_OP_MOVING,
event->x_root, event->y_root, event->x, event->y,
event->time); event->time);
} }
} }
@ -1152,25 +1118,18 @@ meta_frames_button_press_event (GtkWidget *widget,
} }
static gboolean static gboolean
meta_frames_button_release_event (GtkWidget *widget, handle_button_release_event (MetaUIFrame *frame,
GdkEventButton *event) ClutterButtonEvent *event)
{ {
MetaUIFrame *frame; Display *display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
MetaFrames *frames;
frames = META_FRAMES (widget); meta_core_end_grab_op (display, event->time);
frames->current_grab_op = META_GRAB_OP_NONE;
frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window));
if (frame == NULL)
return FALSE;
/* We only handle the releases we handled the presses for (things /* We only handle the releases we handled the presses for (things
* involving frame controls). Window ops that don't require a * involving frame controls). Window ops that don't require a
* frame are handled in the Xlib part of the code, display.c/window.c * frame are handled in the Xlib part of the code, display.c/window.c
*/ */
if (frame->xwindow == frames->grab_xwindow && if (((int) event->button) == frame->grab_button &&
((int) event->button) == frame->grab_button &&
frame->button_state == META_BUTTON_STATE_PRESSED) frame->button_state == META_BUTTON_STATE_PRESSED)
{ {
switch (frame->prelit_control) switch (frame->prelit_control)
@ -1339,18 +1298,12 @@ meta_ui_frame_update_prelit_control (MetaUIFrame *frame,
} }
static gboolean static gboolean
meta_frames_motion_notify_event (GtkWidget *widget, handle_motion_notify_event (MetaUIFrame *frame,
GdkEventMotion *event) ClutterMotionEvent *event)
{ {
MetaUIFrame *frame; MetaFrames *frames = frame->frames;
MetaFrames *frames;
MetaFrameControl control; MetaFrameControl control;
frames = META_FRAMES (widget);
frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window));
if (frame == NULL)
return FALSE;
control = get_control (frame, event->x, event->y); control = get_control (frame, event->x, event->y);
if (frame->button_state == META_BUTTON_STATE_PRESSED) if (frame->button_state == META_BUTTON_STATE_PRESSED)
@ -1369,7 +1322,7 @@ meta_frames_motion_notify_event (GtkWidget *widget,
meta_ui_frame_update_prelit_control (frame, control); meta_ui_frame_update_prelit_control (frame, control);
} }
if ((event->state & GDK_BUTTON1_MASK) && if ((event->modifier_state & CLUTTER_BUTTON1_MASK) &&
frames->current_grab_op != META_GRAB_OP_NONE) frames->current_grab_op != META_GRAB_OP_NONE)
meta_frames_retry_grab_op (frames, event->time); meta_frames_retry_grab_op (frames, event->time);
@ -1578,19 +1531,11 @@ meta_ui_frame_paint (MetaUIFrame *frame,
} }
static gboolean static gboolean
meta_frames_enter_notify_event (GtkWidget *widget, handle_enter_notify_event (MetaUIFrame *frame,
GdkEventCrossing *event) ClutterCrossingEvent *event)
{ {
MetaUIFrame *frame;
MetaFrames *frames;
MetaFrameControl control; MetaFrameControl control;
frames = META_FRAMES (widget);
frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window));
if (frame == NULL)
return FALSE;
frame->maybe_ignore_leave_notify = FALSE; frame->maybe_ignore_leave_notify = FALSE;
control = get_control (frame, event->x, event->y); control = get_control (frame, event->x, event->y);
@ -1600,20 +1545,12 @@ meta_frames_enter_notify_event (GtkWidget *widget,
} }
static gboolean static gboolean
meta_frames_leave_notify_event (GtkWidget *widget, handle_leave_notify_event (MetaUIFrame *frame,
GdkEventCrossing *event) ClutterCrossingEvent *event)
{ {
MetaUIFrame *frame;
MetaFrames *frames;
Display *display; Display *display;
MetaGrabOp grab_op; MetaGrabOp grab_op;
frames = META_FRAMES (widget);
frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window));
if (frame == NULL)
return FALSE;
display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
grab_op = meta_core_get_grab_op (display); grab_op = meta_core_get_grab_op (display);
@ -1631,6 +1568,27 @@ meta_frames_leave_notify_event (GtkWidget *widget,
return TRUE; return TRUE;
} }
gboolean
meta_ui_frame_handle_event (MetaUIFrame *frame,
const ClutterEvent *event)
{
switch (event->any.type)
{
case CLUTTER_BUTTON_PRESS:
return handle_button_press_event (frame, (ClutterButtonEvent *) event);
case CLUTTER_BUTTON_RELEASE:
return handle_button_release_event (frame, (ClutterButtonEvent *) event);
case CLUTTER_MOTION:
return handle_motion_notify_event (frame, (ClutterMotionEvent *) event);
case CLUTTER_ENTER:
return handle_enter_notify_event (frame, (ClutterCrossingEvent *) event);
case CLUTTER_LEAVE:
return handle_leave_notify_event (frame, (ClutterCrossingEvent *) event);
default:
return FALSE;
}
}
static GdkRectangle* static GdkRectangle*
control_rect (MetaFrameControl control, control_rect (MetaFrameControl control,
MetaFrameGeometry *fgeom) MetaFrameGeometry *fgeom)
@ -1705,7 +1663,7 @@ control_rect (MetaFrameControl control,
#define TOP_RESIZE_HEIGHT 4 #define TOP_RESIZE_HEIGHT 4
#define CORNER_SIZE_MULT 2 #define CORNER_SIZE_MULT 2
static MetaFrameControl static MetaFrameControl
get_control (MetaUIFrame *frame, int x, int y) get_control (MetaUIFrame *frame, int root_x, int root_y)
{ {
MetaFrameGeometry fgeom; MetaFrameGeometry fgeom;
MetaFrameFlags flags; MetaFrameFlags flags;
@ -1713,6 +1671,12 @@ get_control (MetaUIFrame *frame, int x, int y)
gboolean has_vert, has_horiz; gboolean has_vert, has_horiz;
gboolean has_north_resize; gboolean has_north_resize;
cairo_rectangle_int_t client; cairo_rectangle_int_t client;
int x, y;
int win_x, win_y;
gdk_window_get_position (frame->window, &win_x, &win_y);
x = root_x - win_x;
y = root_y - win_y;
meta_ui_frame_calc_geometry (frame, &fgeom); meta_ui_frame_calc_geometry (frame, &fgeom);
get_client_rect (&fgeom, &client); get_client_rect (&fgeom, &client);

View File

@ -106,8 +106,6 @@ struct _MetaFrames
guint grab_button; guint grab_button;
gdouble grab_x; gdouble grab_x;
gdouble grab_y; gdouble grab_y;
Window grab_xwindow;
}; };
struct _MetaFramesClass struct _MetaFramesClass
@ -147,4 +145,6 @@ void meta_ui_frame_move_resize (MetaUIFrame *frame,
void meta_ui_frame_queue_draw (MetaUIFrame *frame); void meta_ui_frame_queue_draw (MetaUIFrame *frame);
gboolean meta_ui_frame_handle_event (MetaUIFrame *frame, const ClutterEvent *event);
#endif #endif

View File

@ -80,202 +80,6 @@ meta_ui_get_screen_number (void)
return gdk_screen_get_number (gdk_screen_get_default ()); return gdk_screen_get_number (gdk_screen_get_default ());
} }
/* For XInput2 */
#include "display-private.h"
static gboolean
is_input_event (XEvent *event)
{
MetaDisplay *display = meta_get_display ();
return (event->type == GenericEvent &&
event->xcookie.extension == display->xinput_opcode);
}
static gboolean
is_interesting_input_event (XEvent *event)
{
XIEvent *input_event;
if (!is_input_event (event))
return FALSE;
input_event = (XIEvent *) event->xcookie.data;
switch (input_event->evtype)
{
case XI_ButtonPress:
case XI_ButtonRelease:
case XI_Motion:
case XI_Enter:
case XI_Leave:
case XI_TouchBegin:
case XI_TouchUpdate:
case XI_TouchEnd:
return TRUE;
default:
return FALSE;
}
}
/* We do some of our event handling in frames.c, which expects
* GDK events delivered by GTK+. However, since the transition to
* client side windows, we can't let GDK see button events, since the
* client-side tracking of implicit and explicit grabs it does will
* get confused by our direct use of X grabs in the core code.
*
* So we do a very minimal GDK => GTK event conversion here and send on the
* events we care about, and then filter them out so they don't go
* through the normal GDK event handling.
*
* To reduce the amount of code, the only events fields filled out
* below are the ones that frames.c uses. If frames.c is modified to
* use more fields, more fields need to be filled out below.
*/
static void
maybe_redirect_mouse_event (XEvent *xevent)
{
GdkDisplay *gdisplay;
GdkDeviceManager *gmanager;
GdkDevice *gdevice;
MetaUI *ui;
GdkEvent *gevent;
GdkWindow *gdk_window;
Window window;
XIEvent *xev;
XIDeviceEvent *xev_d = NULL;
XIEnterEvent *xev_e = NULL;
xev = (XIEvent *) xevent->xcookie.data;
switch (xev->evtype)
{
case XI_ButtonPress:
case XI_ButtonRelease:
case XI_Motion:
xev_d = (XIDeviceEvent *) xev;
window = xev_d->event;
break;
case XI_Enter:
case XI_Leave:
xev_e = (XIEnterEvent *) xev;
window = xev_e->event;
break;
default:
/* Not interested in this event. */
return;
}
gdisplay = gdk_x11_lookup_xdisplay (xev->display);
ui = g_object_get_data (G_OBJECT (gdisplay), "meta-ui");
if (!ui)
return;
gdk_window = gdk_x11_window_lookup_for_display (gdisplay, window);
if (gdk_window == NULL)
return;
gmanager = gdk_display_get_device_manager (gdisplay);
gdevice = gdk_x11_device_manager_lookup (gmanager, META_VIRTUAL_CORE_POINTER_ID);
switch (xev->evtype)
{
case XI_ButtonPress:
case XI_ButtonRelease:
if (xev_d->evtype == XI_ButtonPress)
{
GtkSettings *settings = gtk_settings_get_default ();
int double_click_time;
int double_click_distance;
int button;
g_object_get (settings,
"gtk-double-click-time", &double_click_time,
"gtk-double-click-distance", &double_click_distance,
NULL);
button = xev_d->detail;
if (button == ui->button_click_number &&
xev_d->event == ui->button_click_window &&
xev_d->time < ui->button_click_time + double_click_time &&
ABS (xev_d->event_x - ui->button_click_x) <= double_click_distance &&
ABS (xev_d->event_y - ui->button_click_y) <= double_click_distance)
{
gevent = gdk_event_new (GDK_2BUTTON_PRESS);
ui->button_click_number = 0;
}
else
{
gevent = gdk_event_new (GDK_BUTTON_PRESS);
ui->button_click_number = button;
ui->button_click_window = xev_d->event;
ui->button_click_time = xev_d->time;
ui->button_click_x = xev_d->event_x;
ui->button_click_y = xev_d->event_y;
}
gevent->button.button = button;
}
else
{
gevent = gdk_event_new (GDK_BUTTON_RELEASE);
gevent->button.button = xev_d->detail;
}
gevent->button.window = g_object_ref (gdk_window);
gevent->button.time = xev_d->time;
gevent->button.x = xev_d->event_x;
gevent->button.y = xev_d->event_y;
gevent->button.x_root = xev_d->root_x;
gevent->button.y_root = xev_d->root_y;
break;
case XI_Motion:
gevent = gdk_event_new (GDK_MOTION_NOTIFY);
gevent->motion.window = g_object_ref (gdk_window);
gevent->motion.time = xev_d->time;
gevent->motion.x = xev_d->event_x;
gevent->motion.y = xev_d->event_y;
gevent->motion.x_root = xev_d->root_x;
gevent->motion.y_root = xev_d->root_y;
if (XIMaskIsSet (xev_d->buttons.mask, 1))
gevent->motion.state |= GDK_BUTTON1_MASK;
break;
case XI_Enter:
case XI_Leave:
gevent = gdk_event_new (xev_e->evtype == XI_Enter ? GDK_ENTER_NOTIFY : GDK_LEAVE_NOTIFY);
gevent->crossing.window = g_object_ref (gdk_window);
gevent->crossing.time = xev_e->time;
gevent->crossing.x = xev_e->event_x;
gevent->crossing.y = xev_e->event_y;
break;
default:
g_assert_not_reached ();
break;
}
/* If we've gotten here, we've created the gdk_event and should send it on */
gdk_event_set_device (gevent, gdevice);
gtk_main_do_event (gevent);
gdk_event_free (gevent);
}
static GdkFilterReturn
ui_filter_func (GdkXEvent *xevent,
GdkEvent *event,
gpointer data)
{
if (is_interesting_input_event (xevent))
{
maybe_redirect_mouse_event (xevent);
return GDK_FILTER_REMOVE;
}
else
return GDK_FILTER_CONTINUE;
}
MetaUI* MetaUI*
meta_ui_new (Display *xdisplay, meta_ui_new (Display *xdisplay,
Screen *screen) Screen *screen)
@ -299,8 +103,6 @@ meta_ui_new (Display *xdisplay,
*/ */
gtk_widget_show (GTK_WIDGET (ui->frames)); gtk_widget_show (GTK_WIDGET (ui->frames));
gdk_window_add_filter (NULL, ui_filter_func, NULL);
g_object_set_data (G_OBJECT (gdisplay), "meta-ui", ui); g_object_set_data (G_OBJECT (gdisplay), "meta-ui", ui);
return ui; return ui;
@ -316,8 +118,6 @@ meta_ui_free (MetaUI *ui)
gdisplay = gdk_x11_lookup_xdisplay (ui->xdisplay); gdisplay = gdk_x11_lookup_xdisplay (ui->xdisplay);
g_object_set_data (G_OBJECT (gdisplay), "meta-ui", NULL); g_object_set_data (G_OBJECT (gdisplay), "meta-ui", NULL);
gdk_window_remove_filter (NULL, ui_filter_func, NULL);
g_free (ui); g_free (ui);
} }

View File

@ -74,6 +74,7 @@ sync_focus_surface (MetaWaylandPointer *pointer)
{ {
case META_EVENT_ROUTE_WINDOW_OP: case META_EVENT_ROUTE_WINDOW_OP:
case META_EVENT_ROUTE_COMPOSITOR_GRAB: case META_EVENT_ROUTE_COMPOSITOR_GRAB:
case META_EVENT_ROUTE_FRAME_BUTTON:
/* The compositor has a grab, so remove our focus... */ /* The compositor has a grab, so remove our focus... */
meta_wayland_pointer_set_focus (pointer, NULL); meta_wayland_pointer_set_focus (pointer, NULL);
break; break;