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