5 button mouse support from b333rt in IRC with some edits for X11.
[blender.git] / source / blender / windowmanager / intern / wm_event_system.c
index c2c90f055b0173fca887ae1cc99a146cb0fab79c..ebb7adc3cd51ed869f237223d81df6e6aa15ea72 100644 (file)
@@ -177,7 +177,7 @@ void wm_event_do_notifiers(bContext *C)
                                                do_anim= 1;
                                }
                        }
-                       if(ELEM3(note->category, NC_SCENE, NC_OBJECT, NC_GEOM)) {
+                       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);
                        }
@@ -259,20 +259,23 @@ void wm_event_do_notifiers(bContext *C)
 
 /* ********************* operators ******************* */
 
-static int wm_operator_poll(bContext *C, wmOperatorType *ot)
+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))
+               if(0==WM_operator_poll(C, ot))
                        return 0;
        }
        
-       if(ot->poll)
+       /* 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;
 }
 
@@ -284,7 +287,7 @@ static int wm_operator_exec(bContext *C, wmOperator *op, int repeat)
        if(op==NULL || op->type==NULL)
                return retval;
        
-       if(0==wm_operator_poll(C, op->type))
+       if(0==WM_operator_poll(C, op->type))
                return retval;
        
        if(op->type->exec)
@@ -349,8 +352,7 @@ static wmOperator *wm_operator_create(wmWindowManager *wm, wmOperatorType *ot, P
        }
        else {
                op->reports= MEM_mallocN(sizeof(ReportList), "wmOperatorReportList");
-               BKE_reports_init(op->reports, RPT_STORE);
-               op->flag |= OPERATOR_REPORT_FREE;
+               BKE_reports_init(op->reports, RPT_STORE|RPT_FREE);
        }
        
        /* recursive filling of operator macro list */
@@ -398,7 +400,7 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, P
        wmWindowManager *wm= CTX_wm_manager(C);
        int retval= OPERATOR_PASS_THROUGH;
 
-       if(wm_operator_poll(C, ot)) {
+       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)
@@ -555,6 +557,12 @@ int WM_operator_call_py(bContext *C, wmOperatorType *ot, int context, PointerRNA
 
        retval= wm_operator_call_internal(C, ot, context, properties, reports);
        
+       /* keep the reports around if needed later */
+       if (retval & OPERATOR_RUNNING_MODAL || ot->flag & OPTYPE_REGISTER)
+       {
+               reports->flag |= RPT_FREE;
+       }
+       
        return retval;
 }
 
@@ -710,7 +718,7 @@ static int wm_eventmatch(wmEvent *winevent, wmKeymapItem *kmi)
 
        /* 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;
        
@@ -895,9 +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: 
-                       {
-                               char *dir= NULL; 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
@@ -908,8 +914,6 @@ static int wm_handler_fileselect_call(bContext *C, ListBase *handlers, wmEventHa
                                sfile->op= handler->op;
 
                                ED_fileselect_set_params(sfile);
-                               dir = NULL;
-                               MEM_freeN(path);
                                
                                action= WM_HANDLER_BREAK;
                        }
@@ -920,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);
@@ -1013,16 +1017,19 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
                                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;
+                                               }
                                        }
                                }
                        }
@@ -1038,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(!always_pass && action==WM_HANDLER_BREAK)
-                               break;
+                       if(action==WM_HANDLER_BREAK) {
+                               if(always_pass)
+                                       action= WM_HANDLER_CONTINUE;
+                               else
+                                       break;
+                       }
                }
                
                /* fileread case */
@@ -1051,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) {
@@ -1152,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) {
@@ -1250,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.
@@ -1270,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);
 }
@@ -1281,9 +1306,10 @@ 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");
+       wmWindow *win= CTX_wm_window(C);
        
        /* operator was part of macro */
        if(op->opm) {
@@ -1298,15 +1324,20 @@ wmEventHandler *WM_event_add_modal_handler(bContext *C, ListBase *handlers, wmOp
        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)
@@ -1320,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;
        
@@ -1333,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);
        
@@ -1344,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;
        
@@ -1497,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;
@@ -1548,6 +1579,10 @@ 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;