X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gdk%2Fgdkevents.c;h=4a9d0b965a0e73543985559673c3ea7ac9c9ff9f;hb=HEAD;hp=00557fd8ed9b6aaaa853bbb2cb85cd90fefb1a7e;hpb=27bc88f7c2269ac750504c7fe6c7c02c43183149;p=~andy%2Fgtk diff --git a/gdk/gdkevents.c b/gdk/gdkevents.c index 00557fd8e..4a9d0b965 100644 --- a/gdk/gdkevents.c +++ b/gdk/gdkevents.c @@ -12,9 +12,7 @@ * 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, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * License along with this library. If not, see . */ /* @@ -25,11 +23,28 @@ */ #include "config.h" -#include /* For memset() */ -#include -#include "gdk.h" #include "gdkinternals.h" +#include "gdkdisplayprivate.h" + +#include +#include + + +/** + * SECTION:events + * @Short_description: Functions for handling events from the window system + * @Title: Events + * @See_also: Event Structures + * + * This section describes functions dealing with events from the window + * system. + * + * In GTK+ applications the events are handled automatically in + * gtk_main_do_event() and passed on to the appropriate widgets, so these + * functions are rarely needed. Though some of the fields in the + * Event Structures are useful. + */ typedef struct _GdkIOClosure GdkIOClosure; @@ -43,9 +58,16 @@ struct _GdkIOClosure /* Private variable declarations */ -GdkEventFunc _gdk_event_func = NULL; /* Callback for events */ -gpointer _gdk_event_data = NULL; -GDestroyNotify _gdk_event_notify = NULL; +static GdkEventFunc _gdk_event_func = NULL; /* Callback for events */ +static gpointer _gdk_event_data = NULL; +static GDestroyNotify _gdk_event_notify = NULL; + +void +_gdk_event_emit (GdkEvent *event) +{ + if (_gdk_event_func) + (*_gdk_event_func) (event, _gdk_event_data); +} /********************************************* * Functions for maintaining the event queue * @@ -63,13 +85,27 @@ GDestroyNotify _gdk_event_notify = NULL; GList* _gdk_event_queue_find_first (GdkDisplay *display) { - GList *tmp_list = display->queued_events; + GList *tmp_list; + GList *pending_motion = NULL; + + if (display->event_pause_count > 0) + return NULL; + tmp_list = display->queued_events; while (tmp_list) { GdkEventPrivate *event = tmp_list->data; - if (!(event->flags & GDK_EVENT_PENDING)) - return tmp_list; + + if (event->flags & GDK_EVENT_PENDING) + continue; + + if (pending_motion) + return pending_motion; + + if (event->event.type == GDK_MOTION_NOTIFY && !display->flushing_events) + pending_motion = tmp_list; + else + return tmp_list; tmp_list = g_list_next (tmp_list); } @@ -148,15 +184,15 @@ _gdk_event_queue_insert_after (GdkDisplay *display, } /** - * _gdk_event_queue_insert_after: + * _gdk_event_queue_insert_before: * @display: a #GdkDisplay - * @sibling: Append after this event. - * @event: Event to append. + * @sibling: Append before this event + * @event: Event to prepend * - * Appends an event before the specified event, or if it isn't in - * the queue, onto the tail of the event queue. + * Prepends an event before the specified event, or if it isn't in + * the queue, onto the head of the event queue. * - * Returns: the newly appended list node. + * Returns: the newly prepended list node. * * Since: 2.16 */ @@ -226,6 +262,61 @@ _gdk_event_unqueue (GdkDisplay *display) return event; } +void +_gdk_event_queue_handle_motion_compression (GdkDisplay *display) +{ + GList *tmp_list; + GList *pending_motions = NULL; + GdkWindow *pending_motion_window = NULL; + GdkDevice *pending_motion_device = NULL; + + /* If the last N events in the event queue are motion notify + * events for the same window, drop all but the last */ + + tmp_list = display->queued_tail; + + while (tmp_list) + { + GdkEventPrivate *event = tmp_list->data; + + if (event->flags & GDK_EVENT_PENDING) + break; + + if (event->event.type != GDK_MOTION_NOTIFY) + break; + + if (pending_motion_window != NULL && + pending_motion_window != event->event.motion.window) + break; + + if (pending_motion_device != NULL && + pending_motion_device != event->event.motion.device) + break; + + pending_motion_window = event->event.motion.window; + pending_motion_device = event->event.motion.device; + pending_motions = tmp_list; + + tmp_list = tmp_list->prev; + } + + while (pending_motions && pending_motions->next != NULL) + { + GList *next = pending_motions->next; + display->queued_events = g_list_delete_link (display->queued_events, + pending_motions); + pending_motions = next; + } + + if (pending_motions && + pending_motions == display->queued_events && + pending_motions == display->queued_tail) + { + GdkFrameClock *clock = gdk_window_get_frame_clock (pending_motion_window); + gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS); + } +} + /** * gdk_event_handler_set: * @func: the function to call to handle events from GDK. @@ -253,6 +344,45 @@ gdk_event_handler_set (GdkEventFunc func, _gdk_event_notify = notify; } +/** + * gdk_events_pending: + * + * Checks if any events are ready to be processed for any display. + * + * Return value: %TRUE if any events are pending. + */ +gboolean +gdk_events_pending (void) +{ + GSList *list, *l; + gboolean pending; + + pending = FALSE; + list = gdk_display_manager_list_displays (gdk_display_manager_get ()); + for (l = list; l; l = l->next) + { + if (_gdk_event_queue_find_first (l->data)) + { + pending = TRUE; + goto out; + } + } + + for (l = list; l; l = l->next) + { + if (gdk_display_has_pending (l->data)) + { + pending = TRUE; + goto out; + } + } + + out: + g_slist_free (list); + + return pending; +} + /** * gdk_event_get: * @@ -266,16 +396,21 @@ gdk_event_handler_set (GdkEventFunc func, GdkEvent* gdk_event_get (void) { - GSList *tmp_list; + GSList *list, *l; + GdkEvent *event; - for (tmp_list = _gdk_displays; tmp_list; tmp_list = tmp_list->next) + event = NULL; + list = gdk_display_manager_list_displays (gdk_display_manager_get ()); + for (l = list; l; l = l->next) { - GdkEvent *event = gdk_display_get_event (tmp_list->data); + event = gdk_display_get_event (l->data); if (event) - return event; + break; } - return NULL; + g_slist_free (list); + + return event; } /** @@ -291,16 +426,21 @@ gdk_event_get (void) GdkEvent* gdk_event_peek (void) { - GSList *tmp_list; + GSList *list, *l; + GdkEvent *event; - for (tmp_list = _gdk_displays; tmp_list; tmp_list = tmp_list->next) + event = NULL; + list = gdk_display_manager_list_displays (gdk_display_manager_get ()); + for (l = list; l; l = l->next) { - GdkEvent *event = gdk_display_peek_event (tmp_list->data); + event = gdk_display_peek_event (l->data); if (event) - return event; + break; } - return NULL; + g_slist_free (list); + + return event; } /** @@ -319,7 +459,7 @@ gdk_event_put (const GdkEvent *event) g_return_if_fail (event != NULL); if (event->any.window) - display = gdk_drawable_get_display (event->any.window); + display = gdk_window_get_display (event->any.window); else { GDK_NOTE (MULTIHEAD, @@ -386,11 +526,22 @@ gdk_event_new (GdkEventType type) new_event->button.x_root = 0.; new_event->button.y_root = 0.; break; + case GDK_TOUCH_BEGIN: + case GDK_TOUCH_UPDATE: + case GDK_TOUCH_END: + case GDK_TOUCH_CANCEL: + new_event->touch.x = 0.; + new_event->touch.y = 0.; + new_event->touch.x_root = 0.; + new_event->touch.y_root = 0.; + break; case GDK_SCROLL: new_event->scroll.x = 0.; new_event->scroll.y = 0.; new_event->scroll.x_root = 0.; new_event->scroll.y_root = 0.; + new_event->scroll.delta_x = 0.; + new_event->scroll.delta_y = 0.; break; case GDK_ENTER_NOTIFY: case GDK_LEAVE_NOTIFY: @@ -414,7 +565,31 @@ gdk_event_is_allocated (const GdkEvent *event) return FALSE; } - + +void +_gdk_event_set_pointer_emulated (GdkEvent *event, + gboolean emulated) +{ + if (gdk_event_is_allocated (event)) + { + GdkEventPrivate *private = (GdkEventPrivate *) event; + + if (emulated) + private->flags |= GDK_EVENT_POINTER_EMULATED; + else + private->flags &= ~(GDK_EVENT_POINTER_EMULATED); + } +} + +gboolean +_gdk_event_get_pointer_emulated (GdkEvent *event) +{ + if (gdk_event_is_allocated (event)) + return (((GdkEventPrivate *) event)->flags & GDK_EVENT_POINTER_EMULATED) != 0; + + return FALSE; +} + /** * gdk_event_copy: * @event: a #GdkEvent @@ -430,9 +605,9 @@ gdk_event_copy (const GdkEvent *event) { GdkEventPrivate *new_private; GdkEvent *new_event; - + g_return_val_if_fail (event != NULL, NULL); - + new_event = gdk_event_new (GDK_NOTHING); new_private = (GdkEventPrivate *)new_event; @@ -446,21 +621,22 @@ gdk_event_copy (const GdkEvent *event) new_private->screen = private->screen; new_private->device = private->device; + new_private->source_device = private->source_device; } - + switch (event->any.type) { case GDK_KEY_PRESS: case GDK_KEY_RELEASE: new_event->key.string = g_strdup (event->key.string); break; - + case GDK_ENTER_NOTIFY: case GDK_LEAVE_NOTIFY: if (event->crossing.subwindow != NULL) - g_object_ref (event->crossing.subwindow); + g_object_ref (event->crossing.subwindow); break; - + case GDK_DRAG_ENTER: case GDK_DRAG_LEAVE: case GDK_DRAG_MOTION: @@ -469,38 +645,62 @@ gdk_event_copy (const GdkEvent *event) case GDK_DROP_FINISHED: g_object_ref (event->dnd.context); break; - + case GDK_EXPOSE: case GDK_DAMAGE: if (event->expose.region) - new_event->expose.region = cairo_region_copy (event->expose.region); + new_event->expose.region = cairo_region_copy (event->expose.region); break; - + case GDK_SETTING: new_event->setting.name = g_strdup (new_event->setting.name); break; case GDK_BUTTON_PRESS: + case GDK_2BUTTON_PRESS: + case GDK_3BUTTON_PRESS: case GDK_BUTTON_RELEASE: - if (event->button.axes) - new_event->button.axes = g_memdup (event->button.axes, - sizeof (gdouble) * event->button.device->num_axes); + if (event->button.axes) + new_event->button.axes = g_memdup (event->button.axes, + sizeof (gdouble) * gdk_device_get_n_axes (event->button.device)); + break; + + case GDK_TOUCH_BEGIN: + case GDK_TOUCH_UPDATE: + case GDK_TOUCH_END: + case GDK_TOUCH_CANCEL: + if (event->touch.axes) + new_event->touch.axes = g_memdup (event->touch.axes, + sizeof (gdouble) * gdk_device_get_n_axes (event->touch.device)); break; case GDK_MOTION_NOTIFY: - if (event->motion.axes) - new_event->motion.axes = g_memdup (event->motion.axes, - sizeof (gdouble) * event->motion.device->num_axes); - + if (event->motion.axes) + new_event->motion.axes = g_memdup (event->motion.axes, + sizeof (gdouble) * gdk_device_get_n_axes (event->motion.device)); break; - + + case GDK_OWNER_CHANGE: + new_event->owner_change.owner = event->owner_change.owner; + if (new_event->owner_change.owner) + g_object_ref (new_event->owner_change.owner); + break; + + case GDK_SELECTION_CLEAR: + case GDK_SELECTION_NOTIFY: + case GDK_SELECTION_REQUEST: + new_event->selection.requestor = event->selection.requestor; + if (new_event->selection.requestor) + g_object_ref (new_event->selection.requestor); + break; + default: break; } if (gdk_event_is_allocated (event)) - _gdk_windowing_event_data_copy (event, new_event); - + _gdk_display_event_data_copy (gdk_display_get_default (), event, new_event); + return new_event; } @@ -516,6 +716,8 @@ gdk_event_copy (const GdkEvent *event) void gdk_event_free (GdkEvent *event) { + GdkDisplay *display; + g_return_if_fail (event != NULL); if (event->any.window) @@ -540,14 +742,24 @@ gdk_event_free (GdkEvent *event) case GDK_DRAG_STATUS: case GDK_DROP_START: case GDK_DROP_FINISHED: - g_object_unref (event->dnd.context); + if (event->dnd.context != NULL) + g_object_unref (event->dnd.context); break; case GDK_BUTTON_PRESS: + case GDK_2BUTTON_PRESS: + case GDK_3BUTTON_PRESS: case GDK_BUTTON_RELEASE: g_free (event->button.axes); break; - + + case GDK_TOUCH_BEGIN: + case GDK_TOUCH_UPDATE: + case GDK_TOUCH_END: + case GDK_TOUCH_CANCEL: + g_free (event->touch.axes); + break; + case GDK_EXPOSE: case GDK_DAMAGE: if (event->expose.region) @@ -562,11 +774,25 @@ gdk_event_free (GdkEvent *event) g_free (event->setting.name); break; + case GDK_OWNER_CHANGE: + if (event->owner_change.owner) + g_object_unref (event->owner_change.owner); + break; + + case GDK_SELECTION_CLEAR: + case GDK_SELECTION_NOTIFY: + case GDK_SELECTION_REQUEST: + if (event->selection.requestor) + g_object_unref (event->selection.requestor); + break; + default: break; } - _gdk_windowing_event_data_free (event); + display = gdk_display_get_default (); + if (display) + _gdk_display_event_data_free (display, event); g_hash_table_remove (event_hash, event); g_slice_free (GdkEventPrivate, (GdkEventPrivate*) event); @@ -594,6 +820,11 @@ gdk_event_get_time (const GdkEvent *event) case GDK_3BUTTON_PRESS: case GDK_BUTTON_RELEASE: return event->button.time; + case GDK_TOUCH_BEGIN: + case GDK_TOUCH_UPDATE: + case GDK_TOUCH_END: + case GDK_TOUCH_CANCEL: + return event->touch.time; case GDK_SCROLL: return event->scroll.time; case GDK_KEY_PRESS: @@ -620,7 +851,6 @@ gdk_event_get_time (const GdkEvent *event) return event->dnd.time; case GDK_CLIENT_EVENT: case GDK_VISIBILITY_NOTIFY: - case GDK_NO_EXPOSE: case GDK_CONFIGURE: case GDK_FOCUS_CHANGE: case GDK_NOTHING: @@ -670,7 +900,13 @@ gdk_event_get_state (const GdkEvent *event, case GDK_2BUTTON_PRESS: case GDK_3BUTTON_PRESS: case GDK_BUTTON_RELEASE: - *state = event->button.state; + *state = event->button.state; + return TRUE; + case GDK_TOUCH_BEGIN: + case GDK_TOUCH_UPDATE: + case GDK_TOUCH_END: + case GDK_TOUCH_CANCEL: + *state = event->touch.state; return TRUE; case GDK_SCROLL: *state = event->scroll.state; @@ -684,11 +920,8 @@ gdk_event_get_state (const GdkEvent *event, *state = event->crossing.state; return TRUE; case GDK_PROPERTY_NOTIFY: - *state = event->property.state; - return TRUE; case GDK_VISIBILITY_NOTIFY: case GDK_CLIENT_EVENT: - case GDK_NO_EXPOSE: case GDK_CONFIGURE: case GDK_FOCUS_CHANGE: case GDK_SELECTION_CLEAR: @@ -764,6 +997,13 @@ gdk_event_get_coords (const GdkEvent *event, x = event->button.x; y = event->button.y; break; + case GDK_TOUCH_BEGIN: + case GDK_TOUCH_UPDATE: + case GDK_TOUCH_END: + case GDK_TOUCH_CANCEL: + x = event->touch.x; + y = event->touch.y; + break; case GDK_MOTION_NOTIFY: x = event->motion.x; y = event->motion.y; @@ -818,6 +1058,13 @@ gdk_event_get_root_coords (const GdkEvent *event, x = event->button.x_root; y = event->button.y_root; break; + case GDK_TOUCH_BEGIN: + case GDK_TOUCH_UPDATE: + case GDK_TOUCH_END: + case GDK_TOUCH_CANCEL: + x = event->touch.x_root; + y = event->touch.y_root; + break; case GDK_ENTER_NOTIFY: case GDK_LEAVE_NOTIFY: x = event->crossing.x_root; @@ -845,10 +1092,245 @@ gdk_event_get_root_coords (const GdkEvent *event, return fetched; } +/** + * gdk_event_get_button: + * @event: a #GdkEvent + * @button: (out): location to store mouse button number + * + * Extract the button number from an event. + * + * Return value: %TRUE if the event delivered a button number + * + * Since: 3.2 + **/ +gboolean +gdk_event_get_button (const GdkEvent *event, + guint *button) +{ + gboolean fetched = TRUE; + guint number = 0; + + g_return_val_if_fail (event != NULL, FALSE); + + switch (event->type) + { + case GDK_BUTTON_PRESS: + case GDK_2BUTTON_PRESS: + case GDK_3BUTTON_PRESS: + case GDK_BUTTON_RELEASE: + number = event->button.button; + break; + default: + fetched = FALSE; + break; + } + + if (button) + *button = number; + + return fetched; +} + +/** + * gdk_event_get_click_count: + * @event: a #GdkEvent + * @click_count: (out): location to store click count + * + * Extracts the click count from an event. + * + * Return value: %TRUE if the event delivered a click count + * + * Since: 3.2 + */ +gboolean +gdk_event_get_click_count (const GdkEvent *event, + guint *click_count) +{ + gboolean fetched = TRUE; + guint number = 0; + + g_return_val_if_fail (event != NULL, FALSE); + + switch (event->type) + { + case GDK_BUTTON_PRESS: + case GDK_BUTTON_RELEASE: + number = 1; + break; + case GDK_2BUTTON_PRESS: + number = 2; + break; + case GDK_3BUTTON_PRESS: + number = 3; + break; + default: + fetched = FALSE; + break; + } + + if (click_count) + *click_count = number; + + return fetched; +} + +/** + * gdk_event_get_keyval: + * @event: a #GdkEvent + * @keyval: (out): location to store the keyval + * + * Extracts the keyval from an event. + * + * Return value: %TRUE if the event delivered a key symbol + * + * Since: 3.2 + */ +gboolean +gdk_event_get_keyval (const GdkEvent *event, + guint *keyval) +{ + gboolean fetched = TRUE; + guint number = 0; + + switch (event->type) + { + case GDK_KEY_PRESS: + case GDK_KEY_RELEASE: + number = event->key.keyval; + break; + default: + fetched = FALSE; + break; + } + + if (keyval) + *keyval = number; + + return fetched; +} + +/** + * gdk_event_get_keycode: + * @event: a #GdkEvent + * @keycode: (out): location to store the keycode + * + * Extracts the hardware keycode from an event. + * + * Return value: %TRUE if the event delivered a hardware keycode + * + * Since: 3.2 + */ +gboolean +gdk_event_get_keycode (const GdkEvent *event, + guint16 *keycode) +{ + gboolean fetched = TRUE; + guint16 number = 0; + + switch (event->type) + { + case GDK_KEY_PRESS: + case GDK_KEY_RELEASE: + number = event->key.hardware_keycode; + break; + default: + fetched = FALSE; + break; + } + + if (keycode) + *keycode = number; + + return fetched; +} + +/** + * gdk_event_get_scroll_direction: + * @event: a #GdkEvent + * @direction: (out): location to store the scroll direction + * + * Extracts the scroll direction from an event. + * + * Return value: %TRUE if the event delivered a scroll direction + * + * Since: 3.2 + */ +gboolean +gdk_event_get_scroll_direction (const GdkEvent *event, + GdkScrollDirection *direction) +{ + gboolean fetched = TRUE; + GdkScrollDirection dir = 0; + + switch (event->type) + { + case GDK_SCROLL: + if (event->scroll.direction == GDK_SCROLL_SMOOTH) + fetched = FALSE; + else + dir = event->scroll.direction; + break; + default: + fetched = FALSE; + break; + } + + if (direction) + *direction = dir; + + return fetched; +} + +/** + * gdk_event_get_scroll_deltas: + * @event: a #GdkEvent + * @delta_x: (out): return location for X delta + * @delta_y: (out): return location for Y delta + * + * Retrieves the scroll deltas from a #GdkEvent + * + * Returns: %TRUE if the event contains smooth scroll information + * + * Since: 3.4 + **/ +gboolean +gdk_event_get_scroll_deltas (const GdkEvent *event, + gdouble *delta_x, + gdouble *delta_y) +{ + gboolean fetched = TRUE; + gdouble dx = 0.0; + gdouble dy = 0.0; + + switch (event->type) + { + case GDK_SCROLL: + if (event->scroll.direction == GDK_SCROLL_SMOOTH) + { + dx = event->scroll.delta_x; + dy = event->scroll.delta_y; + } + else + fetched = FALSE; + break; + default: + fetched = FALSE; + break; + } + + if (delta_x) + *delta_x = dx; + + if (delta_y) + *delta_y = dy; + + return fetched; +} + /** * gdk_event_get_axis: * @event: a #GdkEvent - * @axis_use: (out): the axis use to look for + * @axis_use: the axis use to look for * @value: (out): location to store the value found * * Extract the axis value for a particular axis use from @@ -872,7 +1354,7 @@ gdk_event_get_axis (const GdkEvent *event, switch (event->type) { - case GDK_MOTION_NOTIFY: + case GDK_MOTION_NOTIFY: x = event->motion.x; y = event->motion.y; break; @@ -885,6 +1367,13 @@ gdk_event_get_axis (const GdkEvent *event, x = event->button.x; y = event->button.y; break; + case GDK_TOUCH_BEGIN: + case GDK_TOUCH_UPDATE: + case GDK_TOUCH_END: + case GDK_TOUCH_CANCEL: + x = event->touch.x; + y = event->touch.y; + break; case GDK_ENTER_NOTIFY: case GDK_LEAVE_NOTIFY: x = event->crossing.x; @@ -908,6 +1397,14 @@ gdk_event_get_axis (const GdkEvent *event, device = event->button.device; axes = event->button.axes; } + else if (event->type == GDK_TOUCH_BEGIN || + event->type == GDK_TOUCH_UPDATE || + event->type == GDK_TOUCH_END || + event->type == GDK_TOUCH_CANCEL) + { + device = event->touch.device; + axes = event->touch.axes; + } else if (event->type == GDK_MOTION_NOTIFY) { device = event->motion.device; @@ -953,6 +1450,12 @@ gdk_event_set_device (GdkEvent *event, case GDK_BUTTON_RELEASE: event->button.device = device; break; + case GDK_TOUCH_BEGIN: + case GDK_TOUCH_UPDATE: + case GDK_TOUCH_END: + case GDK_TOUCH_CANCEL: + event->touch.device = device; + break; case GDK_SCROLL: event->scroll.device = device; break; @@ -998,6 +1501,11 @@ gdk_event_get_device (const GdkEvent *event) case GDK_3BUTTON_PRESS: case GDK_BUTTON_RELEASE: return event->button.device; + case GDK_TOUCH_BEGIN: + case GDK_TOUCH_UPDATE: + case GDK_TOUCH_END: + case GDK_TOUCH_CANCEL: + return event->touch.device; case GDK_SCROLL: return event->scroll.device; case GDK_PROXIMITY_IN: @@ -1015,6 +1523,10 @@ gdk_event_get_device (const GdkEvent *event) case GDK_2BUTTON_PRESS: case GDK_3BUTTON_PRESS: case GDK_BUTTON_RELEASE: + case GDK_TOUCH_BEGIN: + case GDK_TOUCH_UPDATE: + case GDK_TOUCH_END: + case GDK_TOUCH_CANCEL: case GDK_ENTER_NOTIFY: case GDK_LEAVE_NOTIFY: case GDK_FOCUS_CHANGE: @@ -1032,20 +1544,22 @@ gdk_event_get_device (const GdkEvent *event) case GDK_KEY_RELEASE: { GdkDisplay *display; - GdkDevice *core_pointer; + GdkDeviceManager *device_manager; + GdkDevice *client_pointer; g_warning ("Event with type %d not holding a GdkDevice. " "It is most likely synthesized outside Gdk/GTK+\n", event->type); - display = gdk_drawable_get_display (event->any.window); - core_pointer = gdk_display_get_core_pointer (display); + display = gdk_window_get_display (event->any.window); + device_manager = gdk_display_get_device_manager (display); + client_pointer = gdk_device_manager_get_client_pointer (device_manager); if (event->type == GDK_KEY_PRESS || event->type == GDK_KEY_RELEASE) - return gdk_device_get_associated_device (core_pointer); + return gdk_device_get_associated_device (client_pointer); else - return core_pointer; + return client_pointer; } break; default: @@ -1053,11 +1567,75 @@ gdk_event_get_device (const GdkEvent *event) } } +/** + * gdk_event_set_source_device: + * @event: a #GdkEvent + * @device: a #GdkDevice + * + * Sets the slave device for @event to @device. + * + * The event must have been allocated by GTK+, + * for instance by gdk_event_copy(). + * + * Since: 3.0 + **/ +void +gdk_event_set_source_device (GdkEvent *event, + GdkDevice *device) +{ + GdkEventPrivate *private; + + g_return_if_fail (gdk_event_is_allocated (event)); + g_return_if_fail (GDK_IS_DEVICE (device)); + + private = (GdkEventPrivate *) event; + + private->source_device = device; +} + +/** + * gdk_event_get_source_device: + * @event: a #GdkEvent + * + * This function returns the hardware (slave) #GdkDevice that has + * triggered the event, falling back to the virtual (master) device + * (as in gdk_event_get_device()) if the event wasn't caused by + * interaction with a hardware device. This may happen for example + * in synthesized crossing events after a #GdkWindow updates its + * geometry or a grab is acquired/released. + * + * If the event does not contain a device field, this function will + * return %NULL. + * + * Returns: (transfer none): a #GdkDevice, or %NULL. + * + * Since: 3.0 + **/ +GdkDevice * +gdk_event_get_source_device (const GdkEvent *event) +{ + GdkEventPrivate *private; + + g_return_val_if_fail (event != NULL, NULL); + + if (!gdk_event_is_allocated (event)) + return NULL; + + private = (GdkEventPrivate *) event; + + if (private->source_device) + return private->source_device; + + /* Fallback to event device */ + return gdk_event_get_device (event); +} + /** * gdk_event_request_motions: * @event: a valid #GdkEvent * * Request more motion notifies if @event is a motion notify hint event. + * * This function should be used instead of gdk_window_get_pointer() to * request further motion notifies, because it also works for extension * events where motion notifies are provided for devices other than the @@ -1065,7 +1643,7 @@ gdk_event_get_device (const GdkEvent *event) * motion events from a %GDK_MOTION_NOTIFY event usually works like this: * * |[ - * { + * { * /* motion_event handler */ * x = motion_event->x; * y = motion_event->y; @@ -1087,11 +1665,61 @@ gdk_event_request_motions (const GdkEventMotion *event) { gdk_device_get_state (event->device, event->window, NULL, NULL); - display = gdk_drawable_get_display (event->window); + display = gdk_window_get_display (event->window); _gdk_display_enable_motion_hints (display, event->device); } } +/** + * gdk_event_triggers_context_menu: + * @event: a #GdkEvent, currently only button events are meaningful values + * + * This function returns whether a #GdkEventButton should trigger a + * context menu, according to platform conventions. The right mouse + * button always triggers context menus. Additionally, if + * gdk_keymap_get_modifier_mask() returns a non-0 mask for + * %GDK_MODIFIER_INTENT_CONTEXT_MENU, then the left mouse button will + * also trigger a context menu if this modifier is pressed. + * + * This function should always be used instead of simply checking for + * event->button == %GDK_BUTTON_SECONDARY. + * + * Returns: %TRUE if the event should trigger a context menu. + * + * Since: 3.4 + **/ +gboolean +gdk_event_triggers_context_menu (const GdkEvent *event) +{ + g_return_val_if_fail (event != NULL, FALSE); + + if (event->type == GDK_BUTTON_PRESS) + { + const GdkEventButton *bevent = (const GdkEventButton *) event; + GdkDisplay *display; + GdkModifierType modifier; + + g_return_val_if_fail (GDK_IS_WINDOW (bevent->window), FALSE); + + if (bevent->button == GDK_BUTTON_SECONDARY && + ! (bevent->state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK))) + return TRUE; + + display = gdk_window_get_display (bevent->window); + + modifier = gdk_keymap_get_modifier_mask (gdk_keymap_get_for_display (display), + GDK_MODIFIER_INTENT_CONTEXT_MENU); + + if (modifier != 0 && + bevent->button == GDK_BUTTON_PRIMARY && + ! (bevent->state & (GDK_BUTTON2_MASK | GDK_BUTTON3_MASK)) && + (bevent->state & modifier)) + return TRUE; + } + + return FALSE; +} + static gboolean gdk_events_get_axis_distances (GdkEvent *event1, GdkEvent *event2, @@ -1125,7 +1753,7 @@ gdk_events_get_axis_distances (GdkEvent *event1, * gdk_events_get_distance: * @event1: first #GdkEvent * @event2: second #GdkEvent - * @distance: return location for the distance + * @distance: (out): return location for the distance * * If both events have X/Y information, the distance between both coordinates * (as in a straight line going from @event1 to @event2) will be returned. @@ -1148,7 +1776,7 @@ gdk_events_get_distance (GdkEvent *event1, * gdk_events_get_angle: * @event1: first #GdkEvent * @event2: second #GdkEvent - * @angle: return location for the relative angle between both events + * @angle: (out): return location for the relative angle between both events * * If both events contain X/Y information, this function will return %TRUE * and return in @angle the relative angle from @event1 to @event2. The rotation @@ -1259,7 +1887,7 @@ gdk_event_set_screen (GdkEvent *event, * to which event->motion.x_root and * event->motion.y_root are relative. * - * Return value: the screen for the event + * Return value: (transfer none): the screen for the event * * Since: 2.2 **/ @@ -1275,7 +1903,34 @@ gdk_event_get_screen (const GdkEvent *event) } if (event->any.window) - return gdk_drawable_get_screen (event->any.window); + return gdk_window_get_screen (event->any.window); + + return NULL; +} + +/** + * gdk_event_get_event_sequence: + * @event: a #GdkEvent + * + * If @event if of type %GDK_TOUCH_BEGIN, %GDK_TOUCH_UPDATE, + * %GDK_TOUCH_END or %GDK_TOUCH_CANCEL, returns the #GdkEventSequence + * to which the event belongs. Otherwise, return %NULL. + * + * Returns: the event sequence that the event belongs to + * + * Since: 3.4 + */ +GdkEventSequence * +gdk_event_get_event_sequence (const GdkEvent *event) +{ + if (!event) + return NULL; + + if (event->type == GDK_TOUCH_BEGIN || + event->type == GDK_TOUCH_UPDATE || + event->type == GDK_TOUCH_END || + event->type == GDK_TOUCH_CANCEL) + return event->touch.sequence; return NULL; } @@ -1319,20 +1974,15 @@ gdk_get_show_events (void) static void gdk_synthesize_click (GdkDisplay *display, - GdkEvent *event, - gint nclicks) + GdkEvent *event, + gint nclicks) { - GdkEvent temp_event; GdkEvent *event_copy; - GList *link; - - g_return_if_fail (event != NULL); - - temp_event = *event; - temp_event.type = (nclicks == 2) ? GDK_2BUTTON_PRESS : GDK_3BUTTON_PRESS; - event_copy = gdk_event_copy (&temp_event); - link = _gdk_event_queue_append (display, event_copy); + event_copy = gdk_event_copy (event); + event_copy->type = (nclicks == 2) ? GDK_2BUTTON_PRESS : GDK_3BUTTON_PRESS; + + _gdk_event_queue_append (display, event_copy); } void @@ -1341,6 +1991,8 @@ _gdk_event_button_generate (GdkDisplay *display, { GdkMultipleClickInfo *info; + g_return_if_fail (event->type == GDK_BUTTON_PRESS); + info = g_hash_table_lookup (display->multiple_click_info, event->button.device); if (G_UNLIKELY (!info)) @@ -1417,7 +2069,7 @@ gdk_synthesize_window_state (GdkWindow *window, temp_event.window_state.type = GDK_WINDOW_STATE; temp_event.window_state.send_event = FALSE; - old = ((GdkWindowObject*) temp_event.window_state.window)->state; + old = temp_event.window_state.window->state; temp_event.window_state.new_window_state = old; temp_event.window_state.new_window_state |= set_flags; @@ -1432,7 +2084,7 @@ gdk_synthesize_window_state (GdkWindow *window, * inconsistent state to the user. */ - ((GdkWindowObject*) window)->state = temp_event.window_state.new_window_state; + window->state = temp_event.window_state.new_window_state; if (temp_event.window_state.changed_mask & GDK_WINDOW_STATE_WITHDRAWN) _gdk_window_update_viewable (window); @@ -1442,11 +2094,11 @@ gdk_synthesize_window_state (GdkWindow *window, * Non-toplevels do use the GDK_WINDOW_STATE_WITHDRAWN flag * internally so we needed to update window->state. */ - switch (((GdkWindowObject*) window)->window_type) + switch (window->window_type) { case GDK_WINDOW_TOPLEVEL: case GDK_WINDOW_TEMP: /* ? */ - gdk_display_put_event (gdk_drawable_get_display (window), &temp_event); + gdk_display_put_event (gdk_window_get_display (window), &temp_event); break; case GDK_WINDOW_FOREIGN: