5 button mouse support from b333rt in IRC with some edits for X11.
[blender.git] / source / blender / windowmanager / intern / wm_event_system.c
index 78c7f7a7383367cb36f454b6469e2842c81fa39c..ebb7adc3cd51ed869f237223d81df6e6aa15ea72 100644 (file)
@@ -52,6 +52,7 @@
 #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"
@@ -129,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)
@@ -141,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;
@@ -156,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 */
@@ -244,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)
 {
@@ -252,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)
@@ -313,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;
@@ -325,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);
 }
@@ -340,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); 
@@ -390,10 +445,12 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, P
        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, 0);
        wmWindow *window= CTX_wm_window(C);
        wmEvent *event;
        
@@ -421,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);
@@ -436,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;
@@ -451,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, event, properties);
+                               retval= wm_operator_invoke(C, ot, event, properties, reports);
                                CTX_wm_region_set(C, ar);
                                CTX_wm_area_set(C, area);
 
@@ -460,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;
 }
@@ -626,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;
        
@@ -644,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;
 }
@@ -747,7 +844,7 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand
                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)
@@ -806,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_SORT_ALPHA;
-                               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
@@ -818,20 +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;
-                                       dir = sfile->params->dir;
-                               }
 
-                               ED_fileselect_set_params(sfile, handler->op->type->name, dir, path, flag, display, filter, sort);
-                               dir = NULL;
-                               MEM_freeN(path);
+                               ED_fileselect_set_params(sfile);
                                
                                action= WM_HANDLER_BREAK;
                        }
@@ -842,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);
@@ -893,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;
 }
@@ -923,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;
+                                               }
                                        }
                                }
                        }
@@ -948,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 */
@@ -961,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) {
@@ -1062,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) {
@@ -1160,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.
@@ -1180,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);
 }
@@ -1191,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)
@@ -1220,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;
        
@@ -1233,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);
        
@@ -1244,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;
        
@@ -1397,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;
@@ -1435,19 +1566,6 @@ void wm_event_add_ghostevent(wmWindow *win, int type, void *customdata)
                                
                                update_tablet_data(win, &event);
                                wm_event_add(win, &event);
-
-                               cx = abs((win->downx - event.x));
-                               cy = abs((win->downy - event.y));
-
-                               /* probably minimum drag size should be #defined instead of hardcoded 3 */
-                               if (win->downstate == LEFTMOUSE && (cx > 3 || cy > 3)) {
-                                       wmEvent dragevt= *evt;
-                                       dragevt.type= MOUSEDRAG;
-                                       dragevt.customdata= NULL;
-                                       dragevt.customdatafree= 0;
-
-                                       wm_event_add(win, &dragevt);
-                               }
                        }
                        break;
                }
@@ -1461,33 +1579,15 @@ 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);
-
-                       if (event.val) {
-                               win->downstate= event.type;
-                               win->downx= event.x;
-                               win->downy= event.y;
-                       }
-                       else if (win->downstate) {
-                               wmEvent dropevt= *evt;
-                               dropevt.type= MOUSEDROP;
-                               dropevt.customdata= NULL;
-                               dropevt.customdatafree= 0;
-                               win->downstate= 0;
-                               win->downx= 0;
-                               win->downy= 0;
-
-                               wm_event_add(win, &dropevt);
-                       }
                        
                        break;
                }
@@ -1524,6 +1624,12 @@ void wm_event_add_ghostevent(wmWindow *win, int type, void *customdata)
                                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. XXX Keep global for now? */
                        if(event.type==ESCKEY)