]> Pileus Git - ~andy/gtk/blobdiff - gdk/gdkevents.c
Updated Hungarian translation
[~andy/gtk] / gdk / gdkevents.c
index bab5ad5d41df7b9716787eb44a962b13433a0b90..2dbb24237019cd6dfc2cd1932b3ec0b3145cbd43 100644 (file)
  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
  */
 
+#include "config.h"
 #include <string.h>            /* For memset() */
 
 #include "gdk.h"
 #include "gdkinternals.h"
+#include "gdkalias.h"
 
 typedef struct _GdkIOClosure GdkIOClosure;
 
@@ -35,7 +37,7 @@ struct _GdkIOClosure
 {
   GdkInputFunction function;
   GdkInputCondition condition;
-  GdkDestroyNotify notify;
+  GDestroyNotify notify;
   gpointer data;
 };
 
@@ -46,10 +48,6 @@ GdkEventFunc   _gdk_event_func = NULL;    /* Callback for events */
 gpointer       _gdk_event_data = NULL;
 GDestroyNotify _gdk_event_notify = NULL;
 
-#define TRIPLE_CLICK_TIME(display) (2*display->double_click_time)
-#define DOUBLE_CLICK_DIST      5
-#define TRIPLE_CLICK_DIST      5
-
 /*********************************************
  * Functions for maintaining the event queue *
  *********************************************/
@@ -80,6 +78,25 @@ _gdk_event_queue_find_first (GdkDisplay *display)
   return NULL;
 }
 
+/**
+ * _gdk_event_queue_prepend:
+ * @display: a #GdkDisplay
+ * @event: Event to prepend.
+ *
+ * Prepends an event before the head of the event queue.
+ *
+ * Returns: the newly prepended list node.
+ **/
+GList*
+_gdk_event_queue_prepend (GdkDisplay *display,
+                         GdkEvent   *event)
+{
+  display->queued_events = g_list_prepend (display->queued_events, event);
+  if (!display->queued_tail)
+    display->queued_tail = display->queued_events;
+  return display->queued_events;
+}
+
 /**
  * _gdk_event_queue_append:
  * @display: a #GdkDisplay
@@ -103,6 +120,63 @@ _gdk_event_queue_append (GdkDisplay *display,
   return display->queued_tail;
 }
 
+/**
+ * _gdk_event_queue_insert_after:
+ * @display: a #GdkDisplay
+ * @sibling: Append after this event.
+ * @event: Event to append.
+ *
+ * Appends an event after the specified event, or if it isn't in
+ * the queue, onto the tail of the event queue.
+ *
+ * Returns: the newly appended list node.
+ *
+ * Since: 2.16
+ */
+GList*
+_gdk_event_queue_insert_after (GdkDisplay *display,
+                               GdkEvent   *sibling,
+                               GdkEvent   *event)
+{
+  GList *prev = g_list_find (display->queued_events, sibling);
+  if (prev && prev->next)
+    {
+      display->queued_events = g_list_insert_before (display->queued_events, prev->next, event);
+      return prev->next;
+    }
+  else
+    return _gdk_event_queue_append (display, event);
+}
+
+/**
+ * _gdk_event_queue_insert_after:
+ * @display: a #GdkDisplay
+ * @sibling: Append after this event.
+ * @event: Event to append.
+ *
+ * Appends an event before the specified event, or if it isn't in
+ * the queue, onto the tail of the event queue.
+ *
+ * Returns: the newly appended list node.
+ *
+ * Since: 2.16
+ */
+GList*
+_gdk_event_queue_insert_before (GdkDisplay *display,
+                               GdkEvent   *sibling,
+                               GdkEvent   *event)
+{
+  GList *next = g_list_find (display->queued_events, sibling);
+  if (next)
+    {
+      display->queued_events = g_list_insert_before (display->queued_events, next, event);
+      return next->prev;
+    }
+  else
+    return _gdk_event_queue_append (display, event);
+}
+
+
 /**
  * _gdk_event_queue_remove_link:
  * @display: a #GdkDisplay
@@ -239,7 +313,7 @@ gdk_event_peek (void)
  * queue if event->any.window is %NULL. See gdk_display_put_event().
  **/
 void
-gdk_event_put (GdkEvent *event)
+gdk_event_put (const GdkEvent *event)
 {
   GdkDisplay *display;
   
@@ -257,26 +331,29 @@ gdk_event_put (GdkEvent *event)
   gdk_display_put_event (display, event);
 }
 
-static GMemChunk *event_chunk = NULL;
 static GHashTable *event_hash = NULL;
 
+/**
+ * gdk_event_new:
+ * @type: a #GdkEventType 
+ * 
+ * Creates a new event of the given type. All fields are set to 0.
+ * 
+ * Return value: a newly-allocated #GdkEvent. The returned #GdkEvent 
+ * should be freed with gdk_event_free().
+ *
+ * Since: 2.2
+ **/
 GdkEvent*
 gdk_event_new (GdkEventType type)
 {
   GdkEventPrivate *new_private;
   GdkEvent *new_event;
   
-  if (event_chunk == NULL)
-    {
-      event_chunk = g_mem_chunk_new ("events",
-                                    sizeof (GdkEventPrivate),
-                                    4096,
-                                    G_ALLOC_AND_FREE);
-      event_hash = g_hash_table_new (g_direct_hash, NULL);
-    }
-  
-  new_private = g_chunk_new (GdkEventPrivate, event_chunk);
-  memset (new_private, 0, sizeof (GdkEventPrivate));
+  if (!event_hash)
+    event_hash = g_hash_table_new (g_direct_hash, NULL);
+
+  new_private = g_slice_new0 (GdkEventPrivate);
   
   new_private->flags = 0;
   new_private->screen = NULL;
@@ -331,7 +408,7 @@ gdk_event_new (GdkEventType type)
 }
 
 static gboolean
-gdk_event_is_allocated (GdkEvent *event)
+gdk_event_is_allocated (const GdkEvent *event)
 {
   if (event_hash)
     return g_hash_table_lookup (event_hash, event) != NULL;
@@ -350,9 +427,8 @@ gdk_event_is_allocated (GdkEvent *event)
  * gdk_event_free().
  **/
 GdkEvent*
-gdk_event_copy (GdkEvent *event)
+gdk_event_copy (const GdkEvent *event)
 {
-  GdkEventPrivate *private;
   GdkEventPrivate *new_private;
   GdkEvent *new_event;
   
@@ -361,13 +437,16 @@ gdk_event_copy (GdkEvent *event)
   new_event = gdk_event_new (GDK_NOTHING);
   new_private = (GdkEventPrivate *)new_event;
 
-  private = (GdkEventPrivate *)event;
-
   *new_event = *event;
   if (new_event->any.window)
     g_object_ref (new_event->any.window);
 
-  new_private->screen = private->screen;
+  if (gdk_event_is_allocated (event))
+    {
+      GdkEventPrivate *private = (GdkEventPrivate *)event;
+
+      new_private->screen = private->screen;
+    }
   
   switch (event->any.type)
     {
@@ -392,6 +471,7 @@ gdk_event_copy (GdkEvent *event)
       break;
       
     case GDK_EXPOSE:
+    case GDK_DAMAGE:
       if (event->expose.region)
        new_event->expose.region = gdk_region_copy (event->expose.region);
       break;
@@ -399,10 +479,27 @@ gdk_event_copy (GdkEvent *event)
     case GDK_SETTING:
       new_event->setting.name = g_strdup (new_event->setting.name);
       break;
+
+    case GDK_BUTTON_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);
+      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);
+      
+      break;
       
     default:
       break;
     }
+
+  if (gdk_event_is_allocated (event))
+    _gdk_windowing_event_data_copy (event, new_event);
   
   return new_event;
 }
@@ -421,8 +518,6 @@ gdk_event_free (GdkEvent *event)
 {
   g_return_if_fail (event != NULL);
 
-  g_assert (event_chunk != NULL); /* paranoid */
-  
   if (event->any.window)
     g_object_unref (event->any.window);
   
@@ -450,18 +545,17 @@ gdk_event_free (GdkEvent *event)
 
     case GDK_BUTTON_PRESS:
     case GDK_BUTTON_RELEASE:
-      if (event->button.axes)
-       g_free (event->button.axes);
+      g_free (event->button.axes);
       break;
       
     case GDK_EXPOSE:
+    case GDK_DAMAGE:
       if (event->expose.region)
        gdk_region_destroy (event->expose.region);
       break;
       
     case GDK_MOTION_NOTIFY:
-      if (event->motion.axes)
-       g_free (event->motion.axes);
+      g_free (event->motion.axes);
       break;
       
     case GDK_SETTING:
@@ -472,8 +566,10 @@ gdk_event_free (GdkEvent *event)
       break;
     }
 
+  _gdk_windowing_event_data_free (event);
+
   g_hash_table_remove (event_hash, event);
-  g_mem_chunk_free (event_chunk, event);
+  g_slice_free (GdkEventPrivate, (GdkEventPrivate*) event);
 }
 
 /**
@@ -486,7 +582,7 @@ gdk_event_free (GdkEvent *event)
  * Return value: time stamp field from @event
  **/
 guint32
-gdk_event_get_time (GdkEvent *event)
+gdk_event_get_time (const GdkEvent *event)
 {
   if (event)
     switch (event->type)
@@ -528,6 +624,7 @@ gdk_event_get_time (GdkEvent *event)
       case GDK_CONFIGURE:
       case GDK_FOCUS_CHANGE:
       case GDK_NOTHING:
+      case GDK_DAMAGE:
       case GDK_DELETE:
       case GDK_DESTROY:
       case GDK_EXPOSE:
@@ -535,6 +632,9 @@ gdk_event_get_time (GdkEvent *event)
       case GDK_UNMAP:
       case GDK_WINDOW_STATE:
       case GDK_SETTING:
+      case GDK_OWNER_CHANGE:
+      case GDK_GRAB_BROKEN:
+      case GDK_EVENT_LAST:
         /* return current time */
         break;
       }
@@ -555,8 +655,8 @@ gdk_event_get_time (GdkEvent *event)
  * Return value: %TRUE if there was a state field in the event 
  **/
 gboolean
-gdk_event_get_state (GdkEvent        *event,
-                     GdkModifierType *state)
+gdk_event_get_state (const GdkEvent        *event,
+                     GdkModifierType       *state)
 {
   g_return_val_if_fail (state != NULL, FALSE);
   
@@ -596,6 +696,7 @@ gdk_event_get_state (GdkEvent        *event,
       case GDK_SELECTION_NOTIFY:
       case GDK_PROXIMITY_IN:
       case GDK_PROXIMITY_OUT:
+      case GDK_DAMAGE:
       case GDK_DRAG_ENTER:
       case GDK_DRAG_LEAVE:
       case GDK_DRAG_MOTION:
@@ -610,6 +711,9 @@ gdk_event_get_state (GdkEvent        *event,
       case GDK_UNMAP:
       case GDK_WINDOW_STATE:
       case GDK_SETTING:
+      case GDK_OWNER_CHANGE:
+      case GDK_GRAB_BROKEN:
+      case GDK_EVENT_LAST:
         /* no state field */
         break;
       }
@@ -629,9 +733,9 @@ gdk_event_get_state (GdkEvent        *event,
  * Return value: %TRUE if the event delivered event window coordinates
  **/
 gboolean
-gdk_event_get_coords (GdkEvent *event,
-                     gdouble  *x_win,
-                     gdouble  *y_win)
+gdk_event_get_coords (const GdkEvent *event,
+                     gdouble        *x_win,
+                     gdouble        *y_win)
 {
   gdouble x = 0, y = 0;
   gboolean fetched = TRUE;
@@ -688,9 +792,9 @@ gdk_event_get_coords (GdkEvent *event,
  * Return value: %TRUE if the event delivered root window coordinates
  **/
 gboolean
-gdk_event_get_root_coords (GdkEvent *event,
-                          gdouble  *x_root,
-                          gdouble  *y_root)
+gdk_event_get_root_coords (const GdkEvent *event,
+                          gdouble        *x_root,
+                          gdouble        *y_root)
 {
   gdouble x = 0, y = 0;
   gboolean fetched = TRUE;
@@ -703,6 +807,10 @@ gdk_event_get_root_coords (GdkEvent *event,
       x = event->motion.x_root;
       y = event->motion.y_root;
       break;
+    case GDK_SCROLL:
+      x = event->scroll.x_root;
+      y = event->scroll.y_root;
+      break;
     case GDK_BUTTON_PRESS:
     case GDK_2BUTTON_PRESS:
     case GDK_3BUTTON_PRESS:
@@ -749,9 +857,9 @@ gdk_event_get_root_coords (GdkEvent *event,
  * Return value: %TRUE if the specified axis was found, otherwise %FALSE
  **/
 gboolean
-gdk_event_get_axis (GdkEvent   *event,
-                   GdkAxisUse  axis_use,
-                   gdouble    *value)
+gdk_event_get_axis (const GdkEvent *event,
+                   GdkAxisUse      axis_use,
+                   gdouble        *value)
 {
   gdouble *axes;
   GdkDevice *device;
@@ -811,6 +919,45 @@ gdk_event_get_axis (GdkEvent   *event,
   return gdk_device_get_axis (device, axes, axis_use, value);
 }
 
+/**
+ * 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
+ * core pointer. Coordinate extraction, processing and requesting more
+ * motion events from a %GDK_MOTION_NOTIFY event usually works like this:
+ *
+ * |[
+ * { 
+ *   /&ast; motion_event handler &ast;/
+ *   x = motion_event->x;
+ *   y = motion_event->y;
+ *   /&ast; handle (x,y) motion &ast;/
+ *   gdk_event_request_motions (motion_event); /&ast; handles is_hint events &ast;/
+ * }
+ * ]|
+ *
+ * Since: 2.12
+ **/
+void
+gdk_event_request_motions (const GdkEventMotion *event)
+{
+  GdkDisplay *display;
+  
+  g_return_if_fail (event != NULL);
+  
+  if (event->type == GDK_MOTION_NOTIFY && event->is_hint)
+    {
+      gdk_device_get_state (event->device, event->window, NULL, NULL);
+      
+      display = gdk_drawable_get_display (event->window);
+      _gdk_display_enable_motion_hints (display);
+    }
+}
+
 /**
  * gdk_event_set_screen:
  * @event: a #GdkEvent
@@ -819,6 +966,8 @@ gdk_event_get_axis (GdkEvent   *event,
  * Sets the screen for @event to @screen. The event must
  * have been allocated by GTK+, for instance, by
  * gdk_event_copy().
+ *
+ * Since: 2.2
  **/
 void
 gdk_event_set_screen (GdkEvent  *event,
@@ -838,17 +987,19 @@ gdk_event_set_screen (GdkEvent  *event,
  * @event: a #GdkEvent
  * 
  * Returns the screen for the event. The screen is
- * typically the screen for event->any.window, but
+ * typically the screen for <literal>event->any.window</literal>, but
  * for events such as mouse events, it is the screen
- * where the the pointer was when the event occurs -
+ * where the pointer was when the event occurs -
  * that is, the screen which has the root window 
- * to which event->motion.x_root and
- * event->motion.y_root are relative.
+ * to which <literal>event->motion.x_root</literal> and
+ * <literal>event->motion.y_root</literal> are relative.
  * 
  * Return value: the screen for the event
+ *
+ * Since: 2.2
  **/
 GdkScreen *
-gdk_event_get_screen (GdkEvent *event)
+gdk_event_get_screen (const GdkEvent *event)
 {
   if (gdk_event_is_allocated (event))
     {
@@ -933,12 +1084,29 @@ gdk_io_invoke (GIOChannel   *source,
   return TRUE;
 }
 
+/**
+ * gdk_input_add_full:
+ * @source: a file descriptor.
+ * @condition: the condition.
+ * @function: the callback function.
+ * @data: callback data passed to @function.
+ * @destroy: callback function to call with @data when the input
+ * handler is removed.
+ *
+ * Establish a callback when a condition becomes true on
+ * a file descriptor.
+ *
+ * Returns: a tag that can later be used as an argument to
+ * gdk_input_remove().
+ *
+ * Deprecated: 2.14: Use g_io_add_watch_full() on a #GIOChannel
+ */
 gint
 gdk_input_add_full (gint             source,
                    GdkInputCondition condition,
                    GdkInputFunction  function,
                    gpointer          data,
-                   GdkDestroyNotify  destroy)
+                   GDestroyNotify    destroy)
 {
   guint result;
   GdkIOClosure *closure = g_new (GdkIOClosure, 1);
@@ -966,6 +1134,21 @@ gdk_input_add_full (gint        source,
   return result;
 }
 
+/**
+ * gdk_input_add:
+ * @source: a file descriptor.
+ * @condition: the condition.
+ * @function: the callback function.
+ * @data: callback data passed to @function.
+ *
+ * Establish a callback when a condition becomes true on
+ * a file descriptor.
+ *
+ * Returns: a tag that can later be used as an argument to
+ * gdk_input_remove().
+ *
+ * Deprecated: 2.14: Use g_io_add_watch() on a #GIOChannel
+ */
 gint
 gdk_input_add (gint             source,
               GdkInputCondition condition,
@@ -987,35 +1170,44 @@ gdk_synthesize_click (GdkDisplay *display,
                      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;
-  
-  gdk_display_put_event (display, &temp_event);
+
+  event_copy = gdk_event_copy (&temp_event);
+  link = _gdk_event_queue_append (display, event_copy);
 }
 
 void
 _gdk_event_button_generate (GdkDisplay *display,
                            GdkEvent   *event)
 {
-  if ((event->button.time < (display->button_click_time[1] + TRIPLE_CLICK_TIME (display))) &&
+  if ((event->button.time < (display->button_click_time[1] + 2*display->double_click_time)) &&
       (event->button.window == display->button_window[1]) &&
-      (event->button.button == display->button_number[1]))
-    {
+      (event->button.button == display->button_number[1]) &&
+      (ABS (event->button.x - display->button_x[1]) <= display->double_click_distance) &&
+      (ABS (event->button.y - display->button_y[1]) <= display->double_click_distance))
+{
       gdk_synthesize_click (display, event, 3);
-      
+            
       display->button_click_time[1] = 0;
       display->button_click_time[0] = 0;
       display->button_window[1] = NULL;
-      display->button_window[0] = 0;
+      display->button_window[0] = NULL;
       display->button_number[1] = -1;
       display->button_number[0] = -1;
+      display->button_x[0] = display->button_x[1] = 0;
+      display->button_y[0] = display->button_y[1] = 0;
     }
   else if ((event->button.time < (display->button_click_time[0] + display->double_click_time)) &&
           (event->button.window == display->button_window[0]) &&
-          (event->button.button == display->button_number[0]))
+          (event->button.button == display->button_number[0]) &&
+          (ABS (event->button.x - display->button_x[0]) <= display->double_click_distance) &&
+          (ABS (event->button.y - display->button_y[0]) <= display->double_click_distance))
     {
       gdk_synthesize_click (display, event, 2);
       
@@ -1025,6 +1217,10 @@ _gdk_event_button_generate (GdkDisplay *display,
       display->button_window[0] = event->button.window;
       display->button_number[1] = display->button_number[0];
       display->button_number[0] = event->button.button;
+      display->button_x[1] = display->button_x[0];
+      display->button_x[0] = event->button.x;
+      display->button_y[1] = display->button_y[0];
+      display->button_y[0] = event->button.y;
     }
   else
     {
@@ -1034,6 +1230,10 @@ _gdk_event_button_generate (GdkDisplay *display,
       display->button_window[0] = event->button.window;
       display->button_number[1] = -1;
       display->button_number[0] = event->button.button;
+      display->button_x[1] = 0;
+      display->button_x[0] = event->button.x;
+      display->button_y[1] = 0;
+      display->button_y[0] = event->button.y;
     }
 }
 
@@ -1053,10 +1253,10 @@ gdk_synthesize_window_state (GdkWindow     *window,
   
   old = ((GdkWindowObject*) temp_event.window_state.window)->state;
   
-  temp_event.window_state.changed_mask = (unset_flags | set_flags) ^ old;
   temp_event.window_state.new_window_state = old;
   temp_event.window_state.new_window_state |= set_flags;
   temp_event.window_state.new_window_state &= ~unset_flags;
+  temp_event.window_state.changed_mask = temp_event.window_state.new_window_state ^ old;
 
   if (temp_event.window_state.new_window_state == old)
     return; /* No actual work to do, nothing changed. */
@@ -1068,6 +1268,9 @@ gdk_synthesize_window_state (GdkWindow     *window,
   
   ((GdkWindowObject*) 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);
+
   /* We only really send the event to toplevels, since
    * all the window states don't apply to non-toplevels.
    * Non-toplevels do use the GDK_WINDOW_STATE_WITHDRAWN flag
@@ -1095,7 +1298,10 @@ gdk_synthesize_window_state (GdkWindow     *window,
  * 
  * Sets the double click time (two clicks within this time interval
  * count as a double click and result in a #GDK_2BUTTON_PRESS event).
- * Applications should NOT set this, it is a global user-configured setting.
+ * Applications should <emphasis>not</emphasis> set this, it is a global 
+ * user-configured setting.
+ *
+ * Since: 2.2
  **/
 void
 gdk_display_set_double_click_time (GdkDisplay *display,
@@ -1109,8 +1315,10 @@ gdk_display_set_double_click_time (GdkDisplay *display,
  * @msec: double click time in milliseconds (thousandths of a second)
  *
  * Set the double click time for the default display. See
- * gdk_display_set_double_click_time(). Applications should NOT
- * set this, it is a global user-configured setting.
+ * gdk_display_set_double_click_time(). 
+ * See also gdk_display_set_double_click_distance().
+ * Applications should <emphasis>not</emphasis> set this, it is a 
+ * global user-configured setting.
  **/
 void
 gdk_set_double_click_time (guint msec)
@@ -1118,13 +1326,33 @@ gdk_set_double_click_time (guint msec)
   gdk_display_set_double_click_time (gdk_display_get_default (), msec);
 }
 
+/**
+ * gdk_display_set_double_click_distance:
+ * @display: a #GdkDisplay
+ * @distance: distance in pixels
+ * 
+ * Sets the double click distance (two clicks within this distance
+ * count as a double click and result in a #GDK_2BUTTON_PRESS event).
+ * See also gdk_display_set_double_click_time().
+ * Applications should <emphasis>not</emphasis> set this, it is a global 
+ * user-configured setting.
+ *
+ * Since: 2.4
+ **/
+void
+gdk_display_set_double_click_distance (GdkDisplay *display,
+                                      guint       distance)
+{
+  display->double_click_distance = distance;
+}
+
 GType
 gdk_event_get_type (void)
 {
   static GType our_type = 0;
   
   if (our_type == 0)
-    our_type = g_boxed_type_register_static ("GdkEvent",
+    our_type = g_boxed_type_register_static (g_intern_static_string ("GdkEvent"),
                                             (GBoxedCopyFunc)gdk_event_copy,
                                             (GBoxedFreeFunc)gdk_event_free);
   return our_type;
@@ -1138,7 +1366,7 @@ gdk_event_get_type (void)
  * Obtains a desktop-wide setting, such as the double-click time,
  * for the default screen. See gdk_screen_get_setting().
  *
- * Returns : %TRUE if the setting existed and a value was stored
+ * Returns: %TRUE if the setting existed and a value was stored
  *   in @value, %FALSE otherwise.
  **/
 gboolean
@@ -1147,3 +1375,6 @@ gdk_setting_get (const gchar *name,
 {
   return gdk_screen_get_setting (gdk_screen_get_default (), name, value);
 }
+
+#define __GDK_EVENTS_C__
+#include "gdkaliasdef.c"