5 button mouse support from b333rt in IRC with some edits for X11.
[blender.git] / source / blender / windowmanager / intern / wm_event_system.c
index f5c8e53500286ad565e8677f9bc6319d71138007..ebb7adc3cd51ed869f237223d81df6e6aa15ea72 100644 (file)
 #include "BKE_report.h"
 #include "BKE_scene.h"
 #include "BKE_utildefines.h"
+#include "BKE_pointcache.h"
 
 #include "ED_fileselect.h"
+#include "ED_info.h"
 #include "ED_screen.h"
 #include "ED_space_api.h"
 #include "ED_util.h"
@@ -76,7 +78,7 @@ void wm_event_add(wmWindow *win, wmEvent *event_to_add)
        BLI_addtail(&win->queue, event);
 }
 
-static void wm_event_free(wmEvent *event)
+void wm_event_free(wmEvent *event)
 {
        if(event->customdata && event->customdatafree)
                MEM_freeN(event->customdata);
@@ -128,7 +130,7 @@ static wmNotifier *wm_notifier_next(wmWindowManager *wm)
 void wm_event_do_notifiers(bContext *C)
 {
        wmWindowManager *wm= CTX_wm_manager(C);
-       wmNotifier *note;
+       wmNotifier *note, *next;
        wmWindow *win;
        
        if(wm==NULL)
@@ -140,7 +142,9 @@ void wm_event_do_notifiers(bContext *C)
                
                CTX_wm_window_set(C, win);
                
-               for(note= wm->queue.first; note; note= note->next) {
+               for(note= wm->queue.first; note; note= next) {
+                       next= note->next;
+
                        if(note->category==NC_WM) {
                                if( ELEM(note->data, ND_FILEREAD, ND_FILESAVE)) {
                                        wm->file_saved= 1;
@@ -155,16 +159,28 @@ void wm_event_do_notifiers(bContext *C)
                                                ED_screen_set(C, note->reference);      // XXX hrms, think this over!
                                                printf("screen set %p\n", note->reference);
                                        }
+                                       else if(note->data==ND_SCREENDELETE) {
+                                               ED_screen_delete(C, note->reference);   // XXX hrms, think this over!
+                                               printf("screen delete %p\n", note->reference);
+                                       }
                                }
                                else if(note->category==NC_SCENE) {
                                        if(note->data==ND_SCENEBROWSE) {
                                                ED_screen_set_scene(C, note->reference);        // XXX hrms, think this over!
                                                printf("scene set %p\n", note->reference);
                                        }
+                                       if(note->data==ND_SCENEDELETE) {
+                                               ED_screen_delete_scene(C, note->reference);     // XXX hrms, think this over!
+                                               printf("scene delete %p\n", note->reference);
+                                       }
                                        else if(note->data==ND_FRAME)
                                                do_anim= 1;
                                }
                        }
+                       if(ELEM4(note->category, NC_SCENE, NC_OBJECT, NC_GEOM, NC_SCENE)) {
+                               ED_info_stats_clear(CTX_data_scene(C));
+                               WM_event_add_notifier(C, NC_SPACE|ND_SPACE_INFO, NULL);
+                       }
                }
                if(do_anim) {
                        /* depsgraph gets called, might send more notifiers */
@@ -234,6 +250,8 @@ void wm_event_do_notifiers(bContext *C)
                        for(base= scene->base.first; base; base= base->next) {
                                object_handle_update(scene, base->object);
                        }
+
+                       BKE_ptcache_quick_cache_all(scene);
                }               
        }
        CTX_wm_window_set(C, NULL);
@@ -241,6 +259,26 @@ void wm_event_do_notifiers(bContext *C)
 
 /* ********************* operators ******************* */
 
+int WM_operator_poll(bContext *C, wmOperatorType *ot)
+{
+       wmOperatorTypeMacro *otmacro;
+       
+       for(otmacro= ot->macro.first; otmacro; otmacro= otmacro->next) {
+               wmOperatorType *ot= WM_operatortype_find(otmacro->idname, 0);
+               
+               if(0==WM_operator_poll(C, ot))
+                       return 0;
+       }
+       
+       /* python needs operator type, so we added exception for it */
+       if(ot->pyop_poll)
+               return ot->pyop_poll(C, ot);
+       else if(ot->poll)
+               return ot->poll(C);
+
+       return 1;
+}
+
 /* if repeat is true, it doesn't register again, nor does it free */
 static int wm_operator_exec(bContext *C, wmOperator *op, int repeat)
 {
@@ -249,7 +287,7 @@ static int wm_operator_exec(bContext *C, wmOperator *op, int repeat)
        if(op==NULL || op->type==NULL)
                return retval;
        
-       if(op->type->poll && op->type->poll(C)==0)
+       if(0==WM_operator_poll(C, op->type))
                return retval;
        
        if(op->type->exec)
@@ -264,8 +302,8 @@ static int wm_operator_exec(bContext *C, wmOperator *op, int repeat)
                        ED_undo_push_op(C, op);
                
                if(repeat==0) {
-                       if(op->type->flag & OPTYPE_REGISTER)
-                               wm_operator_register(CTX_wm_manager(C), op);
+                       if((op->type->flag & OPTYPE_REGISTER) || (G.f & G_DEBUG))
+                               wm_operator_register(C, op);
                        else
                                WM_operator_free(op);
                }
@@ -310,11 +348,31 @@ static wmOperator *wm_operator_create(wmWindowManager *wm, wmOperatorType *ot, P
 
        /* initialize error reports */
        if (reports) {
-               op->reports= reports; /* must be initialized alredy */
+               op->reports= reports; /* must be initialized already */
        }
        else {
                op->reports= MEM_mallocN(sizeof(ReportList), "wmOperatorReportList");
-               BKE_reports_init(op->reports, RPT_STORE);
+               BKE_reports_init(op->reports, RPT_STORE|RPT_FREE);
+       }
+       
+       /* recursive filling of operator macro list */
+       if(ot->macro.first) {
+               static wmOperator *motherop= NULL;
+               wmOperatorTypeMacro *otmacro;
+               
+               /* ensure all ops are in execution order in 1 list */
+               if(motherop==NULL) 
+                       motherop= op;
+               
+               for(otmacro= ot->macro.first; otmacro; otmacro= otmacro->next) {
+                       wmOperatorType *otm= WM_operatortype_find(otmacro->idname, 0);
+                       wmOperator *opm= wm_operator_create(wm, otm, otmacro->ptr, NULL);
+                       
+                       BLI_addtail(&motherop->macro, opm);
+                       opm->opm= motherop; /* pointer to mom, for modal() */
+               }
+               
+               motherop= NULL;
        }
        
        return op;
@@ -322,7 +380,7 @@ static wmOperator *wm_operator_create(wmWindowManager *wm, wmOperatorType *ot, P
 
 static void wm_operator_print(wmOperator *op)
 {
-       char *buf = WM_operator_pystring(op);
+       char *buf = WM_operator_pystring(NULL, op->type, op->ptr, 1);
        printf("%s\n", buf);
        MEM_freeN(buf);
 }
@@ -337,13 +395,13 @@ static void wm_region_mouse_co(bContext *C, wmEvent *event)
        }
 }
 
-static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, PointerRNA *properties)
+static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, PointerRNA *properties, ReportList *reports)
 {
        wmWindowManager *wm= CTX_wm_manager(C);
        int retval= OPERATOR_PASS_THROUGH;
 
-       if(ot->poll==NULL || ot->poll(C)) {
-               wmOperator *op= wm_operator_create(wm, ot, properties, NULL);
+       if(WM_operator_poll(C, ot)) {
+               wmOperator *op= wm_operator_create(wm, ot, properties, reports); /* if reports==NULL, theyll be initialized */
                
                if((G.f & G_DEBUG) && event && event->type!=MOUSEMOVE)
                        printf("handle evt %d win %d op %s\n", event?event->type:0, CTX_wm_screen(C)->subwinactive, ot->idname); 
@@ -370,23 +428,29 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, P
                        if(ot->flag & OPTYPE_UNDO)
                                ED_undo_push_op(C, op);
                        
-                       if(ot->flag & OPTYPE_REGISTER)
-                               wm_operator_register(wm, op);
+                       if((ot->flag & OPTYPE_REGISTER) || (G.f & G_DEBUG))
+                               wm_operator_register(C, op);
                        else
                                WM_operator_free(op);
                }
-               else if(!(retval & OPERATOR_RUNNING_MODAL)) {
-                       WM_operator_free(op);
+               else if(retval & OPERATOR_RUNNING_MODAL) {
+                       /* grab cursor during blocking modal ops (X11) */
+                       if(ot->flag & OPTYPE_BLOCKING)
+                               WM_cursor_grab(CTX_wm_window(C), 1);
                }
+               else
+                       WM_operator_free(op);
        }
 
        return retval;
 }
 
-/* invokes operator in context */
-int WM_operator_name_call(bContext *C, const char *opstring, int context, PointerRNA *properties)
+/* WM_operator_name_call is the main accessor function
+ * this is for python to access since its done the operator lookup
+ * 
+ * invokes operator in context */
+static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, int context, PointerRNA *properties, ReportList *reports)
 {
-       wmOperatorType *ot= WM_operatortype_find(opstring);
        wmWindow *window= CTX_wm_window(C);
        wmEvent *event;
        
@@ -414,7 +478,7 @@ int WM_operator_name_call(bContext *C, const char *opstring, int context, Pointe
                                                CTX_wm_region_set(C, ar1);
                                }
                                
-                               retval= wm_operator_invoke(C, ot, event, properties);
+                               retval= wm_operator_invoke(C, ot, event, properties, reports);
                                
                                /* set region back */
                                CTX_wm_region_set(C, ar);
@@ -429,7 +493,7 @@ int WM_operator_name_call(bContext *C, const char *opstring, int context, Pointe
                                ARegion *ar= CTX_wm_region(C);
 
                                CTX_wm_region_set(C, NULL);
-                               retval= wm_operator_invoke(C, ot, event, properties);
+                               retval= wm_operator_invoke(C, ot, event, properties, reports);
                                CTX_wm_region_set(C, ar);
 
                                return retval;
@@ -444,7 +508,7 @@ int WM_operator_name_call(bContext *C, const char *opstring, int context, Pointe
 
                                CTX_wm_region_set(C, NULL);
                                CTX_wm_area_set(C, NULL);
-                               retval= wm_operator_invoke(C, ot, window->eventstate, properties);
+                               retval= wm_operator_invoke(C, ot, event, properties, reports);
                                CTX_wm_region_set(C, ar);
                                CTX_wm_area_set(C, area);
 
@@ -453,32 +517,51 @@ int WM_operator_name_call(bContext *C, const char *opstring, int context, Pointe
                        case WM_OP_EXEC_DEFAULT:
                                event= NULL;    /* pass on without break */
                        case WM_OP_INVOKE_DEFAULT:
-                               return wm_operator_invoke(C, ot, event, properties);
+                               return wm_operator_invoke(C, ot, event, properties, reports);
                }
        }
        
        return 0;
 }
 
+
+/* invokes operator in context */
+int WM_operator_name_call(bContext *C, const char *opstring, int context, PointerRNA *properties)
+{
+       wmOperatorType *ot= WM_operatortype_find(opstring, 0);
+       if(ot)
+               return wm_operator_call_internal(C, ot, context, properties, NULL);
+
+       return 0;
+}
+
 /* Similar to WM_operator_name_call called with WM_OP_EXEC_DEFAULT context.
    - wmOperatorType is used instead of operator name since python alredy has the operator type
    - poll() must be called by python before this runs.
    - reports can be passed to this function (so python can report them as exceptions)
 */
-int WM_operator_call_py(bContext *C, wmOperatorType *ot, PointerRNA *properties, ReportList *reports)
+int WM_operator_call_py(bContext *C, wmOperatorType *ot, int context, PointerRNA *properties, ReportList *reports)
 {
-       wmWindowManager *wm=    CTX_wm_manager(C);
-       wmOperator *op=                 wm_operator_create(wm, ot, properties, reports);
        int retval= OPERATOR_CANCELLED;
-       
+
+#if 0
+       wmOperator *op;
+       wmWindowManager *wm=    CTX_wm_manager(C);
+       op= wm_operator_create(wm, ot, properties, reports);
+
        if (op->type->exec)
                retval= op->type->exec(C, op);
        else
                printf("error \"%s\" operator has no exec function, python cannot call it\n", op->type->name);
+#endif
+
+       retval= wm_operator_call_internal(C, ot, context, properties, reports);
        
-       if (reports)
-               op->reports= NULL; /* dont let the operator free reports passed to this function */
-       WM_operator_free(op);
+       /* keep the reports around if needed later */
+       if (retval & OPERATOR_RUNNING_MODAL || ot->flag & OPTYPE_REGISTER)
+       {
+               reports->flag |= RPT_FREE;
+       }
        
        return retval;
 }
@@ -506,8 +589,12 @@ static void wm_handler_op_context(bContext *C, wmEventHandler *handler)
                        for(sa= screen->areabase.first; sa; sa= sa->next)
                                if(sa==handler->op_area)
                                        break;
-                       if(sa==NULL)
-                               printf("internal error: handler (%s) has invalid area\n", handler->op->type->idname);
+                       if(sa==NULL) {
+                               /* when changing screen layouts with running modal handlers (like render display), this
+                                  is not an error to print */
+                               if(handler->op==NULL)
+                                       printf("internal error: handler (%s) has invalid area\n", handler->op->type->idname);
+                       }
                        else {
                                ARegion *ar;
                                CTX_wm_area_set(C, sa);
@@ -545,6 +632,7 @@ void WM_event_remove_handlers(bContext *C, ListBase *handlers)
                        }
 
                        WM_operator_free(handler->op);
+                       WM_cursor_grab(CTX_wm_window(C), 0);
                }
                else if(handler->ui_remove) {
                        ScrArea *area= CTX_wm_area(C);
@@ -614,9 +702,23 @@ static int wm_eventmatch(wmEvent *winevent, wmKeymapItem *kmi)
 {
        int kmitype= wm_userdef_event_map(kmi->type);
 
+       if(kmi->inactive) return 0;
+
+       /* exception for middlemouse emulation */
+       if((U.flag & USER_TWOBUTTONMOUSE) && (kmi->type == MIDDLEMOUSE)) {
+               if(winevent->type == LEFTMOUSE && winevent->alt) {
+                       wmKeymapItem tmp= *kmi;
+
+                       tmp.type= winevent->type;
+                       tmp.alt= winevent->alt;
+                       if(wm_eventmatch(winevent, &tmp))
+                               return 1;
+               }
+       }
+
        /* the matching rules */
        if(kmitype==KM_TEXTINPUT)
-               if(ISKEYBOARD(winevent->type)) return 1;
+               if(ISKEYBOARD(winevent->type) && winevent->ascii) return 1;
        if(kmitype!=KM_ANY)
                if(winevent->type!=kmitype) return 0;
        
@@ -632,8 +734,15 @@ static int wm_eventmatch(wmEvent *winevent, wmKeymapItem *kmi)
                if(winevent->alt != kmi->alt && !(winevent->alt & kmi->alt)) return 0;
        if(kmi->oskey!=KM_ANY)
                if(winevent->oskey != kmi->oskey && !(winevent->oskey & kmi->oskey)) return 0;
+       
        if(kmi->keymodifier)
                if(winevent->keymodifier!=kmi->keymodifier) return 0;
+               
+       /* key modifiers always check when event has it */
+       /* otherwise regular keypresses with keymodifier still work */
+       if(winevent->keymodifier)
+               if(ISKEYBOARD(winevent->type)) 
+                       if(winevent->keymodifier!=kmi->keymodifier) return 0;
        
        return 1;
 }
@@ -644,6 +753,22 @@ static int wm_event_always_pass(wmEvent *event)
        return ELEM5(event->type, TIMER, TIMER0, TIMER1, TIMER2, TIMERJOBS);
 }
 
+/* operator exists */
+static void wm_event_modalkeymap(wmOperator *op, wmEvent *event)
+{
+       if(op->type->modalkeymap) {
+               wmKeymapItem *kmi;
+               
+               for(kmi= op->type->modalkeymap->keymap.first; kmi; kmi= kmi->next) {
+                       if(wm_eventmatch(event, kmi)) {
+                                       
+                               event->type= EVT_MODAL_MAP;
+                               event->val= kmi->propvalue;
+                       }
+               }
+       }
+}
+
 /* Warning: this function removes a modal handler, when finished */
 static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHandler *handler, wmEvent *event, PointerRNA *properties)
 {
@@ -660,8 +785,9 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand
                        ARegion *region= CTX_wm_region(C);
                        
                        wm_handler_op_context(C, handler);
-                       
                        wm_region_mouse_co(C, event);
+                       wm_event_modalkeymap(op, event);
+                       
                        retval= ot->modal(C, op, event);
 
                        /* putting back screen context, reval can pass trough after modal failures! */
@@ -688,8 +814,8 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand
                                if(ot->flag & OPTYPE_UNDO)
                                        ED_undo_push_op(C, op);
                                
-                               if(ot->flag & OPTYPE_REGISTER)
-                                       wm_operator_register(CTX_wm_manager(C), op);
+                               if((ot->flag & OPTYPE_REGISTER) || (G.f & G_DEBUG))
+                                       wm_operator_register(C, op);
                                else
                                        WM_operator_free(op);
                                handler->op= NULL;
@@ -701,6 +827,8 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand
                        
                        /* remove modal handler, operator itself should have been cancelled and freed */
                        if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) {
+                               WM_cursor_grab(CTX_wm_window(C), 0);
+
                                BLI_remlink(handlers, handler);
                                wm_event_free_handler(handler);
                                
@@ -713,10 +841,10 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand
                        printf("wm_handler_operator_call error\n");
        }
        else {
-               wmOperatorType *ot= WM_operatortype_find(event->keymap_idname);
+               wmOperatorType *ot= WM_operatortype_find(event->keymap_idname, 0);
 
                if(ot)
-                       retval= wm_operator_invoke(C, ot, event, properties);
+                       retval= wm_operator_invoke(C, ot, event, properties, NULL);
        }
 
        if(retval & OPERATOR_PASS_THROUGH)
@@ -730,17 +858,20 @@ static int wm_handler_ui_call(bContext *C, wmEventHandler *handler, wmEvent *eve
        ScrArea *area= CTX_wm_area(C);
        ARegion *region= CTX_wm_region(C);
        ARegion *menu= CTX_wm_menu(C);
-       int retval;
+       int retval, always_pass;
                        
        /* we set context to where ui handler came from */
        if(handler->ui_area) CTX_wm_area_set(C, handler->ui_area);
        if(handler->ui_region) CTX_wm_region_set(C, handler->ui_region);
        if(handler->ui_menu) CTX_wm_menu_set(C, handler->ui_menu);
 
+       /* in advance to avoid access to freed event on window close */
+       always_pass= wm_event_always_pass(event);
+
        retval= handler->ui_handle(C, event, handler->ui_userdata);
 
        /* putting back screen context */
-       if((retval != WM_UI_HANDLER_BREAK) || wm_event_always_pass(event)) {
+       if((retval != WM_UI_HANDLER_BREAK) || always_pass) {
                CTX_wm_area_set(C, area);
                CTX_wm_region_set(C, region);
                CTX_wm_menu_set(C, menu);
@@ -772,10 +903,7 @@ static int wm_handler_fileselect_call(bContext *C, ListBase *handlers, wmEventHa
        switch(event->val) {
                case EVT_FILESELECT_OPEN: 
                case EVT_FILESELECT_FULL_OPEN: 
-                       {
-                               short flag =0; short display =FILE_SHORTDISPLAY; short filter =0; short sort =FILE_SORTALPHA;
-                               char *path= RNA_string_get_alloc(handler->op->ptr, "filename", NULL, 0);
-                                       
+                       {       
                                if(event->val==EVT_FILESELECT_OPEN)
                                        ED_area_newspace(C, handler->op_area, SPACE_FILE);
                                else
@@ -784,18 +912,8 @@ static int wm_handler_fileselect_call(bContext *C, ListBase *handlers, wmEventHa
                                /* settings for filebrowser, sfile is not operator owner but sends events */
                                sfile= (SpaceFile*)CTX_wm_space_data(C);
                                sfile->op= handler->op;
-                               
-                               /* XXX for now take the settings from the existing (previous) filebrowser 
-                                  should be stored in settings and passed via the operator */
-                               if (sfile->params) {
-                                       flag = sfile->params->flag;
-                                       filter = sfile->params->filter;
-                                       display = sfile->params->display;
-                                       sort = sfile->params->sort;
-                               }
 
-                               ED_fileselect_set_params(sfile, handler->op->type->name, path, flag, display, filter, sort);
-                               MEM_freeN(path);
+                               ED_fileselect_set_params(sfile);
                                
                                action= WM_HANDLER_BREAK;
                        }
@@ -806,7 +924,7 @@ static int wm_handler_fileselect_call(bContext *C, ListBase *handlers, wmEventHa
                        {
                                /* XXX validate area and region? */
                                bScreen *screen= CTX_wm_screen(C);
-                               char *path= RNA_string_get_alloc(handler->op->ptr, "filename", NULL, 0);
+                               char *path= RNA_string_get_alloc(handler->op->ptr, "path", NULL, 0);
                                
                                if(screen != handler->filescreen)
                                        ED_screen_full_prevspace(C);
@@ -857,10 +975,22 @@ static int handler_boundbox_test(wmEventHandler *handler, wmEvent *event)
                if(handler->bblocal) {
                        rcti rect= *handler->bblocal;
                        BLI_translate_rcti(&rect, handler->bbwin->xmin, handler->bbwin->ymin);
-                       return BLI_in_rcti(&rect, event->x, event->y);
+
+                       if(BLI_in_rcti(&rect, event->x, event->y))
+                               return 1;
+                       else if(event->type==MOUSEMOVE && BLI_in_rcti(&rect, event->prevx, event->prevy))
+                               return 1;
+                       else
+                               return 0;
+               }
+               else {
+                       if(BLI_in_rcti(handler->bbwin, event->x, event->y))
+                               return 1;
+                       else if(event->type==MOUSEMOVE && BLI_in_rcti(handler->bbwin, event->prevx, event->prevy))
+                               return 1;
+                       else
+                               return 0;
                }
-               else 
-                       return BLI_in_rcti(handler->bbwin, event->x, event->y);
        }
        return 1;
 }
@@ -869,6 +999,7 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
 {
        wmEventHandler *handler, *nexthandler;
        int action= WM_HANDLER_CONTINUE;
+       int always_pass;
 
        if(handlers==NULL) return action;
        
@@ -878,22 +1009,27 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
 
                /* optional boundbox */
                if(handler_boundbox_test(handler, event)) {
+                       /* in advance to avoid access to freed event on window close */
+                       always_pass= wm_event_always_pass(event);
                
                        /* modal+blocking handler */
                        if(handler->flag & WM_HANDLER_BLOCKING)
                                action= WM_HANDLER_BREAK;
 
                        if(handler->keymap) {
+                               wmKeyMap *keymap= handler->keymap;
                                wmKeymapItem *kmi;
                                
-                               for(kmi= handler->keymap->first; kmi; kmi= kmi->next) {
-                                       if(wm_eventmatch(event, kmi)) {
-                                               
-                                               event->keymap_idname= kmi->idname;      /* weak, but allows interactive callback to not use rawkey */
-                                               
-                                               action= wm_handler_operator_call(C, handlers, handler, event, kmi->ptr);
-                                               if(action==WM_HANDLER_BREAK)  /* not wm_event_always_pass(event) here, it denotes removed handler */
-                                                       break;
+                               if(!keymap->poll || keymap->poll(C)) {
+                                       for(kmi= keymap->keymap.first; kmi; kmi= kmi->next) {
+                                               if(wm_eventmatch(event, kmi)) {
+                                                       
+                                                       event->keymap_idname= kmi->idname;      /* weak, but allows interactive callback to not use rawkey */
+                                                       
+                                                       action= wm_handler_operator_call(C, handlers, handler, event, kmi->ptr);
+                                                       if(action==WM_HANDLER_BREAK)  /* not always_pass here, it denotes removed handler */
+                                                               break;
+                                               }
                                        }
                                }
                        }
@@ -909,8 +1045,12 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
                                action= wm_handler_operator_call(C, handlers, handler, event, NULL);
                        }
 
-                       if(!wm_event_always_pass(event) && action==WM_HANDLER_BREAK)
-                               break;
+                       if(action==WM_HANDLER_BREAK) {
+                               if(always_pass)
+                                       action= WM_HANDLER_CONTINUE;
+                               else
+                                       break;
+                       }
                }
                
                /* fileread case */
@@ -922,6 +1062,8 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
 
 static int wm_event_inside_i(wmEvent *event, rcti *rect)
 {
+       if(wm_event_always_pass(event))
+               return 1;
        if(BLI_in_rcti(rect, event->x, event->y))
           return 1;
        if(event->type==MOUSEMOVE) {
@@ -1023,58 +1165,70 @@ void wm_event_do_handlers(bContext *C)
                        /* MVC demands to not draw in event handlers... but we need to leave it for ogl selecting etc */
                        wm_window_make_drawable(C, win);
                        
-                       action= wm_handlers_do(C, event, &win->handlers);
+                       /* first we do priority handlers, modal + some limited keymaps */
+                       action= wm_handlers_do(C, event, &win->modalhandlers);
                        
                        /* fileread case */
-                       if(CTX_wm_window(C)==NULL) {
+                       if(CTX_wm_window(C)==NULL)
                                return;
-                       }
                        
                        /* builtin tweak, if action is break it removes tweak */
-                       if(!wm_event_always_pass(event))
-                               wm_tweakevent_test(C, event, action);
+                       wm_tweakevent_test(C, event, action);
                        
-                       if(wm_event_always_pass(event) || action==WM_HANDLER_CONTINUE) {
+                       if(action==WM_HANDLER_CONTINUE) {
                                ScrArea *sa;
                                ARegion *ar;
                                int doit= 0;
                                
                                /* XXX to solve, here screen handlers? */
-                               if(!wm_event_always_pass(event)) {
-                                       if(event->type==MOUSEMOVE) {
-                                               /* state variables in screen, cursors */
-                                               ED_screen_set_subwinactive(win, event); 
-                                               /* for regions having custom cursors */
-                                               wm_paintcursor_test(C, event);
-                                       }
+                               if(event->type==MOUSEMOVE) {
+                                       /* state variables in screen, cursors */
+                                       ED_screen_set_subwinactive(win, event); 
+                                       /* for regions having custom cursors */
+                                       wm_paintcursor_test(C, event);
                                }
                                
                                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_inside_i(event, &sa->totrct)) {
                                                CTX_wm_area_set(C, sa);
-                                               CTX_wm_region_set(C, NULL);
-                                               action= wm_handlers_do(C, event, &sa->handlers);
 
-                                               if(wm_event_always_pass(event) || action==WM_HANDLER_CONTINUE) {
+                                               if(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_inside_i(event, &ar->winrct)) {
                                                                        CTX_wm_region_set(C, ar);
                                                                        action= wm_handlers_do(C, event, &ar->handlers);
 
                                                                        doit |= (BLI_in_rcti(&ar->winrct, event->x, event->y));
                                                                        
-                                                                       if(!wm_event_always_pass(event)) {
-                                                                               if(action==WM_HANDLER_BREAK)
-                                                                                       break;
-                                                                       }
+                                                                       if(action==WM_HANDLER_BREAK)
+                                                                               break;
                                                                }
                                                        }
                                                }
+
+                                               CTX_wm_region_set(C, NULL);
+
+                                               if(action==WM_HANDLER_CONTINUE)
+                                                       action= wm_handlers_do(C, event, &sa->handlers);
+
+                                               CTX_wm_area_set(C, NULL);
+
                                                /* NOTE: do not escape on WM_HANDLER_BREAK, mousemove needs handled for previous area */
                                        }
                                }
                                
+                               if(action==WM_HANDLER_CONTINUE) {
+                                       /* also some non-modal handlers need active area/region */
+                                       CTX_wm_area_set(C, area_event_inside(C, event->x, event->y));
+                                       CTX_wm_region_set(C, region_event_inside(C, event->x, event->y));
+
+                                       action= wm_handlers_do(C, event, &win->handlers);
+
+                                       /* fileread case */
+                                       if(CTX_wm_window(C)==NULL)
+                                               return;
+                               }
+
                                /* 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 && win->screen->subwinactive != win->screen->mainwin) {
@@ -1121,7 +1275,7 @@ void WM_event_fileselect_event(bContext *C, void *ophandle, int eventval)
        }
 }
 
-/* operator is supposed to have a filled "filename" property */
+/* operator is supposed to have a filled "path" property */
 /* optional property: filetype (XXX enum?) */
 
 /* Idea is to keep a handler alive on window queue, owning the operator.
@@ -1141,7 +1295,7 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op)
        handler->op_region= CTX_wm_region(C);
        handler->filescreen= CTX_wm_screen(C);
        
-       BLI_addhead(&win->handlers, handler);
+       BLI_addhead(&win->modalhandlers, handler);
        
        WM_event_fileselect_event(C, op, full?EVT_FILESELECT_FULL_OPEN:EVT_FILESELECT_OPEN);
 }
@@ -1152,22 +1306,38 @@ void WM_event_set_handler_flag(wmEventHandler *handler, int flag)
        handler->flag= flag;
 }
 
-wmEventHandler *WM_event_add_modal_handler(bContext *C, ListBase *handlers, wmOperator *op)
+wmEventHandler *WM_event_add_modal_handler(bContext *C, wmOperator *op)
 {
        wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event modal handler");
-       handler->op= op;
+       wmWindow *win= CTX_wm_window(C);
+       
+       /* operator was part of macro */
+       if(op->opm) {
+               /* give the mother macro to the handler */
+               handler->op= op->opm;
+               /* mother macro opm becomes the macro element */
+               handler->op->opm= op;
+       }
+       else
+               handler->op= op;
+       
        handler->op_area= CTX_wm_area(C);               /* means frozen screen context for modal handlers! */
        handler->op_region= CTX_wm_region(C);
        
-       BLI_addhead(handlers, handler);
+       BLI_addhead(&win->modalhandlers, handler);
 
        return handler;
 }
 
-wmEventHandler *WM_event_add_keymap_handler(ListBase *handlers, ListBase *keymap)
+wmEventHandler *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
 {
        wmEventHandler *handler;
 
+       if(!keymap) {
+               printf("WM_event_add_keymap_handler called with NULL keymap\n");
+               return NULL;
+       }
+
        /* only allow same keymap once */
        for(handler= handlers->first; handler; handler= handler->next)
                if(handler->keymap==keymap)
@@ -1181,7 +1351,7 @@ wmEventHandler *WM_event_add_keymap_handler(ListBase *handlers, ListBase *keymap
 }
 
 /* priorities not implemented yet, for time being just insert in begin of list */
-wmEventHandler *WM_event_add_keymap_handler_priority(ListBase *handlers, ListBase *keymap, int priority)
+wmEventHandler *WM_event_add_keymap_handler_priority(ListBase *handlers, wmKeyMap *keymap, int priority)
 {
        wmEventHandler *handler;
        
@@ -1194,7 +1364,7 @@ wmEventHandler *WM_event_add_keymap_handler_priority(ListBase *handlers, ListBas
        return handler;
 }
 
-wmEventHandler *WM_event_add_keymap_handler_bb(ListBase *handlers, ListBase *keymap, rcti *bblocal, rcti *bbwin)
+wmEventHandler *WM_event_add_keymap_handler_bb(ListBase *handlers, wmKeyMap *keymap, rcti *bblocal, rcti *bbwin)
 {
        wmEventHandler *handler= WM_event_add_keymap_handler(handlers, keymap);
        
@@ -1205,7 +1375,7 @@ wmEventHandler *WM_event_add_keymap_handler_bb(ListBase *handlers, ListBase *key
        return handler;
 }
 
-void WM_event_remove_keymap_handler(ListBase *handlers, ListBase *keymap)
+void WM_event_remove_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
 {
        wmEventHandler *handler;
        
@@ -1358,10 +1528,10 @@ static void update_tablet_data(wmWindow *win, wmEvent *event)
        const GHOST_TabletData *td= GHOST_GetTabletData(win->ghostwin);
        
        /* if there's tablet data from an active tablet device then add it */
-       if ((td != NULL) && td->Active) {
+       if ((td != NULL) && td->Active != GHOST_kTabletModeNone) {
                struct wmTabletData *wmtab= MEM_mallocN(sizeof(wmTabletData), "customdata tablet");
                
-               wmtab->Active = td->Active;
+               wmtab->Active = (int)td->Active;
                wmtab->Pressure = td->Pressure;
                wmtab->Xtilt = td->Xtilt;
                wmtab->Ytilt = td->Ytilt;
@@ -1409,14 +1579,13 @@ void wm_event_add_ghostevent(wmWindow *win, int type, void *customdata)
                                event.type= LEFTMOUSE;
                        else if (bd->button == GHOST_kButtonMaskRight)
                                event.type= RIGHTMOUSE;
+                       else if (bd->button == GHOST_kButtonMaskButton4)
+                               event.type= BUTTON4MOUSE;
+                       else if (bd->button == GHOST_kButtonMaskButton5)
+                               event.type= BUTTON5MOUSE;
                        else
                                event.type= MIDDLEMOUSE;
                        
-                       if(event.val)
-                               event.keymodifier= evt->keymodifier= event.type;
-                       else
-                               event.keymodifier= evt->keymodifier= 0;
-                       
                        update_tablet_data(win, &event);
                        wm_event_add(win, &event);
                        
@@ -1428,7 +1597,7 @@ void wm_event_add_ghostevent(wmWindow *win, int type, void *customdata)
                        GHOST_TEventKeyData *kd= customdata;
                        event.type= convert_key(kd->key);
                        event.ascii= kd->ascii;
-                       event.val= (type==GHOST_kEventKeyDown); /* XXX eventmatch uses defines, bad code... */
+                       event.val= (type==GHOST_kEventKeyDown)?KM_PRESS:KM_RELEASE;
                        
                        /* exclude arrow keys, esc, etc from text input */
                        if(type==GHOST_kEventKeyUp || (event.ascii<32 && event.ascii>14))
@@ -1436,30 +1605,36 @@ void wm_event_add_ghostevent(wmWindow *win, int type, void *customdata)
                        
                        /* modifiers */
                        if (event.type==LEFTSHIFTKEY || event.type==RIGHTSHIFTKEY) {
-                               event.shift= evt->shift= event.val;
-                               if(event.val && (evt->ctrl || evt->alt || evt->oskey))
+                               event.shift= evt->shift= (event.val==KM_PRESS);
+                               if(event.val==KM_PRESS && (evt->ctrl || evt->alt || evt->oskey))
                                   event.shift= evt->shift = 3;         // define?
                        } 
                        else if (event.type==LEFTCTRLKEY || event.type==RIGHTCTRLKEY) {
-                               event.ctrl= evt->ctrl= event.val;
-                               if(event.val && (evt->shift || evt->alt || evt->oskey))
+                               event.ctrl= evt->ctrl= (event.val==KM_PRESS);
+                               if(event.val==KM_PRESS && (evt->shift || evt->alt || evt->oskey))
                                   event.ctrl= evt->ctrl = 3;           // define?
                        } 
                        else if (event.type==LEFTALTKEY || event.type==RIGHTALTKEY) {
-                               event.alt= evt->alt= event.val;
-                               if(event.val && (evt->ctrl || evt->shift || evt->oskey))
+                               event.alt= evt->alt= (event.val==KM_PRESS);
+                               if(event.val==KM_PRESS && (evt->ctrl || evt->shift || evt->oskey))
                                   event.alt= evt->alt = 3;             // define?
                        } 
                        else if (event.type==COMMANDKEY) {
-                               event.oskey= evt->oskey= event.val;
-                               if(event.val && (evt->ctrl || evt->alt || evt->shift))
+                               event.oskey= evt->oskey= (event.val==KM_PRESS);
+                               if(event.val==KM_PRESS && (evt->ctrl || evt->alt || evt->shift))
                                   event.oskey= evt->oskey = 3;         // define?
                        }
+                       else {
+                               if(event.val==KM_PRESS && event.keymodifier==0)
+                                       evt->keymodifier= event.type; /* only set in eventstate, for next event */
+                               else if(event.val==KM_RELEASE && event.keymodifier==event.type)
+                                       event.keymodifier= evt->keymodifier= 0;
+                       }
                        
-                       /* if test_break set, it catches this. Keep global for now? */
+                       /* if test_break set, it catches this. XXX Keep global for now? */
                        if(event.type==ESCKEY)
                                G.afbreek= 1;
-                       
+
                        wm_event_add(win, &event);
                        
                        break;
@@ -1492,4 +1667,3 @@ void wm_event_add_ghostevent(wmWindow *win, int type, void *customdata)
                        break;
        }
 }
-