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