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