]> Pileus Git - ~andy/gtk/blob - gdk/gdkevents.c
8308bbeccdc5d58883057d7c07ea224b83bb39ba
[~andy/gtk] / gdk / gdkevents.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
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.
8  *
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.
13  *
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.
18  */
19
20 /*
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/. 
25  */
26
27 #include "gdk.h"
28 #include "gdkinternals.h"
29
30 typedef struct _GdkIOClosure GdkIOClosure;
31 typedef struct _GdkEventPrivate GdkEventPrivate;
32
33 #define DOUBLE_CLICK_TIME      250
34 #define TRIPLE_CLICK_TIME      500
35 #define DOUBLE_CLICK_DIST      5
36 #define TRIPLE_CLICK_DIST      5
37
38 typedef enum
39 {
40   /* Following flag is set for events on the event queue during
41    * translation and cleared afterwards.
42    */
43   GDK_EVENT_PENDING = 1 << 0
44 } GdkEventFlags;
45
46 struct _GdkIOClosure
47 {
48   GdkInputFunction function;
49   GdkInputCondition condition;
50   GdkDestroyNotify notify;
51   gpointer data;
52 };
53
54 struct _GdkEventPrivate
55 {
56   GdkEvent event;
57   guint    flags;
58 };
59
60 /* 
61  * Private function declarations
62  */
63
64 GdkFilterReturn gdk_wm_protocols_filter (GdkXEvent *xev,
65                                          GdkEvent  *event,
66                                          gpointer   data);
67
68 /* Private variable declarations
69  */
70
71 static guint32 button_click_time[2] = { 0, 0}; /* The last 2 button click times. Used
72                                                 * to determine if the latest button click
73                                                 * is part of a double or triple click.
74                                                 */
75 static GdkWindow *button_window[2] = { NULL, NULL}; /* The last 2 windows to receive button presses.
76                                                      *  Also used to determine if the latest button
77                                                      *  click is part of a double or triple click.
78                                              */
79 static guint button_number[2] = { -1, -1 }; /* The last 2 buttons to be pressed.
80                                              */
81 GdkEventFunc   gdk_event_func = NULL;    /* Callback for events */
82 gpointer       gdk_event_data = NULL;
83 GDestroyNotify gdk_event_notify = NULL;
84
85 GPollFD event_poll_fd;
86
87 /*********************************************
88  * Functions for maintaining the event queue *
89  *********************************************/
90
91 /*************************************************************
92  * gdk_event_queue_find_first:
93  *     Find the first event on the queue that is not still
94  *     being filled in.
95  *   arguments:
96  *     
97  *   results:
98  *     Pointer to the list node for that event, or NULL
99  *************************************************************/
100
101 GList*
102 gdk_event_queue_find_first (void)
103 {
104   GList *tmp_list = gdk_queued_events;
105
106   while (tmp_list)
107     {
108       GdkEventPrivate *event = tmp_list->data;
109       if (!(event->flags & GDK_EVENT_PENDING))
110         return tmp_list;
111
112       tmp_list = g_list_next (tmp_list);
113     }
114
115   return NULL;
116 }
117
118 /*************************************************************
119  * gdk_event_queue_remove_link:
120  *     Remove a specified list node from the event queue.
121  *   arguments:
122  *     node: Node to remove.
123  *   results:
124  *************************************************************/
125
126 void
127 gdk_event_queue_remove_link (GList *node)
128 {
129   if (node->prev)
130     node->prev->next = node->next;
131   else
132     gdk_queued_events = node->next;
133   
134   if (node->next)
135     node->next->prev = node->prev;
136   else
137     gdk_queued_tail = node->prev;
138 }
139
140 /*************************************************************
141  * gdk_event_queue_append:
142  *     Append an event onto the tail of the event queue.
143  *   arguments:
144  *     event: Event to append.
145  *   results:
146  *************************************************************/
147
148 void
149 gdk_event_queue_append (GdkEvent *event)
150 {
151   gdk_queued_tail = g_list_append (gdk_queued_tail, event);
152   
153   if (!gdk_queued_events)
154     gdk_queued_events = gdk_queued_tail;
155   else
156     gdk_queued_tail = gdk_queued_tail->next;
157 }
158
159 /*************************************************************
160  * gdk_event_handler_set:
161  *     
162  *   arguments:
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
166  * 
167  *   results:
168  *************************************************************/
169
170 void 
171 gdk_event_handler_set (GdkEventFunc   func,
172                        gpointer       data,
173                        GDestroyNotify notify)
174 {
175   if (gdk_event_notify)
176     (*gdk_event_notify) (gdk_event_data);
177
178   gdk_event_func = func;
179   gdk_event_data = data;
180   gdk_event_notify = notify;
181 }
182
183 /*
184  *--------------------------------------------------------------
185  * gdk_event_get
186  *
187  *   Gets the next event.
188  *
189  * Arguments:
190  *
191  * Results:
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.
195  *
196  * Side effects:
197  *
198  *--------------------------------------------------------------
199  */
200
201 GdkEvent*
202 gdk_event_get (void)
203 {
204   gdk_events_queue ();
205
206   return gdk_event_unqueue ();
207 }
208
209 /*
210  *--------------------------------------------------------------
211  * gdk_event_peek
212  *
213  *   Gets the next event.
214  *
215  * Arguments:
216  *
217  * Results:
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.
222  *
223  * Side effects:
224  *
225  *--------------------------------------------------------------
226  */
227
228 GdkEvent*
229 gdk_event_peek (void)
230 {
231   GList *tmp_list;
232
233   tmp_list = gdk_event_queue_find_first ();
234   
235   if (tmp_list)
236     return gdk_event_copy (tmp_list->data);
237   else
238     return NULL;
239 }
240
241 void
242 gdk_event_put (GdkEvent *event)
243 {
244   GdkEvent *new_event;
245   
246   g_return_if_fail (event != NULL);
247   
248   new_event = gdk_event_copy (event);
249
250   gdk_event_queue_append (new_event);
251 }
252
253 /*
254  *--------------------------------------------------------------
255  * gdk_event_copy
256  *
257  *   Copy a event structure into new storage.
258  *
259  * Arguments:
260  *   "event" is the event struct to copy.
261  *
262  * Results:
263  *   A new event structure.  Free it with gdk_event_free.
264  *
265  * Side effects:
266  *   The reference count of the window in the event is increased.
267  *
268  *--------------------------------------------------------------
269  */
270
271 static GMemChunk *event_chunk = NULL;
272
273 GdkEvent*
274 gdk_event_new (void)
275 {
276   GdkEventPrivate *new_event;
277   
278   if (event_chunk == NULL)
279     event_chunk = g_mem_chunk_new ("events",
280                                    sizeof (GdkEventPrivate),
281                                    4096,
282                                    G_ALLOC_AND_FREE);
283   
284   new_event = g_chunk_new (GdkEventPrivate, event_chunk);
285   new_event->flags = 0;
286   
287   return (GdkEvent*) new_event;
288 }
289
290 GdkEvent*
291 gdk_event_copy (GdkEvent *event)
292 {
293   GdkEvent *new_event;
294   
295   g_return_val_if_fail (event != NULL, NULL);
296   
297   new_event = gdk_event_new ();
298   
299   *new_event = *event;
300   if (new_event->any.window)
301     gdk_window_ref (new_event->any.window);
302   
303   switch (event->any.type)
304     {
305     case GDK_KEY_PRESS:
306     case GDK_KEY_RELEASE:
307       new_event->key.string = g_strdup (event->key.string);
308       break;
309       
310     case GDK_ENTER_NOTIFY:
311     case GDK_LEAVE_NOTIFY:
312       if (event->crossing.subwindow != NULL)
313         gdk_window_ref (event->crossing.subwindow);
314       break;
315       
316     case GDK_DRAG_ENTER:
317     case GDK_DRAG_LEAVE:
318     case GDK_DRAG_MOTION:
319     case GDK_DRAG_STATUS:
320     case GDK_DROP_START:
321     case GDK_DROP_FINISHED:
322       gdk_drag_context_ref (event->dnd.context);
323       break;
324       
325     default:
326       break;
327     }
328   
329   return new_event;
330 }
331
332 /*
333  *--------------------------------------------------------------
334  * gdk_event_free
335  *
336  *   Free a event structure obtained from gdk_event_copy.  Do not use
337  *   with other event structures.
338  *
339  * Arguments:
340  *   "event" is the event struct to free.
341  *
342  * Results:
343  *
344  * Side effects:
345  *   The reference count of the window in the event is decreased and
346  *   might be freed, too.
347  *
348  *-------------------------------------------------------------- */
349
350 void
351 gdk_event_free (GdkEvent *event)
352 {
353   g_return_if_fail (event != NULL);
354
355   g_assert (event_chunk != NULL); /* paranoid */
356   
357   if (event->any.window)
358     gdk_window_unref (event->any.window);
359   
360   switch (event->any.type)
361     {
362     case GDK_KEY_PRESS:
363     case GDK_KEY_RELEASE:
364       g_free (event->key.string);
365       break;
366       
367     case GDK_ENTER_NOTIFY:
368     case GDK_LEAVE_NOTIFY:
369       if (event->crossing.subwindow != NULL)
370         gdk_window_unref (event->crossing.subwindow);
371       break;
372       
373     case GDK_DRAG_ENTER:
374     case GDK_DRAG_LEAVE:
375     case GDK_DRAG_MOTION:
376     case GDK_DRAG_STATUS:
377     case GDK_DROP_START:
378     case GDK_DROP_FINISHED:
379       gdk_drag_context_unref (event->dnd.context);
380       break;
381
382     case GDK_BUTTON_PRESS:
383     case GDK_BUTTON_RELEASE:
384       if (event->button.axes)
385         g_free (event->button.axes);
386       break;
387
388     case GDK_MOTION_NOTIFY:
389       if (event->motion.axes)
390         g_free (event->motion.axes);
391       break;
392       
393     default:
394       break;
395     }
396   
397   g_mem_chunk_free (event_chunk, event);
398 }
399
400 /**
401  * gdk_event_get_time:
402  * @event: a #GdkEvent
403  * 
404  * Returns the time stamp from @event, if there is one; otherwise
405  * returns #GDK_CURRENT_TIME. If @event is %NULL, returns #GDK_CURRENT_TIME.
406  * 
407  * Return value: time stamp field from @event
408  **/
409 guint32
410 gdk_event_get_time (GdkEvent *event)
411 {
412   if (event)
413     switch (event->type)
414       {
415       case GDK_MOTION_NOTIFY:
416         return event->motion.time;
417       case GDK_BUTTON_PRESS:
418       case GDK_2BUTTON_PRESS:
419       case GDK_3BUTTON_PRESS:
420       case GDK_BUTTON_RELEASE:
421         return event->button.time;
422       case GDK_SCROLL:
423         return event->scroll.time;
424       case GDK_KEY_PRESS:
425       case GDK_KEY_RELEASE:
426         return event->key.time;
427       case GDK_ENTER_NOTIFY:
428       case GDK_LEAVE_NOTIFY:
429         return event->crossing.time;
430       case GDK_PROPERTY_NOTIFY:
431         return event->property.time;
432       case GDK_SELECTION_CLEAR:
433       case GDK_SELECTION_REQUEST:
434       case GDK_SELECTION_NOTIFY:
435         return event->selection.time;
436       case GDK_PROXIMITY_IN:
437       case GDK_PROXIMITY_OUT:
438         return event->proximity.time;
439       case GDK_DRAG_ENTER:
440       case GDK_DRAG_LEAVE:
441       case GDK_DRAG_MOTION:
442       case GDK_DRAG_STATUS:
443       case GDK_DROP_START:
444       case GDK_DROP_FINISHED:
445         return event->dnd.time;
446       case GDK_CLIENT_EVENT:
447       case GDK_VISIBILITY_NOTIFY:
448       case GDK_NO_EXPOSE:
449       case GDK_CONFIGURE:
450       case GDK_FOCUS_CHANGE:
451       case GDK_NOTHING:
452       case GDK_DELETE:
453       case GDK_DESTROY:
454       case GDK_EXPOSE:
455       case GDK_MAP:
456       case GDK_UNMAP:
457         /* return current time */
458         break;
459       }
460   
461   return GDK_CURRENT_TIME;
462 }
463
464 /**
465  * gdk_event_get_state:
466  * @event: a #GdkEvent or NULL
467  * @state: return location for state
468  * 
469  * If the event contains a "state" field, puts that field in @state. Otherwise
470  * stores an empty state (0). Returns %TRUE if there was a state field
471  * in the event. @event may be %NULL, in which case it's treated
472  * as if the event had no state field.
473  * 
474  * Return value: %TRUE if there was a state field in the event 
475  **/
476 gboolean
477 gdk_event_get_state (GdkEvent        *event,
478                      GdkModifierType *state)
479 {
480   g_return_val_if_fail (state != NULL, FALSE);
481   
482   if (event)
483     switch (event->type)
484       {
485       case GDK_MOTION_NOTIFY:
486         *state = event->motion.state;
487         return TRUE;
488       case GDK_BUTTON_PRESS:
489       case GDK_2BUTTON_PRESS:
490       case GDK_3BUTTON_PRESS:
491       case GDK_BUTTON_RELEASE:
492         *state =  event->button.state;
493         return TRUE;
494       case GDK_SCROLL:
495         *state =  event->scroll.state;
496         return TRUE;
497       case GDK_KEY_PRESS:
498       case GDK_KEY_RELEASE:
499         *state =  event->key.state;
500         return TRUE;
501       case GDK_ENTER_NOTIFY:
502       case GDK_LEAVE_NOTIFY:
503         *state =  event->crossing.state;
504         return TRUE;
505       case GDK_PROPERTY_NOTIFY:
506         *state =  event->property.state;
507         return TRUE;
508       case GDK_VISIBILITY_NOTIFY:
509         *state =  event->visibility.state;
510         return TRUE;
511       case GDK_CLIENT_EVENT:
512       case GDK_NO_EXPOSE:
513       case GDK_CONFIGURE:
514       case GDK_FOCUS_CHANGE:
515       case GDK_SELECTION_CLEAR:
516       case GDK_SELECTION_REQUEST:
517       case GDK_SELECTION_NOTIFY:
518       case GDK_PROXIMITY_IN:
519       case GDK_PROXIMITY_OUT:
520       case GDK_DRAG_ENTER:
521       case GDK_DRAG_LEAVE:
522       case GDK_DRAG_MOTION:
523       case GDK_DRAG_STATUS:
524       case GDK_DROP_START:
525       case GDK_DROP_FINISHED:
526       case GDK_NOTHING:
527       case GDK_DELETE:
528       case GDK_DESTROY:
529       case GDK_EXPOSE:
530       case GDK_MAP:
531       case GDK_UNMAP:
532         /* no state field */
533         break;
534       }
535
536   *state = 0;
537   return FALSE;
538 }
539
540 /**
541  * gdk_event_get_axis:
542  * @event: a #GdkEvent
543  * @axis_use: the axis use to look for
544  * @value: location to store the value found
545  * 
546  * Extract the axis value for a particular axis use from
547  * an event structure.
548  * 
549  * Return value: %TRUE if the specified axis was found, otherwise %FALSE
550  **/
551 gboolean
552 gdk_event_get_axis (GdkEvent   *event,
553                     GdkAxisUse  axis_use,
554                     gdouble    *value)
555 {
556   gdouble *axes;
557   GdkDevice *device;
558   
559   g_return_val_if_fail (event != NULL, FALSE);
560   
561   if (axis_use == GDK_AXIS_X || axis_use == GDK_AXIS_Y)
562     {
563       gdouble x, y;
564       
565       switch (event->type)
566         {
567         case GDK_MOTION_NOTIFY:
568           x = event->motion.x;
569           y = event->motion.y;
570           break;
571         case GDK_SCROLL:
572           x = event->scroll.x;
573           y = event->scroll.y;
574           break;
575         case GDK_BUTTON_PRESS:
576         case GDK_BUTTON_RELEASE:
577           x = event->button.x;
578           y = event->button.y;
579           break;
580         case GDK_ENTER_NOTIFY:
581         case GDK_LEAVE_NOTIFY:
582           x = event->crossing.x;
583           y = event->crossing.y;
584           break;
585           
586         default:
587           return FALSE;
588         }
589
590       if (axis_use == GDK_AXIS_X && value)
591         *value = x;
592       if (axis_use == GDK_AXIS_Y && value)
593         *value = y;
594
595       return TRUE;
596     }
597   else if (event->type == GDK_BUTTON_PRESS ||
598            event->type == GDK_BUTTON_RELEASE)
599     {
600       device = event->button.device;
601       axes = event->button.axes;
602     }
603   else if (event->type == GDK_MOTION_NOTIFY)
604     {
605       device = event->motion.device;
606       axes = event->motion.axes;
607     }
608   else
609     return FALSE;
610
611   return gdk_device_get_axis (device, axes, axis_use, value);
612 }
613
614 /*
615  *--------------------------------------------------------------
616  * gdk_set_show_events
617  *
618  *   Turns on/off the showing of events.
619  *
620  * Arguments:
621  *   "show_events" is a boolean describing whether or
622  *   not to show the events gdk receives.
623  *
624  * Results:
625  *
626  * Side effects:
627  *   When "show_events" is TRUE, calls to "gdk_event_get"
628  *   will output debugging informatin regarding the event
629  *   received to stdout.
630  *
631  *--------------------------------------------------------------
632  */
633
634 void
635 gdk_set_show_events (gboolean show_events)
636 {
637   if (show_events)
638     gdk_debug_flags |= GDK_DEBUG_EVENTS;
639   else
640     gdk_debug_flags &= ~GDK_DEBUG_EVENTS;
641 }
642
643 gboolean
644 gdk_get_show_events (void)
645 {
646   return (gdk_debug_flags & GDK_DEBUG_EVENTS) != 0;
647 }
648
649 static void
650 gdk_io_destroy (gpointer data)
651 {
652   GdkIOClosure *closure = data;
653
654   if (closure->notify)
655     closure->notify (closure->data);
656
657   g_free (closure);
658 }
659
660 /* What do we do with G_IO_NVAL?
661  */
662 #define READ_CONDITION (G_IO_IN | G_IO_HUP | G_IO_ERR)
663 #define WRITE_CONDITION (G_IO_OUT | G_IO_ERR)
664 #define EXCEPTION_CONDITION (G_IO_PRI)
665
666 static gboolean  
667 gdk_io_invoke (GIOChannel   *source,
668                GIOCondition  condition,
669                gpointer      data)
670 {
671   GdkIOClosure *closure = data;
672   GdkInputCondition gdk_cond = 0;
673
674   if (condition & READ_CONDITION)
675     gdk_cond |= GDK_INPUT_READ;
676   if (condition & WRITE_CONDITION)
677     gdk_cond |= GDK_INPUT_WRITE;
678   if (condition & EXCEPTION_CONDITION)
679     gdk_cond |= GDK_INPUT_EXCEPTION;
680
681   if (closure->condition & gdk_cond)
682     closure->function (closure->data, g_io_channel_unix_get_fd (source), gdk_cond);
683
684   return TRUE;
685 }
686
687 gint
688 gdk_input_add_full (gint              source,
689                     GdkInputCondition condition,
690                     GdkInputFunction  function,
691                     gpointer          data,
692                     GdkDestroyNotify  destroy)
693 {
694   guint result;
695   GdkIOClosure *closure = g_new (GdkIOClosure, 1);
696   GIOChannel *channel;
697   GIOCondition cond = 0;
698
699   closure->function = function;
700   closure->condition = condition;
701   closure->notify = destroy;
702   closure->data = data;
703
704   if (condition & GDK_INPUT_READ)
705     cond |= READ_CONDITION;
706   if (condition & GDK_INPUT_WRITE)
707     cond |= WRITE_CONDITION;
708   if (condition & GDK_INPUT_EXCEPTION)
709     cond |= EXCEPTION_CONDITION;
710
711   channel = g_io_channel_unix_new (source);
712   result = g_io_add_watch_full (channel, G_PRIORITY_DEFAULT, cond, 
713                                 gdk_io_invoke,
714                                 closure, gdk_io_destroy);
715   g_io_channel_unref (channel);
716
717   return result;
718 }
719
720 gint
721 gdk_input_add (gint              source,
722                GdkInputCondition condition,
723                GdkInputFunction  function,
724                gpointer          data)
725 {
726   return gdk_input_add_full (source, condition, function, data, NULL);
727 }
728
729 void
730 gdk_input_remove (gint tag)
731 {
732   g_source_remove (tag);
733 }
734
735 GdkEvent*
736 gdk_event_unqueue (void)
737 {
738   GdkEvent *event = NULL;
739   GList *tmp_list;
740
741   tmp_list = gdk_event_queue_find_first ();
742
743   if (tmp_list)
744     {
745       event = tmp_list->data;
746       gdk_event_queue_remove_link (tmp_list);
747       g_list_free_1 (tmp_list);
748     }
749
750   return event;
751 }
752
753 void
754 gdk_synthesize_click (GdkEvent *event,
755                       gint      nclicks)
756 {
757   GdkEvent temp_event;
758   
759   g_return_if_fail (event != NULL);
760   
761   temp_event = *event;
762   temp_event.type = (nclicks == 2) ? GDK_2BUTTON_PRESS : GDK_3BUTTON_PRESS;
763   
764   gdk_event_put (&temp_event);
765 }
766
767 void
768 gdk_event_button_generate (GdkEvent *event)
769 {
770   if ((event->button.time < (button_click_time[1] + TRIPLE_CLICK_TIME)) &&
771       (event->button.window == button_window[1]) &&
772       (event->button.button == button_number[1]))
773     {
774       gdk_synthesize_click (event, 3);
775       
776       button_click_time[1] = 0;
777       button_click_time[0] = 0;
778       button_window[1] = NULL;
779       button_window[0] = 0;
780       button_number[1] = -1;
781       button_number[0] = -1;
782     }
783   else if ((event->button.time < (button_click_time[0] + DOUBLE_CLICK_TIME)) &&
784            (event->button.window == button_window[0]) &&
785            (event->button.button == button_number[0]))
786     {
787       gdk_synthesize_click (event, 2);
788       
789       button_click_time[1] = button_click_time[0];
790       button_click_time[0] = event->button.time;
791       button_window[1] = button_window[0];
792       button_window[0] = event->button.window;
793       button_number[1] = button_number[0];
794       button_number[0] = event->button.button;
795     }
796   else
797     {
798       button_click_time[1] = 0;
799       button_click_time[0] = event->button.time;
800       button_window[1] = NULL;
801       button_window[0] = event->button.window;
802       button_number[1] = -1;
803       button_number[0] = event->button.button;
804     }
805 }