diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index 2d515aafc13..aa09a0a7ba7 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -2676,8 +2676,11 @@ static void button_activate_init(bContext *C, ARegion *ar, wmOperator *op, uiBut if(but->block->auto_open_last+BUTTON_AUTO_OPEN_THRESH < PIL_check_seconds_timer()) but->block->auto_open= 0; - /* modal handler */ - WM_event_add_modal_handler(C, &C->window->handlers, op); + if(but->block->flag & UI_BLOCK_LOOP) + WM_event_add_modal_handler(C, &C->window->handlers, op); + else + /* regular button handler on area, handles mouse-exit in WM */ + WM_event_add_modal_handler(C, &C->area->handlers, op); button_activate_state(C, but, BUTTON_STATE_HIGHLIGHT); @@ -2791,19 +2794,19 @@ static int button_activate_try_exit(bContext *C, wmOperator *op, wmEvent *event) ARegion *ar; uiActivateBut *data; uiBut *but; - int state= OPERATOR_FINISHED; data= op->customdata; ar= data->region; but= ui_but_find_activated(data->region, data, NULL); - /* exit the current button, but try to re-init as well */ + /* exit the current button */ button_activate_exit(C, op->customdata, op); - /* XXX re-init has to be done differently... */ - /* XXX state= button_activate_try_init(C, ar, op, event, but); */ + + /* adds empty mousemove in queue for re-init operator (if mouse is still over button) */ + WM_event_add_mousemove(C); - return (state != OPERATOR_RUNNING_MODAL); + return 1; } static int button_activate_invoke(bContext *C, wmOperator *op, wmEvent *event) @@ -2837,10 +2840,8 @@ static int button_activate_modal(bContext *C, wmOperator *op, wmEvent *event) /* check if the button dissappeared somehow */ if(!(but= ui_but_find_activated(data->region, data, &block))) { data->cancel= 1; - if(button_activate_try_exit(C, op, event)) - return OPERATOR_CANCELLED|OPERATOR_PASS_THROUGH; - else - return OPERATOR_RUNNING_MODAL|OPERATOR_PASS_THROUGH; + button_activate_try_exit(C, op, event); + return OPERATOR_CANCELLED|OPERATOR_PASS_THROUGH; } if(data->state == BUTTON_STATE_HIGHLIGHT) { diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 095f6e1a74b..ef8b47a368f 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -278,13 +278,17 @@ static int screen_cursor_test(bContext *C, wmOperator *op, wmEvent *event) } else { WM_set_cursor(C, CURSOR_X_MOVE); } - } else { + return OPERATOR_FINISHED; + } + else { ScrArea *sa= NULL; AZone *az= NULL; + for(sa= C->screen->areabase.first; sa; sa= sa->next) { az= is_in_area_actionzone(sa, event->x, event->y); if(az!=NULL) break; } + if(az!=NULL) WM_set_cursor(C, CURSOR_EDIT); else WM_set_cursor(C, CURSOR_STD); } diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 4b9c01b3e33..509056bfe71 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -75,6 +75,7 @@ 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(wmWindowManager *wm, wmWindow *window, int swinid, int type, diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index 35dad1f0db2..be0fbb4fca6 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -47,7 +47,8 @@ typedef struct wmEvent { short type; /* event code itself (short, is also in keymap) */ short val; /* press, release, scrollvalue */ - short x, y; /* mouse pointer position */ + short x, y; /* mouse pointer position */ + short prevx, prevy; /* previous mouse pointer position */ short unicode; /* future, ghost? */ char ascii; /* from ghost */ char pad1; diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 9432036b4bc..85cf0786403 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -326,7 +326,6 @@ void WM_event_remove_handlers(bContext *C, ListBase *handlers) /* C is zero on freeing database, modal handlers then already were freed */ while((handler=handlers->first)) { - /* we have to remove the handler first, to prevent op->type->cancel() to remove modal handler too */ BLI_remlink(handlers, handler); if(C && handler->op) { @@ -473,18 +472,30 @@ static int wm_event_inside_i(wmEvent *event, rcti *rect) return BLI_in_rcti(rect, event->x, event->y); } +static int wm_event_prev_inside_i(wmEvent *event, rcti *rect) +{ + if(BLI_in_rcti(rect, event->x, event->y)) + return 1; + if(event->type==MOUSEMOVE) { + if( BLI_in_rcti(rect, event->prevx, event->prevy)) { + return 1; + } + return 0; + } + return 0; +} + static ScrArea *area_event_inside(bContext *C, wmEvent *event) { ScrArea *sa; if(C->screen) for(sa= C->screen->areabase.first; sa; sa= sa->next) - if(wm_event_inside_i(event, &sa->totrct)) + if(BLI_in_rcti(&sa->totrct, event->x, event->y)) return sa; return NULL; } - /* called in main loop */ /* goes over entire hierarchy: events -> window -> screen -> area -> region */ void wm_event_do_handlers(bContext *C) @@ -503,10 +514,10 @@ void wm_event_do_handlers(bContext *C) C->window= win; C->screen= win->screen; C->area= area_event_inside(C, event); - + /* MVC demands to not draw in event handlers... for now we leave it */ wm_window_make_drawable(C, win); - + action= wm_handlers_do(C, event, &win->handlers); /* modal menus in Blender use (own) regions linked to screen */ @@ -532,9 +543,11 @@ void wm_event_do_handlers(bContext *C) if(wm_event_always_pass(event) || action==WM_HANDLER_CONTINUE) { ScrArea *sa; ARegion *ar; + int doit= 0; for(sa= win->screen->areabase.first; sa; sa= sa->next) { - if(wm_event_always_pass(event) || wm_event_inside_i(event, &sa->totrct)) { + if(wm_event_always_pass(event) || wm_event_prev_inside_i(event, &sa->totrct)) { + doit= 1; C->area= sa; action= wm_handlers_do(C, event, &sa->handlers); @@ -546,24 +559,26 @@ void wm_event_do_handlers(bContext *C) C->region= NULL; if(!wm_event_always_pass(event)) { - action= WM_HANDLER_BREAK; - break; + if(action==WM_HANDLER_BREAK) + break; } } } } C->area= NULL; - - if(!wm_event_always_pass(event)) { - action= WM_HANDLER_BREAK; - break; - } + /* NOTE: do not escape on WM_HANDLER_BREAK, mousemove needs handled for previous area */ } } + /* XXX hrmf, this gives reliable previous mouse coord for area change, feels bad? + doing it on ghost queue gives errors when mousemoves go over area borders */ + if(doit) { + C->window->eventstate->prevx= event->x; + C->window->eventstate->prevy= event->y; + } } wm_event_free(event); - + C->window= NULL; C->screen= NULL; } @@ -643,6 +658,14 @@ void WM_event_add_message(wmWindowManager *wm, void *customdata, short customdat } } +void WM_event_add_mousemove(bContext *C) +{ + wmEvent event= *(C->window->eventstate); + event.type= MOUSEMOVE; + wm_event_add(C->window, &event); + +} + /* ********************* ghost stuff *************** */ static int convert_key(GHOST_TKey key) diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index fb8101168e2..3346f0607a9 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -164,6 +164,7 @@ void WM_exit(bContext *C) /* modal handlers are on window level freed, others too? */ if(C && C->wm) { for(win= C->wm->windows.first; win; win= win->next) { + ScrArea *sa; ARegion *ar; C->window= win; /* needed by operator close callbacks */ @@ -171,6 +172,12 @@ void WM_exit(bContext *C) for(ar= win->screen->regionbase.first; ar; ar= ar->next) WM_event_remove_handlers(C, &ar->handlers); + + for(sa= win->screen->areabase.first; sa; sa= sa->next) { + WM_event_remove_handlers(C, &sa->handlers); + for(ar= sa->regionbase.first; ar; ar= ar->next) + WM_event_remove_handlers(C, &ar->handlers); + } } } wm_operatortype_free();