事件遮罩(Event Mask)


事件遮罩決定了一個Widget會接收到哪些事件,不同的Widget會有不同預設的事件遮罩,您可以使用gtk_widget_set_events()來設定事件遮罩:
void gtk_widget_set_events(GtkWidget *widget, gint events);

使用gtk_widget_set_events()要特別小心,因為您直接改變了Widget的事件遮罩,不小心的話有可能破壞了Widget的功能,您可以使用gtk_widget_events()增加一些特別事件的事件遮罩:
void gtk_widget_add_events(GtkWidget *widget, gint events);

gtk_widget_set_events()或
gtk_widget_events()必須在Widget實現之前呼叫才有作用,events是GdkEventMask的enum:
typedef enum
{
  GDK_EXPOSURE_MASK        = 1 << 1,
  GDK_POINTER_MOTION_MASK    = 1 << 2,
  GDK_POINTER_MOTION_HINT_MASK    = 1 << 3,
  GDK_BUTTON_MOTION_MASK    = 1 << 4,
  GDK_BUTTON1_MOTION_MASK    = 1 << 5,
  GDK_BUTTON2_MOTION_MASK    = 1 << 6,
  GDK_BUTTON3_MOTION_MASK    = 1 << 7,
  GDK_BUTTON_PRESS_MASK        = 1 << 8,
  GDK_BUTTON_RELEASE_MASK    = 1 << 9,
  GDK_KEY_PRESS_MASK        = 1 << 10,
  GDK_KEY_RELEASE_MASK        = 1 << 11,
  GDK_ENTER_NOTIFY_MASK        = 1 << 12,
  GDK_LEAVE_NOTIFY_MASK        = 1 << 13,
  GDK_FOCUS_CHANGE_MASK        = 1 << 14,
  GDK_STRUCTURE_MASK        = 1 << 15,
  GDK_PROPERTY_CHANGE_MASK    = 1 << 16,
  GDK_VISIBILITY_NOTIFY_MASK    = 1 << 17,
  GDK_PROXIMITY_IN_MASK        = 1 << 18,
  GDK_PROXIMITY_OUT_MASK    = 1 << 19,
  GDK_SUBSTRUCTURE_MASK        = 1 << 20,
  GDK_SCROLL_MASK               = 1 << 21,
  GDK_ALL_EVENTS_MASK        = 0x3FFFFE
} GdkEventMask;

事件遮罩與事件的對應如下(取自 Events 表格三):

遮罩 事件類型
GDK_EXPOSURE_MASK GDK_EXPOSE
GDK_POINTER_MOTION_MASK GDK_MOTION_NOTIFY
GDK_POINTER_MOTION_HINT_MASK N/A
GDK_BUTTON_MOTION_MASK GDK_MOTION_NOTIFY (滑鼠按鈕按下)
GDK_BUTTON1_MOTION_MASK GDK_MOTION_NOTIFY (滑鼠按鈕1按下)
GDK_BUTTON2_MOTION_MASK GDK_MOTION_NOTIFY (滑鼠按鈕2按下)
GDK_BUTTON3_MOTION_MASK GDK_MOTION_NOTIFY (滑鼠按鈕3按下)
GDK_BUTTON_PRESS_MASK GDK_BUTTON_PRESS, GDK_2BUTTON_PRESS, GDK_3BUTTON_PRESS
GDK_BUTTON_RELEASE_MASK GDK_BUTTON_RELEASE
GDK_KEY_PRESS_MASK GDK_KEY_PRESS
GDK_KEY_RELEASE_MASK GDK_KEY_RELEASE
GDK_ENTER_NOTIFY_MASK GDK_ENTER_NOTIFY
GDK_LEAVE_NOTIFY_MASK GDK_LEAVE_NOTIFY
GDK_FOCUS_CHANGE_MASK GDK_FOCUS_IN, GDK_FOCUS_OUT
GDK_STRUCTURE_MASK GDK_CONFIGURE, GDK_DESTROY, GDK_MAP, GDK_UNMAP
GDK_PROPERTY_CHANGE_MASK GDK_PROPERTY_NOTIFY
GDK_VISIBILITY_NOTIFY_MASK GDK_VISIBILITY_NOTIFY
GDK_PROXIMITY_IN_MASK GDK_PROXIMITY_IN
GDK_PROXIMITY_OUT_MASK GDK_PROXIMITY_OUT
GDK_SUBSTRUCTURE_MASK 對子視窗接收 GDK_STRUCTURE_MASK 事件
GDK_ALL_EVENTS_MASK 所有事件

舉個實際的例子來說,GtkWindow預設是不接收滑鼠移動事件,您要使用gtk_widget_events()增加GDK_POINTER_MOTION遮罩,才可以捕捉滑鼠移動事件,例如下面的程式在滑鼠於視窗中移動時,將在標題列中顯示目前的座標值:
  • motion.c
#include <gtk/gtk.h>

gboolean motion_event_handler(
GtkWidget *widget, GdkEventMotion *event, gpointer data) {
char pos[20];

sprintf(pos, "(%d, %d)", (int) event->x, (int) event->y);
gtk_window_set_title(GTK_WINDOW(widget), pos);

return FALSE;
}

int main(int argc, char *argv[]) {
GtkWidget *window;

gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

g_signal_connect(GTK_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), NULL);

gtk_widget_add_events(window, GDK_POINTER_MOTION_MASK);

g_signal_connect(GTK_OBJECT(window), "motion_notify_event",
G_CALLBACK(motion_event_handler), NULL);

gtk_widget_show(window);

gtk_main();

return 0;
}

一個執行的畫面如下所示: