´ÙÀ½ ÀÌÀü Â÷·Ê

21. ³«¼­Àå, °£´ÜÇÑ ±×¸®±â ¿¹Á¦

21.1 °³¿ä

¿©±â¼­ ¿ì¸®´Â °£´ÜÇÑ ±×¸®±â ÇÁ·Î±×·¥À» ¸¸µé °ÍÀÌ´Ù. ±× °úÁ¤¿¡¼­ ¿ì¸®´Â ¸¶¿ì½º À̺¥Æ®¸¦ ¾î¶»°Ô ´Ù·ç´ÂÁö ¾Ë¾Æº¼ °ÍÀÌ°í, À©µµ ¾È¿¡ ¾î¶»°Ô ±×¸²À» ±×¸®´ÂÁö, ±×¸®°í ÇȽº¸ÊÀ» ¹è°æÀ¸·Î Çؼ­ ´õ ³ªÀº ±×¸²À» ±×¸®´Â ¹æ¹ýµµ ¹è¿ï °ÍÀÌ´Ù. °£´ÜÇÑ ±×¸®±â ÇÁ·Î±×·¥À» ¸¸µç ÈÄ¿¡, ¿ì¸®´Â ±×°Í¿¡ drawing tablet °°Àº XInput device¸¦ Áö¿øÇÏ´Â µîÀÇ È®ÀåÀ» ½ÃµµÇÒ °ÍÀÌ´Ù. GTK´Â ±×·± device µé·ÎºÎÅÍ pressure¿Í tilt°°Àº, È®ÀåµÈ Á¤º¸¸¦ ¾ò¾î³¾ ¼ö ÀÖ°Ô ÇÏ´Â support routineÀ» Á¦°øÇÑ´Ù.

21.2 À̺¥Æ® ´Ù·ç±â

¿ì¸®°¡ ÀÌ¹Ì »ìÆ캻 GTKÀÇ ½Ã±×³ÎÀº ¸Þ´º ¾ÆÀÌÅÛ ¼±ÅÃó·³ °í¼öÁØÀÇ µ¿ÀÛÀ» À§ÇÑ °ÍµéÀÌ´Ù. ÇÏÁö¸¸, ¸¶¿ì½ºÀÇ ¿òÁ÷ÀÓÀ̶óµçÁö Å°º¸µåÀÇ ´­·¯Áü°°Àº, Àú¼öÁØÀÇ Á¦¾î¸¦ °øºÎÇÏ´Â °Íµµ ¶§¶§·Î À¯¿ëÇÒ °ÍÀÌ´Ù. GTK ½Ã±×³Î Áß¿¡´Â ÀÌ·± Àú¼öÁØÀÇ À̺¥Æ®¸¦ À§ÇÑ °Íµéµµ ÀÖ´Ù. ÀÌ·± À̺¥Æ®¸¦ À§ÇÑ Çڵ鷯´Â ±×·± À̺¥Æ®¿¡ ´ëÇÑ Á¤º¸¸¦ °¡Áö°í ÀÖ´Â ±¸Á¶Ã¼¸¦ °¡¸®Å°°í ÀÖ´Â ¶Ç´Ù¸¥ ÀÎÀÚµéÀ» °¡Áö°Ô µÈ´Ù. ¿¹¸¦µé¾î, motion event Çڵ鷯´Â ¾Æ·¡¿Í °°Àº GdkEventMotion ±¸Á¶Ã¼¸¦ ÇâÇÑ Æ÷ÀÎÅ͸¦ ÀÎÀÚ·Î °¡Áö°í ÀÖ´Ù.

struct _GdkEventMotion
{
        GdkEventType type;
        GdkWindow *window;
        guint32 time;
        gdouble x;
        gdouble y;
        ...
        guint state;
        ...
};

ÀÎÀÚ typeÀº À̺¥Æ®ÀÇ Å¸ÀÔÀÌ µÇ°í, ÀÌ °æ¿ì¿¡´Â GDK_MOTION_NOTIFYÀÌ´Ù. ÀÎÀÚ window´Â ±× À̺¥Æ®°¡ ¹ß»ýÇÑ À©µµ°¡ µÉ °ÍÀÌ´Ù. ÀÎÀÚ x¿Í y´Â ±× À̺¥Æ®ÀÇ ÁÂÇ¥À̸ç, state´Â À̺¥Æ®°¡ ¹ß»ýÇßÀ» ¶§ÀÇ modifier state¸¦ ¼³Á¤ÇÑ´Ù(Áï, ¾î¶² modifier key¿Í modifier buttonÀÌ ´­·¯Á³´ÂÁö ¼³Á¤). ÀÌ°ÍÀº ¾Æ·¡ º¸ÀÌ´Â »ó¼ö°ªµéÀ» ºñÆ® OR½ÃŲ °ÍÀÌ´Ù.

GDK_SHIFT_MASK
GDK_LOCK_MASK
GDK_CONTROL_MASK
GDK_MOD1_MASK
GDK_MOD2_MASK
GDK_MOD3_MASK
GDK_MOD4_MASK
GDK_MOD5_MASK
GDK_BUTTON1_MASK
GDK_BUTTON2_MASK
GDK_BUTTON3_MASK
GDK_BUTTON4_MASK
GDK_BUTTON5_MASK

´Ù¸¥ ½Ã±×³Îµé¿¡ ´ëÇؼ­Ã³·³, À̺¥Æ®°¡ ¹ß»ýÇßÀ» ¶§ ±×°ÍÀÌ ¾î¶² °ÇÁö °áÁ¤ Çϱâ À§ÇØ ¿ì¸®´Â gtk_signal_connect()¸¦ ÀÌ¿ëÇÑ´Ù. ±×·¯³ª ¶ÇÇÑ ¿ì¸®°¡ ¾î¶² À̺¥Æ®°¡ ŽÁöµÇ¾îÁö±æ ¿øÇÏ´ÂÁö GTK°¡ ¾Ë ¼ö ÀÖµµ·Ï ÇؾßÇÑ´Ù. À̸¦ À§Çؼ­´Â ÀÌ ÇÔ¼ö¸¦ ÀÌ¿ëÇÑ´Ù.

void       gtk_widget_set_events          (GtkWidget           *widget,
                                           gint                 events);

µÎ ¹ø° ÀÎÀÚ´Â ¿ì¸®°¡ °ü½ÉÀ» °¡Áø À̺¥Æ®¸¦ ¼³Á¤ÇÑ´Ù. ÀÌ°ÍÀº ¿©·¯ °¡ÁöÀÇ À̺¥Æ®¸¦ À§Çؼ­ ¸î°¡Áö »ó¼ö¸¦ ºñÆ® OR½ÃŲ °ÍÀÌ´Ù. ¾ÕÀ¸·ÎÀÇ ÂüÁ¶¸¦ À§Çؼ­ ÀÌ »ó¼öµé¸¦ ¼Ò°³ÇÑ´Ù.

GDK_EXPOSURE_MASK
GDK_POINTER_MOTION_MASK
GDK_POINTER_MOTION_HINT_MASK
GDK_BUTTON_MOTION_MASK
GDK_BUTTON1_MOTION_MASK
GDK_BUTTON2_MOTION_MASK
GDK_BUTTON3_MOTION_MASK
GDK_BUTTON_PRESS_MASK
GDK_BUTTON_RELEASE_MASK
GDK_KEY_PRESS_MASK
GDK_KEY_RELEASE_MASK
GDK_ENTER_NOTIFY_MASK
GDK_LEAVE_NOTIFY_MASK
GDK_FOCUS_CHANGE_MASK
GDK_STRUCTURE_MASK
GDK_PROPERTY_CHANGE_MASK
GDK_PROXIMITY_IN_MASK
GDK_PROXIMITY_OUT_MASK

gtk_widget_set_events()¸¦ È£ÃâÇÒ ¶§ °üÂûµÇ¾î¾ß ÇÒ ¸î °³ÀÇ ¹Ì¹¦ÇÑ »çÇ×ÀÌ ÀÖ´Ù. ¸ÕÀú, ±×°ÍÀº GTK widgetÀ» À§ÇÑ XÀ©µµ°¡ ¸¸µé¾îÁö±â ÀÌÀü¿¡ È£ÃâµÇ¾î¾ß ÇÑ´Ù. Áï, ÀÌ°ÍÀº widgetÀ» »õ·Î ¸¸µç Á÷ÈÄ¿¡ È£ÃâµÇ¾î¾ß ÇÑ´Ù´Â ¸»ÀÌ´Ù. µÑ° ·Î, ±× widgetÀº °ü·ÃµÈ XÀ©µµ¸¦ ²À °¡Á®¾ß ÇÑ´Ù. È¿À²À» À§Çؼ­ ¸¹Àº widget typeµéÀº ±×µé¸¸ÀÇ À©µµ¸¦ °¡ÁöÁö ¾Ê°í ±×µéÀÇ parent À©µµ ¾È¿¡ ±×·Á³Ö´Â´Ù. ÀÌ·± widgetÀº ´ÙÀ½°ú °°Àº °ÍµéÀÌ´Ù.

GtkAlignment
GtkArrow
GtkBin
GtkBox
GtkImage
GtkItem
GtkLabel
GtkPaned
GtkPixmap
GtkScrolledWindow
GtkSeparator
GtkTable
GtkViewport
GtkAspectFrame
GtkFrame
GtkVPaned
GtkHPaned
GtkVBox
GtkHBox
GtkVSeparator
GtkHSeparator

ÀÌ·± À̺¥Æ®µéÀ» ŽÁöÇϱâ À§ÇØ ¿ì¸®´Â EventBox widgetÀ» ÇÊ¿ä·Î ÇÑ´Ù. ÀÚ¼¼ ÇÑ °ÍÀº The EventBox WidgetÀ» ÂüÁ¶Ç϶ó.

¿ì¸®ÀÇ ±×¸®±â ÇÁ·Î±×·¥¿¡¼­´Â ¸¶¿ì½º ¹öÆ°ÀÌ ´­·¯Áö´Â °Í°ú ¿òÁ÷ÀÌ´Â °ÍÀ» ŽÁöÇÏ°í ½Í¾îÇϹǷÎ, GDK_POINTER_MOTION_MASK¿Í GDK_BUTTON_PRESS_MASK¸¦ ¼³Á¤ÇÑ´Ù. ¿ì¸®´Â ¶ÇÇÑ À©µµ°¡ ´Ù½Ã ±×·ÁÁ®¾ß ÇÒ ¶§¸¦ ¾Ë¾Æ¾ß ÇϹǷΠGDK_EXPOSURE_MASKµµ ¼³Á¤ÇÑ´Ù. ºñ·Ï ¿ì¸®´Â À©µµÀÇ Å©±â°¡ º¯ÇßÀ» ¶§¸¦ Configure event·Î½á ŽÁöÇØ¾ß ÇÏÁö¸¸, ¿ì¸®´Â À̸¦ À§ÇØ GDK_STRUCTURE_MASK flag¸¦ ¼³Á¤ÇÒ ÇÊ¿ä°¡ ¾ø´Ù. ÀÌ°ÍÀº ¸ðµç À©µµ¿¡ ´ëÇØ ÀÚµ¿ÀûÀ¸·Î ¼³Á¤µÇ±â ¶§¹®ÀÌ´Ù.

±×·±µ¥ GDK_POINTER_MOTION_MASK¸¦ ¼³Á¤ ÇÏ´Â µ¥ ÀÖ¾î ¹®Á¦Á¡ÀÌ ÀÖ´Ù´Â °ÍÀÌ ¹àÇôÁú °ÍÀÌ´Ù. ÀÌ°ÍÀº »ç¿ëÀÚ°¡ ¸¶¿ì½º¸¦ ¿òÁ÷ÀÏ ¶§¸¶´Ù ¼­¹ö°¡ event queue¿¡ motion event¸¦ °è¼Ó ´õÇÒ °ÍÀÌ´Ù. ¾î¶² motion event¸¦ ´Ù·ç±â À§ÇØ 0.1ÃÊ°¡ °É¸°´Ù°í »ý°¢ÇØ º¸ÀÚ. ±×·¯³ª X ¼­¹ö´Â ¸Å 0.05Ãʸ¶´Ù »õ·Î¿î motionÀ» queue¿¡ ÀúÀåÇÑ´Ù. ¿ì¸®´Â °ð »ç¿ëÀÚ°¡ ±×¸®´Â µ¥ ´ëÇÑ ¹æ¹ýÀ» °¡Áö°Ô µÉ °ÍÀÌ´Ù. ¸¸¾à »ç¿ëÀÚ°¡ 5Ãʵ¿¾È ±×¸²À» ±×¸®¸é, ±×µéÀÌ ¸¶¿ì½º ¹öÆ°À» ³õ°í ³­ ÈÄ ¶Ç´Ù¸¥ 5ÃÊ°¡, ±×°ÍÀ» Àâ¾Æ³»±â À§ÇØ ÇÊ¿äÇÏ°Ô µÉ °ÍÀÌ´Ù. ¿ì¸®°¡ ¿øÇÏ´Â °ÍÀº ÁøÇàµÇ´Â °¢°¢ÀÇ À̺¥Æ®¿¡ ´ëÇØ ´Ü ÇϳªÀÇ motion event¸¦ ŽÁöÇÏ´Â °ÍÀÌ´Ù. ÀÌ·¸°Ô Çϱâ À§Çؼ­ ¿ì¸®´Â GDK_POINTER_MOTION_HINT_MASK¸¦ ¼³Á¤ÇÑ´Ù.

¿ì¸®°¡ GDK_POINTER_MOTION_HINT_MASK¸¦ ¼³Á¤Çϸé, ¼­¹ö´Â ¸¶¿ì½º Æ÷ÀÎÅÍ°¡ ¿ì¸®ÀÇ À©µµ¿¡ µé¾î¿À°í ³ª¼­ ¶Ç´Â ¹öÆ°ÀÇ press³ª release À̺¥Æ®°¡ ¹ß»ýÇÏ°í ³ª¼­ óÀ½À¸·Î ¿òÁ÷ÀÏ ¶§ motion event¸¦ º¸³»ÁØ´Ù. µÚµû¸£´Â motion event´Â ¿ì¸®°¡ ¾Æ·¡ÀÇ ÇÔ¼ö·Î½á ºÐ¸íÇÏ°Ô ¸¶¿ì½º Æ÷ÀÎÅÍÀÇ À§Ä¡¸¦ ¹°¾îº¼ ¶§±îÁö ¾ïÁ¦µÉ °ÍÀÌ´Ù.

GdkWindow*    gdk_window_get_pointer     (GdkWindow       *window,
                                          gint            *x,
                                          gint            *y,
                                          GdkModifierType *mask);

(´õ °£´ÜÇÑ ¾²ÀÓ»õ¸¦ °¡Áø gtk_widget_get_pointer()¶ó´Â ÇÔ¼öµµ ÀÖÁö¸¸, ±×´ÙÁö À¯¿ëÇÏÁö´Â ¾ÊÀ½ÀÌ µå·¯³¯ °ÍÀÌ´Ù. ¿Ö³ÄÇÏ¸é ±×°ÍÀº ¸¶¿ì½º ¹öÆ°ÀÇ »óÅ¿¡ °ü°è ¾øÀÌ Æ÷ÀÎÅÍÀÇ À§Ä¡¸¸À» ¸»ÇØÁֱ⠶§¹®ÀÌ´Ù.)

¿ì¸®ÀÇ À©µµ¿¡ À̺¥Æ®¸¦ ¼¼ÆÃÇÏ´Â ÄÚµå´Â ±×·¯¹Ç·Î ÀÌ·± ½ÄÀ¸·Î µÉ °ÍÀÌ´Ù.

gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
          (GtkSignalFunc) expose_event, NULL);
gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
          (GtkSignalFunc) configure_event, NULL);
gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
          (GtkSignalFunc) motion_notify_event, NULL);
gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
          (GtkSignalFunc) button_press_event, NULL);
gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
                   | GDK_LEAVE_NOTIFY_MASK
                   | GDK_BUTTON_PRESS_MASK
                   | GDK_POINTER_MOTION_MASK
                   | GDK_POINTER_MOTION_HINT_MASK);

"expose_event"¿Í "configure_event"´Â ´ÙÀ½À» À§Çؼ­ ³²°ÜµÐ´Ù. "motion_ notify_event"¿Í "button_press_event"ÀÇ Çڵ鷯´Â ²Ï °£´ÜÇÏ´Ù.

static gint
button_press_event (GtkWidget *widget, GdkEventButton *event)
{
  if (event->button == 1 && pixmap != NULL)
      draw_brush (widget, event->x, event->y);
  return TRUE;
}
static gint
motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
{
  int x, y;
  GdkModifierType state;
  if (event->is_hint)
    gdk_window_get_pointer (event->window, &x, &y, &state);
  else
    {
      x = event->x;
      y = event->y;
      state = event->state;
    }
  if (state & GDK_BUTTON1_MASK && pixmap != NULL)
    draw_brush (widget, x, y);
  return TRUE;
}

21.3 DrawingArea widget, ±×¸®°í ±×¸®±â

ÀÌÁ¦ ½ºÅ©¸°¿¡ ±×¸²À» ±×¸®´Â °úÁ¤¿¡ ´ëÇØ ¾Ë¾Æº¸ÀÚ. À̶§ ÇÊ¿äÇÑ °ÍÀº DrawingArea widgetÀÌ´Ù. ±×¸²À» ±×¸®´Â ¿µ¿ªÀÇ widgetÀ̶õ º»ÁúÀûÀ¸·Î ´Ù¸§ ¾Æ´Ñ XÀ©µµ´Ù. ÀÌ°ÍÀº ¿ì¸®°¡ ¿øÇÏ´Â °ÍÀ» ¹«¾ùÀÌµç ±×·Á³ÖÀ» ¼ö ÀÖ´Â ºó ĵ¹ö½º´Ù. Drawing area´Â ÀÌ ÇÔ¼ö¸¦ ÀÌ¿ëÇؼ­ ¸¸µé¾îÁø´Ù.

GtkWidget* gtk_drawing_area_new        (void);

ÀÌ widgetÀÇ µðÆúÆ® Å©±â´Â ÀÌ ÇÔ¼ö·Î½á ¼³Á¤ÇÑ´Ù.

void       gtk_drawing_area_size       (GtkDrawingArea      *darea,
                                        gint                 width,
                                        gint                 height);

¸ðµç widget¿¡ ´ëÇØ ¿øÇÑ´Ù¸é ÀÌ µðÆúÆ® Å©±â´Â gtk_widget_set_usize()·Î½á ¿À¹ö·ÎµåµÉ ¼ö ÀÖ´Ù. ±×¸®°í »ç¿ëÀÚ°¡ Á÷Á¢ ±× drawing area¸¦ Æ÷ÇÔÇÑ À©µµÀÇ Å©±â¸¦ º¯°æÇÏ¸é ¿ª½Ã ¿À¹ö·ÎµåµÈ´Ù.

¿ì¸®°¡ DrawingArea widgetÀ» ¸¸µé ¶§, ±×¸± ´ë»óÀÌ ¹«¾ùÀΰ¡¿¡ ÀüÀûÀ¸·Î ÁÖÀǸ¦ ±â¿ï¿©¾ß ÇÑ´Ù. ¸¸¾à ¿ì¸®ÀÇ À©µµ°¡ °¨Ãß¾îÁ³´Ù°¡ ´Ù½Ã µå·¯³µ´Ù¸é, ¿ì¸®´Â exposure ¸¶½ºÅ©¸¦ ¼³Á¤ÇÏ°í ±×¸®°í ¿ø·¡ °¨Ãß¾îÁ³¾ú´ø ³»¿ëÀÌ ¹«¾ùÀ̾ú´ÂÁö ²À ´Ù½Ã ±×·ÁÁà¾ß ÇÑ´Ù. µ¡ºÙ¿©¼­, À©µµÀÇ ÀϺκÐÀÌ Áö¿öÁ³´Ù°¡ ´Ü°èÀûÀ¸·Î ´Ù½Ã ±×·ÁÁö´Â °ÍÀº ½Ã°¢ÀûÀ¸·Î »ê¸¸ÇØÁú ¼ö ÀÖ´Ù. ÀÌ·± ¹®Á¦¿¡ ´ëÇÑ ÇعýÀº offscreen backing pixmapÀ» ÀÌ¿ëÇÏ´Â °ÍÀÌ´Ù. ½ºÅ©¸° À§·Î ¹Ù·Î ±×¸®´Â ´ë½Å, º¸ÀÌÁö ¾Ê´Â ¼­¹ö ¸Þ¸ð¸®¿¡ ÀúÀåµÈ ¾î¶² À̹ÌÁö À§¿¡ ±×·Á³õ°í, À̹ÌÁö°¡ º¯Ç߰ųª ¶Ç´Â À̹ÌÁöÀÇ »õ·Î¿î ¿µ¿ªÀÌ º¸¿©Áö°Ô µÇ¸é ÇØ´çÇÏ´Â ¿µ¿ªÀ» ½ºÅ©¸°¿¡ º¹»çÇØ ÁÖ´Â °ÍÀÌ´Ù.

¾î¶² offscreen pixmapÀ» ¸¸µé±â À§ÇØ, ¿ì¸®´Â ÀÌ ÇÔ¼ö¸¦ ÀÌ¿ëÇÑ´Ù.

GdkPixmap* gdk_pixmap_new (GdkWindow  *window,
                         gint        width,
                         gint        height,
                         gint        depth);

ÀÎÀÚ window´Â ÀÌ ÇȽº¸ÊÀÌ Æ¯¼ºÀ» À̾î¹ÞÀ» GDK À©µµ¸¦ ¼³Á¤ÇÑ´Ù. width¿Í height´Â ÇȽº¸ÊÀÇ Å©±â¸¦ Á¤ÇÑ´Ù. depth´Â color depth·Î¼­, ÀÌ »õ·Î¿î À©µµ¿¡¼­ÀÇ ÇÑ Çȼ¿´ç ºñÆ®ÀÇ ¼ö´Ù. ¸¸¾à depth°¡ -1·Î ¼³Á¤µÇ¸é, ±×°ÍÀº À©µµÀÇ depth¿Í ¶È°°¾ÆÁø´Ù.

¿ì¸®´Â ÇȽº¸ÊÀ» "configure_event" handler ¾È¿¡ ¸¸µç´Ù. ÀÌ À̺¥Æ®´Â À©µµ°¡ óÀ½ »ý¼ºµÉ ¶§¸¦ Æ÷ÇÔÇؼ­, À©µµÀÇ Å©±â°¡ º¯ÇÒ ¶§¸¶´Ù ¹ß»ýÇÑ´Ù.

/* ±×¸± ¿µ¿ª¿¡ ´ëÇÑ backing pixmap */
static GdkPixmap *pixmap = NULL;
/* Àû´çÇÑ Å©±âÀÇ backing pixmapÀ» Çϳª ¸¸µç´Ù. */
static gint
configure_event (GtkWidget *widget, GdkEventConfigure *event)
{
    if (pixmap)
        {
            gdk_pixmap_destroy(pixmap);
        }
    pixmap = gdk_pixmap_new(widget->window,
                            widget->allocation.width,
                            widget->allocation.height,
                            -1);
    gdk_draw_rectangle (pixmap,
                    widget->style->white_gc,
                    TRUE,
                    0, 0,
                    widget->allocation.width,
                    widget->allocation.height);
    return TRUE;
}

gdk_draw_rectangle()À» ºÎ¸£¸ç ÇȽº¸ÊÀ» white·Î ÃʱâÈ­ÇÑ´Ù. ¿©±â¿¡ ´ëÇØ Àá±ñ ´õ ¾ê±âÇÒ °ÍÀÌ´Ù. ±×·¯¸é ¿ì¸®ÀÇ exposure event handler´Â ´Ü¼øÈ÷ ±× ÇȽº¸ÊÀÇ °ü°èµÈ portionÀ» ½ºÅ©¸° À§·Î º¹»çÇÑ´Ù(¿ì¸®´Â exposure eventÀÇ event->area Çʵå·Î½á redrawÇÒ ¿µ¿ªÀ» °áÁ¤ÇÑ´Ù).

/* Backing pixmapÀ¸·ÎºÎÅÍ ½ºÅ©¸°À» º¹±¸ÇÑ´Ù. */
static gint
expose_event (GtkWidget *widget, GdkEventExpose *event)
{
    gdk_draw_pixmap(widget->window,
                    widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
                    pixmap,
                    event->area.x, event->area.y,
                    event->area.x, event->area.y,
                    event->area.width, event->area.height);
    return FALSE;
}

¿ì¸®´Â ÀÌÁ¦ ÇȽº¸Ê¿¡ ´ëÇØ ¾î¶»°Ô ½ºÅ©¸°À» º¸Á¸ÇÏ´ÂÁö º¸¾Ò´Ù. ±×·±µ¥ ¿ì¸®ÀÇ ÇȽº¸Ê¿¡ ½ÇÁ¦·Î Àç¹ÌÀÖ´Â °ÍµéÀ» ¾î¶»°Ô ±×·Á³ÖÀ»±î? GTKÀÇ GDK ¶óÀ̺귯¸®¿¡´Â drawablesµéÀ» ±×¸®´Â µ¥ ÇÊ¿äÇÑ ¸¹Àº ¼öÀÇ ÇÔ¼öµéÀÌ ÀÖ´Ù. DrawableÀ̶õ °£´ÜÈ÷ ¾îµò°¡¿¡ ±×·ÁÁú ¼ö ÀÖ´Â ±× ¹«¾ùÀÌ´Ù. ¿©±â¼­ ¾îµð¶õ ÇϳªÀÇ window, pixmap, ¶Ç´Â bitmap(Èæ¹éÀÇ À̹ÌÁö)ÀÌ µÉ ¼ö ÀÖ´Ù. ¿ì¸®´Â ÀÌ¹Ì ÀÌ·± ÇÔ¼ö µÎ°¡Áö¸¦ º¸¾Ò´Ù. gdk_draw_rectangle()°ú gdk_draw_pixmap()ÀÌ ±×°ÍÀÌ´Ù. ÀÌ ÇÔ¼öµéÀÇ ¿ÏÀüÇÑ ¸®½ºÆ®´Â ÀÌ·¸´Ù.

gdk_draw_line ()
gdk_draw_rectangle ()
gdk_draw_arc ()
gdk_draw_polygon ()
gdk_draw_string ()
gdk_draw_text ()
gdk_draw_pixmap ()
gdk_draw_bitmap ()
gdk_draw_image ()
gdk_draw_points ()
gdk_draw_segments ()

ÀÌ ÇÔ¼öµé¿¡ ´ëÇØ ´õ ÀÚ¼¼È÷ ¾Ë·Á¸é Âü°í ¹®¼­¸¦ º¸°Å³ª <gdk/gdk.h> ÆÄÀÏÀ» º¸¶ó. ÀÌ ÇÔ¼öµéÀº óÀ½ µÎ °³ÀÇ ÀÎÀÚ¸¦ °øÅëÀûÀ¸·Î °¡Áø´Ù. ù ¹ø°´Â ±×·Á ³ÖÀ» drawable, ±×¸®°í µÎ¹ø°´Â graphics context(GC)ÀÌ´Ù.

C´Â foreground/background color³ª line width°°Àº, ±×·ÁÁú °Í¿¡ ´ëÇÑ Á¤º¸µéÀ» ĸ½¶È­ÇÑ °ÍÀÌ´Ù. GDK´Â GC¸¦ »õ·Î ¸¸µé°í º¯ÇüÇϴµ¥ ÇÊ¿äÇÑ ¸ðµç ÇÔ¼öµéÀ» °¡Áö°í ÀÖÁö¸¸, ¹¹µçÁö °£´ÜÈ÷ À¯ÁöÇϱâ À§Çؼ­(Keep things simple) ¿ì¸®´Â ÀÌ¹Ì Á¤ÀǵǾî ÀÖ´Â GC¸¸À» ¾µ °ÍÀÌ´Ù. °¢ widgetÀº ¿¬°üµÈ ½ºÅ¸ÀÏÀÌ ÀÖ´Ù(À̵éÀº rc ÆÄÀÏÀ» ÆíÁýÇÔÀ¸·Î½á º¯Çü°¡´ÉÇÏ´Ù. GTKÀÇ rc ÆÄÀÏ¿¡ ´ëÇÑ ºÎºÐÀ» ÂüÁ¶). ÀÌ°ÍÀº ´Ù¸¥ °Íµé »çÀÌ¿¡¼­ GCÀÇ °³¼ö¸¦ ÀúÀåÇÑ´Ù. ÀÌ·± GC¿¡ Á¢±ÙÇÏ´Â ¸î°¡Áö ¿¹¸¦ º¸ÀÌ°Ú´Ù.

widget->style->white_gc
widget->style->black_gc
widget->style->fg_gc[GTK_STATE_NORMAL]
widget->style->bg_gc[GTK_WIDGET_STATE(widget)]

Çʵå fg_gc, bg_gc, dark_gc, light_gc µîÀº ¾Æ·¡ °ªµéÀ» °¡Áú ¼ö ÀÖ´Â GtkStateTypeÀ̶ó´Â ÀÎÀÚ·Î ³ªÅ¸³»¾îÁø´Ù.

GTK_STATE_NORMAL,
GTK_STATE_ACTIVE,
GTK_STATE_PRELIGHT,
GTK_STATE_SELECTED,
GTK_STATE_INSENSITIVE

¿¹¸¦µé¾î, GTK_STATE_SELECTED¿¡ ´ëÇØ µðÆúÆ® foreground »ö±òÀº whiteÀÌ°í background »ö±òÀº dark blueÀÌ´Ù. ½ÇÁ¦·Î ½ºÅ©¸° À§·Î ±×¸®´Â ÇÔ¼öÀÎ draw_brush()´Â ±×·¯¹Ç·Î ÀÌ·¸°Ô µÈ´Ù.

/* ½ºÅ©¸°¿¡ »ç°¢ÇüÀ» Çϳª ±×¸°´Ù. */
static void
draw_brush (GtkWidget *widget, gdouble x, gdouble y)
{
    GdkRectangle update_rect;
    update_rect.x = x - 5;
    update_rect.y = y - 5;
    update_rect.width = 10;
    update_rect.height = 10;
    gdk_draw_rectangle (pixmap,
                        widget->style->black_gc,
                        TRUE,
                        update_rect.x, update_rect.y,
                        update_rect.width, update_rect.height);
    gtk_widget_draw (widget, &update_rect);
}

¿ì¸®°¡ ÇȽº¸Ê À§·Î ºê·¯½¬¸¦ Ç¥½ÃÇÏ´Â »ç°¢ÇüÀ» ±×¸®°í ³ª¼­, ÀÌ ÇÔ¼ö¸¦ È£ÃâÇÑ´Ù.

void       gtk_widget_draw              (GtkWidget           *widget,
                                         GdkRectangle        *area);

ÀÌ°ÍÀº area¶ó´Â ÀÎÀÚ·Î ÁÖ¾îÁø ¿µ¿ªÀÌ ¾÷µ¥ÀÌÆ®µÇ¾î¾ß ÇÔÀ» X¿¡°Ô ¾Ë·ÁÁØ´Ù. °á±¹ X´Â expose À̺¥Æ®¸¦ ¹ß»ýÇÏ°í, ÀÌ°ÍÀº ¿ì¸®ÀÇ expose À̺¥Æ® Çڵ鷯°¡ °ü°èµÈ ¿µ¿ªÀ» ½ºÅ©¸° À§·Î º¹»çÇÏ°Ô²û ÇÒ °ÍÀÌ´Ù.

ÀÌÁ¦ ¿ì¸®´Â main À©µµ¸¦ ¸¸µå´Â °Í °°ÀÌ ÀϺΠÈçÇÑ Ç׸ñµéÀ» Á¦¿ÜÇÏ°í ÀÌ ±×¸®±â ÇÁ·Î±×·¥À» ¸ðµÎ »ìÆ캸¾Ò´Ù. ¿ÏÀüÇÑ ¼Ò½ºÄÚµå´Â ÀÌ ¹®¼­¸¦ ±¸ÇÑ °÷À̳ª ´ÙÀ½ À§Ä¡¿¡¼­ ±¸ÇÒ ¼ö ÀÖ´Ù.

http://www.msc.cornell.edu/~otaylor/gtk-gimp/tutorial

21.4 Input support¸¦ ´õÇϱâ

ÀÌÁ¦ drawing tablet °°ÀÌ, ±×´ÙÁö ºñ½ÎÁö ¾ÊÀ¸¸é¼­ ¸¶¿ì½ºº¸´Ù ÈξÀ ¿¹¼úÀûÀΠǥÇöÀ» ÆíÇÏ°Ô ±×¸± ¼ö ÀÖ°Ô ÇØÁÖ´Â ÀÔ·ÂÀåÄ¡(input device)¸¦ ±¸ÀÔÇÏ´Â °ÍÀÌ °¡´ÉÇÑ ½Ã´ë´Ù. ÀÌ·± ÀåÄ¡¸¦ ÀÌ¿ëÇÏ´Â °¡Àå °£´ÜÇÑ ¹æ¹ýÀÌ¾ß °£´ÜÈ÷ ¸¶¿ì½º¸¦ ´ëÄ¡ÇØ ¹ö¸®´Â °ÍÀÌ°ÚÁö¸¸, ÀÌ·² °æ¿ì ±×·± ÀÔ·ÂÀåÄ¡ÀÇ ´ÙÀ½°ú °°Àº ¸¹Àº ÀåÁ¡À» ÀÒ°Ô µÉ ¼öµµ ÀÖ´Ù.

XInput extension¿¡ ´ëÇÑ Á¤º¸¸¦ ¾òÀ¸·Á¸é XInput-HOWTO ¸¦ º¸¶ó. ¿¹¸¦µé¾î GdkEventMotion ±¸Á¶Ã¼ÀÇ Àüü Á¤ÀÇ°°Àº °É ºÁµµ, extended device¸¦ Áö¿øÇϱâ À§ÇÑ Çʵ带 °¡Áö°í ÀÖÀ½À» ¾Ë °ÍÀÌ´Ù.

struct _GdkEventMotion
{
        GdkEventType type;
        GdkWindow *window;
        guint32 time;
        gdouble x;
        gdouble y;
        gdouble pressure;
        gdouble xtilt;
        gdouble ytilt;
        guint state;
        gint16 is_hint;
        GdkInputSource source;
        guint32 deviceid;
};

pressure ÀÎÀÚ´Â 0°ú 1 »çÀÌÀÇ ºÎµ¿¼Ò¼öÁ¡¼ö·Î µÈ pressure¸¦ ÁØ´Ù. xtilt¿Í ytile´Â °¢ ¹æÇâÀ¸·ÎÀÇ tilt °¢µµ¿¡ ÇØ´çÇÏ´Â -1ºÎÅÍ 1 »çÀÌÀÇ °ªÀ» °¡Áú ¼ö ÀÖ´Ù. source¿Í deviceid ÀÎÀÚ´Â µÎ°¡Áö ´Ù¸¥ ¹æ½ÄÀ¸·Î ¹ß»ýÇÑ À̺¥Æ®¿¡ ´ëÇØ ÀåÄ¡(device)¸¦ ¼³Á¤ÇÑ´Ù. source´Â ÀåÄ¡ÀÇ Å¸ÀÔ¿¡ ´ëÇÑ °£´ÜÇÑ Á¤º¸¸¦ ÁØ´Ù. ÀÌ°ÍÀº ´ÙÀ½ÀÇ enumeration °ªµéÀ» °¡Áú ¼ö ÀÖ´Ù.

GDK_SOURCE_MOUSE
GDK_SOURCE_PEN
GDK_SOURCE_ERASER
GDK_SOURCE_CURSOR

deviceid´Â °¢ ÀåÄ¡¿¡ ´ëÇØ °íÀ¯ÀÇ ¼ýÀÚ ID¸¦ ¼³Á¤ÇÑ´Ù. ÀÌ°ÍÀº gdk_input_list_devices() ÇÔ¼ö·Î(µÚ¿¡ ³ª¿È) ±× ÀåÄ¡¿¡ ´ëÇÑ ´õ ¸¹Àº Á¤º¸¸¦ Á¶»çÇÏ°íÀÚ ÇÒ ¶§ ¾²ÀÏ ¼ö ÀÖ´Ù. Core pointer device(º¸Åë ¸¶¿ì½º)¿¡ ´ëÇØ Æ¯º°È÷ GDK_CORE_POINTER¶ó´Â »ó¼ö°ªÀÌ ¾²ÀδÙ.

Extended device Á¤º¸¸¦ »ç¿ë°¡´ÉÇÏ°Ô Çϱâ

GTK¿¡°Ô ¿ì¸®°¡ °ü½ÉÀ» °¡Áø extended deviceÀÇ Á¤º¸°¡ ¹«¾ùÀÎÁö ¾Ë·Á ÁÖ·Á¸é, ¿ì¸® ÇÁ·Î±×·¥¿¡ ´Ü ÇÑ ÁÙ¸¸ ´õÇØÁÖ¸é µÈ´Ù.

gtk_widget_set_extension_events (drawing_area, GDK_EXTENSION_EVENTS_CURSOR);

GDK_EXTENSION_EVENTS_CURSOR¶ó´Â °ªÀ» ÁÜÀ¸·Î½á ¿ì¸®´Â È®ÀåµÈ À̺¥Æ®µé¿¡ °ü½ÉÀÌ ÀÖÀ½À» ¾Ë¸°´Ù. ´Ü, À̶§ ¿ì¸®´Â »õ·Î Ä¿¼­¸¦ ±×·Á¼­´Â ¾ÈµÈ´Ù. Ä¿¼­¸¦ ±×¸®´Â ¹®Á¦¿¡ ´ëÇؼ­´Â µÚ¿¡ ³ª¿Ã º¹ÀâÇÑ ÀÌ¿ë ºÎºÐÀ» ÂüÁ¶Ç϶ó. ¿ì¸®°¡ ¿ì¸®¸¸ÀÇ Ä¿¼­¸¦ ±×¸®·Á ÇÑ´Ù¸é GDK_EXTENSION_EVENTS_ALLÀ» ¾²¸é µÇ°í, µðÆúÆ® ·Î µ¹¾Æ°¡·Á¸é GDK_EXTENSION_EVENTS_NONEÀ» ¾´´Ù.

À̾߱â´Â ÀÌ°ÍÀ¸·Î ³¡³ªÁö ¾Ê´Â´Ù. µðÆúÆ®·Î, extension device´Â disable µÇ¾î ÀÖ´Ù. ¿ì¸®´Â »ç¿ëÀÚ·Î ÇÏ¿©±Ý ±×µéÀÇ extension deviceµéÀ» enable½ÃÅ°°í ¼³Á¤ÇÒ ¼ö ÀÖ°Ô ÇØÁÖ´Â ¸ÅÄ¿´ÏÁòÀÌ ÇÊ¿äÇÏ´Ù. GTK´Â ÀÌ °úÁ¤À» ÀÚµ¿ÀûÀ¸·Î ÇØ ÁÖ´Â InputDialog widgetÀ» Á¦°øÇÑ´Ù. ´ÙÀ½°ú °°Àº °úÁ¤´ë·Î InputDialog widgetÀ» °ü¸®ÇÑ´Ù. ÀÌ°ÍÀº device°¡ Á¸ÀçÇÏÁö ¾ÊÀ¸¸é dialog·Î ¾Ë·ÁÁÖ°í, ³ª¸ÓÁö °æ¿ì¿£ topÀ¸·Î ¿Ã·Áº¸³½´Ù.

void
input_dialog_destroy (GtkWidget *w, gpointer data)
{
    *((GtkWidget **)data) = NULL;
}

void
create_input_dialog ()
{
    static GtkWidget *inputd = NULL;
    if (!inputd)
        {
            inputd = gtk_input_dialog_new();
            gtk_signal_connect (GTK_OBJECT(inputd), "destroy",
                               (GtkSignalFunc)input_dialog_destroy, &inputd);
            gtk_signal_connect_object 
            (GTK_OBJECT(GTK_INPUT_DIALOG(inputd)->close_button),
                     "clicked",
                     (GtkSignalFunc)gtk_widget_hide,
                     GTK_OBJECT(inputd));
            gtk_widget_hide ( GTK_INPUT_DIALOG(inputd)->save_button);
            gtk_widget_show (inputd);
        }
    else
        {
            if (!GTK_WIDGET_MAPPED(inputd))
                gtk_widget_show(inputd);
            else
                gdk_window_raise(inputd->window);
        }
}
(¿ì¸®°¡ ÀÌ dialog¸¦ ´Ù·ç´Â ¹æ¹ý¿¡ ÁÖÀǸ¦ ±â¿ï¿©¾ß ÇÒ °ÍÀÌ´Ù. "destroy" ½Ã±×³Î¿¡ ¿¬°á½ÃÄÑ µÎ´Â °ÍÀ¸·Î, ¿ì¸®´Â dialog°¡ Æı«µÈ ÀÌÈÄ Æ÷ÀÎÅ͸¦ dialog ¿¡ ³²°ÜµÎ´Â ½Ç¼ö - ÀÌ°ÍÀº Segfault(!)¸¦ ºÎ¸¥´Ù - ¸¦ ÇÇÇÒ ¼ö ÀÖ´Ù.)

InputDialog´Â "Close" ±×¸®°í "Save"¶ó´Â µÎ ¹öÆ°À» °¡Áö°í ÀÖÀ¸¸ç, µðÆúÆ® ·Î´Â ¾Æ¹«·± µ¿ÀÛÀÌ ¿¬°áµÇ¾î ÀÖÁö ¾Ê´Ù. À§¿¡¼­´Â "Close" ¹öÆ°À» dialog¸¦ °¨Ãߴµ¥ ½è°í, "Save" ¹öÆ°Àº °¨Ãß¾î ¹ö·È´Ù. ÀÌ ÇÁ·Î±×·¥¿¡¼­ XInputÀ» ÀúÀå ÇÏ´Â ¿É¼ÇÀ» °®ÃßÁö ¾Ê¾Ò±â ¶§¹®ÀÌ´Ù.

Extended device Á¤º¸¸¦ ÀÌ¿ëÇϱâ

ÀÏ´Ü ÀåÄ¡(device)¸¦ enable½ÃÄ×À¸¸é, ¿ì¸®´Â À̺¥Æ® ±¸Á¶Ã¼ÀÇ ³ª¸ÓÁö Çʵ忡 ÀÖ´Â extended deviceÀÇ Á¤º¸¸¦ ÀÌ¿ëÇÒ ¼ö ÀÖ´Ù. »ç½Ç, ÀÌ Á¤º¸¸¦ ÀÌ¿ëÇÏ´Â °Ç ¾ðÁ¦³ª ¾ÈÀüÇÏ´Ù. Extended event°¡ disableµÇ¾î ÀÖ´õ¶óµµ À̵éÀº ÀûÀýÇÑ µðÆúÆ®°ªÀ» °¡Áö°í Àֱ⠶§¹®ÀÌ´Ù.

ÇÑ °¡Áö ÁÖÀÇÇÒ °ÍÀº gdk_window_get_pointer() ´ë½Å¿¡ gdk_input_window_get_pointer()¸¦ È£ÃâÇÑ´Ù´Â °ÍÀÌ´Ù. ÀÌ°ÍÀº gdk_window_get_pointer°¡ extended device Á¤º¸¸¦ ¸®ÅÏÇÏÁö ¸øÇϱ⠶§¹®ÀÌ´Ù.

void gdk_input_window_get_pointer     (GdkWindow       *window,
                                     guint32         deviceid,
                                     gdouble         *x,
                                     gdouble         *y,
                                     gdouble         *pressure,
                                     gdouble         *xtilt,
                                     gdouble         *ytilt,
                                     GdkModifierType *mask);

ÀÌ ÇÔ¼ö¸¦ ºÎ¸¦ ¶§, À©µµÀÇ °æ¿ì¿Í ¸¶Âù°¡Áö·Î deviceÀÇ ID¸¦ ¸í½ÃÇØ Áà¾ß ÇÑ´Ù. º¸Åë, ¿ì¸®´Â device ID¸¦ event ±¸Á¶Ã¼ÀÇ deviceid Çʵå·ÎºÎÅÍ ÃëÇÒ °ÍÀÌ´Ù. ´Ù½Ã Çѹø, ÀÌ ÇÔ¼ö´Â extension event°¡ disableµÈ »óÅ¿¡¼­µµ ÇÕ´çÇÑ °ªÀ» ¸®ÅÏÇÔÀ» ±â¾ïÇÏÀÚ. (ÀÌ °æ¿ì¿£, event->deviceid´Â GDK_CORE_POINTER¶ó´Â °ªÀ» °¡Áú °ÍÀÌ´Ù.)

±×·¡¼­ ¿ì¸®ÀÇ button-press ¿Í motion À̺¥Æ® Çڵ鷯ÀÇ ±âº»ÀûÀÎ ±¸Á¶´Â ±×¸® º¯ÇÏÁö ¾Ê´Â´Ù - ¿ì¸° ´ÜÁö extended¿¡ ÇØ´çÇÏ´Â Á¤º¸¸¦ ´Ù·ê Äڵ带 Ãß°¡Çϱ⸸ ÇÏ¸é µÈ´Ù.

static gint
button_press_event (GtkWidget *widget, GdkEventButton *event)
{
    print_button_press (event->deviceid);
    if (event->button == 1 && pixmap != NULL)
        draw_brush (widget, event->source, event->x, event->y, event->pressure);
    return TRUE;
}

static gint
motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
{
    gdouble x, y;
    gdouble pressure;
    GdkModifierType state;
    if (event->is_hint)
        gdk_input_window_get_pointer (event->window, event->deviceid,
                            &x, &y, &pressure, NULL, NULL, &state);
    else
        {
            x = event->x;
            y = event->y;
            pressure = event->pressure;
            state = event->state;
        }
    if (state & GDK_BUTTON1_MASK && pixmap != NULL)
        draw_brush (widget, event->source, x, y, pressure);
    return TRUE;
}

¿ì¸° ¶ÇÇÑ »õ·Î¿î Á¤º¸¸¦ ÀÌ¿ëÇÏ´Â ÀÏÀ» ¹º°¡ ÇØ¾ß ÇÑ´Ù. ¿ì¸®ÀÇ draw_brush() ÇÔ¼ö´Â °¢ event->source¸¶´Ù ´Ù¸¥ »ö±ò·Î ±×¸± ¼ö ÀÖ°Ô ÇÏ°í, ±×¸®°í pressure¿¡ µû¶ó brushÀÇ Å©±â¸¦ º¯ÇÏ°Ô ÇÑ´Ù.

/* ½ºÅ©¸°¿¡ »ç°¢ÇüÀ» ±×¸°´Ù.  Å©±â´Â pressure¿¡ ÀÇÁ¸ÇÏ°í,
 * ±×¸®°í »ö±òÀº deviceÀÇ Å¸ÀÔ¿¡ ÀÇÁ¸ÇÑ´Ù. */
static void
draw_brush (GtkWidget *widget, GdkInputSource source,
            gdouble x, gdouble y, gdouble pressure)
{
    GdkGC *gc;
    GdkRectangle update_rect;
    switch (source)
        {
        case GDK_SOURCE_MOUSE:
            gc = widget->style->dark_gc[GTK_WIDGET_STATE (widget)];
            break;
        case GDK_SOURCE_PEN:
            gc = widget->style->black_gc;
            break;
        case GDK_SOURCE_ERASER:
            gc = widget->style->white_gc;
            break;
        default:
            gc = widget->style->light_gc[GTK_WIDGET_STATE (widget)];
        }
    update_rect.x = x - 10 * pressure;
    update_rect.y = y - 10 * pressure;
    update_rect.width = 20 * pressure;
    update_rect.height = 20 * pressure;
    gdk_draw_rectangle (pixmap, gc, TRUE,
                        update_rect.x, update_rect.y,
                        update_rect.width, update_rect.height);
    gtk_widget_draw (widget, &update_rect);
}

Device¿¡ ´ëÇØ ´õ ¸¹Àº °É ¾Ë¾Æ³»±â

Device¿¡ ´ëÇÑ Á¤º¸¸¦ ¾î¶»°Ô ´õ ¾Ë¾Æ³»´ÂÁö º¸¿©ÁÖ´Â ¿¹Á¦·Î¼­, ¿ì¸® ÇÁ·Î ±×·¥Àº °¢ ¹öÆ°À» ´©¸£¸é deviceÀÇ À̸§À» ÇÁ¸°Æ®ÇÒ °ÍÀÌ´Ù. DeviceÀÇ À̸§À» ¾Ë¾Æ³»±â À§ÇÏ¿© ÀÌ ÇÔ¼ö¸¦ ÀÌ¿ëÇÑ´Ù.

GList *gdk_input_list_devices               (void);

ÀÌ°ÍÀº GdkDeviceInfo ±¸Á¶Ã¼ÀÇ GList(glib ¶óÀ̺귯¸®¿¡¼­ ¿Â ¿¬°á¸®½ºÆ® ŸÀÔ)¸¦ ¸®ÅÏÇÑ´Ù. GdkDeviceInfo ±¸Á¶Ã¼´Â ÀÌ·¸°Ô Á¤ÀǵǾî ÀÖ´Ù.

struct _GdkDeviceInfo
{
        guint32 deviceid;
        gchar *name;
        GdkInputSource source;
        GdkInputMode mode;
        gint has_cursor;
        gint num_axes;
        GdkAxisUse *axes;
        gint num_keys;
        GdkDeviceKey *keys;
};

¿©±âÀÖ´Â ´ëºÎºÐÀÇ Çʵå´Â ¿©·¯ºÐÀÌ XInput ¼³Á¤À» ÀúÀåÇÏ´Â ±â´ÉÀ» Ãß°¡ÇÏÁö ¾Ê¾Ò´Ù¸é ¹«½ÃÇصµ ±¦ÂúÀº ¼³Á¤ Á¤º¸µéÀÌ´Ù. Áö±Ý ¿ì¸®°¡ °ü½ÉÀ» °¡Áø °ÍÀº ´Ü¼øÈ÷ X°¡ device¿¡ ºÎ¿©ÇÑ À̸§(name)ÀÌ´Ù. ¼³Á¤(configuration)Çʵ忡 ÇØ´çÇÏÁö ¾Ê´Â °ÍÀº has_cursorÀÌ´Ù. ±×·±µ¥ ¿ì¸®´Â GDK_EXTENSION_EVENTS_CURSOR¸¦ ¼³Á¤ÇßÀ¸¹Ç·Î, ÀÌ Çʵ忡 ´ëÇؼ­´Â °ÆÁ¤ÇÏÁö ¸»ÀÚ.

print_button_press() ÇÔ¼ö´Â ¸ÅÄ¡µÇ´Â ¸®½ºÆ®¸¦ ¸®ÅÏÇÒ ¶§±îÁö ´Ü¼øÈ÷ ¹Ýº¹µÉ °ÍÀ̸ç, deviceÀÇ À̸§À» ÇÁ¸°Æ®ÇØ ÁÙ °ÍÀÌ´Ù.

static void
print_button_press (guint32 deviceid)
{
        GList *tmp_list;
        /* gdk_input_list_devices´Â ³»ºÎÀûÀÎ ¸®½ºÆ®¸¦ ¸®ÅÏÇϸç,
         * µû¶ó¼­ ¿ì¸®´Â ÈÄ¿¡ ÀÌ°ÍÀ» ÇØÁ¦ÇØ ÁÖÁö ¾ÊÀ» °ÍÀÌ´Ù. */
        tmp_list = gdk_input_list_devices();
        while (tmp_list)
                {
                        GdkDeviceInfo *info = (GdkDeviceInfo *)tmp_list->data;
                        if (info->deviceid == deviceid)
                                {
                                        printf("Button press on device '%s'\n", info->name);
                                        return;
                                }
                        tmp_list = tmp_list->next;
                }
}

ÀÌ°ÍÀ¸·Î ¿ì¸®ÀÇ ``XInputize'' ÇÁ·Î±×·¥À» ¿ÏÀüÈ÷ º¯°æÇß´Ù. ù ¹öÁ¯°ú ¸¶Âù°¡Áö·Î ÀÌ°ÍÀÇ ¿ÏÀüÇÑ ¼Ò½º ÄÚµå´Â ÀÌ ¹®¼­¸¦ ±¸ÇÑ °÷À̳ª ´ÙÀ½ À§Ä¡¿¡¼­ ±¸ÇÒ ¼ö ÀÖ´Ù.

http://www.msc.cornell.edu/~otaylor/gtk-gimp/tutorial

´õ º¹ÀâÇÑ ÀÌ¿ë

ºñ·Ï ¿ì¸® ÇÁ·Î±×·¥ÀÌ ÀÌÁ¦ XInputÀ» ²Ï Àß Áö¿øÇÔ¿¡µµ ºÒ±¸ÇÏ°í, ¾îÇà ÀüüÀû À¸·Î ºÁ¼­ ¹º°¡ ºÎÁ·ÇØ º¸ÀÌ´Â ¸éµµ ÀÖ´Ù. ¸ÕÀú, »ç¿ëÀÚ´Â ÇÁ·Î±×·¥À» ½ÇÇàÇÒ ¶§¸¶´Ù ±×µéÀÇ ÀåÄ¡µéÀ» ¼³Á¤ÇÏ·Á°í ÇÏÁø ¾ÊÀ» °ÍÀ̹ǷÎ, ¿ì¸®´Â ±× ÀåÄ¡µéÀÇ ¼³Á¤À» ÀúÀåÇÒ ¼ö ÀÖµµ·Ï ÇØÁà¾ß ÇÑ´Ù. ÀÌ°ÍÀº gdk_input_list_devices()ÀÇ ¸®ÅÏÀ» µÇÇ®ÀÌÇÏ°í, ¼³Á¤À» ÆÄÀÏ¿¡ ±â·Ï(write)ÇÏ´Â °ÍÀ¸·Î ÀÌ·ç¾îÁø´Ù.

ÇÁ·Î±×·¥ÀÌ ´ÙÀ½ ¹ø ½ÇÇàµÉ ¶§ ÇöÀçÀÇ state¸¦ º¹±¸ÇØ ÁÖ±â À§Çؼ­, GDK´Â device ¼³Á¤¿¡ ´ëÇÑ ´ÙÀ½ ÇÔ¼öµéÀ» Á¦°øÇÑ´Ù.

gdk_input_set_extension_events()
gdk_input_set_source()
gdk_input_set_mode()
gdk_input_set_axes()
gdk_input_set_key()

(gdk_input_list_devices()°¡ ¸®ÅÏÇÑ ¸®½ºÆ®´Â Á¤È®È÷ º¯°æµÇÁö ¾ÊÀ» ¼ö ÀÖ´Ù.) ÀÌ°Í¿¡ ´ëÇÑ ¿¹Á¦´Â ±×¸®±â ÇÁ·Î±×·¥ÀÎ Gsumi( http://www.msc.cornell.edu/~otaylor/gsumi/¿¡ ÀÖ´Ù.)°¡ µÉ °ÍÀÌ´Ù. °á±¹, ¸ðµç ¾îÇõ鿡 ´ëÇØ ÀÌ ¸ñÀûÀ¸·Î Ç¥ÁØÀûÀÎ ¹æ½ÄÀ» °¡Áú ¼ö ÀÖ´Ù¸é ¸ÚÁø ÀÏÀÌ µÉ °ÍÀÌ´Ù. ÀÌ°ÍÀº ¾Æ¸¶ GNOME ¶óÀ̺귯¸®°¡ GTKº¸´Ù ¾à°£ ³ôÀº ·¹º§¿¡ ¼ÓÇÒ °ÍÀÌ´Ù.

¿ì¸®°¡ ¾Õ¿¡¼­ ´Ù·é °Í¿¡¼­ ºüÁø ¶ÇÇϳª Áß¿äÇÑ °ÍÀº cursor¿¡ ´ëÇÑ °ÍÀÌ´Ù. XFree86°ú ´Ù¸¥ Ç÷§ÆûµéÀº ÇöÀç·Î¼­´Â µ¿½Ã¿¡ µÑÀ» - Core pointer, ±×¸®°í ¾îÇÿ¡ ÀÇÇÑ Á÷Á¢ÀûÀÎ Á¶ÀÛ - »ç¿ëÇÏ¿© ÀåÄ¡¸¦ ´Ù·ê ¼ö ¾ø´Ù. ÀÌ°Í¿¡ ´ëÇØ ´õ ÀÚ¼¼ÇÑ Á¤º¸´Â XInput-HOWTO¸¦ º¸¶ó. ÀÌ°ÍÀº ÃÖ´ëÇÑÀÇ ÀÌ¿ëÀÚ¸¦ È®º¸ÇÏ·Á´Â ¾îÇÃÀ̶ó¸é ÀڽŸ¸ÀÇ Ä¿¼­¸¦ ±×·ÁÁÖ´Â °Ô ÇÊ¿äÇÔÀ» ÀǹÌÇÑ´Ù.

ÀڽŸ¸ÀÇ Ä¿¼­¸¦ ±×¸®´Â ¾îÇÃÀº ´ÙÀ½ÀÇ µÎ ÀÏÀ» ÇØ¾ß ÇÑ´Ù. ù°·Î ÇöÀçÀÇ ÀåÄ¡°¡ ±×·ÁÁø Ä¿¼­¸¦ ÇÊ¿ä·Î ÇÏ´ÂÁöÀÇ ¿©ºÎ¸¦ °áÁ¤ÇÏ°í, µÑ°·Î ÇöÀçÀÇ ÀåÄ¡°¡ Á¢±Ù(proximity)µÇ¾î ÀÖ´ÂÁöÀÇ ¿©ºÎ¸¦ °áÁ¤ÇÑ´Ù. (ÇöÀçÀÇ ÀåÄ¡°¡ drawing tabletÀÏ °æ¿ì, stylus°¡ tablet¿¡¼­ ¶³¾îÁ³À» ¶§ Ä¿¼­°¡ º¸ÀÌÁö ¾Ê°Ô ÇÏ´Â °ÍÀÌ ÁÁÀ» °ÍÀÌ´Ù. ÀåÄ¡°¡ stylus¿Í ºÙ¾î ÀÖÀ» ¶§, À̸¦ Á¢±ÙµÇ¾ú´Ù(in proximity)°í Ç¥ÇöÇÑ´Ù.) ù¹ø° ÀÛ¾÷Àº ¿ì¸®°¡ deviceÀÇ À̸§À» ¾Ë¾Æ³»±â À§ÇØ ÇßµíÀÌ, deviceÀÇ ¸®½ºÆ®¸¦ Á¶»ç ÇÔÀ¸·Î½á ÇØ°áµÈ´Ù. µÎ¹ø° ÀÛ¾÷Àº "proximity_out" À̺¥Æ®¸¦ ¼³Á¤ÇÔÀ¸·Î½á ÇØ°áÇÑ´Ù. °¢ÀÚÀÇ Ä¿¼­¸¦ ±×¸®´Â ¿¹Á¦´Â GTK ¹èÆ÷ÆÇ¿¡ ÀÖ´Â 'testinput' ÇÁ·Î ±×·¥¿¡¼­ ãÀ» ¼ö ÀÖÀ» °ÍÀÌ´Ù.


´ÙÀ½ ÀÌÀü Â÷·Ê