2.5 Audio:
[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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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_main.h"
49 #include "BKE_report.h"
50 #include "BKE_scene.h"
51 #include "BKE_screen.h"
52 #include "BKE_utildefines.h"
53 #include "BKE_sound.h"
54
55 #include "ED_fileselect.h"
56 #include "ED_info.h"
57 #include "ED_screen.h"
58 #include "ED_space_api.h"
59 #include "ED_util.h"
60
61 #include "RNA_access.h"
62
63 #include "UI_interface.h"
64
65 #include "PIL_time.h"
66
67 #include "WM_api.h"
68 #include "WM_types.h"
69 #include "wm.h"
70 #include "wm_window.h"
71 #include "wm_event_system.h"
72 #include "wm_event_types.h"
73
74 /* ************ event management ************** */
75
76 void wm_event_add(wmWindow *win, wmEvent *event_to_add)
77 {
78         wmEvent *event= MEM_callocN(sizeof(wmEvent), "event");
79         
80         *event= *event_to_add;
81         BLI_addtail(&win->queue, event);
82 }
83
84 void wm_event_free(wmEvent *event)
85 {
86         if(event->customdata) {
87                 if(event->customdatafree) {
88                         /* note: pointer to listbase struct elsewhere */
89                         if(event->custom==EVT_DATA_LISTBASE)
90                                 BLI_freelistN(event->customdata);
91                         else
92                                 MEM_freeN(event->customdata);
93                 }
94         }
95         MEM_freeN(event);
96 }
97
98 void wm_event_free_all(wmWindow *win)
99 {
100         wmEvent *event;
101         
102         while((event= win->queue.first)) {
103                 BLI_remlink(&win->queue, event);
104                 wm_event_free(event);
105         }
106 }
107
108 /* ********************* notifiers, listeners *************** */
109
110 /* XXX: in future, which notifiers to send to other windows? */
111 void WM_event_add_notifier(const bContext *C, unsigned int type, void *reference)
112 {
113         wmNotifier *note= MEM_callocN(sizeof(wmNotifier), "notifier");
114         
115         note->wm= CTX_wm_manager(C);
116         BLI_addtail(&note->wm->queue, note);
117         
118         note->window= CTX_wm_window(C);
119         
120         if(CTX_wm_region(C))
121                 note->swinid= CTX_wm_region(C)->swinid;
122         
123         note->category= type & NOTE_CATEGORY;
124         note->data= type & NOTE_DATA;
125         note->subtype= type & NOTE_SUBTYPE;
126         note->action= type & NOTE_ACTION;
127         
128         note->reference= reference;
129 }
130
131 void WM_main_add_notifier(unsigned int type, void *reference)
132 {
133         Main *bmain= G.main;
134         wmWindowManager *wm= bmain->wm.first;
135
136         if(wm) {
137                 wmNotifier *note= MEM_callocN(sizeof(wmNotifier), "notifier");
138                 
139                 note->wm= wm;
140                 BLI_addtail(&note->wm->queue, note);
141                 
142                 note->category= type & NOTE_CATEGORY;
143                 note->data= type & NOTE_DATA;
144                 note->subtype= type & NOTE_SUBTYPE;
145                 note->action= type & NOTE_ACTION;
146                 
147                 note->reference= reference;
148         }
149 }
150
151 static wmNotifier *wm_notifier_next(wmWindowManager *wm)
152 {
153         wmNotifier *note= wm->queue.first;
154         
155         if(note) BLI_remlink(&wm->queue, note);
156         return note;
157 }
158
159 /* called in mainloop */
160 void wm_event_do_notifiers(bContext *C)
161 {
162         wmWindowManager *wm= CTX_wm_manager(C);
163         wmNotifier *note, *next;
164         wmWindow *win;
165         
166         if(wm==NULL)
167                 return;
168         
169         /* cache & catch WM level notifiers, such as frame change, scene/screen set */
170         for(win= wm->windows.first; win; win= win->next) {
171                 int do_anim= 0;
172                 
173                 CTX_wm_window_set(C, win);
174                 
175                 for(note= wm->queue.first; note; note= next) {
176                         next= note->next;
177
178                         if(note->category==NC_WM) {
179                                 if( ELEM(note->data, ND_FILEREAD, ND_FILESAVE)) {
180                                         wm->file_saved= 1;
181                                         wm_window_title(wm, win);
182                                 }
183                                 else if(note->data==ND_DATACHANGED)
184                                         wm_window_title(wm, win);
185                         }
186                         if(note->window==win) {
187                                 if(note->category==NC_SCREEN) {
188                                         if(note->data==ND_SCREENBROWSE) {
189                                                 ED_screen_set(C, note->reference);      // XXX hrms, think this over!
190                                                 if(G.f & G_DEBUG)
191                                                         printf("screen set %p\n", note->reference);
192                                         }
193                                         else if(note->data==ND_SCREENDELETE) {
194                                                 ED_screen_delete(C, note->reference);   // XXX hrms, think this over!
195                                                 if(G.f & G_DEBUG)
196                                                         printf("screen delete %p\n", note->reference);
197                                         }
198                                 }
199                         }
200
201                         if(note->window==win || (note->window == NULL && (note->reference == NULL || note->reference == CTX_data_scene(C)))) {
202                                 if(note->category==NC_SCENE) {
203                                         if(note->data==ND_SCENEBROWSE) {
204                                                 ED_screen_set_scene(C, note->reference);        // XXX hrms, think this over!
205                                                 if(G.f & G_DEBUG)
206                                                         printf("scene set %p\n", note->reference);
207                                         }
208                                         else if(note->data==ND_FRAME)
209                                                 do_anim= 1;
210                                         
211                                         if(note->action == NA_REMOVED) {
212                                                 ED_screen_delete_scene(C, note->reference);     // XXX hrms, think this over!
213                                                 if(G.f & G_DEBUG)
214                                                         printf("scene delete %p\n", note->reference);
215                                         }
216                                                 
217                                 }
218                         }
219                         if(ELEM4(note->category, NC_SCENE, NC_OBJECT, NC_GEOM, NC_SCENE)) {
220                                 ED_info_stats_clear(CTX_data_scene(C));
221                                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_INFO, NULL);
222                         }
223                 }
224                 if(do_anim) {
225                         /* depsgraph gets called, might send more notifiers */
226                         ED_update_for_newframe(C, 1);
227                 }
228         }
229         
230         /* the notifiers are sent without context, to keep it clean */
231         while( (note=wm_notifier_next(wm)) ) {
232                 wmWindow *win;
233                 
234                 for(win= wm->windows.first; win; win= win->next) {
235                         
236                         /* filter out notifiers */
237                         if(note->category==NC_SCREEN && note->reference && note->reference!=win->screen);
238                         else if(note->category==NC_SCENE && note->reference && note->reference!=win->screen->scene);
239                         else {
240                                 ScrArea *sa;
241                                 ARegion *ar;
242
243                                 /* XXX context in notifiers? */
244                                 CTX_wm_window_set(C, win);
245
246                                 /* printf("notifier win %d screen %s cat %x\n", win->winid, win->screen->id.name+2, note->category); */
247                                 ED_screen_do_listen(win, note);
248
249                                 for(ar=win->screen->regionbase.first; ar; ar= ar->next) {
250                                         ED_region_do_listen(ar, note);
251                                 }
252                                 
253                                 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
254                                         ED_area_do_listen(sa, note);
255                                         for(ar=sa->regionbase.first; ar; ar= ar->next) {
256                                                 ED_region_do_listen(ar, note);
257                                         }
258                                 }
259                         }
260                 }
261                 
262                 MEM_freeN(note);
263         }
264         
265         /* cached: editor refresh callbacks now, they get context */
266         for(win= wm->windows.first; win; win= win->next) {
267                 ScrArea *sa;
268                 
269                 CTX_wm_window_set(C, win);
270                 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
271                         if(sa->do_refresh) {
272                                 CTX_wm_area_set(C, sa);
273                                 ED_area_do_refresh(C, sa);
274                         }
275                 }
276                 
277                 /* XXX make lock in future, or separated derivedmesh users in scene */
278                 if(!G.rendering)
279                         /* depsgraph & animation: update tagged datablocks */
280                         scene_update_tagged(win->screen->scene);
281         }
282
283         CTX_wm_window_set(C, NULL);
284 }
285
286 /* ********************* ui handler ******************* */
287
288 static int wm_handler_ui_call(bContext *C, wmEventHandler *handler, wmEvent *event, int always_pass)
289 {
290         ScrArea *area= CTX_wm_area(C);
291         ARegion *region= CTX_wm_region(C);
292         ARegion *menu= CTX_wm_menu(C);
293         int retval;
294                         
295         /* we set context to where ui handler came from */
296         if(handler->ui_area) CTX_wm_area_set(C, handler->ui_area);
297         if(handler->ui_region) CTX_wm_region_set(C, handler->ui_region);
298         if(handler->ui_menu) CTX_wm_menu_set(C, handler->ui_menu);
299
300         retval= handler->ui_handle(C, event, handler->ui_userdata);
301
302         /* putting back screen context */
303         if((retval != WM_UI_HANDLER_BREAK) || always_pass) {
304                 CTX_wm_area_set(C, area);
305                 CTX_wm_region_set(C, region);
306                 CTX_wm_menu_set(C, menu);
307         }
308         else {
309                 /* this special cases is for areas and regions that get removed */
310                 CTX_wm_area_set(C, NULL);
311                 CTX_wm_region_set(C, NULL);
312                 CTX_wm_menu_set(C, NULL);
313         }
314
315         if(retval == WM_UI_HANDLER_BREAK)
316                 return WM_HANDLER_BREAK;
317
318         return WM_HANDLER_CONTINUE;
319 }
320
321 static void wm_handler_ui_cancel(bContext *C)
322 {
323         wmWindow *win= CTX_wm_window(C);
324         ARegion *ar= CTX_wm_region(C);
325         wmEventHandler *handler, *nexthandler;
326
327         if(!ar)
328                 return;
329
330         for(handler= ar->handlers.first; handler; handler= nexthandler) {
331                 nexthandler= handler->next;
332
333                 if(handler->ui_handle) {
334                         wmEvent event= *(win->eventstate);
335                         event.type= EVT_BUT_CANCEL;
336                         handler->ui_handle(C, &event, handler->ui_userdata);
337                 }
338         }
339 }
340
341 /* ********************* operators ******************* */
342
343 int WM_operator_poll(bContext *C, wmOperatorType *ot)
344 {
345         wmOperatorTypeMacro *otmacro;
346         
347         for(otmacro= ot->macro.first; otmacro; otmacro= otmacro->next) {
348                 wmOperatorType *ot= WM_operatortype_find(otmacro->idname, 0);
349                 
350                 if(0==WM_operator_poll(C, ot))
351                         return 0;
352         }
353         
354         /* python needs operator type, so we added exception for it */
355         if(ot->pyop_poll)
356                 return ot->pyop_poll(C, ot);
357         else if(ot->poll)
358                 return ot->poll(C);
359
360         return 1;
361 }
362
363 static void wm_operator_finished(bContext *C, wmOperator *op, int repeat)
364 {
365         wmWindowManager *wm= CTX_wm_manager(C);
366
367         op->customdata= NULL;
368
369         /* we don't want to do undo pushes for operators that are being
370            called from operators that already do an undo push. usually
371            this will happen for python operators that call C operators */
372         if(wm->op_undo_depth == 0)
373                 if(op->type->flag & OPTYPE_UNDO)
374                         ED_undo_push_op(C, op);
375         
376         if(repeat==0) {
377                 if(G.f & G_DEBUG) {
378                         char *buf = WM_operator_pystring(C, op->type, op->ptr, 1);
379                         BKE_report(CTX_wm_reports(C), RPT_OPERATOR, buf);
380                         MEM_freeN(buf);
381                 }
382
383                 if((wm->op_undo_depth == 0) && (op->type->flag & OPTYPE_REGISTER))
384                         wm_operator_register(C, op);
385                 else
386                         WM_operator_free(op);
387         }
388 }
389
390 /* if repeat is true, it doesn't register again, nor does it free */
391 static int wm_operator_exec(bContext *C, wmOperator *op, int repeat)
392 {
393         wmWindowManager *wm= CTX_wm_manager(C);
394         int retval= OPERATOR_CANCELLED;
395         
396         if(op==NULL || op->type==NULL)
397                 return retval;
398         
399         if(0==WM_operator_poll(C, op->type))
400                 return retval;
401         
402         if(op->type->exec) {
403                 if(op->type->flag & OPTYPE_UNDO)
404                         wm->op_undo_depth++;
405
406                 retval= op->type->exec(C, op);
407
408                 if(op->type->flag & OPTYPE_UNDO)
409                         wm->op_undo_depth--;
410         }
411         
412         if(retval & (OPERATOR_FINISHED|OPERATOR_CANCELLED))
413                 if(op->reports->list.first)
414                         uiPupMenuReports(C, op->reports);
415         
416         if(retval & OPERATOR_FINISHED)
417                 wm_operator_finished(C, op, repeat);
418         else if(repeat==0)
419                 WM_operator_free(op);
420         
421         return retval | OPERATOR_HANDLED;
422         
423 }
424
425 /* for running operators with frozen context (modal handlers, menus) */
426 int WM_operator_call(bContext *C, wmOperator *op)
427 {
428         return wm_operator_exec(C, op, 0);
429 }
430
431 /* do this operator again, put here so it can share above code */
432 int WM_operator_repeat(bContext *C, wmOperator *op)
433 {
434         return wm_operator_exec(C, op, 1);
435 }
436
437 static wmOperator *wm_operator_create(wmWindowManager *wm, wmOperatorType *ot, PointerRNA *properties, ReportList *reports)
438 {
439         wmOperator *op= MEM_callocN(sizeof(wmOperator), ot->idname);    /* XXX operatortype names are static still. for debug */
440         
441         /* XXX adding new operator could be function, only happens here now */
442         op->type= ot;
443         BLI_strncpy(op->idname, ot->idname, OP_MAX_TYPENAME);
444         
445         /* initialize properties, either copy or create */
446         op->ptr= MEM_callocN(sizeof(PointerRNA), "wmOperatorPtrRNA");
447         if(properties && properties->data) {
448                 op->properties= IDP_CopyProperty(properties->data);
449         }
450         else {
451                 IDPropertyTemplate val = {0};
452                 op->properties= IDP_New(IDP_GROUP, val, "wmOperatorProperties");
453         }
454         RNA_pointer_create(&wm->id, ot->srna, op->properties, op->ptr);
455
456         /* initialize error reports */
457         if (reports) {
458                 op->reports= reports; /* must be initialized already */
459         }
460         else {
461                 op->reports= MEM_mallocN(sizeof(ReportList), "wmOperatorReportList");
462                 BKE_reports_init(op->reports, RPT_STORE|RPT_FREE);
463         }
464         
465         /* recursive filling of operator macro list */
466         if(ot->macro.first) {
467                 static wmOperator *motherop= NULL;
468                 wmOperatorTypeMacro *otmacro;
469                 int root = 0;
470                 
471                 /* ensure all ops are in execution order in 1 list */
472                 if(motherop==NULL) {
473                         motherop = op;
474                         root = 1;
475                 }
476
477                 
478                 /* if properties exist, it will contain everything needed */
479                 if (properties) {
480                         otmacro= ot->macro.first;
481
482                         RNA_STRUCT_BEGIN(properties, prop) {
483
484                                 if (otmacro == NULL)
485                                         break;
486
487                                 /* skip invalid properties */
488                                 if (strcmp(RNA_property_identifier(prop), otmacro->idname) == 0)
489                                 {
490                                         wmOperatorType *otm= WM_operatortype_find(otmacro->idname, 0);
491                                         PointerRNA someptr = RNA_property_pointer_get(properties, prop);
492                                         wmOperator *opm= wm_operator_create(wm, otm, &someptr, NULL);
493
494                                         IDP_ReplaceGroupInGroup(opm->properties, otmacro->properties);
495
496                                         BLI_addtail(&motherop->macro, opm);
497                                         opm->opm= motherop; /* pointer to mom, for modal() */
498
499                                         otmacro= otmacro->next;
500                                 }
501                         }
502                         RNA_STRUCT_END;
503                 } else {
504                         for (otmacro = ot->macro.first; otmacro; otmacro = otmacro->next) {
505                                 wmOperatorType *otm= WM_operatortype_find(otmacro->idname, 0);
506                                 wmOperator *opm= wm_operator_create(wm, otm, otmacro->ptr, NULL);
507
508                                 BLI_addtail(&motherop->macro, opm);
509                                 opm->opm= motherop; /* pointer to mom, for modal() */
510                         }
511                 }
512                 
513                 if (root)
514                         motherop= NULL;
515         }
516         
517         WM_operator_properties_sanitize(op->ptr, 0);
518
519         return op;
520 }
521
522 static void wm_operator_print(wmOperator *op)
523 {
524         char *buf = WM_operator_pystring(NULL, op->type, op->ptr, 1);
525         printf("%s\n", buf);
526         MEM_freeN(buf);
527 }
528
529 static void wm_region_mouse_co(bContext *C, wmEvent *event)
530 {
531         ARegion *ar= CTX_wm_region(C);
532         if(ar) {
533                 /* compatibility convention */
534                 event->mval[0]= event->x - ar->winrct.xmin;
535                 event->mval[1]= event->y - ar->winrct.ymin;
536         }
537 }
538
539 static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, PointerRNA *properties, ReportList *reports)
540 {
541         wmWindowManager *wm= CTX_wm_manager(C);
542         int retval= OPERATOR_PASS_THROUGH;
543
544         if(WM_operator_poll(C, ot)) {
545                 wmOperator *op= wm_operator_create(wm, ot, properties, reports); /* if reports==NULL, theyll be initialized */
546                 
547                 if((G.f & G_DEBUG) && event && event->type!=MOUSEMOVE)
548                         printf("handle evt %d win %d op %s\n", event?event->type:0, CTX_wm_screen(C)->subwinactive, ot->idname); 
549                 
550                 if(op->type->invoke && event) {
551                         wm_region_mouse_co(C, event);
552
553                         if(op->type->flag & OPTYPE_UNDO)
554                                 wm->op_undo_depth++;
555
556                         retval= op->type->invoke(C, op, event);
557
558                         if(op->type->flag & OPTYPE_UNDO)
559                                 wm->op_undo_depth--;
560                 }
561                 else if(op->type->exec) {
562                         if(op->type->flag & OPTYPE_UNDO)
563                                 wm->op_undo_depth++;
564
565                         retval= op->type->exec(C, op);
566
567                         if(op->type->flag & OPTYPE_UNDO)
568                                 wm->op_undo_depth--;
569                 }
570                 else
571                         printf("invalid operator call %s\n", ot->idname); /* debug, important to leave a while, should never happen */
572
573                 /* Note, if the report is given as an argument then assume the caller will deal with displaying them
574                  * currently python only uses this */
575                 if((retval & (OPERATOR_FINISHED|OPERATOR_CANCELLED)) && reports==NULL)
576                         if(op->reports->list.first) /* only show the report if the report list was not given in the function */
577                                 uiPupMenuReports(C, op->reports);
578                 
579                 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 */
580                         if(G.f & G_DEBUG)
581                                 wm_operator_print(op);
582                 }
583
584                 if(retval & OPERATOR_HANDLED)
585                         ; /* do nothing, wm_operator_exec() has been called somewhere */
586                 else if(retval & OPERATOR_FINISHED) {
587                         wm_operator_finished(C, op, 0);
588                 }
589                 else if(retval & OPERATOR_RUNNING_MODAL) {
590                         /* grab cursor during blocking modal ops (X11)
591                          * Also check for macro
592                          * */
593                         if(ot->flag & OPTYPE_BLOCKING || (op->opm && op->opm->type->flag & OPTYPE_BLOCKING)) {
594                                 int bounds[4] = {-1,-1,-1,-1};
595                                 int wrap;
596
597                                 if (op->opm) {
598                                         wrap = (U.uiflag & USER_CONTINUOUS_MOUSE) && ((op->opm->flag & OP_GRAB_POINTER) || (op->opm->type->flag & OPTYPE_GRAB_POINTER));
599                                 } else {
600                                         wrap = (U.uiflag & USER_CONTINUOUS_MOUSE) && ((op->flag & OP_GRAB_POINTER) || (ot->flag & OPTYPE_GRAB_POINTER));
601                                 }
602
603                                 if(wrap) {
604                                         ARegion *ar= CTX_wm_region(C);
605                                         if(ar) {
606                                                 bounds[0]= ar->winrct.xmin;
607                                                 bounds[1]= ar->winrct.ymax;
608                                                 bounds[2]= ar->winrct.xmax;
609                                                 bounds[3]= ar->winrct.ymin;
610                                         }
611                                 }
612
613                                 WM_cursor_grab(CTX_wm_window(C), wrap, FALSE, bounds);
614                         }
615
616                         /* cancel UI handlers, typically tooltips that can hang around
617                            while dragging the view or worse, that stay there permanently
618                            after the modal operator has swallowed all events and passed
619                            none to the UI handler */
620                         wm_handler_ui_cancel(C);
621                 }
622                 else
623                         WM_operator_free(op);
624         }
625
626         return retval;
627 }
628
629 /* WM_operator_name_call is the main accessor function
630  * this is for python to access since its done the operator lookup
631  * 
632  * invokes operator in context */
633 static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, int context, PointerRNA *properties, ReportList *reports)
634 {
635         wmWindow *window= CTX_wm_window(C);
636         wmEvent *event;
637         
638         int retval;
639
640         /* dummie test */
641         if(ot && C) {
642                 switch(context) {
643                         case WM_OP_INVOKE_DEFAULT:
644                         case WM_OP_INVOKE_REGION_WIN:
645                         case WM_OP_INVOKE_AREA:
646                         case WM_OP_INVOKE_SCREEN:
647                                 /* window is needed for invoke, cancel operator */
648                                 if (window == NULL)
649                                         return 0;
650                                 else
651                                         event= window->eventstate;
652                                 break;
653                         default:
654                                 event = NULL;
655                 }
656
657                 switch(context) {
658                         
659                         case WM_OP_EXEC_REGION_WIN:
660                         case WM_OP_INVOKE_REGION_WIN: 
661                         case WM_OP_EXEC_REGION_CHANNELS:
662                         case WM_OP_INVOKE_REGION_CHANNELS:
663                         case WM_OP_EXEC_REGION_PREVIEW:
664                         case WM_OP_INVOKE_REGION_PREVIEW:
665                         {
666                                 /* forces operator to go to the region window/channels/preview, for header menus
667                                  * but we stay in the same region if we are already in one 
668                                  */
669                                 ARegion *ar= CTX_wm_region(C);
670                                 ScrArea *area= CTX_wm_area(C);
671                                 int type = RGN_TYPE_WINDOW;
672                                 
673                                 switch (context) {
674                                         case WM_OP_EXEC_REGION_CHANNELS:
675                                         case WM_OP_INVOKE_REGION_CHANNELS:
676                                                 type = RGN_TYPE_CHANNELS;
677                                         
678                                         case WM_OP_EXEC_REGION_PREVIEW:
679                                         case WM_OP_INVOKE_REGION_PREVIEW:
680                                                 type = RGN_TYPE_PREVIEW;
681                                                 break;
682                                         
683                                         case WM_OP_EXEC_REGION_WIN:
684                                         case WM_OP_INVOKE_REGION_WIN: 
685                                         default:
686                                                 type = RGN_TYPE_WINDOW;
687                                                 break;
688                                 }
689                                 
690                                 if(!(ar && ar->regiontype == type) && area) {
691                                         ARegion *ar1= BKE_area_find_region_type(area, type);
692                                         if(ar1)
693                                                 CTX_wm_region_set(C, ar1);
694                                 }
695                                 
696                                 retval= wm_operator_invoke(C, ot, event, properties, reports);
697                                 
698                                 /* set region back */
699                                 CTX_wm_region_set(C, ar);
700                                 
701                                 return retval;
702                         }
703                         case WM_OP_EXEC_AREA:
704                         case WM_OP_INVOKE_AREA:
705                         {
706                                         /* remove region from context */
707                                 ARegion *ar= CTX_wm_region(C);
708
709                                 CTX_wm_region_set(C, NULL);
710                                 retval= wm_operator_invoke(C, ot, event, properties, reports);
711                                 CTX_wm_region_set(C, ar);
712
713                                 return retval;
714                         }
715                         case WM_OP_EXEC_SCREEN:
716                         case WM_OP_INVOKE_SCREEN:
717                         {
718                                 /* remove region + area from context */
719                                 ARegion *ar= CTX_wm_region(C);
720                                 ScrArea *area= CTX_wm_area(C);
721
722                                 CTX_wm_region_set(C, NULL);
723                                 CTX_wm_area_set(C, NULL);
724                                 retval= wm_operator_invoke(C, ot, event, properties, reports);
725                                 CTX_wm_region_set(C, ar);
726                                 CTX_wm_area_set(C, area);
727
728                                 return retval;
729                         }
730                         case WM_OP_EXEC_DEFAULT:
731                         case WM_OP_INVOKE_DEFAULT:
732                                 return wm_operator_invoke(C, ot, event, properties, reports);
733                 }
734         }
735         
736         return 0;
737 }
738
739
740 /* invokes operator in context */
741 int WM_operator_name_call(bContext *C, const char *opstring, int context, PointerRNA *properties)
742 {
743         wmOperatorType *ot= WM_operatortype_find(opstring, 0);
744         if(ot)
745                 return wm_operator_call_internal(C, ot, context, properties, NULL);
746
747         return 0;
748 }
749
750 /* Similar to WM_operator_name_call called with WM_OP_EXEC_DEFAULT context.
751    - wmOperatorType is used instead of operator name since python alredy has the operator type
752    - poll() must be called by python before this runs.
753    - reports can be passed to this function (so python can report them as exceptions)
754 */
755 int WM_operator_call_py(bContext *C, wmOperatorType *ot, int context, PointerRNA *properties, ReportList *reports)
756 {
757         int retval= OPERATOR_CANCELLED;
758
759 #if 0
760         wmOperator *op;
761         wmWindowManager *wm=    CTX_wm_manager(C);
762         op= wm_operator_create(wm, ot, properties, reports);
763
764         if (op->type->exec) {
765                 if(op->type->flag & OPTYPE_UNDO)
766                         wm->op_undo_depth++;
767
768                 retval= op->type->exec(C, op);
769
770                 if(op->type->flag & OPTYPE_UNDO)
771                         wm->op_undo_depth--;
772         }
773         else
774                 printf("error \"%s\" operator has no exec function, python cannot call it\n", op->type->name);
775 #endif
776
777         retval= wm_operator_call_internal(C, ot, context, properties, reports);
778         
779         /* keep the reports around if needed later */
780         if (retval & OPERATOR_RUNNING_MODAL || ot->flag & OPTYPE_REGISTER)
781         {
782                 reports->flag |= RPT_FREE;
783         }
784         
785         return retval;
786 }
787
788
789 /* ********************* handlers *************** */
790
791 /* future extra customadata free? */
792 void wm_event_free_handler(wmEventHandler *handler)
793 {
794         MEM_freeN(handler);
795 }
796
797 /* only set context when area/region is part of screen */
798 static void wm_handler_op_context(bContext *C, wmEventHandler *handler)
799 {
800         bScreen *screen= CTX_wm_screen(C);
801         
802         if(screen && handler->op) {
803                 if(handler->op_area==NULL)
804                         CTX_wm_area_set(C, NULL);
805                 else {
806                         ScrArea *sa;
807                         
808                         for(sa= screen->areabase.first; sa; sa= sa->next)
809                                 if(sa==handler->op_area)
810                                         break;
811                         if(sa==NULL) {
812                                 /* when changing screen layouts with running modal handlers (like render display), this
813                                    is not an error to print */
814                                 if(handler->op==NULL)
815                                         printf("internal error: handler (%s) has invalid area\n", handler->op->type->idname);
816                         }
817                         else {
818                                 ARegion *ar;
819                                 CTX_wm_area_set(C, sa);
820                                 for(ar= sa->regionbase.first; ar; ar= ar->next)
821                                         if(ar==handler->op_region)
822                                                 break;
823                                 /* XXX no warning print here, after full-area and back regions are remade */
824                                 if(ar)
825                                         CTX_wm_region_set(C, ar);
826                         }
827                 }
828         }
829 }
830
831 /* called on exit or remove area, only here call cancel callback */
832 void WM_event_remove_handlers(bContext *C, ListBase *handlers)
833 {
834         wmEventHandler *handler;
835         wmWindowManager *wm= CTX_wm_manager(C);
836         
837         /* C is zero on freeing database, modal handlers then already were freed */
838         while((handler=handlers->first)) {
839                 BLI_remlink(handlers, handler);
840                 
841                 if(handler->op) {
842                         if(handler->op->type->cancel) {
843                                 ScrArea *area= CTX_wm_area(C);
844                                 ARegion *region= CTX_wm_region(C);
845                                 
846                                 wm_handler_op_context(C, handler);
847
848                                 if(handler->op->type->flag & OPTYPE_UNDO)
849                                         wm->op_undo_depth++;
850
851                                 handler->op->type->cancel(C, handler->op);
852
853                                 if(handler->op->type->flag & OPTYPE_UNDO)
854                                         wm->op_undo_depth--;
855
856                                 CTX_wm_area_set(C, area);
857                                 CTX_wm_region_set(C, region);
858                         }
859
860                         WM_cursor_ungrab(CTX_wm_window(C));
861                         WM_operator_free(handler->op);
862                 }
863                 else if(handler->ui_remove) {
864                         ScrArea *area= CTX_wm_area(C);
865                         ARegion *region= CTX_wm_region(C);
866                         ARegion *menu= CTX_wm_menu(C);
867                         
868                         if(handler->ui_area) CTX_wm_area_set(C, handler->ui_area);
869                         if(handler->ui_region) CTX_wm_region_set(C, handler->ui_region);
870                         if(handler->ui_menu) CTX_wm_menu_set(C, handler->ui_menu);
871
872                         handler->ui_remove(C, handler->ui_userdata);
873
874                         CTX_wm_area_set(C, area);
875                         CTX_wm_region_set(C, region);
876                         CTX_wm_menu_set(C, menu);
877                 }
878
879                 wm_event_free_handler(handler);
880         }
881 }
882
883 /* do userdef mappings */
884 int WM_userdef_event_map(int kmitype)
885 {
886         switch(kmitype) {
887                 case SELECTMOUSE:
888                         if(U.flag & USER_LMOUSESELECT)
889                                 return LEFTMOUSE;
890                         else
891                                 return RIGHTMOUSE;
892                         
893                 case ACTIONMOUSE:
894                         if(U.flag & USER_LMOUSESELECT)
895                                 return RIGHTMOUSE;
896                         else
897                                 return LEFTMOUSE;
898                         
899                 case WHEELOUTMOUSE:
900                         if(U.uiflag & USER_WHEELZOOMDIR)
901                                 return WHEELUPMOUSE;
902                         else
903                                 return WHEELDOWNMOUSE;
904                         
905                 case WHEELINMOUSE:
906                         if(U.uiflag & USER_WHEELZOOMDIR)
907                                 return WHEELDOWNMOUSE;
908                         else
909                                 return WHEELUPMOUSE;
910                         
911                 case EVT_TWEAK_A:
912                         if(U.flag & USER_LMOUSESELECT)
913                                 return EVT_TWEAK_R;
914                         else
915                                 return EVT_TWEAK_L;
916                         
917                 case EVT_TWEAK_S:
918                         if(U.flag & USER_LMOUSESELECT)
919                                 return EVT_TWEAK_L;
920                         else
921                                 return EVT_TWEAK_R;
922         }
923         
924         return kmitype;
925 }
926
927 static void wm_eventemulation(wmEvent *event)
928 {
929         static int mmb_emulated = 0; /* this should be in a data structure somwhere */
930         
931         /* middlemouse emulation */
932         if(U.flag & USER_TWOBUTTONMOUSE) {
933                 if(event->type == LEFTMOUSE && (event->alt || mmb_emulated == KM_PRESS)) {
934                         event->type = MIDDLEMOUSE;
935                         event->alt = 0;
936                         mmb_emulated = event->val;
937                 }
938         }
939
940 #ifdef __APPLE__
941         /* rightmouse emulation */
942         if(U.flag & USER_TWOBUTTONMOUSE) {
943                 if(event->type == LEFTMOUSE && (event->oskey || mmb_emulated == KM_PRESS)) {
944                         event->type = RIGHTMOUSE;
945                         event->oskey = 0;
946                         mmb_emulated = event->val;
947                 }
948         }
949 #endif
950
951         /* numpad emulation */
952         if(U.flag & USER_NONUMPAD) {
953                 switch(event->type) {
954                         case ZEROKEY: event->type = PAD0; break;
955                         case ONEKEY: event->type = PAD1; break;
956                         case TWOKEY: event->type = PAD2; break;
957                         case THREEKEY: event->type = PAD3; break;
958                         case FOURKEY: event->type = PAD4; break;
959                         case FIVEKEY: event->type = PAD5; break;
960                         case SIXKEY: event->type = PAD6; break;
961                         case SEVENKEY: event->type = PAD7; break;
962                         case EIGHTKEY: event->type = PAD8; break;
963                         case NINEKEY: event->type = PAD9; break;
964                         case MINUSKEY: event->type = PADMINUS; break;
965                         case EQUALKEY: event->type = PADPLUSKEY; break;
966                         case BACKSLASHKEY: event->type = PADSLASHKEY; break;
967                 }
968         }
969 }
970
971 static int wm_eventmatch(wmEvent *winevent, wmKeyMapItem *kmi)
972 {
973         int kmitype= WM_userdef_event_map(kmi->type);
974
975         if(kmi->flag & KMI_INACTIVE) return 0;
976
977         /* the matching rules */
978         if(kmitype==KM_TEXTINPUT)
979                 if(ISTEXTINPUT(winevent->type) && winevent->ascii) return 1;
980         if(kmitype!=KM_ANY)
981                 if(winevent->type!=kmitype) return 0;
982         
983         if(kmi->val!=KM_ANY)
984                 if(winevent->val!=kmi->val) return 0;
985         
986         /* modifiers also check bits, so it allows modifier order */
987         if(kmi->shift!=KM_ANY)
988                 if(winevent->shift != kmi->shift && !(winevent->shift & kmi->shift)) return 0;
989         if(kmi->ctrl!=KM_ANY)
990                 if(winevent->ctrl != kmi->ctrl && !(winevent->ctrl & kmi->ctrl)) return 0;
991         if(kmi->alt!=KM_ANY)
992                 if(winevent->alt != kmi->alt && !(winevent->alt & kmi->alt)) return 0;
993         if(kmi->oskey!=KM_ANY)
994                 if(winevent->oskey != kmi->oskey && !(winevent->oskey & kmi->oskey)) return 0;
995         
996         if(kmi->keymodifier)
997                 if(winevent->keymodifier!=kmi->keymodifier) return 0;
998                 
999         /* key modifiers always check when event has it */
1000         /* otherwise regular keypresses with keymodifier still work */
1001         if(winevent->keymodifier)
1002                 if(ISTEXTINPUT(winevent->type)) 
1003                         if(winevent->keymodifier!=kmi->keymodifier) return 0;
1004         
1005         return 1;
1006 }
1007
1008 static int wm_event_always_pass(wmEvent *event)
1009 {
1010         /* some events we always pass on, to ensure proper communication */
1011         return ISTIMER(event->type) || (event->type == WINDEACTIVATE);
1012 }
1013
1014 /* operator exists */
1015 static void wm_event_modalkeymap(const bContext *C, wmOperator *op, wmEvent *event)
1016 {
1017         /* support for modal keymap in macros */
1018         if (op->opm)
1019                 op = op->opm;
1020
1021         if(op->type->modalkeymap) {
1022                 wmKeyMap *keymap= WM_keymap_active(CTX_wm_manager(C), op->type->modalkeymap);
1023                 wmKeyMapItem *kmi;
1024
1025                 for(kmi= keymap->items.first; kmi; kmi= kmi->next) {
1026                         if(wm_eventmatch(event, kmi)) {
1027                                         
1028                                 event->type= EVT_MODAL_MAP;
1029                                 event->val= kmi->propvalue;
1030                         }
1031                 }
1032         }
1033 }
1034
1035 /* Warning: this function removes a modal handler, when finished */
1036 static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHandler *handler, wmEvent *event, PointerRNA *properties)
1037 {
1038         int retval= OPERATOR_PASS_THROUGH;
1039         
1040         /* derived, modal or blocking operator */
1041         if(handler->op) {
1042                 wmOperator *op= handler->op;
1043                 wmOperatorType *ot= op->type;
1044
1045                 if(ot->modal) {
1046                         /* we set context to where modal handler came from */
1047                         wmWindowManager *wm= CTX_wm_manager(C);
1048                         ScrArea *area= CTX_wm_area(C);
1049                         ARegion *region= CTX_wm_region(C);
1050                         
1051                         wm_handler_op_context(C, handler);
1052                         wm_region_mouse_co(C, event);
1053                         wm_event_modalkeymap(C, op, event);
1054                         
1055                         if(ot->flag & OPTYPE_UNDO)
1056                                 wm->op_undo_depth++;
1057
1058                         retval= ot->modal(C, op, event);
1059
1060                         if(ot->flag & OPTYPE_UNDO)
1061                                 wm->op_undo_depth--;
1062
1063                         /* putting back screen context, reval can pass trough after modal failures! */
1064                         if((retval & OPERATOR_PASS_THROUGH) || wm_event_always_pass(event)) {
1065                                 CTX_wm_area_set(C, area);
1066                                 CTX_wm_region_set(C, region);
1067                         }
1068                         else {
1069                                 /* this special cases is for areas and regions that get removed */
1070                                 CTX_wm_area_set(C, NULL);
1071                                 CTX_wm_region_set(C, NULL);
1072                         }
1073
1074                         if(retval & (OPERATOR_FINISHED|OPERATOR_CANCELLED))
1075                                 if(op->reports->list.first)
1076                                         uiPupMenuReports(C, op->reports);
1077
1078                         if (retval & OPERATOR_FINISHED) {
1079                                 if(G.f & G_DEBUG)
1080                                         wm_operator_print(op); /* todo - this print may double up, might want to check more flags then the FINISHED */
1081                         }                       
1082
1083                         if(retval & OPERATOR_FINISHED) {
1084                                 wm_operator_finished(C, op, 0);
1085                                 handler->op= NULL;
1086                         }
1087                         else if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) {
1088                                 WM_operator_free(op);
1089                                 handler->op= NULL;
1090                         }
1091                         
1092                         /* remove modal handler, operator itself should have been cancelled and freed */
1093                         if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) {
1094                                 WM_cursor_ungrab(CTX_wm_window(C));
1095
1096                                 BLI_remlink(handlers, handler);
1097                                 wm_event_free_handler(handler);
1098                                 
1099                                 /* prevent silly errors from operator users */
1100                                 //retval &= ~OPERATOR_PASS_THROUGH;
1101                         }
1102                         
1103                 }
1104                 else
1105                         printf("wm_handler_operator_call error\n");
1106         }
1107         else {
1108                 wmOperatorType *ot= WM_operatortype_find(event->keymap_idname, 0);
1109
1110                 if(ot)
1111                         retval= wm_operator_invoke(C, ot, event, properties, NULL);
1112         }
1113
1114         /* Finished and pass through flag as handled */
1115         if(retval == (OPERATOR_FINISHED|OPERATOR_PASS_THROUGH))
1116                 return WM_HANDLER_HANDLED;
1117
1118         /* Modal unhandled, break */
1119         if(retval == (OPERATOR_PASS_THROUGH|OPERATOR_RUNNING_MODAL))
1120                 return (WM_HANDLER_BREAK|WM_HANDLER_MODAL);
1121
1122         if(retval & OPERATOR_PASS_THROUGH)
1123                 return WM_HANDLER_CONTINUE;
1124
1125         return WM_HANDLER_BREAK;
1126 }
1127
1128 /* fileselect handlers are only in the window queue, so it's save to switch screens or area types */
1129 static int wm_handler_fileselect_call(bContext *C, ListBase *handlers, wmEventHandler *handler, wmEvent *event)
1130 {
1131         wmWindowManager *wm= CTX_wm_manager(C);
1132         SpaceFile *sfile;
1133         int action= WM_HANDLER_CONTINUE;
1134         
1135         if(event->type != EVT_FILESELECT)
1136                 return action;
1137         if(handler->op != (wmOperator *)event->customdata)
1138                 return action;
1139         
1140         switch(event->val) {
1141                 case EVT_FILESELECT_OPEN: 
1142                 case EVT_FILESELECT_FULL_OPEN: 
1143                         {       
1144                                 ScrArea *sa;
1145                                 
1146                                 /* sa can be null when window A is active, but mouse is over window B */
1147                                 /* in this case, open file select in original window A */
1148                                 if (handler->op_area == NULL) {
1149                                         bScreen *screen = CTX_wm_screen(C);
1150                                         sa = (ScrArea *)screen->areabase.first;
1151                                 } else
1152                                         sa = handler->op_area;
1153                                         
1154                                 if(event->val==EVT_FILESELECT_OPEN)
1155                                         ED_area_newspace(C, sa, SPACE_FILE);
1156                                 else
1157                                         ED_screen_full_newspace(C, sa, SPACE_FILE);     /* sets context */
1158                                 
1159                                 /* settings for filebrowser, sfile is not operator owner but sends events */
1160                                 sa = CTX_wm_area(C);
1161                                 sfile= (SpaceFile*)sa->spacedata.first;
1162                                 sfile->op= handler->op;
1163
1164                                 ED_fileselect_set_params(sfile);
1165                                 
1166                                 action= WM_HANDLER_BREAK;
1167                         }
1168                         break;
1169                         
1170                 case EVT_FILESELECT_EXEC:
1171                 case EVT_FILESELECT_CANCEL:
1172                         {
1173                                 /* XXX validate area and region? */
1174                                 bScreen *screen= CTX_wm_screen(C);
1175                                 char *path= RNA_string_get_alloc(handler->op->ptr, "path", NULL, 0);
1176                                 
1177                                 if(screen != handler->filescreen)
1178                                         ED_screen_full_prevspace(C, CTX_wm_area(C));
1179                                 else
1180                                         ED_area_prevspace(C, CTX_wm_area(C));
1181                                 
1182                                 /* remlink now, for load file case */
1183                                 BLI_remlink(handlers, handler);
1184                                 
1185                                 wm_handler_op_context(C, handler);
1186
1187                                 /* needed for uiPupMenuReports */
1188
1189                                 if(event->val==EVT_FILESELECT_EXEC) {
1190                                         /* a bit weak, might become arg for WM_event_fileselect? */
1191                                         /* XXX also extension code in image-save doesnt work for this yet */
1192                                         if (RNA_struct_find_property(handler->op->ptr, "check_existing") && 
1193                                                         RNA_boolean_get(handler->op->ptr, "check_existing")) {
1194                                                 /* this gives ownership to pupmenu */
1195                                                 uiPupMenuSaveOver(C, handler->op, (path)? path: "");
1196                                         }
1197                                         else {
1198                                                 int retval;
1199                                                 
1200                                                 if(handler->op->type->flag & OPTYPE_UNDO)
1201                                                         wm->op_undo_depth++;
1202
1203                                                 retval= handler->op->type->exec(C, handler->op);
1204
1205                                                 if(handler->op->type->flag & OPTYPE_UNDO)
1206                                                         wm->op_undo_depth--;
1207                                                 
1208                                                 if (retval & OPERATOR_FINISHED)
1209                                                         if(G.f & G_DEBUG)
1210                                                                 wm_operator_print(handler->op);
1211                                                 
1212                                                 if(wm->op_undo_depth == 0)
1213                                                         if(handler->op->type->flag & OPTYPE_UNDO)
1214                                                                 ED_undo_push_op(C, handler->op);
1215
1216                                                 if(handler->op->reports->list.first) {
1217
1218                                                         /* FIXME, temp setting window, this is really bad!
1219                                                          * only have because lib linking errors need to be seen by users :(
1220                                                          * it can be removed without breaking anything but then no linking errors - campbell */
1221                                                         wmWindow *win_prev= CTX_wm_window(C);
1222                                                         if(win_prev==NULL)
1223                                                                 CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first);
1224
1225                                                         handler->op->reports->printlevel = RPT_WARNING;
1226                                                         uiPupMenuReports(C, handler->op->reports);
1227
1228                                                         CTX_wm_window_set(C, win_prev);
1229                                                 }
1230
1231                                                 WM_operator_free(handler->op);
1232                                         }
1233                                 }
1234                                 else {
1235                                         if(handler->op->type->cancel) {
1236                                                 if(handler->op->type->flag & OPTYPE_UNDO)
1237                                                         wm->op_undo_depth++;
1238
1239                                                 handler->op->type->cancel(C, handler->op);
1240
1241                                                 if(handler->op->type->flag & OPTYPE_UNDO)
1242                                                         wm->op_undo_depth--;
1243                                         }
1244
1245                                         WM_operator_free(handler->op);
1246                                 }
1247
1248                                 CTX_wm_area_set(C, NULL);
1249                                 
1250                                 wm_event_free_handler(handler);
1251                                 if(path)
1252                                         MEM_freeN(path);
1253                                 
1254                                 action= WM_HANDLER_BREAK;
1255                         }
1256                         break;
1257         }
1258         
1259         return action;
1260 }
1261
1262 static int handler_boundbox_test(wmEventHandler *handler, wmEvent *event)
1263 {
1264         if(handler->bbwin) {
1265                 if(handler->bblocal) {
1266                         rcti rect= *handler->bblocal;
1267                         BLI_translate_rcti(&rect, handler->bbwin->xmin, handler->bbwin->ymin);
1268
1269                         if(BLI_in_rcti(&rect, event->x, event->y))
1270                                 return 1;
1271                         else if(event->type==MOUSEMOVE && BLI_in_rcti(&rect, event->prevx, event->prevy))
1272                                 return 1;
1273                         else
1274                                 return 0;
1275                 }
1276                 else {
1277                         if(BLI_in_rcti(handler->bbwin, event->x, event->y))
1278                                 return 1;
1279                         else if(event->type==MOUSEMOVE && BLI_in_rcti(handler->bbwin, event->prevx, event->prevy))
1280                                 return 1;
1281                         else
1282                                 return 0;
1283                 }
1284         }
1285         return 1;
1286 }
1287
1288 static int wm_action_not_handled(int action)
1289 {
1290         return action == WM_HANDLER_CONTINUE || action == (WM_HANDLER_BREAK|WM_HANDLER_MODAL);
1291 }
1292
1293 static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
1294 {
1295         wmWindowManager *wm= CTX_wm_manager(C);
1296         wmEventHandler *handler, *nexthandler;
1297         int action= WM_HANDLER_CONTINUE;
1298         int always_pass;
1299
1300         if(handlers==NULL) return action;
1301
1302         /* modal handlers can get removed in this loop, we keep the loop this way */
1303         for(handler= handlers->first; handler; handler= nexthandler) {
1304                 nexthandler= handler->next;
1305
1306                 /* optional boundbox */
1307                 if(handler_boundbox_test(handler, event)) {
1308                         /* in advance to avoid access to freed event on window close */
1309                         always_pass= wm_event_always_pass(event);
1310                 
1311                         /* modal+blocking handler */
1312                         if(handler->flag & WM_HANDLER_BLOCKING)
1313                                 action |= WM_HANDLER_BREAK;
1314
1315                         if(handler->keymap) {
1316                                 wmKeyMap *keymap= WM_keymap_active(wm, handler->keymap);
1317                                 wmKeyMapItem *kmi;
1318                                 
1319                                 if(!keymap->poll || keymap->poll(C)) {
1320                                         for(kmi= keymap->items.first; kmi; kmi= kmi->next) {
1321                                                 if(wm_eventmatch(event, kmi)) {
1322                                                         
1323                                                         event->keymap_idname= kmi->idname;      /* weak, but allows interactive callback to not use rawkey */
1324                                                         
1325                                                         action |= wm_handler_operator_call(C, handlers, handler, event, kmi->ptr);
1326                                                         if(action & WM_HANDLER_BREAK)  /* not always_pass here, it denotes removed handler */
1327                                                                 break;
1328                                                 }
1329                                         }
1330                                 }
1331                         }
1332                         else if(handler->ui_handle) {
1333                                 action |= wm_handler_ui_call(C, handler, event, always_pass);
1334                         }
1335                         else if(handler->type==WM_HANDLER_FILESELECT) {
1336                                 /* screen context changes here */
1337                                 action |= wm_handler_fileselect_call(C, handlers, handler, event);
1338                         }
1339                         else if(handler->dropboxes) {
1340                                 if(event->type==EVT_DROP) {
1341                                         wmDropBox *drop= handler->dropboxes->first;
1342                                         for(; drop; drop= drop->next) {
1343                                                 /* other drop custom types allowed */
1344                                                 if(event->custom==EVT_DATA_LISTBASE) {
1345                                                         ListBase *lb= (ListBase *)event->customdata;
1346                                                         wmDrag *drag;
1347                                                         for(drag= lb->first; drag; drag= drag->next) {
1348                                                                 if(drop->poll(C, drag, event)) {
1349                                                                         drop->copy(drag, drop);
1350                                                                         
1351                                                                         wm_operator_invoke(C, drop->ot, event, drop->ptr, NULL);
1352                                                                         action |= WM_HANDLER_BREAK;
1353                                                                 }
1354                                                         }
1355                                                 }
1356                                         }
1357                                 }
1358                         }
1359                         else {
1360                                 /* modal, swallows all */
1361                                 action |= wm_handler_operator_call(C, handlers, handler, event, NULL);
1362                         }
1363
1364                         if(action & WM_HANDLER_BREAK) {
1365                                 if(always_pass)
1366                                         action &= ~WM_HANDLER_BREAK;
1367                                 else
1368                                         break;
1369                         }
1370                 }
1371                 
1372                 /* fileread case */
1373                 if(CTX_wm_window(C)==NULL)
1374                         return action;
1375         }
1376
1377         /* test for CLICK event */
1378         if (wm_action_not_handled(action) && event->val == KM_RELEASE) {
1379                 wmWindow *win = CTX_wm_window(C);
1380
1381                 if (win && win->eventstate->prevtype == event->type && win->eventstate->prevval == KM_PRESS) {
1382                         /* test for double click first */
1383                         if ((PIL_check_seconds_timer() - win->eventstate->prevclicktime) * 1000 < U.dbl_click_time) {
1384                                 event->val = KM_DBL_CLICK;
1385                                 action |= wm_handlers_do(C, event, handlers);
1386                         }
1387
1388                         if (wm_action_not_handled(action)) {
1389                                 event->val = KM_CLICK;
1390                                 action |= wm_handlers_do(C, event, handlers);
1391                         }
1392
1393
1394                         /* revert value if not handled */
1395                         if (wm_action_not_handled(action)) {
1396                                 event->val = KM_RELEASE;
1397                         }
1398                 }
1399         }
1400
1401         return action;
1402 }
1403
1404 static int wm_event_inside_i(wmEvent *event, rcti *rect)
1405 {
1406         if(wm_event_always_pass(event))
1407                 return 1;
1408         if(BLI_in_rcti(rect, event->x, event->y))
1409            return 1;
1410         if(event->type==MOUSEMOVE) {
1411                 if( BLI_in_rcti(rect, event->prevx, event->prevy)) {
1412                         return 1;
1413                 }
1414                 return 0;
1415         }
1416         return 0;
1417 }
1418
1419 static ScrArea *area_event_inside(bContext *C, int x, int y)
1420 {
1421         bScreen *screen= CTX_wm_screen(C);
1422         ScrArea *sa;
1423         
1424         if(screen)
1425                 for(sa= screen->areabase.first; sa; sa= sa->next)
1426                         if(BLI_in_rcti(&sa->totrct, x, y))
1427                                 return sa;
1428         return NULL;
1429 }
1430
1431 static ARegion *region_event_inside(bContext *C, int x, int y)
1432 {
1433         bScreen *screen= CTX_wm_screen(C);
1434         ScrArea *area= CTX_wm_area(C);
1435         ARegion *ar;
1436         
1437         if(screen && area)
1438                 for(ar= area->regionbase.first; ar; ar= ar->next)
1439                         if(BLI_in_rcti(&ar->winrct, x, y))
1440                                 return ar;
1441         return NULL;
1442 }
1443
1444 static void wm_paintcursor_tag(bContext *C, wmPaintCursor *pc, ARegion *ar)
1445 {
1446         if(ar) {
1447                 for(; pc; pc= pc->next) {
1448                         if(pc->poll == NULL || pc->poll(C)) {
1449                                 wmWindow *win= CTX_wm_window(C);
1450                                 win->screen->do_draw_paintcursor= 1;
1451
1452                                 if(win->drawmethod != USER_DRAW_TRIPLE)
1453                                         ED_region_tag_redraw(ar);
1454                         }
1455                 }
1456         }
1457 }
1458
1459 /* called on mousemove, check updates for paintcursors */
1460 /* context was set on active area and region */
1461 static void wm_paintcursor_test(bContext *C, wmEvent *event)
1462 {
1463         wmWindowManager *wm= CTX_wm_manager(C);
1464         
1465         if(wm->paintcursors.first) {
1466                 ARegion *ar= CTX_wm_region(C);
1467                 if(ar)
1468                         wm_paintcursor_tag(C, wm->paintcursors.first, ar);
1469                 
1470                 /* if previous position was not in current region, we have to set a temp new context */
1471                 if(ar==NULL || !BLI_in_rcti(&ar->winrct, event->prevx, event->prevy)) {
1472                         ScrArea *sa= CTX_wm_area(C);
1473                         
1474                         CTX_wm_area_set(C, area_event_inside(C, event->prevx, event->prevy));
1475                         CTX_wm_region_set(C, region_event_inside(C, event->prevx, event->prevy));
1476
1477                         wm_paintcursor_tag(C, wm->paintcursors.first, CTX_wm_region(C));
1478                         
1479                         CTX_wm_area_set(C, sa);
1480                         CTX_wm_region_set(C, ar);
1481                 }
1482         }
1483 }
1484
1485 static void wm_event_drag_test(wmWindowManager *wm, wmWindow *win, wmEvent *event)
1486 {
1487         if(wm->drags.first==NULL) return;
1488         
1489         if(event->type==MOUSEMOVE)
1490                 win->screen->do_draw_drag= 1;
1491         else if(event->type==ESCKEY) {
1492                 BLI_freelistN(&wm->drags);
1493                 win->screen->do_draw_drag= 1;
1494         }
1495         else if(event->type==LEFTMOUSE && event->val==KM_RELEASE) {
1496                 event->type= EVT_DROP;
1497                 
1498                 /* create customdata, first free existing */
1499                 if(event->customdata) {
1500                         if(event->customdatafree)
1501                                 MEM_freeN(event->customdata);
1502                 }
1503                 
1504                 event->custom= EVT_DATA_LISTBASE;
1505                 event->customdata= &wm->drags;
1506                 event->customdatafree= 1;
1507                 
1508                 /* clear drop icon */
1509                 win->screen->do_draw_drag= 1;
1510                 
1511                 /* restore cursor (disabled, see wm_dragdrop.c) */
1512                 // WM_cursor_restore(win);
1513         }
1514         
1515         /* overlap fails otherwise */
1516         if(win->screen->do_draw_drag)
1517                 if(win->drawmethod == USER_DRAW_OVERLAP)
1518                         win->screen->do_draw= 1;
1519         
1520 }
1521
1522 /* called in main loop */
1523 /* goes over entire hierarchy:  events -> window -> screen -> area -> region */
1524 void wm_event_do_handlers(bContext *C)
1525 {
1526         wmWindowManager *wm= CTX_wm_manager(C);
1527         wmWindow *win;
1528
1529         for(win= wm->windows.first; win; win= win->next) {
1530                 wmEvent *event;
1531                 
1532                 if( win->screen==NULL )
1533                         wm_event_free_all(win);
1534                 else
1535                 {
1536                         if(win->screen->scene)
1537                         {
1538                                 int playing = sound_scene_playing(win->screen->scene);
1539                                 if(playing != -1)
1540                                 {
1541                                         if(((playing == 1) && (!win->screen->animtimer)) || ((playing == 0) && (win->screen->animtimer)))
1542                                         {
1543                                                 CTX_wm_window_set(C, win);
1544                                                 CTX_wm_screen_set(C, win->screen);
1545                                                 CTX_data_scene_set(C, win->screen->scene);
1546
1547                                                 ED_screen_animation_play(C, -1, 1);
1548
1549                                                 CTX_data_scene_set(C, NULL);
1550                                                 CTX_wm_screen_set(C, NULL);
1551                                                 CTX_wm_window_set(C, NULL);
1552                                         }
1553                                 }
1554                         }
1555                 }
1556                 
1557                 while( (event= win->queue.first) ) {
1558                         int action = WM_HANDLER_CONTINUE;
1559
1560                         wm_eventemulation(event);
1561
1562                         CTX_wm_window_set(C, win);
1563                         
1564                         /* we let modal handlers get active area/region, also wm_paintcursor_test needs it */
1565                         CTX_wm_area_set(C, area_event_inside(C, event->x, event->y));
1566                         CTX_wm_region_set(C, region_event_inside(C, event->x, event->y));
1567                         
1568                         /* MVC demands to not draw in event handlers... but we need to leave it for ogl selecting etc */
1569                         wm_window_make_drawable(C, win);
1570                         
1571                         /* first we do priority handlers, modal + some limited keymaps */
1572                         action |= wm_handlers_do(C, event, &win->modalhandlers);
1573                         
1574                         /* fileread case */
1575                         if(CTX_wm_window(C)==NULL)
1576                                 return;
1577                         
1578                         /* check dragging, creates new event or frees, adds draw tag */
1579                         wm_event_drag_test(wm, win, event);
1580                         
1581                         /* builtin tweak, if action is break it removes tweak */
1582                         wm_tweakevent_test(C, event, action);
1583
1584                         if((action & WM_HANDLER_BREAK) == 0) {
1585                                 ScrArea *sa;
1586                                 ARegion *ar;
1587                                 int doit= 0;
1588                                 
1589                                 /* XXX to solve, here screen handlers? */
1590                                 if(event->type==MOUSEMOVE) {
1591                                         /* state variables in screen, cursors */
1592                                         ED_screen_set_subwinactive(win, event); 
1593                                         /* for regions having custom cursors */
1594                                         wm_paintcursor_test(C, event);
1595                                 }
1596
1597                                 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
1598                                         if(wm_event_inside_i(event, &sa->totrct)) {
1599                                                 CTX_wm_area_set(C, sa);
1600
1601                                                 if((action & WM_HANDLER_BREAK) == 0) {
1602                                                         for(ar=sa->regionbase.first; ar; ar= ar->next) {
1603                                                                 if(wm_event_inside_i(event, &ar->winrct)) {
1604                                                                         CTX_wm_region_set(C, ar);
1605                                                                         
1606                                                                         /* does polls for drop regions and checks uibuts */
1607                                                                         /* need to be here to make sure region context is true */
1608                                                                         if(event->type==MOUSEMOVE) {
1609                                                                                 wm_region_mouse_co(C, event);
1610                                                                                 wm_drags_check_ops(C, event);
1611                                                                         }
1612                                                                         
1613                                                                         action |= wm_handlers_do(C, event, &ar->handlers);
1614                                                                         
1615                                                                         doit |= (BLI_in_rcti(&ar->winrct, event->x, event->y));
1616                                                                         
1617                                                                         if(action & WM_HANDLER_BREAK)
1618                                                                                 break;
1619                                                                 }
1620                                                         }
1621                                                 }
1622
1623                                                 CTX_wm_region_set(C, NULL);
1624
1625                                                 if((action & WM_HANDLER_BREAK) == 0)
1626                                                         action |= wm_handlers_do(C, event, &sa->handlers);
1627
1628                                                 CTX_wm_area_set(C, NULL);
1629
1630                                                 /* NOTE: do not escape on WM_HANDLER_BREAK, mousemove needs handled for previous area */
1631                                         }
1632                                 }
1633                                 
1634                                 if((action & WM_HANDLER_BREAK) == 0) {
1635                                         /* also some non-modal handlers need active area/region */
1636                                         CTX_wm_area_set(C, area_event_inside(C, event->x, event->y));
1637                                         CTX_wm_region_set(C, region_event_inside(C, event->x, event->y));
1638
1639                                         action |= wm_handlers_do(C, event, &win->handlers);
1640
1641                                         /* fileread case */
1642                                         if(CTX_wm_window(C)==NULL)
1643                                                 return;
1644                                 }
1645
1646                                 /* XXX hrmf, this gives reliable previous mouse coord for area change, feels bad? 
1647                                    doing it on ghost queue gives errors when mousemoves go over area borders */
1648                                 if(doit && win->screen && win->screen->subwinactive != win->screen->mainwin) {
1649                                         win->eventstate->prevx= event->x;
1650                                         win->eventstate->prevy= event->y;
1651                                 }
1652                         }
1653                         
1654                         /* store last event for this window */
1655                         /* mousemove and timer events don't overwrite last type */
1656                         if (event->type != MOUSEMOVE && !ISTIMER(event->type)) {
1657                                 if (wm_action_not_handled(action)) {
1658                                         if (win->eventstate->prevtype == event->type) {
1659                                                 /* set click time on first click (press -> release) */
1660                                                 if (win->eventstate->prevval == KM_PRESS && event->val == KM_RELEASE) {
1661                                                         win->eventstate->prevclicktime = PIL_check_seconds_timer();
1662                                                 }
1663                                         } else {
1664                                                 /* reset click time if event type not the same */
1665                                                 win->eventstate->prevclicktime = 0;
1666                                         }
1667
1668                                         win->eventstate->prevval = event->val;
1669                                         win->eventstate->prevtype = event->type;
1670                                 } else if (event->val == KM_CLICK) { /* keep click for double click later */
1671                                         win->eventstate->prevtype = event->type;
1672                                         win->eventstate->prevval = event->val;
1673                                         win->eventstate->prevclicktime = PIL_check_seconds_timer();
1674                                 } else { /* reset if not */
1675                                         win->eventstate->prevtype = -1;
1676                                         win->eventstate->prevval = 0;
1677                                         win->eventstate->prevclicktime = 0;
1678                                 }
1679                         }
1680
1681                         /* unlink and free here, blender-quit then frees all */
1682                         BLI_remlink(&win->queue, event);
1683                         wm_event_free(event);
1684                         
1685                 }
1686                 
1687                 /* only add mousemove when queue was read entirely */
1688                 if(win->addmousemove && win->eventstate) {
1689                         wmEvent event= *(win->eventstate);
1690                         event.type= MOUSEMOVE;
1691                         event.prevx= event.x;
1692                         event.prevy= event.y;
1693                         wm_event_add(win, &event);
1694                         win->addmousemove= 0;
1695                 }
1696                 
1697                 CTX_wm_window_set(C, NULL);
1698         }
1699 }
1700
1701 /* ********** filesector handling ************ */
1702
1703 void WM_event_fileselect_event(bContext *C, void *ophandle, int eventval)
1704 {
1705         /* add to all windows! */
1706         wmWindow *win;
1707         
1708         for(win= CTX_wm_manager(C)->windows.first; win; win= win->next) {
1709                 wmEvent event= *win->eventstate;
1710                 
1711                 event.type= EVT_FILESELECT;
1712                 event.val= eventval;
1713                 event.customdata= ophandle;             // only as void pointer type check
1714
1715                 wm_event_add(win, &event);
1716         }
1717 }
1718
1719 /* operator is supposed to have a filled "path" property */
1720 /* optional property: filetype (XXX enum?) */
1721
1722 /* Idea is to keep a handler alive on window queue, owning the operator.
1723    The filewindow can send event to make it execute, thus ensuring
1724    executing happens outside of lower level queues, with UI refreshed. 
1725    Should also allow multiwin solutions */
1726
1727 void WM_event_add_fileselect(bContext *C, wmOperator *op)
1728 {
1729         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "fileselect handler");
1730         wmWindow *win= CTX_wm_window(C);
1731         int full= 1;    // XXX preset?
1732         
1733         handler->type= WM_HANDLER_FILESELECT;
1734         handler->op= op;
1735         handler->op_area= CTX_wm_area(C);
1736         handler->op_region= CTX_wm_region(C);
1737         handler->filescreen= CTX_wm_screen(C);
1738         
1739         BLI_addhead(&win->modalhandlers, handler);
1740         
1741         WM_event_fileselect_event(C, op, full?EVT_FILESELECT_FULL_OPEN:EVT_FILESELECT_OPEN);
1742 }
1743
1744 /* lets not expose struct outside wm? */
1745 void WM_event_set_handler_flag(wmEventHandler *handler, int flag)
1746 {
1747         handler->flag= flag;
1748 }
1749
1750 wmEventHandler *WM_event_add_modal_handler(bContext *C, wmOperator *op)
1751 {
1752         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event modal handler");
1753         wmWindow *win= CTX_wm_window(C);
1754         
1755         /* operator was part of macro */
1756         if(op->opm) {
1757                 /* give the mother macro to the handler */
1758                 handler->op= op->opm;
1759                 /* mother macro opm becomes the macro element */
1760                 handler->op->opm= op;
1761         }
1762         else
1763                 handler->op= op;
1764         
1765         handler->op_area= CTX_wm_area(C);               /* means frozen screen context for modal handlers! */
1766         handler->op_region= CTX_wm_region(C);
1767         
1768         BLI_addhead(&win->modalhandlers, handler);
1769
1770         return handler;
1771 }
1772
1773 wmEventHandler *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
1774 {
1775         wmEventHandler *handler;
1776
1777         if(!keymap) {
1778                 printf("WM_event_add_keymap_handler called with NULL keymap\n");
1779                 return NULL;
1780         }
1781
1782         /* only allow same keymap once */
1783         for(handler= handlers->first; handler; handler= handler->next)
1784                 if(handler->keymap==keymap)
1785                         return handler;
1786         
1787         handler= MEM_callocN(sizeof(wmEventHandler), "event keymap handler");
1788         BLI_addtail(handlers, handler);
1789         handler->keymap= keymap;
1790
1791         return handler;
1792 }
1793
1794 /* priorities not implemented yet, for time being just insert in begin of list */
1795 wmEventHandler *WM_event_add_keymap_handler_priority(ListBase *handlers, wmKeyMap *keymap, int priority)
1796 {
1797         wmEventHandler *handler;
1798         
1799         WM_event_remove_keymap_handler(handlers, keymap);
1800         
1801         handler= MEM_callocN(sizeof(wmEventHandler), "event keymap handler");
1802         BLI_addhead(handlers, handler);
1803         handler->keymap= keymap;
1804         
1805         return handler;
1806 }
1807
1808 wmEventHandler *WM_event_add_keymap_handler_bb(ListBase *handlers, wmKeyMap *keymap, rcti *bblocal, rcti *bbwin)
1809 {
1810         wmEventHandler *handler= WM_event_add_keymap_handler(handlers, keymap);
1811         
1812         if(handler) {
1813                 handler->bblocal= bblocal;
1814                 handler->bbwin= bbwin;
1815         }
1816         return handler;
1817 }
1818
1819 void WM_event_remove_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
1820 {
1821         wmEventHandler *handler;
1822         
1823         for(handler= handlers->first; handler; handler= handler->next) {
1824                 if(handler->keymap==keymap) {
1825                         BLI_remlink(handlers, handler);
1826                         wm_event_free_handler(handler);
1827                         break;
1828                 }
1829         }
1830 }
1831
1832 wmEventHandler *WM_event_add_ui_handler(const bContext *C, ListBase *handlers, wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata)
1833 {
1834         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event ui handler");
1835         handler->ui_handle= func;
1836         handler->ui_remove= remove;
1837         handler->ui_userdata= userdata;
1838         handler->ui_area= (C)? CTX_wm_area(C): NULL;
1839         handler->ui_region= (C)? CTX_wm_region(C): NULL;
1840         handler->ui_menu= (C)? CTX_wm_menu(C): NULL;
1841         
1842         BLI_addhead(handlers, handler);
1843         
1844         return handler;
1845 }
1846
1847 void WM_event_remove_ui_handler(ListBase *handlers, wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata)
1848 {
1849         wmEventHandler *handler;
1850         
1851         for(handler= handlers->first; handler; handler= handler->next) {
1852                 if(handler->ui_handle == func && handler->ui_remove == remove && handler->ui_userdata == userdata) {
1853                         BLI_remlink(handlers, handler);
1854                         wm_event_free_handler(handler);
1855                         break;
1856                 }
1857         }
1858 }
1859
1860 wmEventHandler *WM_event_add_dropbox_handler(ListBase *handlers, ListBase *dropboxes)
1861 {
1862         wmEventHandler *handler;
1863
1864         /* only allow same dropbox once */
1865         for(handler= handlers->first; handler; handler= handler->next)
1866                 if(handler->dropboxes==dropboxes)
1867                         return handler;
1868         
1869         handler= MEM_callocN(sizeof(wmEventHandler), "dropbox handler");
1870         
1871         /* dropbox stored static, no free or copy */
1872         handler->dropboxes= dropboxes;
1873         BLI_addhead(handlers, handler);
1874         
1875         return handler;
1876 }
1877
1878 /* XXX solution works, still better check the real cause (ton) */
1879 void WM_event_remove_area_handler(ListBase *handlers, void *area)
1880 {
1881         wmEventHandler *handler, *nexthandler;
1882
1883         for(handler = handlers->first; handler; handler= nexthandler) {
1884                 nexthandler = handler->next;
1885                 if (handler->type != WM_HANDLER_FILESELECT) {
1886                         if (handler->ui_area == area) {
1887                                 BLI_remlink(handlers, handler);
1888                                 wm_event_free_handler(handler);
1889                         }
1890                 }
1891         }
1892 }
1893
1894 void WM_event_remove_handler(ListBase *handlers, wmEventHandler *handler)
1895 {
1896         BLI_remlink(handlers, handler);
1897         wm_event_free_handler(handler);
1898 }
1899
1900 void WM_event_add_mousemove(bContext *C)
1901 {
1902         wmWindow *window= CTX_wm_window(C);
1903         
1904         window->addmousemove= 1;
1905 }
1906
1907 /* for modal callbacks, check configuration for how to interpret exit with tweaks  */
1908 int WM_modal_tweak_exit(wmEvent *evt, int tweak_event)
1909 {
1910         /* user preset or keymap? dunno... */
1911         int tweak_modal= (U.flag & USER_DRAGIMMEDIATE)==0;
1912         
1913         switch(tweak_event) {
1914                 case EVT_TWEAK_L:
1915                 case EVT_TWEAK_M:
1916                 case EVT_TWEAK_R:
1917                         if(evt->val==tweak_modal)
1918                                 return 1;
1919                 default:
1920                         /* this case is when modal callcback didnt get started with a tweak */
1921                         if(evt->val)
1922                                 return 1;
1923         }
1924         return 0;
1925 }
1926
1927 /* ********************* ghost stuff *************** */
1928
1929 static int convert_key(GHOST_TKey key) 
1930 {
1931         if (key>=GHOST_kKeyA && key<=GHOST_kKeyZ) {
1932                 return (AKEY + ((int) key - GHOST_kKeyA));
1933         } else if (key>=GHOST_kKey0 && key<=GHOST_kKey9) {
1934                 return (ZEROKEY + ((int) key - GHOST_kKey0));
1935         } else if (key>=GHOST_kKeyNumpad0 && key<=GHOST_kKeyNumpad9) {
1936                 return (PAD0 + ((int) key - GHOST_kKeyNumpad0));
1937         } else if (key>=GHOST_kKeyF1 && key<=GHOST_kKeyF12) {
1938                 return (F1KEY + ((int) key - GHOST_kKeyF1));
1939         } else {
1940                 switch (key) {
1941                         case GHOST_kKeyBackSpace:               return BACKSPACEKEY;
1942                         case GHOST_kKeyTab:                             return TABKEY;
1943                         case GHOST_kKeyLinefeed:                return LINEFEEDKEY;
1944                         case GHOST_kKeyClear:                   return 0;
1945                         case GHOST_kKeyEnter:                   return RETKEY;
1946                                 
1947                         case GHOST_kKeyEsc:                             return ESCKEY;
1948                         case GHOST_kKeySpace:                   return SPACEKEY;
1949                         case GHOST_kKeyQuote:                   return QUOTEKEY;
1950                         case GHOST_kKeyComma:                   return COMMAKEY;
1951                         case GHOST_kKeyMinus:                   return MINUSKEY;
1952                         case GHOST_kKeyPeriod:                  return PERIODKEY;
1953                         case GHOST_kKeySlash:                   return SLASHKEY;
1954                                 
1955                         case GHOST_kKeySemicolon:               return SEMICOLONKEY;
1956                         case GHOST_kKeyEqual:                   return EQUALKEY;
1957                                 
1958                         case GHOST_kKeyLeftBracket:             return LEFTBRACKETKEY;
1959                         case GHOST_kKeyRightBracket:    return RIGHTBRACKETKEY;
1960                         case GHOST_kKeyBackslash:               return BACKSLASHKEY;
1961                         case GHOST_kKeyAccentGrave:             return ACCENTGRAVEKEY;
1962                                 
1963                         case GHOST_kKeyLeftShift:               return LEFTSHIFTKEY;
1964                         case GHOST_kKeyRightShift:              return RIGHTSHIFTKEY;
1965                         case GHOST_kKeyLeftControl:             return LEFTCTRLKEY;
1966                         case GHOST_kKeyRightControl:    return RIGHTCTRLKEY;
1967                         case GHOST_kKeyCommand:                 return COMMANDKEY;
1968                         case GHOST_kKeyLeftAlt:                 return LEFTALTKEY;
1969                         case GHOST_kKeyRightAlt:                return RIGHTALTKEY;
1970                                 
1971                         case GHOST_kKeyCapsLock:                return CAPSLOCKKEY;
1972                         case GHOST_kKeyNumLock:                 return 0;
1973                         case GHOST_kKeyScrollLock:              return 0;
1974                                 
1975                         case GHOST_kKeyLeftArrow:               return LEFTARROWKEY;
1976                         case GHOST_kKeyRightArrow:              return RIGHTARROWKEY;
1977                         case GHOST_kKeyUpArrow:                 return UPARROWKEY;
1978                         case GHOST_kKeyDownArrow:               return DOWNARROWKEY;
1979                                 
1980                         case GHOST_kKeyPrintScreen:             return 0;
1981                         case GHOST_kKeyPause:                   return PAUSEKEY;
1982                                 
1983                         case GHOST_kKeyInsert:                  return INSERTKEY;
1984                         case GHOST_kKeyDelete:                  return DELKEY;
1985                         case GHOST_kKeyHome:                    return HOMEKEY;
1986                         case GHOST_kKeyEnd:                             return ENDKEY;
1987                         case GHOST_kKeyUpPage:                  return PAGEUPKEY;
1988                         case GHOST_kKeyDownPage:                return PAGEDOWNKEY;
1989                                 
1990                         case GHOST_kKeyNumpadPeriod:    return PADPERIOD;
1991                         case GHOST_kKeyNumpadEnter:             return PADENTER;
1992                         case GHOST_kKeyNumpadPlus:              return PADPLUSKEY;
1993                         case GHOST_kKeyNumpadMinus:             return PADMINUS;
1994                         case GHOST_kKeyNumpadAsterisk:  return PADASTERKEY;
1995                         case GHOST_kKeyNumpadSlash:             return PADSLASHKEY;
1996                                 
1997                         case GHOST_kKeyGrLess:              return GRLESSKEY; 
1998                                 
1999                         default:
2000                                 return UNKNOWNKEY;      /* GHOST_kKeyUnknown */
2001                 }
2002         }
2003 }
2004
2005 /* adds customdata to event */
2006 static void update_tablet_data(wmWindow *win, wmEvent *event)
2007 {
2008         const GHOST_TabletData *td= GHOST_GetTabletData(win->ghostwin);
2009         
2010         /* if there's tablet data from an active tablet device then add it */
2011         if ((td != NULL) && td->Active != GHOST_kTabletModeNone) {
2012                 struct wmTabletData *wmtab= MEM_mallocN(sizeof(wmTabletData), "customdata tablet");
2013                 
2014                 wmtab->Active = (int)td->Active;
2015                 wmtab->Pressure = td->Pressure;
2016                 wmtab->Xtilt = td->Xtilt;
2017                 wmtab->Ytilt = td->Ytilt;
2018                 
2019                 event->custom= EVT_DATA_TABLET;
2020                 event->customdata= wmtab;
2021                 event->customdatafree= 1;
2022         } 
2023 }
2024
2025 /* imperfect but probably usable... draw/enable drags to other windows */
2026 static wmWindow *wm_event_cursor_other_windows(wmWindowManager *wm, wmWindow *win, wmEvent *evt)
2027 {
2028         short mx= evt->x, my= evt->y;
2029         
2030         if(wm->windows.first== wm->windows.last)
2031                 return NULL;
2032         
2033         /* top window bar... */
2034         if(mx<0 || my<0 || mx>win->sizex || my>win->sizey+30) { 
2035                 wmWindow *owin;
2036                 wmEventHandler *handler;
2037                 
2038                 /* let's skip windows having modal handlers now */
2039                 /* potential XXX ugly... I wouldn't have added a modalhandlers list (introduced in rev 23331, ton) */
2040                 for(handler= win->modalhandlers.first; handler; handler= handler->next)
2041                         if(handler->ui_handle || handler->op)
2042                                 return NULL;
2043                 
2044                 /* to desktop space */
2045                 mx+= win->posx;
2046                 my+= win->posy;
2047                 
2048                 /* check other windows to see if it has mouse inside */
2049                 for(owin= wm->windows.first; owin; owin= owin->next) {
2050                         
2051                         if(owin!=win) {
2052                                 if(mx-owin->posx >= 0 && my-owin->posy >= 0 &&
2053                                    mx-owin->posx <= owin->sizex && my-owin->posy <= owin->sizey) {
2054                                         evt->x= mx-owin->posx;
2055                                         evt->y= my-owin->posy;
2056                                         
2057                                         return owin;
2058                                 }
2059                         }
2060                 }
2061         }
2062         return NULL;
2063 }
2064
2065 /* windows store own event queues, no bContext here */
2066 /* time is in 1000s of seconds, from ghost */
2067 void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int time, void *customdata)
2068 {
2069         wmWindow *owin;
2070         wmEvent event, *evt= win->eventstate;
2071         
2072         /* initialize and copy state (only mouse x y and modifiers) */
2073         event= *evt;
2074         
2075         switch (type) {
2076                 /* mouse move */
2077                 case GHOST_kEventCursorMove: {
2078                         if(win->active) {
2079                                 GHOST_TEventCursorData *cd= customdata;
2080                                 
2081 #if defined(__APPLE__) && defined(GHOST_COCOA)
2082                                 //Cocoa already uses coordinates with y=0 at bottom, and returns inwindow coordinates on mouse moved event
2083                                 evt->x= cd->x;
2084                                 evt->y= cd->y;
2085 #else
2086                                 int cx, cy;
2087                                 
2088                                 GHOST_ScreenToClient(win->ghostwin, cd->x, cd->y, &cx, &cy);
2089                                 evt->x= cx;
2090                                 evt->y= (win->sizey-1) - cy;
2091 #endif
2092                                 
2093                                 event.x= evt->x;
2094                                 event.y= evt->y;
2095
2096                                 event.type= MOUSEMOVE;
2097
2098                                 update_tablet_data(win, &event);
2099                                 wm_event_add(win, &event);
2100                                 
2101                                 /* also add to other window if event is there, this makes overdraws disappear nicely */
2102                                 /* it remaps mousecoord to other window in event */
2103                                 owin= wm_event_cursor_other_windows(wm, win, &event);
2104                                 if(owin) {
2105                                         wmEvent oevent= *(owin->eventstate);
2106                                         
2107                                         oevent.x= event.x;
2108                                         oevent.y= event.y;
2109                                         oevent.type= MOUSEMOVE;
2110                                         
2111                                         *(owin->eventstate)= oevent;
2112                                         update_tablet_data(owin, &oevent);
2113                                         wm_event_add(owin, &oevent);
2114                                 }
2115                                 
2116                         }
2117                         break;
2118                 }
2119                 case GHOST_kEventTrackpad: {
2120                         GHOST_TEventTrackpadData * pd = customdata;
2121                         switch (pd->subtype) {
2122                                 case GHOST_kTrackpadEventMagnify:
2123                                         event.type = MOUSEZOOM;
2124                                         break;
2125                                 case GHOST_kTrackpadEventRotate:
2126                                         event.type = MOUSEROTATE;
2127                                         break;
2128                                 case GHOST_kTrackpadEventScroll:
2129                                 default:
2130                                         event.type= MOUSEPAN;
2131                                         break;
2132                         }
2133 #if defined(__APPLE__) && defined(GHOST_COCOA)
2134                         //Cocoa already uses coordinates with y=0 at bottom, and returns inwindow coordinates on mouse moved event
2135                         event.x= evt->x = pd->x;
2136                         event.y = evt->y = pd->y;
2137 #else
2138                         {
2139                         int cx, cy;
2140                         GHOST_ScreenToClient(win->ghostwin, pd->x, pd->y, &cx, &cy);
2141                         event.x= evt->x= cx;
2142                         event.y= evt->y= (win->sizey-1) - cy;
2143                         }
2144 #endif
2145                         // Use prevx/prevy so we can calculate the delta later
2146                         event.prevx= event.x - pd->deltaX;
2147                         event.prevy= event.y - pd->deltaY;
2148                         
2149                         update_tablet_data(win, &event);
2150                         wm_event_add(win, &event);
2151                         break;
2152                 }
2153                 /* mouse button */
2154                 case GHOST_kEventButtonDown:
2155                 case GHOST_kEventButtonUp: {
2156                         GHOST_TEventButtonData *bd= customdata;
2157                         event.val= (type==GHOST_kEventButtonDown) ? KM_PRESS:KM_RELEASE; /* Note!, this starts as 0/1 but later is converted to KM_PRESS/KM_RELEASE by tweak */
2158                         
2159                         if (bd->button == GHOST_kButtonMaskLeft)
2160                                 event.type= LEFTMOUSE;
2161                         else if (bd->button == GHOST_kButtonMaskRight)
2162                                 event.type= RIGHTMOUSE;
2163                         else if (bd->button == GHOST_kButtonMaskButton4)
2164                                 event.type= BUTTON4MOUSE;
2165                         else if (bd->button == GHOST_kButtonMaskButton5)
2166                                 event.type= BUTTON5MOUSE;
2167                         else
2168                                 event.type= MIDDLEMOUSE;
2169                         
2170                         /* add to other window if event is there (not to both!) */
2171                         owin= wm_event_cursor_other_windows(wm, win, &event);
2172                         if(owin) {
2173                                 wmEvent oevent= *(owin->eventstate);
2174                                 
2175                                 oevent.x= event.x;
2176                                 oevent.y= event.y;
2177                                 oevent.type= event.type;
2178                                 oevent.val= event.val;
2179                                 
2180                                 update_tablet_data(owin, &oevent);
2181                                 wm_event_add(owin, &oevent);
2182                         }
2183                         else {
2184                                 update_tablet_data(win, &event);
2185                                 wm_event_add(win, &event);
2186                         }
2187                         
2188                         break;
2189                 }
2190                 /* keyboard */
2191                 case GHOST_kEventKeyDown:
2192                 case GHOST_kEventKeyUp: {
2193                         GHOST_TEventKeyData *kd= customdata;
2194                         event.type= convert_key(kd->key);
2195                         event.ascii= kd->ascii;
2196                         event.val= (type==GHOST_kEventKeyDown)?KM_PRESS:KM_RELEASE;
2197                         
2198                         /* exclude arrow keys, esc, etc from text input */
2199                         if(type==GHOST_kEventKeyUp || (event.ascii<32 && event.ascii>0))
2200                                 event.ascii= '\0';
2201                         
2202                         /* modifiers */
2203                         if (event.type==LEFTSHIFTKEY || event.type==RIGHTSHIFTKEY) {
2204                                 event.shift= evt->shift= (event.val==KM_PRESS);
2205                                 if(event.val==KM_PRESS && (evt->ctrl || evt->alt || evt->oskey))
2206                                    event.shift= evt->shift = 3;         // define?
2207                         } 
2208                         else if (event.type==LEFTCTRLKEY || event.type==RIGHTCTRLKEY) {
2209                                 event.ctrl= evt->ctrl= (event.val==KM_PRESS);
2210                                 if(event.val==KM_PRESS && (evt->shift || evt->alt || evt->oskey))
2211                                    event.ctrl= evt->ctrl = 3;           // define?
2212                         } 
2213                         else if (event.type==LEFTALTKEY || event.type==RIGHTALTKEY) {
2214                                 event.alt= evt->alt= (event.val==KM_PRESS);
2215                                 if(event.val==KM_PRESS && (evt->ctrl || evt->shift || evt->oskey))
2216                                    event.alt= evt->alt = 3;             // define?
2217                         } 
2218                         else if (event.type==COMMANDKEY) {
2219                                 event.oskey= evt->oskey= (event.val==KM_PRESS);
2220                                 if(event.val==KM_PRESS && (evt->ctrl || evt->alt || evt->shift))
2221                                    event.oskey= evt->oskey = 3;         // define?
2222                         }
2223                         else {
2224                                 if(event.val==KM_PRESS && event.keymodifier==0)
2225                                         evt->keymodifier= event.type; /* only set in eventstate, for next event */
2226                                 else if(event.val==KM_RELEASE && event.keymodifier==event.type)
2227                                         event.keymodifier= evt->keymodifier= 0;
2228                         }
2229
2230                         /* this case happens on some systems that on holding a key pressed,
2231                            generate press events without release, we still want to keep the
2232                            modifier in win->eventstate, but for the press event of the same
2233                            key we don't want the key modifier */
2234                         if(event.keymodifier == event.type)
2235                                 event.keymodifier= 0;
2236                         
2237                         /* if test_break set, it catches this. XXX Keep global for now? */
2238                         if(event.type==ESCKEY)
2239                                 G.afbreek= 1;
2240                         
2241                         wm_event_add(win, &event);
2242                         
2243                         break;
2244                 }
2245                         
2246                 case GHOST_kEventWheel: {
2247                         GHOST_TEventWheelData* wheelData = customdata;
2248                         
2249                         if (wheelData->z > 0)
2250                                 event.type= WHEELUPMOUSE;
2251                         else
2252                                 event.type= WHEELDOWNMOUSE;
2253                         
2254                         event.val= KM_PRESS;
2255                         wm_event_add(win, &event);
2256                         
2257                         break;
2258                 }
2259                 case GHOST_kEventTimer: {
2260                         event.type= TIMER;
2261                         event.custom= EVT_DATA_TIMER;
2262                         event.customdata= customdata;
2263                         wm_event_add(win, &event);
2264
2265                         break;
2266                 }
2267
2268                 case GHOST_kEventUnknown:
2269                 case GHOST_kNumEventTypes:
2270                         break;
2271
2272                 case GHOST_kEventWindowDeactivate: {
2273                         event.type= WINDEACTIVATE;
2274                         wm_event_add(win, &event);
2275
2276                         break;
2277                         
2278                 }
2279
2280         }
2281 }