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
55 /* Private variable declarations
58 GdkEventFunc _gdk_event_func = NULL; /* Callback for events */
59 gpointer _gdk_event_data = NULL;
60 GDestroyNotify _gdk_event_notify = NULL;
62 #define TRIPLE_CLICK_TIME(display) (2*display->double_click_time)
63 #define DOUBLE_CLICK_DIST 5
64 #define TRIPLE_CLICK_DIST 5
66 /*********************************************
67 * Functions for maintaining the event queue *
68 *********************************************/
71 * _gdk_event_queue_find_first:
72 * @display: a #GdkDisplay
74 * Find the first event on the queue that is not still
77 * Return value: Pointer to the list node for that event, or NULL.
80 _gdk_event_queue_find_first (GdkDisplay *display)
82 GList *tmp_list = display->queued_events;
86 GdkEventPrivate *event = tmp_list->data;
87 if (!(event->flags & GDK_EVENT_PENDING))
90 tmp_list = g_list_next (tmp_list);
97 * _gdk_event_queue_append:
98 * @display: a #GdkDisplay
99 * @event: Event to append.
101 * Appends an event onto the tail of the event queue.
103 * Returns: the newly appended list node.
106 _gdk_event_queue_append (GdkDisplay *display,
109 display->queued_tail = g_list_append (display->queued_tail, event);
111 if (!display->queued_events)
112 display->queued_events = display->queued_tail;
114 display->queued_tail = display->queued_tail->next;
116 return display->queued_tail;
120 * _gdk_event_queue_remove_link:
121 * @display: a #GdkDisplay
122 * @node: node to remove
124 * Removes a specified list node from the event queue.
127 _gdk_event_queue_remove_link (GdkDisplay *display,
131 node->prev->next = node->next;
133 display->queued_events = node->next;
136 node->next->prev = node->prev;
138 display->queued_tail = node->prev;
142 * _gdk_event_unqueue:
143 * @display: a #GdkDisplay
145 * Removes and returns the first event from the event
146 * queue that is not still being filled in.
148 * Return value: the event, or %NULL. Ownership is transferred
152 _gdk_event_unqueue (GdkDisplay *display)
154 GdkEvent *event = NULL;
157 tmp_list = _gdk_event_queue_find_first (display);
161 event = tmp_list->data;
162 _gdk_event_queue_remove_link (display, tmp_list);
163 g_list_free_1 (tmp_list);
170 * gdk_event_handler_set:
171 * @func: the function to call to handle events from GDK.
172 * @data: user data to pass to the function.
173 * @notify: the function to call when the handler function is removed, i.e. when
174 * gdk_event_handler_set() is called with another event handler.
176 * Sets the function to call to handle all events from GDK.
178 * Note that GTK+ uses this to install its own event handler, so it is
179 * usually not useful for GTK+ applications. (Although an application
180 * can call this function then call gtk_main_do_event() to pass
184 gdk_event_handler_set (GdkEventFunc func,
186 GDestroyNotify notify)
188 if (_gdk_event_notify)
189 (*_gdk_event_notify) (_gdk_event_data);
191 _gdk_event_func = func;
192 _gdk_event_data = data;
193 _gdk_event_notify = notify;
199 * Checks all open displays for a #GdkEvent to process,to be processed
200 * on, fetching events from the windowing system if necessary.
201 * See gdk_display_get_event().
203 * Return value: the next #GdkEvent to be processed, or %NULL if no events
204 * are pending. The returned #GdkEvent should be freed with gdk_event_free().
211 for (tmp_list = _gdk_displays; tmp_list; tmp_list = tmp_list->next)
213 GdkEvent *event = gdk_display_get_event (tmp_list->data);
224 * If there is an event waiting in the event queue of some open
225 * display, returns a copy of it. See gdk_display_peek_event().
227 * Return value: a copy of the first #GdkEvent on some event queue, or %NULL if no
228 * events are in any queues. The returned #GdkEvent should be freed with
232 gdk_event_peek (void)
236 for (tmp_list = _gdk_displays; tmp_list; tmp_list = tmp_list->next)
238 GdkEvent *event = gdk_display_peek_event (tmp_list->data);
248 * @event: a #GdkEvent.
250 * Appends a copy of the given event onto the front of the event
251 * queue for event->any.window's display, or the default event
252 * queue if event->any.window is %NULL. See gdk_display_put_event().
255 gdk_event_put (GdkEvent *event)
259 g_return_if_fail (event != NULL);
261 if (event->any.window)
262 display = gdk_drawable_get_display (event->any.window);
266 g_message ("Falling back to default display for gdk_event_put()"));
267 display = gdk_display_get_default ();
270 gdk_display_put_event (display, event);
273 static GMemChunk *event_chunk = NULL;
276 _gdk_event_new (void)
278 GdkEventPrivate *new_event;
280 if (event_chunk == NULL)
281 event_chunk = g_mem_chunk_new ("events",
282 sizeof (GdkEventPrivate),
286 new_event = g_chunk_new (GdkEventPrivate, event_chunk);
287 new_event->flags = 0;
289 return (GdkEvent*) new_event;
294 * @event: a #GdkEvent
296 * Copies a #GdkEvent, copying or incrementing the reference count of the
297 * resources associated with it (e.g. #GdkWindow's and strings).
299 * Return value: a copy of @event. The returned #GdkEvent should be freed with
303 gdk_event_copy (GdkEvent *event)
307 g_return_val_if_fail (event != NULL, NULL);
309 new_event = _gdk_event_new ();
312 if (new_event->any.window)
313 gdk_window_ref (new_event->any.window);
315 switch (event->any.type)
318 case GDK_KEY_RELEASE:
319 new_event->key.string = g_strdup (event->key.string);
322 case GDK_ENTER_NOTIFY:
323 case GDK_LEAVE_NOTIFY:
324 if (event->crossing.subwindow != NULL)
325 gdk_window_ref (event->crossing.subwindow);
330 case GDK_DRAG_MOTION:
331 case GDK_DRAG_STATUS:
333 case GDK_DROP_FINISHED:
334 gdk_drag_context_ref (event->dnd.context);
338 if (event->expose.region)
339 new_event->expose.region = gdk_region_copy (event->expose.region);
343 new_event->setting.name = g_strdup (new_event->setting.name);
355 * @event: a #GdkEvent.
357 * Frees a #GdkEvent, freeing or decrementing any resources associated with it.
358 * Note that this function should only be called with events returned from
359 * functions such as gdk_event_peek(), gdk_event_get(),
360 * gdk_event_get_graphics_expose() and gdk_event_copy().
363 gdk_event_free (GdkEvent *event)
365 g_return_if_fail (event != NULL);
367 g_assert (event_chunk != NULL); /* paranoid */
369 if (event->any.window)
370 gdk_window_unref (event->any.window);
372 switch (event->any.type)
375 case GDK_KEY_RELEASE:
376 g_free (event->key.string);
379 case GDK_ENTER_NOTIFY:
380 case GDK_LEAVE_NOTIFY:
381 if (event->crossing.subwindow != NULL)
382 gdk_window_unref (event->crossing.subwindow);
387 case GDK_DRAG_MOTION:
388 case GDK_DRAG_STATUS:
390 case GDK_DROP_FINISHED:
391 gdk_drag_context_unref (event->dnd.context);
394 case GDK_BUTTON_PRESS:
395 case GDK_BUTTON_RELEASE:
396 if (event->button.axes)
397 g_free (event->button.axes);
401 if (event->expose.region)
402 gdk_region_destroy (event->expose.region);
405 case GDK_MOTION_NOTIFY:
406 if (event->motion.axes)
407 g_free (event->motion.axes);
411 g_free (event->setting.name);
418 g_mem_chunk_free (event_chunk, event);
422 * gdk_event_get_time:
423 * @event: a #GdkEvent
425 * Returns the time stamp from @event, if there is one; otherwise
426 * returns #GDK_CURRENT_TIME. If @event is %NULL, returns #GDK_CURRENT_TIME.
428 * Return value: time stamp field from @event
431 gdk_event_get_time (GdkEvent *event)
436 case GDK_MOTION_NOTIFY:
437 return event->motion.time;
438 case GDK_BUTTON_PRESS:
439 case GDK_2BUTTON_PRESS:
440 case GDK_3BUTTON_PRESS:
441 case GDK_BUTTON_RELEASE:
442 return event->button.time;
444 return event->scroll.time;
446 case GDK_KEY_RELEASE:
447 return event->key.time;
448 case GDK_ENTER_NOTIFY:
449 case GDK_LEAVE_NOTIFY:
450 return event->crossing.time;
451 case GDK_PROPERTY_NOTIFY:
452 return event->property.time;
453 case GDK_SELECTION_CLEAR:
454 case GDK_SELECTION_REQUEST:
455 case GDK_SELECTION_NOTIFY:
456 return event->selection.time;
457 case GDK_PROXIMITY_IN:
458 case GDK_PROXIMITY_OUT:
459 return event->proximity.time;
462 case GDK_DRAG_MOTION:
463 case GDK_DRAG_STATUS:
465 case GDK_DROP_FINISHED:
466 return event->dnd.time;
467 case GDK_CLIENT_EVENT:
468 case GDK_VISIBILITY_NOTIFY:
471 case GDK_FOCUS_CHANGE:
478 case GDK_WINDOW_STATE:
480 /* return current time */
484 return GDK_CURRENT_TIME;
488 * gdk_event_get_state:
489 * @event: a #GdkEvent or NULL
490 * @state: return location for state
492 * If the event contains a "state" field, puts that field in @state. Otherwise
493 * stores an empty state (0). Returns %TRUE if there was a state field
494 * in the event. @event may be %NULL, in which case it's treated
495 * as if the event had no state field.
497 * Return value: %TRUE if there was a state field in the event
500 gdk_event_get_state (GdkEvent *event,
501 GdkModifierType *state)
503 g_return_val_if_fail (state != NULL, FALSE);
508 case GDK_MOTION_NOTIFY:
509 *state = event->motion.state;
511 case GDK_BUTTON_PRESS:
512 case GDK_2BUTTON_PRESS:
513 case GDK_3BUTTON_PRESS:
514 case GDK_BUTTON_RELEASE:
515 *state = event->button.state;
518 *state = event->scroll.state;
521 case GDK_KEY_RELEASE:
522 *state = event->key.state;
524 case GDK_ENTER_NOTIFY:
525 case GDK_LEAVE_NOTIFY:
526 *state = event->crossing.state;
528 case GDK_PROPERTY_NOTIFY:
529 *state = event->property.state;
531 case GDK_VISIBILITY_NOTIFY:
532 case GDK_CLIENT_EVENT:
535 case GDK_FOCUS_CHANGE:
536 case GDK_SELECTION_CLEAR:
537 case GDK_SELECTION_REQUEST:
538 case GDK_SELECTION_NOTIFY:
539 case GDK_PROXIMITY_IN:
540 case GDK_PROXIMITY_OUT:
543 case GDK_DRAG_MOTION:
544 case GDK_DRAG_STATUS:
546 case GDK_DROP_FINISHED:
553 case GDK_WINDOW_STATE:
564 * gdk_event_get_coords:
565 * @event: a #GdkEvent
566 * @x_win: location to put event window x coordinate
567 * @y_win: location to put event window y coordinate
569 * Extract the event window relative x/y coordinates from an event.
571 * Return value: %TRUE if the event delivered event window coordinates
574 gdk_event_get_coords (GdkEvent *event,
578 gdouble x = 0, y = 0;
579 gboolean fetched = TRUE;
581 g_return_val_if_fail (event != NULL, FALSE);
586 x = event->configure.x;
587 y = event->configure.y;
589 case GDK_ENTER_NOTIFY:
590 case GDK_LEAVE_NOTIFY:
591 x = event->crossing.x;
592 y = event->crossing.y;
598 case GDK_BUTTON_PRESS:
599 case GDK_2BUTTON_PRESS:
600 case GDK_3BUTTON_PRESS:
601 case GDK_BUTTON_RELEASE:
605 case GDK_MOTION_NOTIFY:
623 * gdk_event_get_root_coords:
624 * @event: a #GdkEvent
625 * @x_root: location to put root window x coordinate
626 * @y_root: location to put root window y coordinate
628 * Extract the root window relative x/y coordinates from an event.
630 * Return value: %TRUE if the event delivered root window coordinates
633 gdk_event_get_root_coords (GdkEvent *event,
637 gdouble x = 0, y = 0;
638 gboolean fetched = TRUE;
640 g_return_val_if_fail (event != NULL, FALSE);
644 case GDK_MOTION_NOTIFY:
645 x = event->motion.x_root;
646 y = event->motion.y_root;
648 case GDK_BUTTON_PRESS:
649 case GDK_2BUTTON_PRESS:
650 case GDK_3BUTTON_PRESS:
651 case GDK_BUTTON_RELEASE:
652 x = event->button.x_root;
653 y = event->button.y_root;
655 case GDK_ENTER_NOTIFY:
656 case GDK_LEAVE_NOTIFY:
657 x = event->crossing.x_root;
658 y = event->crossing.y_root;
662 case GDK_DRAG_MOTION:
663 case GDK_DRAG_STATUS:
665 case GDK_DROP_FINISHED:
666 x = event->dnd.x_root;
667 y = event->dnd.y_root;
683 * gdk_event_get_axis:
684 * @event: a #GdkEvent
685 * @axis_use: the axis use to look for
686 * @value: location to store the value found
688 * Extract the axis value for a particular axis use from
689 * an event structure.
691 * Return value: %TRUE if the specified axis was found, otherwise %FALSE
694 gdk_event_get_axis (GdkEvent *event,
701 g_return_val_if_fail (event != NULL, FALSE);
703 if (axis_use == GDK_AXIS_X || axis_use == GDK_AXIS_Y)
709 case GDK_MOTION_NOTIFY:
717 case GDK_BUTTON_PRESS:
718 case GDK_BUTTON_RELEASE:
722 case GDK_ENTER_NOTIFY:
723 case GDK_LEAVE_NOTIFY:
724 x = event->crossing.x;
725 y = event->crossing.y;
732 if (axis_use == GDK_AXIS_X && value)
734 if (axis_use == GDK_AXIS_Y && value)
739 else if (event->type == GDK_BUTTON_PRESS ||
740 event->type == GDK_BUTTON_RELEASE)
742 device = event->button.device;
743 axes = event->button.axes;
745 else if (event->type == GDK_MOTION_NOTIFY)
747 device = event->motion.device;
748 axes = event->motion.axes;
753 return gdk_device_get_axis (device, axes, axis_use, value);
757 * gdk_set_show_events:
758 * @show_events: %TRUE to output event debugging information.
760 * Sets whether a trace of received events is output.
761 * Note that GTK+ must be compiled with debugging (that is,
762 * configured using the <option>--enable-debug</option> option)
763 * to use this option.
766 gdk_set_show_events (gboolean show_events)
769 _gdk_debug_flags |= GDK_DEBUG_EVENTS;
771 _gdk_debug_flags &= ~GDK_DEBUG_EVENTS;
775 * gdk_get_show_events:
777 * Gets whether event debugging output is enabled.
779 * Return value: %TRUE if event debugging output is enabled.
782 gdk_get_show_events (void)
784 return (_gdk_debug_flags & GDK_DEBUG_EVENTS) != 0;
788 gdk_io_destroy (gpointer data)
790 GdkIOClosure *closure = data;
793 closure->notify (closure->data);
798 /* What do we do with G_IO_NVAL?
800 #define READ_CONDITION (G_IO_IN | G_IO_HUP | G_IO_ERR)
801 #define WRITE_CONDITION (G_IO_OUT | G_IO_ERR)
802 #define EXCEPTION_CONDITION (G_IO_PRI)
805 gdk_io_invoke (GIOChannel *source,
806 GIOCondition condition,
809 GdkIOClosure *closure = data;
810 GdkInputCondition gdk_cond = 0;
812 if (condition & READ_CONDITION)
813 gdk_cond |= GDK_INPUT_READ;
814 if (condition & WRITE_CONDITION)
815 gdk_cond |= GDK_INPUT_WRITE;
816 if (condition & EXCEPTION_CONDITION)
817 gdk_cond |= GDK_INPUT_EXCEPTION;
819 if (closure->condition & gdk_cond)
820 closure->function (closure->data, g_io_channel_unix_get_fd (source), gdk_cond);
826 gdk_input_add_full (gint source,
827 GdkInputCondition condition,
828 GdkInputFunction function,
830 GdkDestroyNotify destroy)
833 GdkIOClosure *closure = g_new (GdkIOClosure, 1);
835 GIOCondition cond = 0;
837 closure->function = function;
838 closure->condition = condition;
839 closure->notify = destroy;
840 closure->data = data;
842 if (condition & GDK_INPUT_READ)
843 cond |= READ_CONDITION;
844 if (condition & GDK_INPUT_WRITE)
845 cond |= WRITE_CONDITION;
846 if (condition & GDK_INPUT_EXCEPTION)
847 cond |= EXCEPTION_CONDITION;
849 channel = g_io_channel_unix_new (source);
850 result = g_io_add_watch_full (channel, G_PRIORITY_DEFAULT, cond,
852 closure, gdk_io_destroy);
853 g_io_channel_unref (channel);
859 gdk_input_add (gint source,
860 GdkInputCondition condition,
861 GdkInputFunction function,
864 return gdk_input_add_full (source, condition, function, data, NULL);
868 gdk_input_remove (gint tag)
870 g_source_remove (tag);
874 gdk_synthesize_click (GdkDisplay *display,
880 g_return_if_fail (event != NULL);
883 temp_event.type = (nclicks == 2) ? GDK_2BUTTON_PRESS : GDK_3BUTTON_PRESS;
885 gdk_display_put_event (display, &temp_event);
889 _gdk_event_button_generate (GdkDisplay *display,
892 if ((event->button.time < (display->button_click_time[1] + TRIPLE_CLICK_TIME (display))) &&
893 (event->button.window == display->button_window[1]) &&
894 (event->button.button == display->button_number[1]))
896 gdk_synthesize_click (display, event, 3);
898 display->button_click_time[1] = 0;
899 display->button_click_time[0] = 0;
900 display->button_window[1] = NULL;
901 display->button_window[0] = 0;
902 display->button_number[1] = -1;
903 display->button_number[0] = -1;
905 else if ((event->button.time < (display->button_click_time[0] + display->double_click_time)) &&
906 (event->button.window == display->button_window[0]) &&
907 (event->button.button == display->button_number[0]))
909 gdk_synthesize_click (display, event, 2);
911 display->button_click_time[1] = display->button_click_time[0];
912 display->button_click_time[0] = event->button.time;
913 display->button_window[1] = display->button_window[0];
914 display->button_window[0] = event->button.window;
915 display->button_number[1] = display->button_number[0];
916 display->button_number[0] = event->button.button;
920 display->button_click_time[1] = 0;
921 display->button_click_time[0] = event->button.time;
922 display->button_window[1] = NULL;
923 display->button_window[0] = event->button.window;
924 display->button_number[1] = -1;
925 display->button_number[0] = event->button.button;
930 gdk_synthesize_window_state (GdkWindow *window,
931 GdkWindowState unset_flags,
932 GdkWindowState set_flags)
937 g_return_if_fail (window != NULL);
939 temp_event.window_state.window = window;
940 temp_event.window_state.type = GDK_WINDOW_STATE;
941 temp_event.window_state.send_event = FALSE;
943 old = ((GdkWindowObject*) temp_event.window_state.window)->state;
945 temp_event.window_state.changed_mask = (unset_flags | set_flags) ^ old;
946 temp_event.window_state.new_window_state = old;
947 temp_event.window_state.new_window_state |= set_flags;
948 temp_event.window_state.new_window_state &= ~unset_flags;
950 if (temp_event.window_state.new_window_state == old)
951 return; /* No actual work to do, nothing changed. */
953 /* Actually update the field in GdkWindow, this is sort of an odd
954 * place to do it, but seems like the safest since it ensures we expose no
955 * inconsistent state to the user.
958 ((GdkWindowObject*) window)->state = temp_event.window_state.new_window_state;
960 /* We only really send the event to toplevels, since
961 * all the window states don't apply to non-toplevels.
962 * Non-toplevels do use the GDK_WINDOW_STATE_WITHDRAWN flag
963 * internally so we needed to update window->state.
965 switch (((GdkWindowObject*) window)->window_type)
967 case GDK_WINDOW_TOPLEVEL:
968 case GDK_WINDOW_DIALOG:
969 case GDK_WINDOW_TEMP: /* ? */
970 gdk_display_put_event (gdk_drawable_get_display (window), &temp_event);
973 case GDK_WINDOW_FOREIGN:
974 case GDK_WINDOW_ROOT:
975 case GDK_WINDOW_CHILD:
981 * gdk_display_set_double_click_time:
982 * @display: a #GdkDisplay
983 * @msec: double click time in milliseconds (thousandths of a second)
985 * Sets the double click time (two clicks within this time interval
986 * count as a double click and result in a #GDK_2BUTTON_PRESS event).
987 * Applications should NOT set this, it is a global user-configured setting.
990 gdk_display_set_double_click_time (GdkDisplay *display,
993 display->double_click_time = msec;
997 * gdk_set_double_click_time:
998 * @msec: double click time in milliseconds (thousandths of a second)
1000 * Set the double click time for the default display. See
1001 * gdk_display_set_double_click_time(). Applications should NOT
1002 * set this, it is a global user-configured setting.
1005 gdk_set_double_click_time (guint msec)
1007 gdk_display_set_double_click_time (gdk_display_get_default (), msec);
1011 gdk_event_get_type (void)
1013 static GType our_type = 0;
1016 our_type = g_boxed_type_register_static ("GdkEvent",
1017 (GBoxedCopyFunc)gdk_event_copy,
1018 (GBoxedFreeFunc)gdk_event_free);
1024 * @name: the name of the setting.
1025 * @value: location to store the value of the setting.
1027 * Obtains a desktop-wide setting, such as the double-click time,
1028 * for the default screen. See gdk_screen_get_setting().
1030 * Returns : %TRUE if the setting existed and a value was stored
1031 * in @value, %FALSE otherwise.
1034 gdk_setting_get (const gchar *name,
1037 return gdk_screen_get_setting (gdk_screen_get_default (), name, value);