GDK 事件結構


GTK透過GDK來處理事件,GDK會將每個接受到的XEvent轉換為GdkEvent,然後傳播給GtkWidget,引發一個與事件相對應的事件Signal,再透過Callback函式處理事件。

GdkEvent 是個C union的定義:
union GdkEvent
{
  GdkEventType            type;
  GdkEventAny            any;
  GdkEventExpose        expose;
  GdkEventNoExpose        no_expose;
  GdkEventVisibility        visibility;
  GdkEventMotion        motion;
  GdkEventButton        button;
  GdkEventScroll            scroll;
  GdkEventKey            key;
  GdkEventCrossing        crossing;
  GdkEventFocus            focus_change;
  GdkEventConfigure        configure;
  GdkEventProperty        property;
  GdkEventSelection        selection;
  GdkEventOwnerChange          owner_change;
  GdkEventProximity        proximity;
  GdkEventClient        client;
  GdkEventDND               dnd;
  GdkEventWindowState       window_state;
  GdkEventSetting           setting;
  GdkEventGrabBroken        grab_broken;
};

GdkEvent代表所有的事件型態,其成員 GdkEventType 為enum型態,可透過它來了解目前的事件是哪個類型:
GdkEventType type = event->type; // event 的宣告為 GdkEvent *event
switch(type) {
    case GDK_DELETE:
        g_print("GDK_DELETE");
        ...
        break;
    case GDK_DESTROY:
        g_print("GDK_DELETE");
        ...
        break;
        ...
}

一個使用的例子是,您可以設計一個接受所有事件的處理函式,根據GdkEventType來決定對所有事件作過濾處理,方 式就如上面的程式碼片段所示範的,一個GdkEvent可能對應多個GdkEventType,例如GdkButtonEvent可以對應的 GdkEventType有
GDK_BUTTON_PRESSGDK_2BUTTON_PRESSGDK_3BUTTON_PRESSGDK_BUTTON_RELEASE

每個事件結構有其個別成員,例如GdkEventButton有x與y成員,代表滑鼠游標相對於視窗的位置:
typedef struct {
  GdkEventType type;
  GdkWindow *window;
  gint8 send_event;
  guint32 time;
  gdouble x;
  gdouble y;
  gdouble *axes;
  guint state;
  guint button;
  GdkDevice *device;
  gdouble x_root, y_root;
} GdkEventButton;

您可以這麼存取x或y成員:
gdouble x = event->button.x;
gdouble y = event->button.y;

或是將之轉型為GdkEventButton再進行存取:
gdouble x = ((GdkEventButton*)event)->x;
gdouble y = ((GdkEventButton*)event)->y;

GdkEvent傳播給GtkWidget,引發一個與事件相 對應的事件Signal,您可以使用g_signal_connect()函式連結該Signal與Callback函式來處理事件,事件類型與對應的事 件Signal名稱,基本上就是去掉GDK_名稱,轉為小寫並加上_event名稱,例如:
GDK_DELETE delete_event
GDK_DESTROY destroy_event
GDK_EXPOSE expose_event
GDK_MOTION_NOTIFY motion_notify_event
GDK_BUTTON_PRESS button_press_event
GDK_2BUTTON_PRESS button_press_event
GDK_3BUTTON_PRESS button_press_event
GDK_BUTTON_RELEASE button_release_event
GDK_KEY_PRESS key_press_event
GDK_KEY_RELEASE key_release_event
GDK_ENTER_NOTIFY enter_notify_event
GDK_LEAVE_NOTIFY leave_notify_event
GDK_FOCUS_CHANGE focus_in_event, focus_out_event
GDK_CONFIGURE configure_event
GDK_MAP map_event
GDK_UNMAP unmap_event
GDK_PROPERTY_NOTIFY property_notify_event
GDK_SELECTION_CLEAR selection_clear_event
GDK_SELECTION_REQUEST selection_request_event
GDK_SELECTION_NOTIFY selection_notify_event
GDK_PROXIMITY_IN proximity_in_event
GDK_PROXIMITY_OUT proximity_out_event
GDK_CLIENT_EVENT client_event
GDK_VISIBILITY_NOTIFY visibility_notify_event
GDK_WINDOW_STATE window_state_event
GDK_NO_EXPOSE no_expose_event

如果是"event",則代表所有的事件。多個事件類型可能會對應同一個事件Signal,GDK_BUTTON、GDK_2BUTTON、GDK_3BUTTON,在事件的Signal連結時,都是使用button_press_event,在Callback函式中,再根據GdkEventType加以處理,部份的事件則有特殊的方式處理,例如滑鼠拖曳事件。

您也可以參考 GDK Event Types,以及 Events 中之說明。