frames: Handle touch events
This is just done on wayland as it'll break horribly on X11, we let this happen through pointer emulated events in XISelectEvents evmask instead. Some things had to be made slightly more generic to accomodate touch events. The MetaFrames shall lock onto a single touch at a time, we don't allow crazy stuff like multi-window drag nor multi-edge resizes. https://bugzilla.gnome.org/show_bug.cgi?id=770185
This commit is contained in:
parent
3561082aba
commit
ac20bf2000
146
src/ui/frames.c
146
src/ui/frames.c
@ -71,6 +71,13 @@ static MetaFrameControl get_control (MetaUIFrame *frame,
|
||||
|
||||
G_DEFINE_TYPE (MetaFrames, meta_frames, GTK_TYPE_WINDOW);
|
||||
|
||||
enum {
|
||||
META_ACTION_CLICK,
|
||||
META_ACTION_RIGHT_CLICK,
|
||||
META_ACTION_MIDDLE_CLICK,
|
||||
META_ACTION_DOUBLE_CLICK
|
||||
};
|
||||
|
||||
static GObject *
|
||||
meta_frames_constructor (GType gtype,
|
||||
guint n_properties,
|
||||
@ -748,8 +755,11 @@ meta_frame_titlebar_event (MetaUIFrame *frame,
|
||||
{
|
||||
MetaFrameFlags flags;
|
||||
Display *display;
|
||||
guint32 evtime;
|
||||
gfloat x, y;
|
||||
uint32_t evtime;
|
||||
float x, y;
|
||||
|
||||
g_assert (event->type == CLUTTER_BUTTON_PRESS ||
|
||||
event->type == CLUTTER_TOUCH_BEGIN);
|
||||
|
||||
display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
|
||||
|
||||
@ -884,6 +894,8 @@ meta_frames_try_grab_op (MetaUIFrame *frame,
|
||||
frames->grab_x = grab_x;
|
||||
frames->grab_y = grab_y;
|
||||
}
|
||||
else
|
||||
frames->grab_touch = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -894,6 +906,7 @@ meta_frames_retry_grab_op (MetaFrames *frames,
|
||||
{
|
||||
Display *display;
|
||||
MetaGrabOp op;
|
||||
gboolean ret;
|
||||
|
||||
if (frames->current_grab_op == META_GRAB_OP_NONE)
|
||||
return TRUE;
|
||||
@ -902,7 +915,7 @@ meta_frames_retry_grab_op (MetaFrames *frames,
|
||||
frames->current_grab_op = META_GRAB_OP_NONE;
|
||||
display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
|
||||
|
||||
return meta_core_begin_grab_op (display,
|
||||
ret = meta_core_begin_grab_op (display,
|
||||
frames->grab_frame->xwindow,
|
||||
op,
|
||||
FALSE,
|
||||
@ -912,6 +925,10 @@ meta_frames_retry_grab_op (MetaFrames *frames,
|
||||
time,
|
||||
frames->grab_x,
|
||||
frames->grab_y);
|
||||
if (ret)
|
||||
frames->grab_touch = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static MetaGrabOp
|
||||
@ -940,18 +957,60 @@ grab_op_from_resize_control (MetaFrameControl control)
|
||||
}
|
||||
}
|
||||
|
||||
static guint
|
||||
get_action (const ClutterEvent *event)
|
||||
{
|
||||
if (event->type == CLUTTER_BUTTON_PRESS ||
|
||||
event->type == CLUTTER_BUTTON_RELEASE)
|
||||
{
|
||||
switch (event->button.button)
|
||||
{
|
||||
case CLUTTER_BUTTON_PRIMARY:
|
||||
if (clutter_event_get_click_count (event) == 2)
|
||||
return META_ACTION_DOUBLE_CLICK;
|
||||
else
|
||||
return META_ACTION_CLICK;
|
||||
case CLUTTER_BUTTON_SECONDARY:
|
||||
return META_ACTION_RIGHT_CLICK;
|
||||
case CLUTTER_BUTTON_MIDDLE:
|
||||
return META_ACTION_MIDDLE_CLICK;
|
||||
}
|
||||
}
|
||||
else if (event->type == CLUTTER_TOUCH_BEGIN ||
|
||||
event->type == CLUTTER_TOUCH_UPDATE ||
|
||||
event->type == CLUTTER_TOUCH_END)
|
||||
{
|
||||
return META_ACTION_CLICK;
|
||||
}
|
||||
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
get_button_number (const ClutterEvent *event)
|
||||
{
|
||||
if (event->type == CLUTTER_TOUCH_BEGIN ||
|
||||
event->type == CLUTTER_TOUCH_UPDATE ||
|
||||
event->type == CLUTTER_TOUCH_END)
|
||||
return -1;
|
||||
else if (event->type == CLUTTER_BUTTON_PRESS ||
|
||||
event->type == CLUTTER_BUTTON_RELEASE)
|
||||
return clutter_event_get_button (event);
|
||||
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_frame_left_click_event (MetaUIFrame *frame,
|
||||
const ClutterEvent *event)
|
||||
{
|
||||
Display *display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
|
||||
MetaFrameControl control;
|
||||
guint32 evtime, button;
|
||||
guint32 evtime;
|
||||
gfloat x, y;
|
||||
|
||||
evtime = clutter_event_get_time (event);
|
||||
clutter_event_get_coords (event, &x, &y);
|
||||
button = clutter_event_get_button (event);
|
||||
control = get_control (frame, x, y);
|
||||
|
||||
switch (control)
|
||||
@ -962,7 +1021,7 @@ meta_frame_left_click_event (MetaUIFrame *frame,
|
||||
case META_FRAME_CONTROL_DELETE:
|
||||
case META_FRAME_CONTROL_MENU:
|
||||
case META_FRAME_CONTROL_APPMENU:
|
||||
frame->grab_button = button;
|
||||
frame->grab_button = get_button_number (event);
|
||||
frame->button_state = META_BUTTON_STATE_PRESSED;
|
||||
frame->prelit_control = control;
|
||||
redraw_control (frame, control);
|
||||
@ -1050,21 +1109,24 @@ handle_press_event (MetaUIFrame *frame,
|
||||
{
|
||||
MetaFrameControl control;
|
||||
Display *display;
|
||||
guint evtime, button;
|
||||
gfloat x, y;
|
||||
uint32_t evtime, action;
|
||||
float x, y;
|
||||
|
||||
g_assert (event->type == CLUTTER_BUTTON_PRESS ||
|
||||
event->type == CLUTTER_TOUCH_BEGIN);
|
||||
|
||||
display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
|
||||
|
||||
evtime = clutter_event_get_time (event);
|
||||
clutter_event_get_coords (event, &x, &y);
|
||||
control = get_control (frame, x, y);
|
||||
button = clutter_event_get_button (event);
|
||||
action = get_action (event);
|
||||
|
||||
/* don't do the rest of this if on client area */
|
||||
if (control == META_FRAME_CONTROL_CLIENT_AREA)
|
||||
return FALSE; /* not on the frame, just passed through from client */
|
||||
|
||||
if (button == 1 &&
|
||||
if (action == META_ACTION_CLICK &&
|
||||
!(control == META_FRAME_CONTROL_MINIMIZE ||
|
||||
control == META_FRAME_CONTROL_DELETE ||
|
||||
control == META_FRAME_CONTROL_MAXIMIZE))
|
||||
@ -1079,8 +1141,7 @@ handle_press_event (MetaUIFrame *frame,
|
||||
* if we double click the titlebar.
|
||||
*/
|
||||
if (control == META_FRAME_CONTROL_TITLE &&
|
||||
button == 1 &&
|
||||
clutter_event_get_click_count (event) == 2)
|
||||
action == META_ACTION_DOUBLE_CLICK)
|
||||
{
|
||||
meta_core_end_grab_op (display, evtime);
|
||||
return meta_frame_double_click_event (frame, event);
|
||||
@ -1089,15 +1150,15 @@ handle_press_event (MetaUIFrame *frame,
|
||||
if (meta_core_get_grab_op (display) != META_GRAB_OP_NONE)
|
||||
return FALSE; /* already up to something */
|
||||
|
||||
frame->grab_button = button;
|
||||
frame->grab_button = get_button_number (event);
|
||||
|
||||
switch (button)
|
||||
switch (action)
|
||||
{
|
||||
case 1:
|
||||
case META_ACTION_CLICK:
|
||||
return meta_frame_left_click_event (frame, event);
|
||||
case 2:
|
||||
case META_ACTION_MIDDLE_CLICK:
|
||||
return meta_frame_middle_click_event (frame, (ClutterButtonEvent *) event);
|
||||
case 3:
|
||||
case META_ACTION_RIGHT_CLICK:
|
||||
return meta_frame_right_click_event (frame, (ClutterButtonEvent *) event);
|
||||
default:
|
||||
return FALSE;
|
||||
@ -1112,9 +1173,12 @@ handle_release_event (MetaUIFrame *frame,
|
||||
guint32 evtime, button;
|
||||
gfloat x, y;
|
||||
|
||||
g_assert (event->type == CLUTTER_BUTTON_RELEASE ||
|
||||
event->type == CLUTTER_TOUCH_END);
|
||||
|
||||
evtime = clutter_event_get_time (event);
|
||||
clutter_event_get_coords (event, &x, &y);
|
||||
button = clutter_event_get_button (event);
|
||||
button = get_button_number (event);
|
||||
|
||||
frame->frames->current_grab_op = META_GRAB_OP_NONE;
|
||||
meta_core_end_grab_op (display, evtime);
|
||||
@ -1265,6 +1329,9 @@ handle_motion_event (MetaUIFrame *frame,
|
||||
guint32 evtime;
|
||||
gfloat x, y;
|
||||
|
||||
g_assert (event->type == CLUTTER_MOTION ||
|
||||
event->type == CLUTTER_TOUCH_UPDATE);
|
||||
|
||||
modifiers = clutter_event_get_state (event);
|
||||
evtime = clutter_event_get_time (event);
|
||||
clutter_event_get_coords (event, &x, &y);
|
||||
@ -1286,8 +1353,10 @@ handle_motion_event (MetaUIFrame *frame,
|
||||
meta_ui_frame_update_prelit_control (frame, control);
|
||||
}
|
||||
|
||||
if ((modifiers & CLUTTER_BUTTON1_MASK) &&
|
||||
frames->current_grab_op != META_GRAB_OP_NONE)
|
||||
if (frames->current_grab_op != META_GRAB_OP_NONE &&
|
||||
(event->type == CLUTTER_TOUCH_UPDATE ||
|
||||
(event->type == CLUTTER_MOTION &&
|
||||
(modifiers & CLUTTER_BUTTON1_MASK))))
|
||||
meta_frames_retry_grab_op (frames, evtime);
|
||||
|
||||
return TRUE;
|
||||
@ -1542,13 +1611,50 @@ gboolean
|
||||
meta_ui_frame_handle_event (MetaUIFrame *frame,
|
||||
const ClutterEvent *event)
|
||||
{
|
||||
if (event->type == CLUTTER_TOUCH_BEGIN ||
|
||||
event->type == CLUTTER_TOUCH_UPDATE ||
|
||||
event->type == CLUTTER_TOUCH_END)
|
||||
{
|
||||
ClutterEventSequence *sequence;
|
||||
MetaFrames *frames = frame->frames;
|
||||
|
||||
/* In X11, mutter sets up passive touch grabs which basically
|
||||
* means we handle those events twice (once through the passive
|
||||
* grab, and then through XISelectEvents).
|
||||
*
|
||||
* Receiving touch events here means we are going through the
|
||||
* former, but passive grabs are exclusively for gesture
|
||||
* recognition purposes.
|
||||
*
|
||||
* We do actually want this to happen though the regular event
|
||||
* selection paths to avoid breaking internal state, which means
|
||||
* we will get pointer events, because we don't select for XI_Touch*.
|
||||
*/
|
||||
if (!meta_is_wayland_compositor ())
|
||||
return FALSE;
|
||||
|
||||
sequence = clutter_event_get_event_sequence (event);
|
||||
|
||||
/* Lock onto a single touch */
|
||||
if (frames->grab_touch && frames->grab_touch != sequence)
|
||||
return FALSE;
|
||||
|
||||
if (event->type == CLUTTER_TOUCH_BEGIN)
|
||||
frames->grab_touch = sequence;
|
||||
else if (event->type == CLUTTER_TOUCH_END)
|
||||
frames->grab_touch = NULL;
|
||||
}
|
||||
|
||||
switch (event->any.type)
|
||||
{
|
||||
case CLUTTER_BUTTON_PRESS:
|
||||
case CLUTTER_TOUCH_BEGIN:
|
||||
return handle_press_event (frame, event);
|
||||
case CLUTTER_BUTTON_RELEASE:
|
||||
case CLUTTER_TOUCH_END:
|
||||
return handle_release_event (frame, event);
|
||||
case CLUTTER_MOTION:
|
||||
case CLUTTER_TOUCH_UPDATE:
|
||||
return handle_motion_event (frame, event);
|
||||
case CLUTTER_ENTER:
|
||||
return handle_enter_notify_event (frame, (ClutterCrossingEvent *) event);
|
||||
|
@ -99,6 +99,8 @@ struct _MetaFrames
|
||||
guint grab_button;
|
||||
gdouble grab_x;
|
||||
gdouble grab_y;
|
||||
|
||||
ClutterEventSequence *grab_touch;
|
||||
};
|
||||
|
||||
struct _MetaFramesClass
|
||||
|
Loading…
Reference in New Issue
Block a user