1 /* GDK - The GIMP Drawing Kit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
22 * file for a list of people on the GTK+ Team. See the ChangeLog
23 * files for a list of changes. These files are distributed with
24 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
28 #include "gdkinternals.h"
30 typedef struct _GdkIOClosure GdkIOClosure;
31 typedef struct _GdkEventPrivate GdkEventPrivate;
35 /* Following flag is set for events on the event queue during
36 * translation and cleared afterwards.
38 GDK_EVENT_PENDING = 1 << 0
43 GdkInputFunction function;
44 GdkInputCondition condition;
45 GdkDestroyNotify notify;
49 struct _GdkEventPrivate
56 * Private function declarations
59 GdkFilterReturn gdk_wm_protocols_filter (GdkXEvent *xev,
63 /* Private variable declarations
66 static guint32 button_click_time[2] = { 0, 0}; /* The last 2 button click times. Used
67 * to determine if the latest button click
68 * is part of a double or triple click.
70 static GdkWindow *button_window[2] = { NULL, NULL}; /* The last 2 windows to receive button presses.
71 * Also used to determine if the latest button
72 * click is part of a double or triple click.
74 static guint button_number[2] = { -1, -1 }; /* The last 2 buttons to be pressed.
76 GdkEventFunc gdk_event_func = NULL; /* Callback for events */
77 gpointer gdk_event_data = NULL;
78 GDestroyNotify gdk_event_notify = NULL;
80 GPollFD event_poll_fd;
82 static guint double_click_time = 250;
83 #define TRIPLE_CLICK_TIME (2*double_click_time)
84 #define DOUBLE_CLICK_DIST 5
85 #define TRIPLE_CLICK_DIST 5
87 /*********************************************
88 * Functions for maintaining the event queue *
89 *********************************************/
91 /*************************************************************
92 * gdk_event_queue_find_first:
93 * Find the first event on the queue that is not still
98 * Pointer to the list node for that event, or NULL
99 *************************************************************/
102 gdk_event_queue_find_first (void)
104 GList *tmp_list = gdk_queued_events;
108 GdkEventPrivate *event = tmp_list->data;
109 if (!(event->flags & GDK_EVENT_PENDING))
112 tmp_list = g_list_next (tmp_list);
118 /*************************************************************
119 * gdk_event_queue_remove_link:
120 * Remove a specified list node from the event queue.
122 * node: Node to remove.
124 *************************************************************/
127 gdk_event_queue_remove_link (GList *node)
130 node->prev->next = node->next;
132 gdk_queued_events = node->next;
135 node->next->prev = node->prev;
137 gdk_queued_tail = node->prev;
140 /*************************************************************
141 * gdk_event_queue_append:
142 * Append an event onto the tail of the event queue.
144 * event: Event to append.
146 *************************************************************/
149 gdk_event_queue_append (GdkEvent *event)
151 gdk_queued_tail = g_list_append (gdk_queued_tail, event);
153 if (!gdk_queued_events)
154 gdk_queued_events = gdk_queued_tail;
156 gdk_queued_tail = gdk_queued_tail->next;
159 /*************************************************************
160 * gdk_event_handler_set:
163 * func: Callback function to be called for each event.
164 * data: Data supplied to the function
165 * notify: function called when function is no longer needed
168 *************************************************************/
171 gdk_event_handler_set (GdkEventFunc func,
173 GDestroyNotify notify)
175 if (gdk_event_notify)
176 (*gdk_event_notify) (gdk_event_data);
178 gdk_event_func = func;
179 gdk_event_data = data;
180 gdk_event_notify = notify;
184 *--------------------------------------------------------------
187 * Gets the next event.
192 * If an event is waiting that we care about, returns
193 * a pointer to that event, to be freed with gdk_event_free.
194 * Otherwise, returns NULL.
198 *--------------------------------------------------------------
206 return gdk_event_unqueue ();
210 *--------------------------------------------------------------
213 * Gets the next event.
218 * If an event is waiting that we care about, returns
219 * a copy of that event, but does not remove it from
220 * the queue. The pointer is to be freed with gdk_event_free.
221 * Otherwise, returns NULL.
225 *--------------------------------------------------------------
229 gdk_event_peek (void)
233 tmp_list = gdk_event_queue_find_first ();
236 return gdk_event_copy (tmp_list->data);
242 gdk_event_put (GdkEvent *event)
246 g_return_if_fail (event != NULL);
248 new_event = gdk_event_copy (event);
250 gdk_event_queue_append (new_event);
254 *--------------------------------------------------------------
257 * Copy a event structure into new storage.
260 * "event" is the event struct to copy.
263 * A new event structure. Free it with gdk_event_free.
266 * The reference count of the window in the event is increased.
268 *--------------------------------------------------------------
271 static GMemChunk *event_chunk = NULL;
276 GdkEventPrivate *new_event;
278 if (event_chunk == NULL)
279 event_chunk = g_mem_chunk_new ("events",
280 sizeof (GdkEventPrivate),
284 new_event = g_chunk_new (GdkEventPrivate, event_chunk);
285 new_event->flags = 0;
287 return (GdkEvent*) new_event;
291 gdk_event_copy (GdkEvent *event)
295 g_return_val_if_fail (event != NULL, NULL);
297 new_event = gdk_event_new ();
300 if (new_event->any.window)
301 gdk_window_ref (new_event->any.window);
303 switch (event->any.type)
306 case GDK_KEY_RELEASE:
307 new_event->key.string = g_strdup (event->key.string);
310 case GDK_ENTER_NOTIFY:
311 case GDK_LEAVE_NOTIFY:
312 if (event->crossing.subwindow != NULL)
313 gdk_window_ref (event->crossing.subwindow);
318 case GDK_DRAG_MOTION:
319 case GDK_DRAG_STATUS:
321 case GDK_DROP_FINISHED:
322 gdk_drag_context_ref (event->dnd.context);
326 if (event->expose.region)
327 new_event->expose.region = gdk_region_copy (event->expose.region);
331 new_event->setting.name = g_strdup (new_event->setting.name);
342 *--------------------------------------------------------------
345 * Free a event structure obtained from gdk_event_copy. Do not use
346 * with other event structures.
349 * "event" is the event struct to free.
354 * The reference count of the window in the event is decreased and
355 * might be freed, too.
357 *-------------------------------------------------------------- */
360 gdk_event_free (GdkEvent *event)
362 g_return_if_fail (event != NULL);
364 g_assert (event_chunk != NULL); /* paranoid */
366 if (event->any.window)
367 gdk_window_unref (event->any.window);
369 switch (event->any.type)
372 case GDK_KEY_RELEASE:
373 g_free (event->key.string);
376 case GDK_ENTER_NOTIFY:
377 case GDK_LEAVE_NOTIFY:
378 if (event->crossing.subwindow != NULL)
379 gdk_window_unref (event->crossing.subwindow);
384 case GDK_DRAG_MOTION:
385 case GDK_DRAG_STATUS:
387 case GDK_DROP_FINISHED:
388 gdk_drag_context_unref (event->dnd.context);
391 case GDK_BUTTON_PRESS:
392 case GDK_BUTTON_RELEASE:
393 if (event->button.axes)
394 g_free (event->button.axes);
398 if (event->expose.region)
399 gdk_region_destroy (event->expose.region);
402 case GDK_MOTION_NOTIFY:
403 if (event->motion.axes)
404 g_free (event->motion.axes);
408 g_free (event->setting.name);
415 g_mem_chunk_free (event_chunk, event);
419 * gdk_event_get_time:
420 * @event: a #GdkEvent
422 * Returns the time stamp from @event, if there is one; otherwise
423 * returns #GDK_CURRENT_TIME. If @event is %NULL, returns #GDK_CURRENT_TIME.
425 * Return value: time stamp field from @event
428 gdk_event_get_time (GdkEvent *event)
433 case GDK_MOTION_NOTIFY:
434 return event->motion.time;
435 case GDK_BUTTON_PRESS:
436 case GDK_2BUTTON_PRESS:
437 case GDK_3BUTTON_PRESS:
438 case GDK_BUTTON_RELEASE:
439 return event->button.time;
441 return event->scroll.time;
443 case GDK_KEY_RELEASE:
444 return event->key.time;
445 case GDK_ENTER_NOTIFY:
446 case GDK_LEAVE_NOTIFY:
447 return event->crossing.time;
448 case GDK_PROPERTY_NOTIFY:
449 return event->property.time;
450 case GDK_SELECTION_CLEAR:
451 case GDK_SELECTION_REQUEST:
452 case GDK_SELECTION_NOTIFY:
453 return event->selection.time;
454 case GDK_PROXIMITY_IN:
455 case GDK_PROXIMITY_OUT:
456 return event->proximity.time;
459 case GDK_DRAG_MOTION:
460 case GDK_DRAG_STATUS:
462 case GDK_DROP_FINISHED:
463 return event->dnd.time;
464 case GDK_CLIENT_EVENT:
465 case GDK_VISIBILITY_NOTIFY:
468 case GDK_FOCUS_CHANGE:
475 case GDK_WINDOW_STATE:
477 /* return current time */
481 return GDK_CURRENT_TIME;
485 * gdk_event_get_state:
486 * @event: a #GdkEvent or NULL
487 * @state: return location for state
489 * If the event contains a "state" field, puts that field in @state. Otherwise
490 * stores an empty state (0). Returns %TRUE if there was a state field
491 * in the event. @event may be %NULL, in which case it's treated
492 * as if the event had no state field.
494 * Return value: %TRUE if there was a state field in the event
497 gdk_event_get_state (GdkEvent *event,
498 GdkModifierType *state)
500 g_return_val_if_fail (state != NULL, FALSE);
505 case GDK_MOTION_NOTIFY:
506 *state = event->motion.state;
508 case GDK_BUTTON_PRESS:
509 case GDK_2BUTTON_PRESS:
510 case GDK_3BUTTON_PRESS:
511 case GDK_BUTTON_RELEASE:
512 *state = event->button.state;
515 *state = event->scroll.state;
518 case GDK_KEY_RELEASE:
519 *state = event->key.state;
521 case GDK_ENTER_NOTIFY:
522 case GDK_LEAVE_NOTIFY:
523 *state = event->crossing.state;
525 case GDK_PROPERTY_NOTIFY:
526 *state = event->property.state;
528 case GDK_VISIBILITY_NOTIFY:
529 *state = event->visibility.state;
531 case GDK_CLIENT_EVENT:
534 case GDK_FOCUS_CHANGE:
535 case GDK_SELECTION_CLEAR:
536 case GDK_SELECTION_REQUEST:
537 case GDK_SELECTION_NOTIFY:
538 case GDK_PROXIMITY_IN:
539 case GDK_PROXIMITY_OUT:
542 case GDK_DRAG_MOTION:
543 case GDK_DRAG_STATUS:
545 case GDK_DROP_FINISHED:
552 case GDK_WINDOW_STATE:
563 * gdk_event_get_axis:
564 * @event: a #GdkEvent
565 * @axis_use: the axis use to look for
566 * @value: location to store the value found
568 * Extract the axis value for a particular axis use from
569 * an event structure.
571 * Return value: %TRUE if the specified axis was found, otherwise %FALSE
574 gdk_event_get_axis (GdkEvent *event,
581 g_return_val_if_fail (event != NULL, FALSE);
583 if (axis_use == GDK_AXIS_X || axis_use == GDK_AXIS_Y)
589 case GDK_MOTION_NOTIFY:
597 case GDK_BUTTON_PRESS:
598 case GDK_BUTTON_RELEASE:
602 case GDK_ENTER_NOTIFY:
603 case GDK_LEAVE_NOTIFY:
604 x = event->crossing.x;
605 y = event->crossing.y;
612 if (axis_use == GDK_AXIS_X && value)
614 if (axis_use == GDK_AXIS_Y && value)
619 else if (event->type == GDK_BUTTON_PRESS ||
620 event->type == GDK_BUTTON_RELEASE)
622 device = event->button.device;
623 axes = event->button.axes;
625 else if (event->type == GDK_MOTION_NOTIFY)
627 device = event->motion.device;
628 axes = event->motion.axes;
633 return gdk_device_get_axis (device, axes, axis_use, value);
637 *--------------------------------------------------------------
638 * gdk_set_show_events
640 * Turns on/off the showing of events.
643 * "show_events" is a boolean describing whether or
644 * not to show the events gdk receives.
649 * When "show_events" is TRUE, calls to "gdk_event_get"
650 * will output debugging informatin regarding the event
651 * received to stdout.
653 *--------------------------------------------------------------
657 gdk_set_show_events (gboolean show_events)
660 gdk_debug_flags |= GDK_DEBUG_EVENTS;
662 gdk_debug_flags &= ~GDK_DEBUG_EVENTS;
666 gdk_get_show_events (void)
668 return (gdk_debug_flags & GDK_DEBUG_EVENTS) != 0;
672 gdk_io_destroy (gpointer data)
674 GdkIOClosure *closure = data;
677 closure->notify (closure->data);
682 /* What do we do with G_IO_NVAL?
684 #define READ_CONDITION (G_IO_IN | G_IO_HUP | G_IO_ERR)
685 #define WRITE_CONDITION (G_IO_OUT | G_IO_ERR)
686 #define EXCEPTION_CONDITION (G_IO_PRI)
689 gdk_io_invoke (GIOChannel *source,
690 GIOCondition condition,
693 GdkIOClosure *closure = data;
694 GdkInputCondition gdk_cond = 0;
696 if (condition & READ_CONDITION)
697 gdk_cond |= GDK_INPUT_READ;
698 if (condition & WRITE_CONDITION)
699 gdk_cond |= GDK_INPUT_WRITE;
700 if (condition & EXCEPTION_CONDITION)
701 gdk_cond |= GDK_INPUT_EXCEPTION;
703 if (closure->condition & gdk_cond)
704 closure->function (closure->data, g_io_channel_unix_get_fd (source), gdk_cond);
710 gdk_input_add_full (gint source,
711 GdkInputCondition condition,
712 GdkInputFunction function,
714 GdkDestroyNotify destroy)
717 GdkIOClosure *closure = g_new (GdkIOClosure, 1);
719 GIOCondition cond = 0;
721 closure->function = function;
722 closure->condition = condition;
723 closure->notify = destroy;
724 closure->data = data;
726 if (condition & GDK_INPUT_READ)
727 cond |= READ_CONDITION;
728 if (condition & GDK_INPUT_WRITE)
729 cond |= WRITE_CONDITION;
730 if (condition & GDK_INPUT_EXCEPTION)
731 cond |= EXCEPTION_CONDITION;
733 channel = g_io_channel_unix_new (source);
734 result = g_io_add_watch_full (channel, G_PRIORITY_DEFAULT, cond,
736 closure, gdk_io_destroy);
737 g_io_channel_unref (channel);
743 gdk_input_add (gint source,
744 GdkInputCondition condition,
745 GdkInputFunction function,
748 return gdk_input_add_full (source, condition, function, data, NULL);
752 gdk_input_remove (gint tag)
754 g_source_remove (tag);
758 gdk_event_unqueue (void)
760 GdkEvent *event = NULL;
763 tmp_list = gdk_event_queue_find_first ();
767 event = tmp_list->data;
768 gdk_event_queue_remove_link (tmp_list);
769 g_list_free_1 (tmp_list);
776 gdk_synthesize_click (GdkEvent *event,
781 g_return_if_fail (event != NULL);
784 temp_event.type = (nclicks == 2) ? GDK_2BUTTON_PRESS : GDK_3BUTTON_PRESS;
786 gdk_event_put (&temp_event);
790 gdk_event_button_generate (GdkEvent *event)
792 if ((event->button.time < (button_click_time[1] + TRIPLE_CLICK_TIME)) &&
793 (event->button.window == button_window[1]) &&
794 (event->button.button == button_number[1]))
796 gdk_synthesize_click (event, 3);
798 button_click_time[1] = 0;
799 button_click_time[0] = 0;
800 button_window[1] = NULL;
801 button_window[0] = 0;
802 button_number[1] = -1;
803 button_number[0] = -1;
805 else if ((event->button.time < (button_click_time[0] + double_click_time)) &&
806 (event->button.window == button_window[0]) &&
807 (event->button.button == button_number[0]))
809 gdk_synthesize_click (event, 2);
811 button_click_time[1] = button_click_time[0];
812 button_click_time[0] = event->button.time;
813 button_window[1] = button_window[0];
814 button_window[0] = event->button.window;
815 button_number[1] = button_number[0];
816 button_number[0] = event->button.button;
820 button_click_time[1] = 0;
821 button_click_time[0] = event->button.time;
822 button_window[1] = NULL;
823 button_window[0] = event->button.window;
824 button_number[1] = -1;
825 button_number[0] = event->button.button;
831 gdk_synthesize_window_state (GdkWindow *window,
832 GdkWindowState unset_flags,
833 GdkWindowState set_flags)
835 GdkEventWindowState temp_event;
838 g_return_if_fail (window != NULL);
840 temp_event.window = window;
841 temp_event.type = GDK_WINDOW_STATE;
842 temp_event.send_event = FALSE;
844 old = ((GdkWindowObject*) temp_event.window)->state;
846 temp_event.changed_mask = (unset_flags | set_flags) ^ old;
847 temp_event.new_window_state = old;
848 temp_event.new_window_state |= set_flags;
849 temp_event.new_window_state &= ~unset_flags;
851 if (temp_event.new_window_state == old)
852 return; /* No actual work to do, nothing changed. */
854 /* Actually update the field in GdkWindow, this is sort of an odd
855 * place to do it, but seems like the safest since it ensures we expose no
856 * inconsistent state to the user.
859 ((GdkWindowObject*) window)->state = temp_event.new_window_state;
861 /* We only really send the event to toplevels, since
862 * all the window states don't apply to non-toplevels.
863 * Non-toplevels do use the GDK_WINDOW_STATE_WITHDRAWN flag
864 * internally so we needed to update window->state.
866 switch (((GdkWindowObject*) window)->window_type)
868 case GDK_WINDOW_TOPLEVEL:
869 case GDK_WINDOW_DIALOG:
870 case GDK_WINDOW_TEMP: /* ? */
871 gdk_event_put ((GdkEvent*) &temp_event);
874 case GDK_WINDOW_FOREIGN:
875 case GDK_WINDOW_ROOT:
876 case GDK_WINDOW_CHILD:
882 gdk_set_double_click_time (guint msec)
884 double_click_time = msec;
888 gdk_event_get_type (void)
890 static GType our_type = 0;
893 our_type = g_boxed_type_register_static ("GdkEvent",
895 (GBoxedCopyFunc)gdk_event_copy,
896 (GBoxedFreeFunc)gdk_event_free,