From fa0e71e0ee22ec9401732d9ac8b3c1d1fd9d2c31 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 29 Nov 2006 20:59:18 +1100 Subject: Add mouse enter/leave events for pixmaps/windows. The current "target" is the one under the mouse and also receives mouse movements and button down events. However, once the button has been pressed in a window, all subsequent mouse events will be sent to that window (and no mouse leave will be generated) until the button has been released. Signed-off-by: Benjamin Herrenschmidt --- twin.h | 34 +++++++++++++++++-------- twin_screen.c | 80 +++++++++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 82 insertions(+), 32 deletions(-) diff --git a/twin.h b/twin.h index b7fbe5b..c2603c6 100644 --- a/twin.h +++ b/twin.h @@ -159,9 +159,10 @@ typedef struct _twin_screen { */ twin_pixmap_t *active; /* - * pointer down for this window + * this pixmap is target of mouse events */ - twin_pixmap_t *pointer; + twin_pixmap_t *target; + twin_bool_t clicklock; /* * mouse image (optional) */ @@ -317,14 +318,27 @@ extern twin_font_t twin_Default_Font_Roman; */ typedef enum _twin_event_kind { - TwinEventButtonDown, TwinEventButtonUp, TwinEventMotion, - TwinEventKeyDown, TwinEventKeyUp, TwinEventUcs4, - TwinEventActivate, TwinEventDeactivate, - TwinEventPaint, - TwinEventShow, - TwinEventQueryGeometry, - TwinEventConfigure, - TwinEventDestroy, + /* Mouse */ + TwinEventButtonDown = 0x0001, + TwinEventButtonUp = 0x0002, + TwinEventMotion = 0x0003, + TwinEventEnter = 0x0004, + TwinEventLeave = 0x0005, + + /* keyboard */ + TwinEventKeyDown = 0x0101, + TwinEventKeyUp = 0x0102, + TwinEventUcs4 = 0x0103, + + /* Focus */ + TwinEventActivate = 0x0201, + TwinEventDeactivate = 0x0202, + + /* Widgets */ + TwinEventPaint = 0x1001, + TwinEventQueryGeometry = 0x1002, + TwinEventConfigure = 0x1003, + TwinEventDestroy = 0x1004, } twin_event_kind_t; typedef struct _twin_event { diff --git a/twin_screen.c b/twin_screen.c index 8de8007..b2cc6dd 100644 --- a/twin_screen.c +++ b/twin_screen.c @@ -323,44 +323,80 @@ twin_screen_update_cursor(twin_screen_t *screen, } } -twin_bool_t -twin_screen_dispatch (twin_screen_t *screen, - twin_event_t *event) +static void _twin_adj_mouse_evt(twin_event_t *event, twin_pixmap_t *pixmap) +{ + event->u.pointer.x = event->u.pointer.screen_x - pixmap->x; + event->u.pointer.y = event->u.pointer.screen_y - pixmap->y; +} + +twin_bool_t twin_screen_dispatch (twin_screen_t *screen, + twin_event_t *event) { - twin_pixmap_t *pixmap; + twin_pixmap_t *pixmap, *ntarget; switch (event->kind) { case TwinEventMotion: case TwinEventButtonDown: case TwinEventButtonUp: + /* update mouse cursor */ twin_screen_update_cursor(screen, event->u.pointer.screen_x, event->u.pointer.screen_y); - pixmap = screen->pointer; - if (!pixmap) - { - for (pixmap = screen->top; pixmap; pixmap = pixmap->down) - if (!twin_pixmap_transparent (pixmap, - event->u.pointer.screen_x, - event->u.pointer.screen_y)) - { - break; - } - if (event->kind == TwinEventButtonDown) - screen->pointer = pixmap; - } + + /* if target is tracking the mouse, check for mouse up, if not, + * just pass the event along + */ + pixmap = screen->target; + if (screen->clicklock && event->kind != TwinEventButtonUp) + goto mouse_passup; + + /* if event is mouse up, stop tracking if any */ if (event->kind == TwinEventButtonUp) - screen->pointer = NULL; - if (pixmap) - { - event->u.pointer.x = event->u.pointer.screen_x - pixmap->x; - event->u.pointer.y = event->u.pointer.screen_y - pixmap->y; + screen->clicklock = 0; + + /* check who the mouse is over now */ + for (ntarget = screen->top; ntarget; ntarget = ntarget->down) + if (!twin_pixmap_transparent (ntarget, + event->u.pointer.screen_x, + event->u.pointer.screen_y)) + break; + + /* ah, somebody new ... send leave/enter events and set new target */ + if (pixmap != ntarget) { + twin_event_t evt; + + if (pixmap) { + evt = *event; + evt.kind = TwinEventLeave; + _twin_adj_mouse_evt (&evt, pixmap); + twin_pixmap_dispatch (pixmap, &evt); + } + + pixmap = screen->target = ntarget; + + if (pixmap) { + evt = *event; + _twin_adj_mouse_evt (&evt, pixmap); + evt.kind = TwinEventEnter; + twin_pixmap_dispatch (pixmap, &evt); + } } + + /* check for new click locking */ + if (pixmap && event->kind == TwinEventButtonDown) + screen->clicklock = 1; + + mouse_passup: + /* adjust event to pixmap coordinates before passing up */ + if (pixmap) + _twin_adj_mouse_evt (event, pixmap); break; + case TwinEventKeyDown: case TwinEventKeyUp: case TwinEventUcs4: pixmap = screen->active; break; + default: pixmap = NULL; break; -- cgit v1.2.3