diff options
author | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2008-12-10 07:36:33 +0300 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2008-12-10 07:36:33 +0300 |
commit | 4a9ee46c1446603bf67b37e9970ddbbc1320fb73 (patch) | |
tree | 8afaaab719f3890c3cf00f4fb5c8843374e8ebde /source/blender/windowmanager | |
parent | b205ec4f18b704edc63f914cefc2d16b2784803a (diff) |
UI: don't use operators anymore for handling user interface events, but rather
a special UI handler which makes the code clearer. This UI handler is attached
to the region along with other handlers, and also gets a callback when all
handlers for the region are removed to ensure things are properly cleaned up.
This should fix XXX's in the UI code related to events and context switching.
Most of the changes are in interface_handlers.c, which was renamed from
interface_ops.c, to convert operators to the UI handler. UI code notes:
* uiBeginBlock/uiEndBlock/uiFreeBlocks now takes a context argument, this is
required to properly cancel things like timers or tooltips when the region
gets removed.
* UI_add_region_handlers will add the region level UI handlers, to be used
when adding keymap handlers etc. This replaces the UI keymap.
* When the UI code starts a modal interaction (number sliding, text editing,
opening a menu, ..), it will add an UI handler at the window level which
will block events.
Windowmanager changes:
* Added an UI handler next to the existing keymap and operator modal handlers.
It has an event handling and remove callback, and like operator modal handlers
will remember the area and region if it is registered at the window level.
* Removed the MESSAGE event.
* Operator cancel and UI handler remove callbacks now get the
window/area/region restored in the context, like the operator modal and UI
handler event callbacks.
* Regions now receive MOUSEMOVE events for the mouse going outside of the
region. This was already happening for areas, but UI buttons are at the region
level so we need it there.
Issues:
* Tooltips and menus stay open when switching to another window, and button
highlight doesn't work without moving the mouse first when Blender starts up.
I tried using some events like Q_FIRSTTIME, WINTHAW, but those don't seem to
arrive..
* Timeline header buttons seem to be moving one pixel or so sometimes when
interacting with them.
* Seems not due to this commit, but UI and keymap handlers are leaking. It
seems that handlers are being added to regions in all screens, also in regions
of areas that are not visible, but these handlers are not removed. Probably
there should only be handlers in visible regions?
Diffstat (limited to 'source/blender/windowmanager')
-rw-r--r-- | source/blender/windowmanager/WM_api.h | 8 | ||||
-rw-r--r-- | source/blender/windowmanager/WM_types.h | 9 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_event_system.c | 119 | ||||
-rw-r--r-- | source/blender/windowmanager/wm_event_system.h | 16 | ||||
-rw-r--r-- | source/blender/windowmanager/wm_event_types.h | 2 |
5 files changed, 103 insertions, 51 deletions
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 9dbb4c46947..2f53545f544 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -74,11 +74,13 @@ ListBase *WM_keymap_listbase (wmWindowManager *wm, const char *nameid, struct wmEventHandler *WM_event_add_keymap_handler(ListBase *handlers, ListBase *keymap); void WM_event_remove_keymap_handler(ListBase *handlers, ListBase *keymap); +struct wmEventHandler *WM_event_add_ui_handler(bContext *C, ListBase *handlers, + int (*func)(bContext *C, struct wmEvent *event), void (*remove)(bContext *C)); +void WM_event_remove_ui_handler(ListBase *handlers); + struct wmEventHandler *WM_event_add_modal_handler(bContext *C, ListBase *handlers, wmOperator *op); -void WM_event_remove_handlers (bContext *C, ListBase *handlers); +void WM_event_remove_handlers(bContext *C, ListBase *handlers); -void WM_event_add_message(wmWindowManager *wm, void *customdata, - short customdatafree); void WM_event_add_mousemove(bContext *C); void WM_event_add_notifier(bContext *C, int type, int value, void *data); diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index be0fbb4fca6..c8ca8195db0 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -86,8 +86,15 @@ typedef struct wmEvent { #define KM_RELEASE 0 #define KM_PRESS 1 +/* ************** UI Handler ***************** */ -/* ************** notifiers ****************** */ +#define WM_UI_HANDLER_CONTINUE 0 +#define WM_UI_HANDLER_BREAK 1 + +typedef int (*wmUIHandlerFunc)(bContext *C, struct wmEvent *event); +typedef void (*wmUIHandlerRemoveFunc)(bContext *C); + +/* ************** Notifiers ****************** */ typedef struct wmNotifier { struct wmNotifier *prev, *next; diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 9d71688fd77..94df7abfed9 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -337,11 +337,35 @@ void WM_event_remove_handlers(bContext *C, ListBase *handlers) while((handler=handlers->first)) { BLI_remlink(handlers, handler); - if(C && handler->op) { - if(handler->op->type->cancel) + if(handler->op) { + if(handler->op->type->cancel) { + ScrArea *area= C->area; + ARegion *region= C->region; + + C->area= handler->op_area; + C->region= handler->op_region; + handler->op->type->cancel(C, handler->op); + + C->area= area; + C->region= region; + } + wm_operator_free(handler->op); } + else if(handler->ui_remove) { + ScrArea *area= C->area; + ARegion *region= C->region; + + if(handler->ui_area) C->area= handler->ui_area; + if(handler->ui_region) C->region= handler->ui_region; + + handler->ui_remove(C); + + C->area= area; + C->region= region; + } + wm_event_free_handler(handler); MEM_freeN(handler); } @@ -428,10 +452,32 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand return WM_HANDLER_BREAK; } +static int wm_handler_ui_call(bContext *C, wmEventHandler *handler, wmEvent *event) +{ + ScrArea *area= C->area; + ARegion *region= C->region; + int retval; + + /* we set context to where ui handler came from */ + if(handler->ui_area) C->area= handler->ui_area; + if(handler->ui_region) C->region= handler->ui_region; + + retval= handler->ui_handle(C, event); + + /* putting back screen context */ + C->area= area; + C->region= region; + + if(retval == WM_UI_HANDLER_BREAK) + return WM_HANDLER_BREAK; + + return WM_HANDLER_CONTINUE; +} + static int wm_event_always_pass(wmEvent *event) { /* some events we always pass on, to ensure proper communication */ - return (event->type == TIMER || event->type == MESSAGE); + return (event->type == TIMER); } static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) @@ -465,6 +511,9 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) } } } + else if(handler->ui_handle) { + action= wm_handler_ui_call(C, handler, event); + } else { /* modal, swallows all */ action= wm_handler_operator_call(C, handlers, handler, event); @@ -543,26 +592,6 @@ void wm_event_do_handlers(bContext *C) action= wm_handlers_do(C, event, &win->handlers); - /* modal menus in Blender use (own) regions linked to screen */ - if(wm_event_always_pass(event) || action==WM_HANDLER_CONTINUE) { - ARegion *ar; - - /* region are in drawing order, i.e. frontmost region last so - * we handle events in the opposite order last to first */ - for(ar=win->screen->regionbase.last; ar; ar= ar->prev) { - if(wm_event_always_pass(event) || wm_event_inside_i(event, &ar->winrct)) { - C->region= ar; - wm_handlers_do(C, event, &ar->handlers); - C->region= NULL; - - if(!wm_event_always_pass(event)) { - action= WM_HANDLER_BREAK; - break; - } - } - } - } - if(wm_event_always_pass(event) || action==WM_HANDLER_CONTINUE) { ScrArea *sa; ARegion *ar; @@ -576,7 +605,7 @@ void wm_event_do_handlers(bContext *C) if(wm_event_always_pass(event) || action==WM_HANDLER_CONTINUE) { for(ar=sa->regionbase.first; ar; ar= ar->next) { - if(wm_event_always_pass(event) || wm_event_inside_i(event, &ar->winrct)) { + if(wm_event_always_pass(event) || wm_event_inside_i(event, &ar->winrct) || wm_event_prev_inside_i(event, &ar->winrct)) { C->region= ar; action= wm_handlers_do(C, event, &ar->handlers); C->region= NULL; @@ -616,13 +645,13 @@ void WM_event_set_handler_flag(wmEventHandler *handler, int flag) wmEventHandler *WM_event_add_modal_handler(bContext *C, ListBase *handlers, wmOperator *op) { - wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event handler"); + wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event modal handler"); handler->op= op; handler->op_area= C->area; /* means frozen screen context for modal handlers! */ handler->op_region= C->region; BLI_addhead(handlers, handler); - + return handler; } @@ -635,7 +664,7 @@ wmEventHandler *WM_event_add_keymap_handler(ListBase *handlers, ListBase *keymap if(handler->keymap==keymap) return handler; - handler= MEM_callocN(sizeof(wmEventHandler), "event handler"); + handler= MEM_callocN(sizeof(wmEventHandler), "event keymap handler"); BLI_addtail(handlers, handler); handler->keymap= keymap; @@ -656,21 +685,30 @@ void WM_event_remove_keymap_handler(ListBase *handlers, ListBase *keymap) } } -void WM_event_add_message(wmWindowManager *wm, void *customdata, short customdatafree) +wmEventHandler *WM_event_add_ui_handler(bContext *C, ListBase *handlers, wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove) { - wmEvent event; - wmWindow *win; - - for(win=wm->windows.first; win; win=win->next) { - event= *(win->eventstate); + wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event ui handler"); + handler->ui_handle= func; + handler->ui_remove= remove; + handler->ui_area= (C)? C->area: NULL; + handler->ui_region= (C)? C->region: NULL; + + BLI_addhead(handlers, handler); + + return handler; +} - event.type= MESSAGE; - if(customdata) { - event.custom= EVT_DATA_MESSAGE; - event.customdata= customdata; - event.customdatafree= customdatafree; +void WM_event_remove_ui_handler(ListBase *handlers) +{ + wmEventHandler *handler; + + for(handler= handlers->first; handler; handler= handler->next) { + if(handler->ui_handle) { + BLI_remlink(handlers, handler); + wm_event_free_handler(handler); + MEM_freeN(handler); + break; } - wm_event_add(win, &event); } } @@ -678,8 +716,9 @@ void WM_event_add_mousemove(bContext *C) { wmEvent event= *(C->window->eventstate); event.type= MOUSEMOVE; + event.prevx= event.x; + event.prevy= event.y; wm_event_add(C->window, &event); - } /* ********************* ghost stuff *************** */ diff --git a/source/blender/windowmanager/wm_event_system.h b/source/blender/windowmanager/wm_event_system.h index 0c37c56778f..61670388879 100644 --- a/source/blender/windowmanager/wm_event_system.h +++ b/source/blender/windowmanager/wm_event_system.h @@ -40,15 +40,21 @@ struct ARegion; typedef struct wmEventHandler { struct wmEventHandler *next, *prev; - int type, flag; /* type default=0, rest is custom */ + int type, flag; /* type default=0, rest is custom */ - ListBase *keymap; /* pointer to builtin/custom keymaps */ + /* keymap handler */ + ListBase *keymap; /* pointer to builtin/custom keymaps */ - rctf boundbox; /* float, in bContext space (window, area, region) */ - - wmOperator *op; /* for derived/modal handlers */ + /* modal operator handler */ + wmOperator *op; /* for derived/modal handlers */ struct ScrArea *op_area; /* for derived/modal handlers */ struct ARegion *op_region; /* for derived/modal handlers */ + + /* ui handler */ + wmUIHandlerFunc ui_handle; /* callback receiving events */ + wmUIHandlerRemoveFunc ui_remove; /* callback when handler is removed */ + struct ScrArea *ui_area; /* for derived/modal handlers */ + struct ARegion *ui_region; /* for derived/modal handlers */ } wmEventHandler; diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h index 265132eacf9..87c9e3cb2db 100644 --- a/source/blender/windowmanager/wm_event_types.h +++ b/source/blender/windowmanager/wm_event_types.h @@ -39,7 +39,6 @@ #define EVT_DATA_TABLET 1 #define EVT_DATA_GESTURE 2 #define EVT_DATA_TIMER 3 -#define EVT_DATA_MESSAGE 4 #define MOUSEX 0x004 #define MOUSEY 0x005 @@ -69,7 +68,6 @@ #define WINQUIT 0x0108 /* signal from user that app is to go away */ #define Q_FIRSTTIME 0x0109 /* on startup */ #define TIMER 0x0110 /* timer event */ -#define MESSAGE 0x0111 /* message event */ /* standard keyboard */ |