📄 gdkevents.c
字号:
/* GDK - The GIMP Drawing Kit * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library 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. *//* * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS * file for a list of people on the GTK+ Team. See the ChangeLog * files for a list of changes. These files are distributed with * GTK+ at ftp://ftp.gtk.org/pub/gtk/. */#include "gdk.h"#include "gdkx.h"#include "gdkprivate.h"#include "gdkkeysyms.h"#if HAVE_CONFIG_H# include <config.h># if STDC_HEADERS# include <string.h># endif#endif#include "gdkinput.h"typedef struct _GdkIOClosure GdkIOClosure;typedef struct _GdkEventPrivate GdkEventPrivate;#define DOUBLE_CLICK_TIME 250#define TRIPLE_CLICK_TIME 500#define DOUBLE_CLICK_DIST 5#define TRIPLE_CLICK_DIST 5typedef enum{ /* Following flag is set for events on the event queue during * translation and cleared afterwards. */ GDK_EVENT_PENDING = 1 << 0} GdkEventFlags;struct _GdkIOClosure{ GdkInputFunction function; GdkInputCondition condition; GdkDestroyNotify notify; gpointer data;};struct _GdkEventPrivate{ GdkEvent event; guint flags;};/* * Private function declarations */static GdkEvent *gdk_event_new (void);static gint gdk_event_apply_filters (XEvent *xevent, GdkEvent *event, GList *filters);static gint gdk_event_translate (GdkEvent *event, XEvent *xevent);#if 0static Bool gdk_event_get_type (Display *display, XEvent *xevent, XPointer arg);#endifstatic void gdk_events_queue (void);static GdkEvent* gdk_event_unqueue (void);static gboolean gdk_event_prepare (gpointer source_data, GTimeVal *current_time, gint *timeout, gpointer user_data);static gboolean gdk_event_check (gpointer source_data, GTimeVal *current_time, gpointer user_data);static gboolean gdk_event_dispatch (gpointer source_data, GTimeVal *current_time, gpointer user_data);static void gdk_synthesize_click (GdkEvent *event, gint nclicks);GdkFilterReturn gdk_wm_protocols_filter (GdkXEvent *xev, GdkEvent *event, gpointer data);/* Private variable declarations */static int connection_number = 0; /* The file descriptor number of our * connection to the X server. This * is used so that we may determine * when events are pending by using * the "select" system call. */static guint32 button_click_time[2]; /* The last 2 button click times. Used * to determine if the latest button click * is part of a double or triple click. */static GdkWindow *button_window[2]; /* The last 2 windows to receive button presses. * Also used to determine if the latest button * click is part of a double or triple click. */static guint button_number[2]; /* The last 2 buttons to be pressed. */static GdkEventFunc event_func = NULL; /* Callback for events */static gpointer event_data = NULL;static GDestroyNotify event_notify = NULL;static GList *client_filters; /* Filters for client messages *//* FIFO's for event queue, and for events put back using * gdk_event_put(). */static GList *queued_events = NULL;static GList *queued_tail = NULL;static GSourceFuncs event_funcs = { gdk_event_prepare, gdk_event_check, gdk_event_dispatch, (GDestroyNotify)g_free};GPollFD event_poll_fd;/********************************************* * Functions for maintaining the event queue * *********************************************//************************************************************* * gdk_event_queue_find_first: * Find the first event on the queue that is not still * being filled in. * arguments: * * results: * Pointer to the list node for that event, or NULL *************************************************************/static GList*gdk_event_queue_find_first (void){ GList *tmp_list = queued_events; while (tmp_list) { GdkEventPrivate *event = tmp_list->data; if (!(event->flags & GDK_EVENT_PENDING)) return tmp_list; tmp_list = g_list_next (tmp_list); } return NULL;}/************************************************************* * gdk_event_queue_remove_link: * Remove a specified list node from the event queue. * arguments: * node: Node to remove. * results: *************************************************************/static voidgdk_event_queue_remove_link (GList *node){ if (node->prev) node->prev->next = node->next; else queued_events = node->next; if (node->next) node->next->prev = node->prev; else queued_tail = node->prev; }/************************************************************* * gdk_event_queue_append: * Append an event onto the tail of the event queue. * arguments: * event: Event to append. * results: *************************************************************/static voidgdk_event_queue_append (GdkEvent *event){ queued_tail = g_list_append (queued_tail, event); if (!queued_events) queued_events = queued_tail; else queued_tail = queued_tail->next;}void gdk_events_init (void){ connection_number = ConnectionNumber (gdk_display); GDK_NOTE (MISC, g_message ("connection number: %d", connection_number)); g_source_add (GDK_PRIORITY_EVENTS, TRUE, &event_funcs, NULL, NULL, NULL); event_poll_fd.fd = connection_number; event_poll_fd.events = G_IO_IN; g_main_add_poll (&event_poll_fd, GDK_PRIORITY_EVENTS); button_click_time[0] = 0; button_click_time[1] = 0; button_window[0] = NULL; button_window[1] = NULL; button_number[0] = -1; button_number[1] = -1; gdk_add_client_message_filter (gdk_wm_protocols, gdk_wm_protocols_filter, NULL);}/* *-------------------------------------------------------------- * gdk_events_pending * * Returns if events are pending on the queue. * * Arguments: * * Results: * Returns TRUE if events are pending * * Side effects: * *-------------------------------------------------------------- */gbooleangdk_events_pending (void){ return (gdk_event_queue_find_first() || XPending (gdk_display));}/* *-------------------------------------------------------------- * gdk_event_get_graphics_expose * * Waits for a GraphicsExpose or NoExpose event * * Arguments: * * Results: * For GraphicsExpose events, returns a pointer to the event * converted into a GdkEvent Otherwise, returns NULL. * * Side effects: * *-------------------------------------------------------------- */static Boolgraphics_expose_predicate (Display *display, XEvent *xevent, XPointer arg){ GdkWindowPrivate *private = (GdkWindowPrivate*) arg; g_return_val_if_fail (private != NULL, False); if (xevent->xany.window == private->xwindow && (xevent->xany.type == GraphicsExpose || xevent->xany.type == NoExpose)) return True; else return False;}GdkEvent*gdk_event_get_graphics_expose (GdkWindow *window){ XEvent xevent; GdkEvent *event; g_return_val_if_fail (window != NULL, NULL); XIfEvent (gdk_display, &xevent, graphics_expose_predicate, (XPointer) window); if (xevent.xany.type == GraphicsExpose) { event = gdk_event_new (); if (gdk_event_translate (event, &xevent)) return event; else gdk_event_free (event); } return NULL; }/************************ * Exposure compression * ************************//* * The following implements simple exposure compression. It is * modelled after the way Xt does exposure compression - in * particular compress_expose = XtExposeCompressMultiple. * It compress consecutive sequences of exposure events, * but not sequences that cross other events. (This is because * if it crosses a ConfigureNotify, we could screw up and * mistakenly compress the exposures generated for the new * size - could we just check for ConfigureNotify?) * * Xt compresses to a region / bounding rectangle, we compress * to two rectangles, and try find the two rectangles of minimal * area for this - this is supposed to handle the typical * L-shaped regions generated by OpaqueMove. *//* Given three rectangles, find the two rectangles that cover * them with the smallest area. */static voidgdk_add_rect_to_rects (GdkRectangle *rect1, GdkRectangle *rect2, GdkRectangle *new_rect){ GdkRectangle t1, t2, t3; gint size1, size2, size3; gdk_rectangle_union (rect1, rect2, &t1); gdk_rectangle_union (rect1, new_rect, &t2); gdk_rectangle_union (rect2, new_rect, &t3); size1 = t1.width * t1.height + new_rect->width * new_rect->height; size2 = t2.width * t2.height + rect2->width * rect2->height; size3 = t1.width * t1.height + rect1->width * rect1->height; if (size1 < size2) { if (size1 < size3) { *rect1 = t1; *rect2 = *new_rect; } else *rect2 = t3; } else { if (size2 < size3) *rect1 = t2; else *rect2 = t3; }}typedef struct _GdkExposeInfo GdkExposeInfo;struct _GdkExposeInfo{ Window window; gboolean seen_nonmatching;};static Boolexpose_predicate (Display *display, XEvent *xevent, XPointer arg){ GdkExposeInfo *info = (GdkExposeInfo*) arg; /* Compressing across GravityNotify events is safe, because * we completely ignore them, so they can't change what * we are going to draw. Compressing across GravityNotify * events is necessay because during window-unshading animation * we'll get a whole bunch of them interspersed with * expose events. */ if (xevent->xany.type != Expose && xevent->xany.type != GravityNotify) { info->seen_nonmatching = TRUE; } if (info->seen_nonmatching || xevent->xany.type != Expose || xevent->xany.window != info->window) return FALSE; else return TRUE;}voidgdk_compress_exposures (XEvent *xevent, GdkWindow *window){ gint nrects = 1; gint count = 0; GdkRectangle rect1; GdkRectangle rect2; GdkRectangle tmp_rect; XEvent tmp_event; GdkFilterReturn result; GdkExposeInfo info; GdkEvent event; info.window = xevent->xany.window; info.seen_nonmatching = FALSE; rect1.x = xevent->xexpose.x; rect1.y = xevent->xexpose.y; rect1.width = xevent->xexpose.width; rect1.height = xevent->xexpose.height; event.any.type = GDK_EXPOSE; event.any.window = None; event.any.send_event = FALSE; while (1) { if (count == 0) { if (!XCheckIfEvent (gdk_display, &tmp_event, expose_predicate, (XPointer)&info)) break; } else XIfEvent (gdk_display, &tmp_event, expose_predicate, (XPointer)&info); event.any.window = window; /* We apply filters here, and if it was filtered, completely * ignore the return */ result = gdk_event_apply_filters (xevent, &event, window ? ((GdkWindowPrivate *)window)->filters : gdk_default_filters); if (result != GDK_FILTER_CONTINUE) { if (result == GDK_FILTER_TRANSLATE) gdk_event_put (&event); continue; } if (nrects == 1) { rect2.x = tmp_event.xexpose.x; rect2.y = tmp_event.xexpose.y; rect2.width = tmp_event.xexpose.width; rect2.height = tmp_event.xexpose.height; nrects++; } else { tmp_rect.x = tmp_event.xexpose.x; tmp_rect.y = tmp_event.xexpose.y; tmp_rect.width = tmp_event.xexpose.width; tmp_rect.height = tmp_event.xexpose.height; gdk_add_rect_to_rects (&rect1, &rect2, &tmp_rect); } count = tmp_event.xexpose.count; } if (nrects == 2) { gdk_rectangle_union (&rect1, &rect2, &tmp_rect); if ((tmp_rect.width * tmp_rect.height) < 2 * (rect1.height * rect1.width + rect2.height * rect2.width)) { rect1 = tmp_rect; nrects = 1; } } if (nrects == 2) { event.expose.type = GDK_EXPOSE; event.expose.window = window; event.expose.area.x = rect2.x; event.expose.area.y = rect2.y; event.expose.area.width = rect2.width; event.expose.area.height = rect2.height; event.expose.count = 0; gdk_event_put (&event); } xevent->xexpose.count = nrects - 1; xevent->xexpose.x = rect1.x; xevent->xexpose.y = rect1.y; xevent->xexpose.width = rect1.width; xevent->xexpose.height = rect1.height;}/************************************************************* * gdk_event_handler_set: * * arguments: * func: Callback function to be called for each event. * data: Data supplied to the function * notify: function called when function is no longer needed * * results: *************************************************************/void gdk_event_handler_set (GdkEventFunc func, gpointer data, GDestroyNotify notify){ if (event_notify) (*event_notify) (event_data); event_func = func; event_data = data; event_notify = notify;}/* *-------------------------------------------------------------- * gdk_event_get * * Gets the next event. * * Arguments: * * Results: * If an event is waiting that we care about, returns * a pointer to that event, to be freed with gdk_event_free. * Otherwise, returns NULL. * * Side effects: * *-------------------------------------------------------------- */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -