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