2.5 / Drag & Drop
[blender.git] / source / blender / windowmanager / intern / wm_event_system.c
1 /**
2  * $Id:
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2007 Blender Foundation.
21  * All rights reserved.
22  *
23  * 
24  * Contributor(s): Blender Foundation
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include <stdlib.h>
30 #include <string.h>
31
32 #include "DNA_listBase.h"
33 #include "DNA_screen_types.h"
34 #include "DNA_scene_types.h"
35 #include "DNA_windowmanager_types.h"
36 #include "DNA_userdef_types.h"
37
38 #include "MEM_guardedalloc.h"
39
40 #include "GHOST_C-api.h"
41
42 #include "BLI_blenlib.h"
43
44 #include "BKE_blender.h"
45 #include "BKE_context.h"
46 #include "BKE_idprop.h"
47 #include "BKE_global.h"
48 #include "BKE_object.h"
49 #include "BKE_report.h"
50 #include "BKE_scene.h"
51 #include "BKE_utildefines.h"
52 #include "BKE_pointcache.h"
53
54 #include "ED_fileselect.h"
55 #include "ED_screen.h"
56 #include "ED_space_api.h"
57 #include "ED_util.h"
58
59 #include "RNA_access.h"
60
61 #include "UI_interface.h"
62
63 #include "WM_api.h"
64 #include "WM_types.h"
65 #include "wm.h"
66 #include "wm_window.h"
67 #include "wm_event_system.h"
68 #include "wm_event_types.h"
69
70 /* ************ event management ************** */
71
72 void wm_event_add(wmWindow *win, wmEvent *event_to_add)
73 {
74         wmEvent *event= MEM_callocN(sizeof(wmEvent), "event");
75         
76         *event= *event_to_add;
77         BLI_addtail(&win->queue, event);
78 }
79
80 void wm_event_free(wmEvent *event)
81 {
82         if(event->customdata && event->customdatafree)
83                 MEM_freeN(event->customdata);
84         MEM_freeN(event);
85 }
86
87 void wm_event_free_all(wmWindow *win)
88 {
89         wmEvent *event;
90         
91         while((event= win->queue.first)) {
92                 BLI_remlink(&win->queue, event);
93                 wm_event_free(event);
94         }
95 }
96
97 /* ********************* notifiers, listeners *************** */
98
99 /* XXX: in future, which notifiers to send to other windows? */
100 void WM_event_add_notifier(const bContext *C, unsigned int type, void *reference)
101 {
102         wmNotifier *note= MEM_callocN(sizeof(wmNotifier), "notifier");
103         
104         note->wm= CTX_wm_manager(C);
105         BLI_addtail(&note->wm->queue, note);
106         
107         note->window= CTX_wm_window(C);
108         
109         if(CTX_wm_region(C))
110                 note->swinid= CTX_wm_region(C)->swinid;
111         
112         note->category= type & NOTE_CATEGORY;
113         note->data= type & NOTE_DATA;
114         note->subtype= type & NOTE_SUBTYPE;
115         note->action= type & NOTE_ACTION;
116         
117         note->reference= reference;
118 }
119
120 static wmNotifier *wm_notifier_next(wmWindowManager *wm)
121 {
122         wmNotifier *note= wm->queue.first;
123         
124         if(note) BLI_remlink(&wm->queue, note);
125         return note;
126 }
127
128 /* called in mainloop */
129 void wm_event_do_notifiers(bContext *C)
130 {
131         wmWindowManager *wm= CTX_wm_manager(C);
132         wmNotifier *note;
133         wmWindow *win;
134         
135         if(wm==NULL)
136                 return;
137         
138         /* cache & catch WM level notifiers, such as frame change, scene/screen set */
139         for(win= wm->windows.first; win; win= win->next) {
140                 int do_anim= 0;
141                 
142                 CTX_wm_window_set(C, win);
143                 
144                 for(note= wm->queue.first; note; note= note->next) {
145                         if(note->category==NC_WM) {
146                                 if( ELEM(note->data, ND_FILEREAD, ND_FILESAVE)) {
147                                         wm->file_saved= 1;
148                                         wm_window_title(wm, win);
149                                 }
150                                 else if(note->data==ND_DATACHANGED)
151                                         wm_window_title(wm, win);
152                         }
153                         if(note->window==win) {
154                                 if(note->category==NC_SCREEN) {
155                                         if(note->data==ND_SCREENBROWSE) {
156                                                 ED_screen_set(C, note->reference);      // XXX hrms, think this over!
157                                                 printf("screen set %p\n", note->reference);
158                                         }
159                                 }
160                                 else if(note->category==NC_SCENE) {
161                                         if(note->data==ND_SCENEBROWSE) {
162                                                 ED_screen_set_scene(C, note->reference);        // XXX hrms, think this over!
163                                                 printf("scene set %p\n", note->reference);
164                                         }
165                                         else if(note->data==ND_FRAME)
166                                                 do_anim= 1;
167                                 }
168                         }
169                 }
170                 if(do_anim) {
171                         /* depsgraph gets called, might send more notifiers */
172                         ED_update_for_newframe(C, 1);
173                 }
174         }
175         
176         /* the notifiers are sent without context, to keep it clean */
177         while( (note=wm_notifier_next(wm)) ) {
178                 wmWindow *win;
179                 
180                 for(win= wm->windows.first; win; win= win->next) {
181                         
182                         /* filter out notifiers */
183                         if(note->category==NC_SCREEN && note->reference && note->reference!=win->screen);
184                         else if(note->category==NC_SCENE && note->reference && note->reference!=win->screen->scene);
185                         else {
186                                 ScrArea *sa;
187                                 ARegion *ar;
188
189                                 /* XXX context in notifiers? */
190                                 CTX_wm_window_set(C, win);
191
192                                 /* printf("notifier win %d screen %s cat %x\n", win->winid, win->screen->id.name+2, note->category); */
193                                 ED_screen_do_listen(win, note);
194
195                                 for(ar=win->screen->regionbase.first; ar; ar= ar->next) {
196                                         ED_region_do_listen(ar, note);
197                                 }
198                                 
199                                 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
200                                         ED_area_do_listen(sa, note);
201                                         for(ar=sa->regionbase.first; ar; ar= ar->next) {
202                                                 ED_region_do_listen(ar, note);
203                                         }
204                                 }
205                         }
206                 }
207                 
208                 MEM_freeN(note);
209         }
210         
211         /* cached: editor refresh callbacks now, they get context */
212         for(win= wm->windows.first; win; win= win->next) {
213                 Scene *sce, *scene= win->screen->scene;
214                 ScrArea *sa;
215                 Base *base;
216                 
217                 CTX_wm_window_set(C, win);
218                 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
219                         if(sa->do_refresh) {
220                                 CTX_wm_area_set(C, sa);
221                                 ED_area_do_refresh(C, sa);
222                         }
223                 }
224                 
225                 if(G.rendering==0) { // XXX make lock in future, or separated derivedmesh users in scene
226                         
227                         /* update all objects, ipos, matrices, displists, etc. Flags set by depgraph or manual, 
228                                 no layer check here, gets correct flushed */
229                         /* sets first, we allow per definition current scene to have dependencies on sets */
230                         if(scene->set) {
231                                 for(SETLOOPER(scene->set, base))
232                                         object_handle_update(scene, base->object);
233                         }
234                         
235                         for(base= scene->base.first; base; base= base->next) {
236                                 object_handle_update(scene, base->object);
237                         }
238
239                         BKE_ptcache_quick_cache_all(scene);
240                 }               
241         }
242         CTX_wm_window_set(C, NULL);
243 }
244
245 /* ********************* operators ******************* */
246
247 static int wm_operator_poll(bContext *C, wmOperatorType *ot)
248 {
249         wmOperatorTypeMacro *otmacro;
250         
251         for(otmacro= ot->macro.first; otmacro; otmacro= otmacro->next) {
252                 wmOperatorType *ot= WM_operatortype_find(otmacro->idname, 0);
253                 
254                 if(0==wm_operator_poll(C, ot))
255                         return 0;
256         }
257         
258         if(ot->poll)
259                 return ot->poll(C);
260         
261         return 1;
262 }
263
264 /* if repeat is true, it doesn't register again, nor does it free */
265 static int wm_operator_exec(bContext *C, wmOperator *op, int repeat)
266 {
267         int retval= OPERATOR_CANCELLED;
268         
269         if(op==NULL || op->type==NULL)
270                 return retval;
271         
272         if(0==wm_operator_poll(C, op->type))
273                 return retval;
274         
275         if(op->type->exec)
276                 retval= op->type->exec(C, op);
277         
278         if(!(retval & OPERATOR_RUNNING_MODAL))
279                 if(op->reports->list.first)
280                         uiPupMenuReports(C, op->reports);
281         
282         if(retval & OPERATOR_FINISHED) {
283                 if(op->type->flag & OPTYPE_UNDO)
284                         ED_undo_push_op(C, op);
285                 
286                 if(repeat==0) {
287                         if((op->type->flag & OPTYPE_REGISTER) || (G.f & G_DEBUG))
288                                 wm_operator_register(C, op);
289                         else
290                                 WM_operator_free(op);
291                 }
292         }
293         else if(repeat==0)
294                 WM_operator_free(op);
295         
296         return retval;
297         
298 }
299
300 /* for running operators with frozen context (modal handlers, menus) */
301 int WM_operator_call(bContext *C, wmOperator *op)
302 {
303         return wm_operator_exec(C, op, 0);
304 }
305
306 /* do this operator again, put here so it can share above code */
307 int WM_operator_repeat(bContext *C, wmOperator *op)
308 {
309         return wm_operator_exec(C, op, 1);
310 }
311
312 static wmOperator *wm_operator_create(wmWindowManager *wm, wmOperatorType *ot, PointerRNA *properties, ReportList *reports)
313 {
314         wmOperator *op= MEM_callocN(sizeof(wmOperator), ot->idname);    /* XXX operatortype names are static still. for debug */
315         
316         /* XXX adding new operator could be function, only happens here now */
317         op->type= ot;
318         BLI_strncpy(op->idname, ot->idname, OP_MAX_TYPENAME);
319         
320         /* initialize properties, either copy or create */
321         op->ptr= MEM_callocN(sizeof(PointerRNA), "wmOperatorPtrRNA");
322         if(properties && properties->data) {
323                 op->properties= IDP_CopyProperty(properties->data);
324         }
325         else {
326                 IDPropertyTemplate val = {0};
327                 op->properties= IDP_New(IDP_GROUP, val, "wmOperatorProperties");
328         }
329         RNA_pointer_create(&wm->id, ot->srna, op->properties, op->ptr);
330
331         /* initialize error reports */
332         if (reports) {
333                 op->reports= reports; /* must be initialized alredy */
334         }
335         else {
336                 op->reports= MEM_mallocN(sizeof(ReportList), "wmOperatorReportList");
337                 BKE_reports_init(op->reports, RPT_STORE);
338         }
339         
340         /* recursive filling of operator macro list */
341         if(ot->macro.first) {
342                 static wmOperator *motherop= NULL;
343                 wmOperatorTypeMacro *otmacro;
344                 
345                 /* ensure all ops are in execution order in 1 list */
346                 if(motherop==NULL) 
347                         motherop= op;
348                 
349                 for(otmacro= ot->macro.first; otmacro; otmacro= otmacro->next) {
350                         wmOperatorType *otm= WM_operatortype_find(otmacro->idname, 0);
351                         wmOperator *opm= wm_operator_create(wm, otm, otmacro->ptr, NULL);
352                         
353                         BLI_addtail(&motherop->macro, opm);
354                         opm->opm= motherop; /* pointer to mom, for modal() */
355                 }
356                 
357                 motherop= NULL;
358         }
359         
360         return op;
361 }
362
363 static void wm_operator_print(wmOperator *op)
364 {
365         char *buf = WM_operator_pystring(op);
366         printf("%s\n", buf);
367         MEM_freeN(buf);
368 }
369
370 static void wm_region_mouse_co(bContext *C, wmEvent *event)
371 {
372         ARegion *ar= CTX_wm_region(C);
373         if(ar) {
374                 /* compatibility convention */
375                 event->mval[0]= event->x - ar->winrct.xmin;
376                 event->mval[1]= event->y - ar->winrct.ymin;
377         }
378 }
379
380 static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, PointerRNA *properties)
381 {
382         wmWindowManager *wm= CTX_wm_manager(C);
383         int retval= OPERATOR_PASS_THROUGH;
384
385         if(wm_operator_poll(C, ot)) {
386                 wmOperator *op= wm_operator_create(wm, ot, properties, NULL);
387                 
388                 if((G.f & G_DEBUG) && event && event->type!=MOUSEMOVE)
389                         printf("handle evt %d win %d op %s\n", event?event->type:0, CTX_wm_screen(C)->subwinactive, ot->idname); 
390                 
391                 if(op->type->invoke && event) {
392                         wm_region_mouse_co(C, event);
393                         retval= op->type->invoke(C, op, event);
394                 }
395                 else if(op->type->exec)
396                         retval= op->type->exec(C, op);
397                 else
398                         printf("invalid operator call %s\n", ot->idname); /* debug, important to leave a while, should never happen */
399
400                 if(!(retval & OPERATOR_RUNNING_MODAL)) {
401                         if(op->reports->list.first) /* only show the report if the report list was not given in the function */
402                                 uiPupMenuReports(C, op->reports);
403                 
404                 if (retval & OPERATOR_FINISHED) /* todo - this may conflict with the other wm_operator_print, if theres ever 2 prints for 1 action will may need to add modal check here */
405                         if(G.f & G_DEBUG)
406                                 wm_operator_print(op);
407                 }
408
409                 if(retval & OPERATOR_FINISHED) {
410                         if(ot->flag & OPTYPE_UNDO)
411                                 ED_undo_push_op(C, op);
412                         
413                         if((ot->flag & OPTYPE_REGISTER) || (G.f & G_DEBUG))
414                                 wm_operator_register(C, op);
415                         else
416                                 WM_operator_free(op);
417                 }
418                 else if(retval & OPERATOR_RUNNING_MODAL) {
419                         /* grab cursor during blocking modal ops (X11) */
420                         if(ot->flag & OPTYPE_BLOCKING)
421                                 WM_cursor_grab(CTX_wm_window(C), 1);
422                 }
423                 else
424                         WM_operator_free(op);
425         }
426
427         return retval;
428 }
429
430 /* invokes operator in context */
431 int WM_operator_name_call(bContext *C, const char *opstring, int context, PointerRNA *properties)
432 {
433         wmOperatorType *ot= WM_operatortype_find(opstring, 0);
434         wmWindow *window= CTX_wm_window(C);
435         wmEvent *event;
436         
437         int retval;
438
439         /* dummie test */
440         if(ot && C && window) {
441                 event= window->eventstate;
442                 switch(context) {
443                         
444                         case WM_OP_EXEC_REGION_WIN:
445                                 event= NULL;    /* pass on without break */
446                         case WM_OP_INVOKE_REGION_WIN: 
447                         {
448                                 /* forces operator to go to the region window, for header menus */
449                                 ARegion *ar= CTX_wm_region(C);
450                                 ScrArea *area= CTX_wm_area(C);
451                                 
452                                 if(area) {
453                                         ARegion *ar1= area->regionbase.first;
454                                         for(; ar1; ar1= ar1->next)
455                                                 if(ar1->regiontype==RGN_TYPE_WINDOW)
456                                                         break;
457                                         if(ar1)
458                                                 CTX_wm_region_set(C, ar1);
459                                 }
460                                 
461                                 retval= wm_operator_invoke(C, ot, event, properties);
462                                 
463                                 /* set region back */
464                                 CTX_wm_region_set(C, ar);
465                                 
466                                 return retval;
467                         }
468                         case WM_OP_EXEC_AREA:
469                                 event= NULL;    /* pass on without break */
470                         case WM_OP_INVOKE_AREA:
471                         {
472                                         /* remove region from context */
473                                 ARegion *ar= CTX_wm_region(C);
474
475                                 CTX_wm_region_set(C, NULL);
476                                 retval= wm_operator_invoke(C, ot, event, properties);
477                                 CTX_wm_region_set(C, ar);
478
479                                 return retval;
480                         }
481                         case WM_OP_EXEC_SCREEN:
482                                 event= NULL;    /* pass on without break */
483                         case WM_OP_INVOKE_SCREEN:
484                         {
485                                 /* remove region + area from context */
486                                 ARegion *ar= CTX_wm_region(C);
487                                 ScrArea *area= CTX_wm_area(C);
488
489                                 CTX_wm_region_set(C, NULL);
490                                 CTX_wm_area_set(C, NULL);
491                                 retval= wm_operator_invoke(C, ot, event, properties);
492                                 CTX_wm_region_set(C, ar);
493                                 CTX_wm_area_set(C, area);
494
495                                 return retval;
496                         }
497                         case WM_OP_EXEC_DEFAULT:
498                                 event= NULL;    /* pass on without break */
499                         case WM_OP_INVOKE_DEFAULT:
500                                 return wm_operator_invoke(C, ot, event, properties);
501                 }
502         }
503         
504         return 0;
505 }
506
507 /* Similar to WM_operator_name_call called with WM_OP_EXEC_DEFAULT context.
508    - wmOperatorType is used instead of operator name since python alredy has the operator type
509    - poll() must be called by python before this runs.
510    - reports can be passed to this function (so python can report them as exceptions)
511 */
512 int WM_operator_call_py(bContext *C, wmOperatorType *ot, PointerRNA *properties, ReportList *reports)
513 {
514         wmWindowManager *wm=    CTX_wm_manager(C);
515         wmOperator *op=                 wm_operator_create(wm, ot, properties, reports);
516         int retval= OPERATOR_CANCELLED;
517         
518         if (op->type->exec)
519                 retval= op->type->exec(C, op);
520         else
521                 printf("error \"%s\" operator has no exec function, python cannot call it\n", op->type->name);
522         
523         if (reports)
524                 op->reports= NULL; /* dont let the operator free reports passed to this function */
525         WM_operator_free(op);
526         
527         return retval;
528 }
529
530
531 /* ********************* handlers *************** */
532
533 /* future extra customadata free? */
534 static void wm_event_free_handler(wmEventHandler *handler)
535 {
536         MEM_freeN(handler);
537 }
538
539 /* only set context when area/region is part of screen */
540 static void wm_handler_op_context(bContext *C, wmEventHandler *handler)
541 {
542         bScreen *screen= CTX_wm_screen(C);
543         
544         if(screen && handler->op) {
545                 if(handler->op_area==NULL)
546                         CTX_wm_area_set(C, NULL);
547                 else {
548                         ScrArea *sa;
549                         
550                         for(sa= screen->areabase.first; sa; sa= sa->next)
551                                 if(sa==handler->op_area)
552                                         break;
553                         if(sa==NULL) {
554                                 /* when changing screen layouts with running modal handlers (like render display), this
555                                    is not an error to print */
556                                 if(handler->op==NULL)
557                                         printf("internal error: handler (%s) has invalid area\n", handler->op->type->idname);
558                         }
559                         else {
560                                 ARegion *ar;
561                                 CTX_wm_area_set(C, sa);
562                                 for(ar= sa->regionbase.first; ar; ar= ar->next)
563                                         if(ar==handler->op_region)
564                                                 break;
565                                 /* XXX no warning print here, after full-area and back regions are remade */
566                                 if(ar)
567                                         CTX_wm_region_set(C, ar);
568                         }
569                 }
570         }
571 }
572
573 /* called on exit or remove area, only here call cancel callback */
574 void WM_event_remove_handlers(bContext *C, ListBase *handlers)
575 {
576         wmEventHandler *handler;
577         
578         /* C is zero on freeing database, modal handlers then already were freed */
579         while((handler=handlers->first)) {
580                 BLI_remlink(handlers, handler);
581                 
582                 if(handler->op) {
583                         if(handler->op->type->cancel) {
584                                 ScrArea *area= CTX_wm_area(C);
585                                 ARegion *region= CTX_wm_region(C);
586                                 
587                                 wm_handler_op_context(C, handler);
588
589                                 handler->op->type->cancel(C, handler->op);
590
591                                 CTX_wm_area_set(C, area);
592                                 CTX_wm_region_set(C, region);
593                         }
594
595                         WM_operator_free(handler->op);
596                         WM_cursor_grab(CTX_wm_window(C), 0);
597                 }
598                 else if(handler->ui_remove) {
599                         ScrArea *area= CTX_wm_area(C);
600                         ARegion *region= CTX_wm_region(C);
601                         ARegion *menu= CTX_wm_menu(C);
602                         
603                         if(handler->ui_area) CTX_wm_area_set(C, handler->ui_area);
604                         if(handler->ui_region) CTX_wm_region_set(C, handler->ui_region);
605                         if(handler->ui_menu) CTX_wm_menu_set(C, handler->ui_menu);
606
607                         handler->ui_remove(C, handler->ui_userdata);
608
609                         CTX_wm_area_set(C, area);
610                         CTX_wm_region_set(C, region);
611                         CTX_wm_menu_set(C, menu);
612                 }
613
614                 wm_event_free_handler(handler);
615         }
616 }
617
618 /* do userdef mappings */
619 static int wm_userdef_event_map(int kmitype)
620 {
621         switch(kmitype) {
622                 case SELECTMOUSE:
623                         if(U.flag & USER_LMOUSESELECT)
624                                 return LEFTMOUSE;
625                         else
626                                 return RIGHTMOUSE;
627                         
628                 case ACTIONMOUSE:
629                         if(U.flag & USER_LMOUSESELECT)
630                                 return RIGHTMOUSE;
631                         else
632                                 return LEFTMOUSE;
633                         
634                 case WHEELOUTMOUSE:
635                         if(U.uiflag & USER_WHEELZOOMDIR)
636                                 return WHEELUPMOUSE;
637                         else
638                                 return WHEELDOWNMOUSE;
639                         
640                 case WHEELINMOUSE:
641                         if(U.uiflag & USER_WHEELZOOMDIR)
642                                 return WHEELDOWNMOUSE;
643                         else
644                                 return WHEELUPMOUSE;
645                         
646                 case EVT_TWEAK_A:
647                         if(U.flag & USER_LMOUSESELECT)
648                                 return EVT_TWEAK_R;
649                         else
650                                 return EVT_TWEAK_L;
651                         
652                 case EVT_TWEAK_S:
653                         if(U.flag & USER_LMOUSESELECT)
654                                 return EVT_TWEAK_L;
655                         else
656                                 return EVT_TWEAK_R;
657         }
658         
659         return kmitype;
660 }
661
662 static int wm_eventmatch(wmEvent *winevent, wmKeymapItem *kmi)
663 {
664         int kmitype= wm_userdef_event_map(kmi->type);
665
666         if(kmi->inactive) return 0;
667         
668         /* the matching rules */
669         if(kmitype==KM_TEXTINPUT)
670                 if(ISKEYBOARD(winevent->type)) return 1;
671         if(kmitype!=KM_ANY)
672                 if(winevent->type!=kmitype) return 0;
673         
674         if(kmi->val!=KM_ANY)
675                 if(winevent->val!=kmi->val) return 0;
676         
677         /* modifiers also check bits, so it allows modifier order */
678         if(kmi->shift!=KM_ANY)
679                 if(winevent->shift != kmi->shift && !(winevent->shift & kmi->shift)) return 0;
680         if(kmi->ctrl!=KM_ANY)
681                 if(winevent->ctrl != kmi->ctrl && !(winevent->ctrl & kmi->ctrl)) return 0;
682         if(kmi->alt!=KM_ANY)
683                 if(winevent->alt != kmi->alt && !(winevent->alt & kmi->alt)) return 0;
684         if(kmi->oskey!=KM_ANY)
685                 if(winevent->oskey != kmi->oskey && !(winevent->oskey & kmi->oskey)) return 0;
686         if(kmi->keymodifier)
687                 if(winevent->keymodifier!=kmi->keymodifier) return 0;
688         
689         return 1;
690 }
691
692 static int wm_event_always_pass(wmEvent *event)
693 {
694         /* some events we always pass on, to ensure proper communication */
695         return ELEM5(event->type, TIMER, TIMER0, TIMER1, TIMER2, TIMERJOBS);
696 }
697
698 /* operator exists */
699 static void wm_event_modalkeymap(wmOperator *op, wmEvent *event)
700 {
701         if(op->type->modalkeymap) {
702                 wmKeymapItem *kmi;
703                 
704                 for(kmi= op->type->modalkeymap->keymap.first; kmi; kmi= kmi->next) {
705                         if(wm_eventmatch(event, kmi)) {
706                                         
707                                 event->type= EVT_MODAL_MAP;
708                                 event->val= kmi->propvalue;
709                         }
710                 }
711         }
712 }
713
714 /* Warning: this function removes a modal handler, when finished */
715 static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHandler *handler, wmEvent *event, PointerRNA *properties)
716 {
717         int retval= OPERATOR_PASS_THROUGH;
718         
719         /* derived, modal or blocking operator */
720         if(handler->op) {
721                 wmOperator *op= handler->op;
722                 wmOperatorType *ot= op->type;
723
724                 if(ot->modal) {
725                         /* we set context to where modal handler came from */
726                         ScrArea *area= CTX_wm_area(C);
727                         ARegion *region= CTX_wm_region(C);
728                         
729                         wm_handler_op_context(C, handler);
730                         wm_region_mouse_co(C, event);
731                         wm_event_modalkeymap(op, event);
732                         
733                         retval= ot->modal(C, op, event);
734
735                         /* putting back screen context, reval can pass trough after modal failures! */
736                         if((retval & OPERATOR_PASS_THROUGH) || wm_event_always_pass(event)) {
737                                 CTX_wm_area_set(C, area);
738                                 CTX_wm_region_set(C, region);
739                         }
740                         else {
741                                 /* this special cases is for areas and regions that get removed */
742                                 CTX_wm_area_set(C, NULL);
743                                 CTX_wm_region_set(C, NULL);
744                         }
745
746                         if(!(retval & OPERATOR_RUNNING_MODAL))
747                                 if(op->reports->list.first)
748                                         uiPupMenuReports(C, op->reports);
749
750                         if (retval & OPERATOR_FINISHED) {
751                                 if(G.f & G_DEBUG)
752                                         wm_operator_print(op); /* todo - this print may double up, might want to check more flags then the FINISHED */
753                         }                       
754
755                         if(retval & OPERATOR_FINISHED) {
756                                 if(ot->flag & OPTYPE_UNDO)
757                                         ED_undo_push_op(C, op);
758                                 
759                                 if((ot->flag & OPTYPE_REGISTER) || (G.f & G_DEBUG))
760                                         wm_operator_register(C, op);
761                                 else
762                                         WM_operator_free(op);
763                                 handler->op= NULL;
764                         }
765                         else if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) {
766                                 WM_operator_free(op);
767                                 handler->op= NULL;
768                         }
769                         
770                         /* remove modal handler, operator itself should have been cancelled and freed */
771                         if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) {
772                                 WM_cursor_grab(CTX_wm_window(C), 0);
773
774                                 BLI_remlink(handlers, handler);
775                                 wm_event_free_handler(handler);
776                                 
777                                 /* prevent silly errors from operator users */
778                                 //retval &= ~OPERATOR_PASS_THROUGH;
779                         }
780                         
781                 }
782                 else
783                         printf("wm_handler_operator_call error\n");
784         }
785         else {
786                 wmOperatorType *ot= WM_operatortype_find(event->keymap_idname, 0);
787
788                 if(ot)
789                         retval= wm_operator_invoke(C, ot, event, properties);
790         }
791
792         if(retval & OPERATOR_PASS_THROUGH)
793                 return WM_HANDLER_CONTINUE;
794
795         return WM_HANDLER_BREAK;
796 }
797
798 static int wm_handler_ui_call(bContext *C, wmEventHandler *handler, wmEvent *event)
799 {
800         ScrArea *area= CTX_wm_area(C);
801         ARegion *region= CTX_wm_region(C);
802         ARegion *menu= CTX_wm_menu(C);
803         int retval, always_pass;
804                         
805         /* we set context to where ui handler came from */
806         if(handler->ui_area) CTX_wm_area_set(C, handler->ui_area);
807         if(handler->ui_region) CTX_wm_region_set(C, handler->ui_region);
808         if(handler->ui_menu) CTX_wm_menu_set(C, handler->ui_menu);
809
810         /* in advance to avoid access to freed event on window close */
811         always_pass= wm_event_always_pass(event);
812
813         retval= handler->ui_handle(C, event, handler->ui_userdata);
814
815         /* putting back screen context */
816         if((retval != WM_UI_HANDLER_BREAK) || always_pass) {
817                 CTX_wm_area_set(C, area);
818                 CTX_wm_region_set(C, region);
819                 CTX_wm_menu_set(C, menu);
820         }
821         else {
822                 /* this special cases is for areas and regions that get removed */
823                 CTX_wm_area_set(C, NULL);
824                 CTX_wm_region_set(C, NULL);
825                 CTX_wm_menu_set(C, NULL);
826         }
827
828         if(retval == WM_UI_HANDLER_BREAK)
829                 return WM_HANDLER_BREAK;
830
831         return WM_HANDLER_CONTINUE;
832 }
833
834 /* fileselect handlers are only in the window queue, so it's save to switch screens or area types */
835 static int wm_handler_fileselect_call(bContext *C, ListBase *handlers, wmEventHandler *handler, wmEvent *event)
836 {
837         SpaceFile *sfile;
838         int action= WM_HANDLER_CONTINUE;
839         
840         if(event->type != EVT_FILESELECT)
841                 return action;
842         if(handler->op != (wmOperator *)event->customdata)
843                 return action;
844         
845         switch(event->val) {
846                 case EVT_FILESELECT_OPEN: 
847                 case EVT_FILESELECT_FULL_OPEN: 
848                         {
849                                 char *dir= NULL; char *path= RNA_string_get_alloc(handler->op->ptr, "filename", NULL, 0);
850                                         
851                                 if(event->val==EVT_FILESELECT_OPEN)
852                                         ED_area_newspace(C, handler->op_area, SPACE_FILE);
853                                 else
854                                         ED_screen_full_newspace(C, handler->op_area, SPACE_FILE);
855                                 
856                                 /* settings for filebrowser, sfile is not operator owner but sends events */
857                                 sfile= (SpaceFile*)CTX_wm_space_data(C);
858                                 sfile->op= handler->op;
859
860                                 ED_fileselect_set_params(sfile);
861                                 dir = NULL;
862                                 MEM_freeN(path);
863                                 
864                                 action= WM_HANDLER_BREAK;
865                         }
866                         break;
867                         
868                 case EVT_FILESELECT_EXEC:
869                 case EVT_FILESELECT_CANCEL:
870                         {
871                                 /* XXX validate area and region? */
872                                 bScreen *screen= CTX_wm_screen(C);
873                                 char *path= RNA_string_get_alloc(handler->op->ptr, "filename", NULL, 0);
874                                 
875                                 if(screen != handler->filescreen)
876                                         ED_screen_full_prevspace(C);
877                                 else
878                                         ED_area_prevspace(C);
879                                 
880                                 /* remlink now, for load file case */
881                                 BLI_remlink(handlers, handler);
882                                 
883                                 if(event->val==EVT_FILESELECT_EXEC) {
884                                         wm_handler_op_context(C, handler);
885                                 
886                                         /* a bit weak, might become arg for WM_event_fileselect? */
887                                         /* XXX also extension code in image-save doesnt work for this yet */
888                                         if(strncmp(handler->op->type->name, "Save", 4)==0) {
889                                                 /* this gives ownership to pupmenu */
890                                                 uiPupMenuSaveOver(C, handler->op, path);
891                                         }
892                                         else {
893                                                 int retval= handler->op->type->exec(C, handler->op);
894                                                 
895                                                 if (retval & OPERATOR_FINISHED)
896                                                         if(G.f & G_DEBUG)
897                                                                 wm_operator_print(handler->op);
898                                                 
899                                                 WM_operator_free(handler->op);
900                                         }
901                                         
902                                         CTX_wm_area_set(C, NULL);
903                                 }
904                                 else 
905                                         WM_operator_free(handler->op);
906                                 
907                                 wm_event_free_handler(handler);
908                                 MEM_freeN(path);
909                                 
910                                 action= WM_HANDLER_BREAK;
911                         }
912                         break;
913         }
914         
915         return action;
916 }
917
918 static int handler_boundbox_test(wmEventHandler *handler, wmEvent *event)
919 {
920         if(handler->bbwin) {
921                 if(handler->bblocal) {
922                         rcti rect= *handler->bblocal;
923                         BLI_translate_rcti(&rect, handler->bbwin->xmin, handler->bbwin->ymin);
924
925                         if(BLI_in_rcti(&rect, event->x, event->y))
926                                 return 1;
927                         else if(event->type==MOUSEMOVE && BLI_in_rcti(&rect, event->prevx, event->prevy))
928                                 return 1;
929                         else
930                                 return 0;
931                 }
932                 else {
933                         if(BLI_in_rcti(handler->bbwin, event->x, event->y))
934                                 return 1;
935                         else if(event->type==MOUSEMOVE && BLI_in_rcti(handler->bbwin, event->prevx, event->prevy))
936                                 return 1;
937                         else
938                                 return 0;
939                 }
940         }
941         return 1;
942 }
943
944 static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
945 {
946         wmEventHandler *handler, *nexthandler;
947         int action= WM_HANDLER_CONTINUE;
948         int always_pass;
949
950         if(handlers==NULL) return action;
951         
952         /* modal handlers can get removed in this loop, we keep the loop this way */
953         for(handler= handlers->first; handler; handler= nexthandler) {
954                 nexthandler= handler->next;
955
956                 /* optional boundbox */
957                 if(handler_boundbox_test(handler, event)) {
958                         /* in advance to avoid access to freed event on window close */
959                         always_pass= wm_event_always_pass(event);
960                 
961                         /* modal+blocking handler */
962                         if(handler->flag & WM_HANDLER_BLOCKING)
963                                 action= WM_HANDLER_BREAK;
964
965                         if(handler->keymap) {
966                                 wmKeymapItem *kmi;
967                                 
968                                 for(kmi= handler->keymap->first; kmi; kmi= kmi->next) {
969                                         if(wm_eventmatch(event, kmi)) {
970                                                 
971                                                 event->keymap_idname= kmi->idname;      /* weak, but allows interactive callback to not use rawkey */
972                                                 
973                                                 action= wm_handler_operator_call(C, handlers, handler, event, kmi->ptr);
974                                                 if(action==WM_HANDLER_BREAK)  /* not wm_event_always_pass(event) here, it denotes removed handler */
975                                                         break;
976                                         }
977                                 }
978                         }
979                         else if(handler->ui_handle) {
980                                 action= wm_handler_ui_call(C, handler, event);
981                         }
982                         else if(handler->type==WM_HANDLER_FILESELECT) {
983                                 /* screen context changes here */
984                                 action= wm_handler_fileselect_call(C, handlers, handler, event);
985                         }
986                         else {
987                                 /* modal, swallows all */
988                                 action= wm_handler_operator_call(C, handlers, handler, event, NULL);
989                         }
990
991                         if(!always_pass && action==WM_HANDLER_BREAK)
992                                 break;
993                 }
994                 
995                 /* fileread case */
996                 if(CTX_wm_window(C)==NULL)
997                         break;
998         }
999         return action;
1000 }
1001
1002 static int wm_event_inside_i(wmEvent *event, rcti *rect)
1003 {
1004         if(BLI_in_rcti(rect, event->x, event->y))
1005            return 1;
1006         if(event->type==MOUSEMOVE) {
1007                 if( BLI_in_rcti(rect, event->prevx, event->prevy)) {
1008                         return 1;
1009                 }
1010                 return 0;
1011         }
1012         return 0;
1013 }
1014
1015 static ScrArea *area_event_inside(bContext *C, int x, int y)
1016 {
1017         bScreen *screen= CTX_wm_screen(C);
1018         ScrArea *sa;
1019         
1020         if(screen)
1021                 for(sa= screen->areabase.first; sa; sa= sa->next)
1022                         if(BLI_in_rcti(&sa->totrct, x, y))
1023                                 return sa;
1024         return NULL;
1025 }
1026
1027 static ARegion *region_event_inside(bContext *C, int x, int y)
1028 {
1029         bScreen *screen= CTX_wm_screen(C);
1030         ScrArea *area= CTX_wm_area(C);
1031         ARegion *ar;
1032         
1033         if(screen && area)
1034                 for(ar= area->regionbase.first; ar; ar= ar->next)
1035                         if(BLI_in_rcti(&ar->winrct, x, y))
1036                                 return ar;
1037         return NULL;
1038 }
1039
1040 static void wm_paintcursor_tag(bContext *C, wmPaintCursor *pc, ARegion *ar)
1041 {
1042         if(ar) {
1043                 for(; pc; pc= pc->next) {
1044                         if(pc->poll(C)) {
1045                                 wmWindow *win= CTX_wm_window(C);
1046                                 win->screen->do_draw_paintcursor= 1;
1047
1048                                 if(win->drawmethod != USER_DRAW_TRIPLE)
1049                                         ED_region_tag_redraw(ar);
1050                         }
1051                 }
1052         }
1053 }
1054
1055 /* called on mousemove, check updates for paintcursors */
1056 /* context was set on active area and region */
1057 static void wm_paintcursor_test(bContext *C, wmEvent *event)
1058 {
1059         wmWindowManager *wm= CTX_wm_manager(C);
1060         
1061         if(wm->paintcursors.first) {
1062                 ARegion *ar= CTX_wm_region(C);
1063                 if(ar)
1064                         wm_paintcursor_tag(C, wm->paintcursors.first, ar);
1065                 
1066                 /* if previous position was not in current region, we have to set a temp new context */
1067                 if(ar==NULL || !BLI_in_rcti(&ar->winrct, event->prevx, event->prevy)) {
1068                         ScrArea *sa= CTX_wm_area(C);
1069                         
1070                         CTX_wm_area_set(C, area_event_inside(C, event->prevx, event->prevy));
1071                         CTX_wm_region_set(C, region_event_inside(C, event->prevx, event->prevy));
1072
1073                         wm_paintcursor_tag(C, wm->paintcursors.first, CTX_wm_region(C));
1074                         
1075                         CTX_wm_area_set(C, sa);
1076                         CTX_wm_region_set(C, ar);
1077                 }
1078         }
1079 }
1080
1081 /* called in main loop */
1082 /* goes over entire hierarchy:  events -> window -> screen -> area -> region */
1083 void wm_event_do_handlers(bContext *C)
1084 {
1085         wmWindow *win;
1086
1087         for(win= CTX_wm_manager(C)->windows.first; win; win= win->next) {
1088                 wmEvent *event;
1089                 
1090                 if( win->screen==NULL )
1091                         wm_event_free_all(win);
1092                 
1093                 while( (event= win->queue.first) ) {
1094                         int action;
1095                         
1096                         CTX_wm_window_set(C, win);
1097                         
1098                         /* we let modal handlers get active area/region, also wm_paintcursor_test needs it */
1099                         CTX_wm_area_set(C, area_event_inside(C, event->x, event->y));
1100                         CTX_wm_region_set(C, region_event_inside(C, event->x, event->y));
1101                         
1102                         /* MVC demands to not draw in event handlers... but we need to leave it for ogl selecting etc */
1103                         wm_window_make_drawable(C, win);
1104                         
1105                         action= wm_handlers_do(C, event, &win->handlers);
1106                         
1107                         /* fileread case */
1108                         if(CTX_wm_window(C)==NULL) {
1109                                 return;
1110                         }
1111                         
1112                         /* builtin tweak, if action is break it removes tweak */
1113                         if(!wm_event_always_pass(event))
1114                                 wm_tweakevent_test(C, event, action);
1115                         
1116                         if(wm_event_always_pass(event) || action==WM_HANDLER_CONTINUE) {
1117                                 ScrArea *sa;
1118                                 ARegion *ar;
1119                                 int doit= 0;
1120                                 
1121                                 /* XXX to solve, here screen handlers? */
1122                                 if(!wm_event_always_pass(event)) {
1123                                         if(event->type==MOUSEMOVE) {
1124                                                 /* state variables in screen, cursors */
1125                                                 ED_screen_set_subwinactive(win, event); 
1126                                                 /* for regions having custom cursors */
1127                                                 wm_paintcursor_test(C, event);
1128                                         }
1129                                 }
1130                                 
1131                                 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
1132                                         if(wm_event_always_pass(event) || wm_event_inside_i(event, &sa->totrct)) {
1133                                                 
1134                                                 CTX_wm_area_set(C, sa);
1135                                                 CTX_wm_region_set(C, NULL);
1136                                                 action= wm_handlers_do(C, event, &sa->handlers);
1137
1138                                                 if(wm_event_always_pass(event) || action==WM_HANDLER_CONTINUE) {
1139                                                         for(ar=sa->regionbase.first; ar; ar= ar->next) {
1140                                                                 if(wm_event_always_pass(event) || wm_event_inside_i(event, &ar->winrct)) {
1141                                                                         CTX_wm_region_set(C, ar);
1142                                                                         action= wm_handlers_do(C, event, &ar->handlers);
1143
1144                                                                         doit |= (BLI_in_rcti(&ar->winrct, event->x, event->y));
1145                                                                         
1146                                                                         if(!wm_event_always_pass(event)) {
1147                                                                                 if(action==WM_HANDLER_BREAK)
1148                                                                                         break;
1149                                                                         }
1150                                                                 }
1151                                                         }
1152                                                 }
1153                                                 /* NOTE: do not escape on WM_HANDLER_BREAK, mousemove needs handled for previous area */
1154                                         }
1155                                 }
1156                                 
1157                                 /* XXX hrmf, this gives reliable previous mouse coord for area change, feels bad? 
1158                                    doing it on ghost queue gives errors when mousemoves go over area borders */
1159                                 if(doit && win->screen->subwinactive != win->screen->mainwin) {
1160                                         win->eventstate->prevx= event->x;
1161                                         win->eventstate->prevy= event->y;
1162                                 }
1163                         }
1164                         
1165                         /* unlink and free here, blender-quit then frees all */
1166                         BLI_remlink(&win->queue, event);
1167                         wm_event_free(event);
1168                         
1169                 }
1170                 
1171                 /* only add mousemove when queue was read entirely */
1172                 if(win->addmousemove) {
1173                         wmEvent event= *(win->eventstate);
1174                         event.type= MOUSEMOVE;
1175                         event.prevx= event.x;
1176                         event.prevy= event.y;
1177                         wm_event_add(win, &event);
1178                         win->addmousemove= 0;
1179                 }
1180                 
1181                 CTX_wm_window_set(C, NULL);
1182         }
1183 }
1184
1185 /* ********** filesector handling ************ */
1186
1187 void WM_event_fileselect_event(bContext *C, void *ophandle, int eventval)
1188 {
1189         /* add to all windows! */
1190         wmWindow *win;
1191         
1192         for(win= CTX_wm_manager(C)->windows.first; win; win= win->next) {
1193                 wmEvent event= *win->eventstate;
1194                 
1195                 event.type= EVT_FILESELECT;
1196                 event.val= eventval;
1197                 event.customdata= ophandle;             // only as void pointer type check
1198
1199                 wm_event_add(win, &event);
1200         }
1201 }
1202
1203 /* operator is supposed to have a filled "filename" property */
1204 /* optional property: filetype (XXX enum?) */
1205
1206 /* Idea is to keep a handler alive on window queue, owning the operator.
1207    The filewindow can send event to make it execute, thus ensuring
1208    executing happens outside of lower level queues, with UI refreshed. 
1209    Should also allow multiwin solutions */
1210
1211 void WM_event_add_fileselect(bContext *C, wmOperator *op)
1212 {
1213         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "fileselect handler");
1214         wmWindow *win= CTX_wm_window(C);
1215         int full= 1;    // XXX preset?
1216         
1217         handler->type= WM_HANDLER_FILESELECT;
1218         handler->op= op;
1219         handler->op_area= CTX_wm_area(C);
1220         handler->op_region= CTX_wm_region(C);
1221         handler->filescreen= CTX_wm_screen(C);
1222         
1223         BLI_addhead(&win->handlers, handler);
1224         
1225         WM_event_fileselect_event(C, op, full?EVT_FILESELECT_FULL_OPEN:EVT_FILESELECT_OPEN);
1226 }
1227
1228 /* lets not expose struct outside wm? */
1229 void WM_event_set_handler_flag(wmEventHandler *handler, int flag)
1230 {
1231         handler->flag= flag;
1232 }
1233
1234 wmEventHandler *WM_event_add_modal_handler(bContext *C, ListBase *handlers, wmOperator *op)
1235 {
1236         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event modal handler");
1237         
1238         /* operator was part of macro */
1239         if(op->opm) {
1240                 /* give the mother macro to the handler */
1241                 handler->op= op->opm;
1242                 /* mother macro opm becomes the macro element */
1243                 handler->op->opm= op;
1244         }
1245         else
1246                 handler->op= op;
1247         
1248         handler->op_area= CTX_wm_area(C);               /* means frozen screen context for modal handlers! */
1249         handler->op_region= CTX_wm_region(C);
1250         
1251         BLI_addhead(handlers, handler);
1252
1253         return handler;
1254 }
1255
1256 wmEventHandler *WM_event_add_keymap_handler(ListBase *handlers, ListBase *keymap)
1257 {
1258         wmEventHandler *handler;
1259
1260         /* only allow same keymap once */
1261         for(handler= handlers->first; handler; handler= handler->next)
1262                 if(handler->keymap==keymap)
1263                         return handler;
1264         
1265         handler= MEM_callocN(sizeof(wmEventHandler), "event keymap handler");
1266         BLI_addtail(handlers, handler);
1267         handler->keymap= keymap;
1268
1269         return handler;
1270 }
1271
1272 /* priorities not implemented yet, for time being just insert in begin of list */
1273 wmEventHandler *WM_event_add_keymap_handler_priority(ListBase *handlers, ListBase *keymap, int priority)
1274 {
1275         wmEventHandler *handler;
1276         
1277         WM_event_remove_keymap_handler(handlers, keymap);
1278         
1279         handler= MEM_callocN(sizeof(wmEventHandler), "event keymap handler");
1280         BLI_addhead(handlers, handler);
1281         handler->keymap= keymap;
1282         
1283         return handler;
1284 }
1285
1286 wmEventHandler *WM_event_add_keymap_handler_bb(ListBase *handlers, ListBase *keymap, rcti *bblocal, rcti *bbwin)
1287 {
1288         wmEventHandler *handler= WM_event_add_keymap_handler(handlers, keymap);
1289         
1290         if(handler) {
1291                 handler->bblocal= bblocal;
1292                 handler->bbwin= bbwin;
1293         }
1294         return handler;
1295 }
1296
1297 void WM_event_remove_keymap_handler(ListBase *handlers, ListBase *keymap)
1298 {
1299         wmEventHandler *handler;
1300         
1301         for(handler= handlers->first; handler; handler= handler->next) {
1302                 if(handler->keymap==keymap) {
1303                         BLI_remlink(handlers, handler);
1304                         wm_event_free_handler(handler);
1305                         break;
1306                 }
1307         }
1308 }
1309
1310 wmEventHandler *WM_event_add_ui_handler(const bContext *C, ListBase *handlers, wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata)
1311 {
1312         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event ui handler");
1313         handler->ui_handle= func;
1314         handler->ui_remove= remove;
1315         handler->ui_userdata= userdata;
1316         handler->ui_area= (C)? CTX_wm_area(C): NULL;
1317         handler->ui_region= (C)? CTX_wm_region(C): NULL;
1318         handler->ui_menu= (C)? CTX_wm_menu(C): NULL;
1319         
1320         BLI_addhead(handlers, handler);
1321         
1322         return handler;
1323 }
1324
1325 void WM_event_remove_ui_handler(ListBase *handlers, wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata)
1326 {
1327         wmEventHandler *handler;
1328         
1329         for(handler= handlers->first; handler; handler= handler->next) {
1330                 if(handler->ui_handle == func && handler->ui_remove == remove && handler->ui_userdata == userdata) {
1331                         BLI_remlink(handlers, handler);
1332                         wm_event_free_handler(handler);
1333                         break;
1334                 }
1335         }
1336 }
1337
1338 void WM_event_add_mousemove(bContext *C)
1339 {
1340         wmWindow *window= CTX_wm_window(C);
1341         
1342         window->addmousemove= 1;
1343 }
1344
1345 /* for modal callbacks, check configuration for how to interpret exit with tweaks  */
1346 int WM_modal_tweak_exit(wmEvent *evt, int tweak_event)
1347 {
1348         /* user preset or keymap? dunno... */
1349         int tweak_modal= (U.flag & USER_DRAGIMMEDIATE)==0;
1350         
1351         switch(tweak_event) {
1352                 case EVT_TWEAK_L:
1353                 case EVT_TWEAK_M:
1354                 case EVT_TWEAK_R:
1355                         if(evt->val==tweak_modal)
1356                                 return 1;
1357                 default:
1358                         /* this case is when modal callcback didnt get started with a tweak */
1359                         if(evt->val)
1360                                 return 1;
1361         }
1362         return 0;
1363 }
1364
1365
1366 /* ********************* ghost stuff *************** */
1367
1368 static int convert_key(GHOST_TKey key) 
1369 {
1370         if (key>=GHOST_kKeyA && key<=GHOST_kKeyZ) {
1371                 return (AKEY + ((int) key - GHOST_kKeyA));
1372         } else if (key>=GHOST_kKey0 && key<=GHOST_kKey9) {
1373                 return (ZEROKEY + ((int) key - GHOST_kKey0));
1374         } else if (key>=GHOST_kKeyNumpad0 && key<=GHOST_kKeyNumpad9) {
1375                 return (PAD0 + ((int) key - GHOST_kKeyNumpad0));
1376         } else if (key>=GHOST_kKeyF1 && key<=GHOST_kKeyF12) {
1377                 return (F1KEY + ((int) key - GHOST_kKeyF1));
1378         } else {
1379                 switch (key) {
1380                         case GHOST_kKeyBackSpace:               return BACKSPACEKEY;
1381                         case GHOST_kKeyTab:                             return TABKEY;
1382                         case GHOST_kKeyLinefeed:                return LINEFEEDKEY;
1383                         case GHOST_kKeyClear:                   return 0;
1384                         case GHOST_kKeyEnter:                   return RETKEY;
1385                                 
1386                         case GHOST_kKeyEsc:                             return ESCKEY;
1387                         case GHOST_kKeySpace:                   return SPACEKEY;
1388                         case GHOST_kKeyQuote:                   return QUOTEKEY;
1389                         case GHOST_kKeyComma:                   return COMMAKEY;
1390                         case GHOST_kKeyMinus:                   return MINUSKEY;
1391                         case GHOST_kKeyPeriod:                  return PERIODKEY;
1392                         case GHOST_kKeySlash:                   return SLASHKEY;
1393                                 
1394                         case GHOST_kKeySemicolon:               return SEMICOLONKEY;
1395                         case GHOST_kKeyEqual:                   return EQUALKEY;
1396                                 
1397                         case GHOST_kKeyLeftBracket:             return LEFTBRACKETKEY;
1398                         case GHOST_kKeyRightBracket:    return RIGHTBRACKETKEY;
1399                         case GHOST_kKeyBackslash:               return BACKSLASHKEY;
1400                         case GHOST_kKeyAccentGrave:             return ACCENTGRAVEKEY;
1401                                 
1402                         case GHOST_kKeyLeftShift:               return LEFTSHIFTKEY;
1403                         case GHOST_kKeyRightShift:              return RIGHTSHIFTKEY;
1404                         case GHOST_kKeyLeftControl:             return LEFTCTRLKEY;
1405                         case GHOST_kKeyRightControl:    return RIGHTCTRLKEY;
1406                         case GHOST_kKeyCommand:                 return COMMANDKEY;
1407                         case GHOST_kKeyLeftAlt:                 return LEFTALTKEY;
1408                         case GHOST_kKeyRightAlt:                return RIGHTALTKEY;
1409                                 
1410                         case GHOST_kKeyCapsLock:                return CAPSLOCKKEY;
1411                         case GHOST_kKeyNumLock:                 return 0;
1412                         case GHOST_kKeyScrollLock:              return 0;
1413                                 
1414                         case GHOST_kKeyLeftArrow:               return LEFTARROWKEY;
1415                         case GHOST_kKeyRightArrow:              return RIGHTARROWKEY;
1416                         case GHOST_kKeyUpArrow:                 return UPARROWKEY;
1417                         case GHOST_kKeyDownArrow:               return DOWNARROWKEY;
1418                                 
1419                         case GHOST_kKeyPrintScreen:             return 0;
1420                         case GHOST_kKeyPause:                   return PAUSEKEY;
1421                                 
1422                         case GHOST_kKeyInsert:                  return INSERTKEY;
1423                         case GHOST_kKeyDelete:                  return DELKEY;
1424                         case GHOST_kKeyHome:                    return HOMEKEY;
1425                         case GHOST_kKeyEnd:                             return ENDKEY;
1426                         case GHOST_kKeyUpPage:                  return PAGEUPKEY;
1427                         case GHOST_kKeyDownPage:                return PAGEDOWNKEY;
1428                                 
1429                         case GHOST_kKeyNumpadPeriod:    return PADPERIOD;
1430                         case GHOST_kKeyNumpadEnter:             return PADENTER;
1431                         case GHOST_kKeyNumpadPlus:              return PADPLUSKEY;
1432                         case GHOST_kKeyNumpadMinus:             return PADMINUS;
1433                         case GHOST_kKeyNumpadAsterisk:  return PADASTERKEY;
1434                         case GHOST_kKeyNumpadSlash:             return PADSLASHKEY;
1435                                 
1436                         case GHOST_kKeyGrLess:              return GRLESSKEY; 
1437                                 
1438                         default:
1439                                 return UNKNOWNKEY;      /* GHOST_kKeyUnknown */
1440                 }
1441         }
1442 }
1443
1444 /* adds customdata to event */
1445 static void update_tablet_data(wmWindow *win, wmEvent *event)
1446 {
1447         const GHOST_TabletData *td= GHOST_GetTabletData(win->ghostwin);
1448         
1449         /* if there's tablet data from an active tablet device then add it */
1450         if ((td != NULL) && td->Active) {
1451                 struct wmTabletData *wmtab= MEM_mallocN(sizeof(wmTabletData), "customdata tablet");
1452                 
1453                 wmtab->Active = td->Active;
1454                 wmtab->Pressure = td->Pressure;
1455                 wmtab->Xtilt = td->Xtilt;
1456                 wmtab->Ytilt = td->Ytilt;
1457                 
1458                 event->custom= EVT_DATA_TABLET;
1459                 event->customdata= wmtab;
1460                 event->customdatafree= 1;
1461         } 
1462 }
1463
1464
1465 /* windows store own event queues, no bContext here */
1466 void wm_event_add_ghostevent(wmWindow *win, int type, void *customdata)
1467 {
1468         wmEvent event, *evt= win->eventstate;
1469         
1470         /* initialize and copy state (only mouse x y and modifiers) */
1471         event= *evt;
1472         
1473         switch (type) {
1474                 /* mouse move */
1475                 case GHOST_kEventCursorMove: {
1476                         if(win->active) {
1477                                 GHOST_TEventCursorData *cd= customdata;
1478                                 int cx, cy;
1479
1480                                 GHOST_ScreenToClient(win->ghostwin, cd->x, cd->y, &cx, &cy);
1481                                 
1482                                 event.type= MOUSEMOVE;
1483                                 event.x= evt->x= cx;
1484                                 event.y= evt->y= (win->sizey-1) - cy;
1485                                 
1486                                 update_tablet_data(win, &event);
1487                                 wm_event_add(win, &event);
1488                         }
1489                         break;
1490                 }
1491                 /* mouse button */
1492                 case GHOST_kEventButtonDown:
1493                 case GHOST_kEventButtonUp: {
1494                         GHOST_TEventButtonData *bd= customdata;
1495                         event.val= (type==GHOST_kEventButtonDown);
1496                         
1497                         if (bd->button == GHOST_kButtonMaskLeft)
1498                                 event.type= LEFTMOUSE;
1499                         else if (bd->button == GHOST_kButtonMaskRight)
1500                                 event.type= RIGHTMOUSE;
1501                         else
1502                                 event.type= MIDDLEMOUSE;
1503                         
1504                         if(event.val)
1505                                 event.keymodifier= evt->keymodifier= event.type;
1506                         else
1507                                 event.keymodifier= evt->keymodifier= 0;
1508                         
1509                         update_tablet_data(win, &event);
1510                         wm_event_add(win, &event);
1511                         
1512                         break;
1513                 }
1514                 /* keyboard */
1515                 case GHOST_kEventKeyDown:
1516                 case GHOST_kEventKeyUp: {
1517                         GHOST_TEventKeyData *kd= customdata;
1518                         event.type= convert_key(kd->key);
1519                         event.ascii= kd->ascii;
1520                         event.val= (type==GHOST_kEventKeyDown)?KM_PRESS:KM_RELEASE;
1521                         
1522                         /* exclude arrow keys, esc, etc from text input */
1523                         if(type==GHOST_kEventKeyUp || (event.ascii<32 && event.ascii>14))
1524                                 event.ascii= '\0';
1525                         
1526                         /* modifiers */
1527                         if (event.type==LEFTSHIFTKEY || event.type==RIGHTSHIFTKEY) {
1528                                 event.shift= evt->shift= (event.val==KM_PRESS);
1529                                 if(event.val==KM_PRESS && (evt->ctrl || evt->alt || evt->oskey))
1530                                    event.shift= evt->shift = 3;         // define?
1531                         } 
1532                         else if (event.type==LEFTCTRLKEY || event.type==RIGHTCTRLKEY) {
1533                                 event.ctrl= evt->ctrl= (event.val==KM_PRESS);
1534                                 if(event.val==KM_PRESS && (evt->shift || evt->alt || evt->oskey))
1535                                    event.ctrl= evt->ctrl = 3;           // define?
1536                         } 
1537                         else if (event.type==LEFTALTKEY || event.type==RIGHTALTKEY) {
1538                                 event.alt= evt->alt= (event.val==KM_PRESS);
1539                                 if(event.val==KM_PRESS && (evt->ctrl || evt->shift || evt->oskey))
1540                                    event.alt= evt->alt = 3;             // define?
1541                         } 
1542                         else if (event.type==COMMANDKEY) {
1543                                 event.oskey= evt->oskey= (event.val==KM_PRESS);
1544                                 if(event.val==KM_PRESS && (evt->ctrl || evt->alt || evt->shift))
1545                                    event.oskey= evt->oskey = 3;         // define?
1546                         }
1547                         
1548                         /* if test_break set, it catches this. XXX Keep global for now? */
1549                         if(event.type==ESCKEY)
1550                                 G.afbreek= 1;
1551
1552                         wm_event_add(win, &event);
1553                         
1554                         break;
1555                 }
1556                         
1557                 case GHOST_kEventWheel: {
1558                         GHOST_TEventWheelData* wheelData = customdata;
1559                         
1560                         if (wheelData->z > 0)
1561                                 event.type= WHEELUPMOUSE;
1562                         else
1563                                 event.type= WHEELDOWNMOUSE;
1564                         
1565                         event.val= KM_PRESS;
1566                         wm_event_add(win, &event);
1567                         
1568                         break;
1569                 }
1570                 case GHOST_kEventTimer: {
1571                         event.type= TIMER;
1572                         event.custom= EVT_DATA_TIMER;
1573                         event.customdata= customdata;
1574                         wm_event_add(win, &event);
1575
1576                         break;
1577                 }
1578
1579                 case GHOST_kEventUnknown:
1580                 case GHOST_kNumEventTypes:
1581                         break;
1582         }
1583 }