migrated NDOF code from soc-2010-merwin, SpaceNavigator now works on Mac blender
[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 aggressive 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         else {
665                 /* these values are invalid (avoid odd behavior by relying on old mval values) */
666                 event->mval[0]= -1;
667                 event->mval[1]= -1;
668         }
669 }
670
671 static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, PointerRNA *properties, ReportList *reports, short poll_only)
672 {
673         wmWindowManager *wm= CTX_wm_manager(C);
674         int retval= OPERATOR_PASS_THROUGH;
675
676         /* this is done because complicated setup is done to call this function that is better not duplicated */
677         if(poll_only)
678                 return WM_operator_poll(C, ot);
679
680         if(WM_operator_poll(C, ot)) {
681                 wmOperator *op= wm_operator_create(wm, ot, properties, reports); /* if reports==NULL, theyll be initialized */
682                 
683                 if((G.f & G_DEBUG) && event && event->type!=MOUSEMOVE)
684                         printf("handle evt %d win %d op %s\n", event?event->type:0, CTX_wm_screen(C)->subwinactive, ot->idname); 
685                 
686                 if(op->type->invoke && event) {
687                         wm_region_mouse_co(C, event);
688
689                         if(op->type->flag & OPTYPE_UNDO)
690                                 wm->op_undo_depth++;
691
692                         retval= op->type->invoke(C, op, event);
693
694                         if(op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm)
695                                 wm->op_undo_depth--;
696                 }
697                 else if(op->type->exec) {
698                         if(op->type->flag & OPTYPE_UNDO)
699                                 wm->op_undo_depth++;
700
701                         retval= op->type->exec(C, op);
702
703                         if(op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm)
704                                 wm->op_undo_depth--;
705                 }
706                 else
707                         printf("invalid operator call %s\n", ot->idname); /* debug, important to leave a while, should never happen */
708                 
709                 /* Note, if the report is given as an argument then assume the caller will deal with displaying them
710                  * currently python only uses this */
711                 if (!(retval & OPERATOR_HANDLED) && retval & (OPERATOR_FINISHED|OPERATOR_CANCELLED))
712                         /* only show the report if the report list was not given in the function */
713                         wm_operator_reports(C, op, retval, (reports==NULL));
714                 
715                 if(retval & OPERATOR_HANDLED)
716                         ; /* do nothing, wm_operator_exec() has been called somewhere */
717                 else if(retval & OPERATOR_FINISHED) {
718                         wm_operator_finished(C, op, 0);
719                 }
720                 else if(retval & OPERATOR_RUNNING_MODAL) {
721                         /* grab cursor during blocking modal ops (X11)
722                          * Also check for macro
723                          * */
724                         if(ot->flag & OPTYPE_BLOCKING || (op->opm && op->opm->type->flag & OPTYPE_BLOCKING)) {
725                                 int bounds[4] = {-1,-1,-1,-1};
726                                 int wrap;
727
728                                 if (op->opm) {
729                                         wrap = (U.uiflag & USER_CONTINUOUS_MOUSE) && ((op->opm->flag & OP_GRAB_POINTER) || (op->opm->type->flag & OPTYPE_GRAB_POINTER));
730                                 } else {
731                                         wrap = (U.uiflag & USER_CONTINUOUS_MOUSE) && ((op->flag & OP_GRAB_POINTER) || (ot->flag & OPTYPE_GRAB_POINTER));
732                                 }
733
734                                 /* exception, cont. grab in header is annoying */
735                                 if(wrap) {
736                                         ARegion *ar= CTX_wm_region(C);
737                                         if(ar && ar->regiontype == RGN_TYPE_HEADER) {
738                                                 wrap= FALSE;
739                                         }
740                                 }
741
742                                 if(wrap) {
743                                         rcti *winrect= NULL;
744                                         ARegion *ar= CTX_wm_region(C);
745                                         ScrArea *sa= CTX_wm_area(C);
746
747                                         if(ar && ar->regiontype == RGN_TYPE_WINDOW && event && BLI_in_rcti(&ar->winrct, event->x, event->y)) {
748                                                 winrect= &ar->winrct;
749                                         }
750                                         else if(sa) {
751                                                 winrect= &sa->totrct;
752                                         }
753
754                                         if(winrect) {
755                                                 bounds[0]= winrect->xmin;
756                                                 bounds[1]= winrect->ymax;
757                                                 bounds[2]= winrect->xmax;
758                                                 bounds[3]= winrect->ymin;
759                                         }
760                                 }
761
762                                 WM_cursor_grab(CTX_wm_window(C), wrap, FALSE, bounds);
763                         }
764
765                         /* cancel UI handlers, typically tooltips that can hang around
766                            while dragging the view or worse, that stay there permanently
767                            after the modal operator has swallowed all events and passed
768                            none to the UI handler */
769                         wm_handler_ui_cancel(C);
770                 }
771                 else
772                         WM_operator_free(op);
773         }
774
775         return retval;
776 }
777
778 /* WM_operator_name_call is the main accessor function
779  * this is for python to access since its done the operator lookup
780  * 
781  * invokes operator in context */
782 static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA *properties, ReportList *reports, short context, short poll_only)
783 {
784         wmWindow *window= CTX_wm_window(C);
785         wmEvent *event;
786         
787         int retval;
788
789         CTX_wm_operator_poll_msg_set(C, NULL);
790
791         /* dummie test */
792         if(ot && C) {
793                 switch(context) {
794                         case WM_OP_INVOKE_DEFAULT:
795                         case WM_OP_INVOKE_REGION_WIN:
796                         case WM_OP_INVOKE_AREA:
797                         case WM_OP_INVOKE_SCREEN:
798                                 /* window is needed for invoke, cancel operator */
799                                 if (window == NULL)
800                                         return 0;
801                                 else
802                                         event= window->eventstate;
803                                 break;
804                         default:
805                                 event = NULL;
806                 }
807
808                 switch(context) {
809                         
810                         case WM_OP_EXEC_REGION_WIN:
811                         case WM_OP_INVOKE_REGION_WIN: 
812                         case WM_OP_EXEC_REGION_CHANNELS:
813                         case WM_OP_INVOKE_REGION_CHANNELS:
814                         case WM_OP_EXEC_REGION_PREVIEW:
815                         case WM_OP_INVOKE_REGION_PREVIEW:
816                         {
817                                 /* forces operator to go to the region window/channels/preview, for header menus
818                                  * but we stay in the same region if we are already in one 
819                                  */
820                                 ARegion *ar= CTX_wm_region(C);
821                                 ScrArea *area= CTX_wm_area(C);
822                                 int type = RGN_TYPE_WINDOW;
823                                 
824                                 switch (context) {
825                                         case WM_OP_EXEC_REGION_CHANNELS:
826                                         case WM_OP_INVOKE_REGION_CHANNELS:
827                                                 type = RGN_TYPE_CHANNELS;
828                                                 break;
829                                         
830                                         case WM_OP_EXEC_REGION_PREVIEW:
831                                         case WM_OP_INVOKE_REGION_PREVIEW:
832                                                 type = RGN_TYPE_PREVIEW;
833                                                 break;
834                                         
835                                         case WM_OP_EXEC_REGION_WIN:
836                                         case WM_OP_INVOKE_REGION_WIN: 
837                                         default:
838                                                 type = RGN_TYPE_WINDOW;
839                                                 break;
840                                 }
841                                 
842                                 if(!(ar && ar->regiontype == type) && area) {
843                                         ARegion *ar1= BKE_area_find_region_type(area, type);
844                                         if(ar1)
845                                                 CTX_wm_region_set(C, ar1);
846                                 }
847                                 
848                                 retval= wm_operator_invoke(C, ot, event, properties, reports, poll_only);
849                                 
850                                 /* set region back */
851                                 CTX_wm_region_set(C, ar);
852                                 
853                                 return retval;
854                         }
855                         case WM_OP_EXEC_AREA:
856                         case WM_OP_INVOKE_AREA:
857                         {
858                                         /* remove region from context */
859                                 ARegion *ar= CTX_wm_region(C);
860
861                                 CTX_wm_region_set(C, NULL);
862                                 retval= wm_operator_invoke(C, ot, event, properties, reports, poll_only);
863                                 CTX_wm_region_set(C, ar);
864
865                                 return retval;
866                         }
867                         case WM_OP_EXEC_SCREEN:
868                         case WM_OP_INVOKE_SCREEN:
869                         {
870                                 /* remove region + area from context */
871                                 ARegion *ar= CTX_wm_region(C);
872                                 ScrArea *area= CTX_wm_area(C);
873
874                                 CTX_wm_region_set(C, NULL);
875                                 CTX_wm_area_set(C, NULL);
876                                 retval= wm_operator_invoke(C, ot, event, properties, reports, poll_only);
877                                 CTX_wm_region_set(C, ar);
878                                 CTX_wm_area_set(C, area);
879
880                                 return retval;
881                         }
882                         case WM_OP_EXEC_DEFAULT:
883                         case WM_OP_INVOKE_DEFAULT:
884                                 return wm_operator_invoke(C, ot, event, properties, reports, poll_only);
885                 }
886         }
887         
888         return 0;
889 }
890
891
892 /* invokes operator in context */
893 int WM_operator_name_call(bContext *C, const char *opstring, int context, PointerRNA *properties)
894 {
895         wmOperatorType *ot= WM_operatortype_find(opstring, 0);
896         if(ot)
897                 return wm_operator_call_internal(C, ot, properties, NULL, context, FALSE);
898
899         return 0;
900 }
901
902 /* Similar to WM_operator_name_call called with WM_OP_EXEC_DEFAULT context.
903    - wmOperatorType is used instead of operator name since python already has the operator type
904    - poll() must be called by python before this runs.
905    - reports can be passed to this function (so python can report them as exceptions)
906 */
907 int WM_operator_call_py(bContext *C, wmOperatorType *ot, int context, PointerRNA *properties, ReportList *reports)
908 {
909         int retval= OPERATOR_CANCELLED;
910
911 #if 0
912         wmOperator *op;
913         op= wm_operator_create(wm, ot, properties, reports);
914
915         if (op->type->exec) {
916                 if(op->type->flag & OPTYPE_UNDO)
917                         wm->op_undo_depth++;
918
919                 retval= op->type->exec(C, op);
920
921                 if(op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm)
922                         wm->op_undo_depth--;
923         }
924         else
925                 printf("error \"%s\" operator has no exec function, python cannot call it\n", op->type->name);
926 #endif
927
928         retval= wm_operator_call_internal(C, ot, properties, reports, context, FALSE);
929         
930         /* keep the reports around if needed later */
931         if (    (retval & OPERATOR_RUNNING_MODAL) ||
932                         ((retval & OPERATOR_FINISHED) && wm_operator_register_check(CTX_wm_manager(C), ot))
933         ) {
934                 reports->flag |= RPT_FREE; /* let blender manage freeing */
935         }
936         
937         return retval;
938 }
939
940
941 /* ********************* handlers *************** */
942
943 /* future extra customadata free? */
944 void wm_event_free_handler(wmEventHandler *handler)
945 {
946         MEM_freeN(handler);
947 }
948
949 /* only set context when area/region is part of screen */
950 static void wm_handler_op_context(bContext *C, wmEventHandler *handler)
951 {
952         bScreen *screen= CTX_wm_screen(C);
953         
954         if(screen && handler->op) {
955                 if(handler->op_area==NULL)
956                         CTX_wm_area_set(C, NULL);
957                 else {
958                         ScrArea *sa;
959                         
960                         for(sa= screen->areabase.first; sa; sa= sa->next)
961                                 if(sa==handler->op_area)
962                                         break;
963                         if(sa==NULL) {
964                                 /* when changing screen layouts with running modal handlers (like render display), this
965                                    is not an error to print */
966                                 if(handler->op==NULL)
967                                         printf("internal error: handler (%s) has invalid area\n", handler->op->type->idname);
968                         }
969                         else {
970                                 ARegion *ar;
971                                 CTX_wm_area_set(C, sa);
972                                 for(ar= sa->regionbase.first; ar; ar= ar->next)
973                                         if(ar==handler->op_region)
974                                                 break;
975                                 /* XXX no warning print here, after full-area and back regions are remade */
976                                 if(ar)
977                                         CTX_wm_region_set(C, ar);
978                         }
979                 }
980         }
981 }
982
983 /* called on exit or remove area, only here call cancel callback */
984 void WM_event_remove_handlers(bContext *C, ListBase *handlers)
985 {
986         wmEventHandler *handler;
987         wmWindowManager *wm= CTX_wm_manager(C);
988         
989         /* C is zero on freeing database, modal handlers then already were freed */
990         while((handler=handlers->first)) {
991                 BLI_remlink(handlers, handler);
992                 
993                 if(handler->op) {
994                         if(handler->op->type->cancel) {
995                                 ScrArea *area= CTX_wm_area(C);
996                                 ARegion *region= CTX_wm_region(C);
997                                 
998                                 wm_handler_op_context(C, handler);
999
1000                                 if(handler->op->type->flag & OPTYPE_UNDO)
1001                                         wm->op_undo_depth++;
1002
1003                                 handler->op->type->cancel(C, handler->op);
1004
1005                                 if(handler->op->type->flag & OPTYPE_UNDO)
1006                                         wm->op_undo_depth--;
1007
1008                                 CTX_wm_area_set(C, area);
1009                                 CTX_wm_region_set(C, region);
1010                         }
1011
1012                         WM_cursor_ungrab(CTX_wm_window(C));
1013                         WM_operator_free(handler->op);
1014                 }
1015                 else if(handler->ui_remove) {
1016                         ScrArea *area= CTX_wm_area(C);
1017                         ARegion *region= CTX_wm_region(C);
1018                         ARegion *menu= CTX_wm_menu(C);
1019                         
1020                         if(handler->ui_area) CTX_wm_area_set(C, handler->ui_area);
1021                         if(handler->ui_region) CTX_wm_region_set(C, handler->ui_region);
1022                         if(handler->ui_menu) CTX_wm_menu_set(C, handler->ui_menu);
1023
1024                         handler->ui_remove(C, handler->ui_userdata);
1025
1026                         CTX_wm_area_set(C, area);
1027                         CTX_wm_region_set(C, region);
1028                         CTX_wm_menu_set(C, menu);
1029                 }
1030
1031                 wm_event_free_handler(handler);
1032         }
1033 }
1034
1035 /* do userdef mappings */
1036 int WM_userdef_event_map(int kmitype)
1037 {
1038         switch(kmitype) {
1039                 case SELECTMOUSE:
1040                         if(U.flag & USER_LMOUSESELECT)
1041                                 return LEFTMOUSE;
1042                         else
1043                                 return RIGHTMOUSE;
1044                         
1045                 case ACTIONMOUSE:
1046                         if(U.flag & USER_LMOUSESELECT)
1047                                 return RIGHTMOUSE;
1048                         else
1049                                 return LEFTMOUSE;
1050                         
1051                 case WHEELOUTMOUSE:
1052                         if(U.uiflag & USER_WHEELZOOMDIR)
1053                                 return WHEELUPMOUSE;
1054                         else
1055                                 return WHEELDOWNMOUSE;
1056                         
1057                 case WHEELINMOUSE:
1058                         if(U.uiflag & USER_WHEELZOOMDIR)
1059                                 return WHEELDOWNMOUSE;
1060                         else
1061                                 return WHEELUPMOUSE;
1062                         
1063                 case EVT_TWEAK_A:
1064                         if(U.flag & USER_LMOUSESELECT)
1065                                 return EVT_TWEAK_R;
1066                         else
1067                                 return EVT_TWEAK_L;
1068                         
1069                 case EVT_TWEAK_S:
1070                         if(U.flag & USER_LMOUSESELECT)
1071                                 return EVT_TWEAK_L;
1072                         else
1073                                 return EVT_TWEAK_R;
1074         }
1075         
1076         return kmitype;
1077 }
1078
1079 static void wm_eventemulation(wmEvent *event)
1080 {
1081         static int mmb_emulated = 0; /* this should be in a data structure somwhere */
1082         
1083         /* middlemouse emulation */
1084         if(U.flag & USER_TWOBUTTONMOUSE) {
1085                 if(event->type == LEFTMOUSE && (event->alt || mmb_emulated == KM_PRESS)) {
1086                         event->type = MIDDLEMOUSE;
1087                         event->alt = 0;
1088                         mmb_emulated = event->val;
1089                 }
1090         }
1091
1092 #ifdef __APPLE__
1093         /* rightmouse emulation */
1094         if(U.flag & USER_TWOBUTTONMOUSE) {
1095                 if(event->type == LEFTMOUSE && (event->oskey || mmb_emulated == KM_PRESS)) {
1096                         event->type = RIGHTMOUSE;
1097                         event->oskey = 0;
1098                         mmb_emulated = event->val;
1099                 }
1100         }
1101 #endif
1102
1103         /* numpad emulation */
1104         if(U.flag & USER_NONUMPAD) {
1105                 switch(event->type) {
1106                         case ZEROKEY: event->type = PAD0; break;
1107                         case ONEKEY: event->type = PAD1; break;
1108                         case TWOKEY: event->type = PAD2; break;
1109                         case THREEKEY: event->type = PAD3; break;
1110                         case FOURKEY: event->type = PAD4; break;
1111                         case FIVEKEY: event->type = PAD5; break;
1112                         case SIXKEY: event->type = PAD6; break;
1113                         case SEVENKEY: event->type = PAD7; break;
1114                         case EIGHTKEY: event->type = PAD8; break;
1115                         case NINEKEY: event->type = PAD9; break;
1116                         case MINUSKEY: event->type = PADMINUS; break;
1117                         case EQUALKEY: event->type = PADPLUSKEY; break;
1118                         case BACKSLASHKEY: event->type = PADSLASHKEY; break;
1119                 }
1120         }
1121 }
1122
1123 static int wm_eventmatch(wmEvent *winevent, wmKeyMapItem *kmi)
1124 {
1125         int kmitype= WM_userdef_event_map(kmi->type);
1126
1127         if(kmi->flag & KMI_INACTIVE) return 0;
1128
1129         /* the matching rules */
1130         if(kmitype==KM_TEXTINPUT)
1131                 if(ISTEXTINPUT(winevent->type) && winevent->ascii) return 1;
1132         if(kmitype!=KM_ANY)
1133                 if(winevent->type!=kmitype) return 0;
1134         
1135         if(kmi->val!=KM_ANY)
1136                 if(winevent->val!=kmi->val) return 0;
1137         
1138         /* modifiers also check bits, so it allows modifier order */
1139         if(kmi->shift!=KM_ANY)
1140                 if(winevent->shift != kmi->shift && !(winevent->shift & kmi->shift)) return 0;
1141         if(kmi->ctrl!=KM_ANY)
1142                 if(winevent->ctrl != kmi->ctrl && !(winevent->ctrl & kmi->ctrl)) return 0;
1143         if(kmi->alt!=KM_ANY)
1144                 if(winevent->alt != kmi->alt && !(winevent->alt & kmi->alt)) return 0;
1145         if(kmi->oskey!=KM_ANY)
1146                 if(winevent->oskey != kmi->oskey && !(winevent->oskey & kmi->oskey)) return 0;
1147         
1148         if(kmi->keymodifier)
1149                 if(winevent->keymodifier!=kmi->keymodifier) return 0;
1150                 
1151         /* key modifiers always check when event has it */
1152         /* otherwise regular keypresses with keymodifier still work */
1153         if(winevent->keymodifier)
1154                 if(ISTEXTINPUT(winevent->type)) 
1155                         if(winevent->keymodifier!=kmi->keymodifier) return 0;
1156         
1157         return 1;
1158 }
1159
1160
1161 /* operator exists */
1162 static void wm_event_modalkeymap(const bContext *C, wmOperator *op, wmEvent *event)
1163 {
1164         /* support for modal keymap in macros */
1165         if (op->opm)
1166                 op = op->opm;
1167
1168         if(op->type->modalkeymap) {
1169                 wmKeyMap *keymap= WM_keymap_active(CTX_wm_manager(C), op->type->modalkeymap);
1170                 wmKeyMapItem *kmi;
1171
1172                 for(kmi= keymap->items.first; kmi; kmi= kmi->next) {
1173                         if(wm_eventmatch(event, kmi)) {
1174                                         
1175                                 event->type= EVT_MODAL_MAP;
1176                                 event->val= kmi->propvalue;
1177                         }
1178                 }
1179         }
1180 }
1181
1182 /* Warning: this function removes a modal handler, when finished */
1183 static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHandler *handler, wmEvent *event, PointerRNA *properties)
1184 {
1185         int retval= OPERATOR_PASS_THROUGH;
1186         
1187         /* derived, modal or blocking operator */
1188         if(handler->op) {
1189                 wmOperator *op= handler->op;
1190                 wmOperatorType *ot= op->type;
1191
1192                 if(ot->modal) {
1193                         /* we set context to where modal handler came from */
1194                         wmWindowManager *wm= CTX_wm_manager(C);
1195                         ScrArea *area= CTX_wm_area(C);
1196                         ARegion *region= CTX_wm_region(C);
1197                         
1198                         wm_handler_op_context(C, handler);
1199                         wm_region_mouse_co(C, event);
1200                         wm_event_modalkeymap(C, op, event);
1201                         
1202                         if(ot->flag & OPTYPE_UNDO)
1203                                 wm->op_undo_depth++;
1204
1205                         retval= ot->modal(C, op, event);
1206
1207                         if(ot->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm)
1208                                 wm->op_undo_depth--;
1209
1210                         /* putting back screen context, reval can pass trough after modal failures! */
1211                         if((retval & OPERATOR_PASS_THROUGH) || wm_event_always_pass(event)) {
1212                                 CTX_wm_area_set(C, area);
1213                                 CTX_wm_region_set(C, region);
1214                         }
1215                         else {
1216                                 /* this special cases is for areas and regions that get removed */
1217                                 CTX_wm_area_set(C, NULL);
1218                                 CTX_wm_region_set(C, NULL);
1219                         }               
1220
1221                         if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED))
1222                                 wm_operator_reports(C, op, retval, 0);
1223                         
1224                         if(retval & OPERATOR_FINISHED) {
1225                                 wm_operator_finished(C, op, 0);
1226                                 handler->op= NULL;
1227                         }
1228                         else if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) {
1229                                 WM_operator_free(op);
1230                                 handler->op= NULL;
1231                         }
1232                         
1233                         /* remove modal handler, operator itself should have been cancelled and freed */
1234                         if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) {
1235                                 WM_cursor_ungrab(CTX_wm_window(C));
1236
1237                                 BLI_remlink(handlers, handler);
1238                                 wm_event_free_handler(handler);
1239                                 
1240                                 /* prevent silly errors from operator users */
1241                                 //retval &= ~OPERATOR_PASS_THROUGH;
1242                         }
1243                         
1244                 }
1245                 else
1246                         printf("wm_handler_operator_call error\n");
1247         }
1248         else {
1249                 wmOperatorType *ot= WM_operatortype_find(event->keymap_idname, 0);
1250
1251                 if(ot)
1252                         retval= wm_operator_invoke(C, ot, event, properties, NULL, FALSE);
1253         }
1254
1255         /* Finished and pass through flag as handled */
1256         if(retval == (OPERATOR_FINISHED|OPERATOR_PASS_THROUGH))
1257                 return WM_HANDLER_HANDLED;
1258
1259         /* Modal unhandled, break */
1260         if(retval == (OPERATOR_PASS_THROUGH|OPERATOR_RUNNING_MODAL))
1261                 return (WM_HANDLER_BREAK|WM_HANDLER_MODAL);
1262
1263         if(retval & OPERATOR_PASS_THROUGH)
1264                 return WM_HANDLER_CONTINUE;
1265
1266         return WM_HANDLER_BREAK;
1267 }
1268
1269 /* fileselect handlers are only in the window queue, so it's save to switch screens or area types */
1270 static int wm_handler_fileselect_call(bContext *C, ListBase *handlers, wmEventHandler *handler, wmEvent *event)
1271 {
1272         wmWindowManager *wm= CTX_wm_manager(C);
1273         SpaceFile *sfile;
1274         int action= WM_HANDLER_CONTINUE;
1275         
1276         if(event->type != EVT_FILESELECT)
1277                 return action;
1278         if(handler->op != (wmOperator *)event->customdata)
1279                 return action;
1280         
1281         switch(event->val) {
1282                 case EVT_FILESELECT_OPEN: 
1283                 case EVT_FILESELECT_FULL_OPEN: 
1284                         {       
1285                                 ScrArea *sa;
1286                                 
1287                                 /* sa can be null when window A is active, but mouse is over window B */
1288                                 /* in this case, open file select in original window A */
1289                                 if (handler->op_area == NULL) {
1290                                         bScreen *screen = CTX_wm_screen(C);
1291                                         sa = (ScrArea *)screen->areabase.first;
1292                                 }
1293                                 else {
1294                                         sa = handler->op_area;
1295                                 }
1296                                         
1297                                 if(event->val==EVT_FILESELECT_OPEN) {
1298                                         ED_area_newspace(C, sa, SPACE_FILE); /* 'sa' is modified in-place */
1299                                 }
1300                                 else {
1301                                         sa= ED_screen_full_newspace(C, sa, SPACE_FILE); /* sets context */
1302                                 }
1303
1304                                 /* note, getting the 'sa' back from the context causes a nasty bug where the newly created
1305                                  * 'sa' != CTX_wm_area(C). removed the line below and set 'sa' in the 'if' above */
1306                                 /* sa = CTX_wm_area(C); */
1307
1308                                 /* settings for filebrowser, sfile is not operator owner but sends events */
1309                                 sfile= (SpaceFile*)sa->spacedata.first;
1310                                 sfile->op= handler->op;
1311
1312                                 ED_fileselect_set_params(sfile);
1313                                 
1314                                 action= WM_HANDLER_BREAK;
1315                         }
1316                         break;
1317                         
1318                 case EVT_FILESELECT_EXEC:
1319                 case EVT_FILESELECT_CANCEL:
1320                 case EVT_FILESELECT_EXTERNAL_CANCEL:
1321                         {
1322                                 /* XXX validate area and region? */
1323                                 bScreen *screen= CTX_wm_screen(C);
1324
1325                                 /* remlink now, for load file case before removing*/
1326                                 BLI_remlink(handlers, handler);
1327                                 
1328                                 if(event->val!=EVT_FILESELECT_EXTERNAL_CANCEL) {
1329                                         if(screen != handler->filescreen) {
1330                                                 ED_screen_full_prevspace(C, CTX_wm_area(C));
1331                                         }
1332                                         else {
1333                                                 ED_area_prevspace(C, CTX_wm_area(C));
1334                                         }
1335                                 }
1336                                 
1337                                 wm_handler_op_context(C, handler);
1338
1339                                 /* needed for uiPupMenuReports */
1340
1341                                 if(event->val==EVT_FILESELECT_EXEC) {
1342 #if 0                           // use REDALERT now
1343
1344                                         /* a bit weak, might become arg for WM_event_fileselect? */
1345                                         /* XXX also extension code in image-save doesnt work for this yet */
1346                                         if (RNA_struct_find_property(handler->op->ptr, "check_existing") && 
1347                                                         RNA_boolean_get(handler->op->ptr, "check_existing")) {
1348                                                 char *path= RNA_string_get_alloc(handler->op->ptr, "filepath", NULL, 0);
1349                                                 /* this gives ownership to pupmenu */
1350                                                 uiPupMenuSaveOver(C, handler->op, (path)? path: "");
1351                                                 if(path)
1352                                                         MEM_freeN(path);
1353                                         }
1354                                         else
1355 #endif
1356                                         {
1357                                                 int retval;
1358                                                 
1359                                                 if(handler->op->type->flag & OPTYPE_UNDO)
1360                                                         wm->op_undo_depth++;
1361
1362                                                 retval= handler->op->type->exec(C, handler->op);
1363
1364                                                 /* XXX check this carefully, CTX_wm_manager(C) == wm is a bit hackish */
1365                                                 if(handler->op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm)
1366                                                         wm->op_undo_depth--;
1367                                                 
1368                                                 if (retval & OPERATOR_FINISHED)
1369                                                         if(G.f & G_DEBUG)
1370                                                                 wm_operator_print(C, handler->op);
1371                                                 
1372                                                 /* XXX check this carefully, CTX_wm_manager(C) == wm is a bit hackish */
1373                                                 if(CTX_wm_manager(C) == wm && wm->op_undo_depth == 0)
1374                                                         if(handler->op->type->flag & OPTYPE_UNDO)
1375                                                                 ED_undo_push_op(C, handler->op);
1376
1377                                                 if(handler->op->reports->list.first) {
1378
1379                                                         /* FIXME, temp setting window, this is really bad!
1380                                                          * only have because lib linking errors need to be seen by users :(
1381                                                          * it can be removed without breaking anything but then no linking errors - campbell */
1382                                                         wmWindow *win_prev= CTX_wm_window(C);
1383                                                         if(win_prev==NULL)
1384                                                                 CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first);
1385
1386                                                         handler->op->reports->printlevel = RPT_WARNING;
1387                                                         uiPupMenuReports(C, handler->op->reports);
1388
1389                                                         /* XXX - copied from 'wm_operator_finished()' */
1390                                                         /* add reports to the global list, otherwise they are not seen */
1391                                                         BLI_movelisttolist(&CTX_wm_reports(C)->list, &handler->op->reports->list);
1392
1393                                                         CTX_wm_window_set(C, win_prev);
1394                                                 }
1395
1396                                                 WM_operator_free(handler->op);
1397                                         }
1398                                 }
1399                                 else {
1400                                         if(handler->op->type->cancel) {
1401                                                 if(handler->op->type->flag & OPTYPE_UNDO)
1402                                                         wm->op_undo_depth++;
1403
1404                                                 handler->op->type->cancel(C, handler->op);
1405
1406                                                 if(handler->op->type->flag & OPTYPE_UNDO)
1407                                                         wm->op_undo_depth--;
1408                                         }
1409
1410                                         WM_operator_free(handler->op);
1411                                 }
1412
1413                                 CTX_wm_area_set(C, NULL);
1414                                 
1415                                 wm_event_free_handler(handler);
1416                                 
1417                                 action= WM_HANDLER_BREAK;
1418                         }
1419                         break;
1420         }
1421         
1422         return action;
1423 }
1424
1425 static int handler_boundbox_test(wmEventHandler *handler, wmEvent *event)
1426 {
1427         if(handler->bbwin) {
1428                 if(handler->bblocal) {
1429                         rcti rect= *handler->bblocal;
1430                         BLI_translate_rcti(&rect, handler->bbwin->xmin, handler->bbwin->ymin);
1431
1432                         if(BLI_in_rcti(&rect, event->x, event->y))
1433                                 return 1;
1434                         else if(event->type==MOUSEMOVE && BLI_in_rcti(&rect, event->prevx, event->prevy))
1435                                 return 1;
1436                         else
1437                                 return 0;
1438                 }
1439                 else {
1440                         if(BLI_in_rcti(handler->bbwin, event->x, event->y))
1441                                 return 1;
1442                         else if(event->type==MOUSEMOVE && BLI_in_rcti(handler->bbwin, event->prevx, event->prevy))
1443                                 return 1;
1444                         else
1445                                 return 0;
1446                 }
1447         }
1448         return 1;
1449 }
1450
1451 static int wm_action_not_handled(int action)
1452 {
1453         return action == WM_HANDLER_CONTINUE || action == (WM_HANDLER_BREAK|WM_HANDLER_MODAL);
1454 }
1455
1456 static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
1457 {
1458         wmWindowManager *wm= CTX_wm_manager(C);
1459         wmEventHandler *handler, *nexthandler;
1460         int action= WM_HANDLER_CONTINUE;
1461         int always_pass;
1462
1463         if(handlers==NULL) return action;
1464
1465         /* modal handlers can get removed in this loop, we keep the loop this way */
1466         for(handler= handlers->first; handler; handler= nexthandler) {
1467                 
1468                 nexthandler= handler->next;
1469                 
1470                 /* during this loop, ui handlers for nested menus can tag multiple handlers free */
1471                 if(handler->flag & WM_HANDLER_DO_FREE);
1472                         /* optional boundbox */
1473                 else if(handler_boundbox_test(handler, event)) {
1474                         /* in advance to avoid access to freed event on window close */
1475                         always_pass= wm_event_always_pass(event);
1476                 
1477                         /* modal+blocking handler */
1478                         if(handler->flag & WM_HANDLER_BLOCKING)
1479                                 action |= WM_HANDLER_BREAK;
1480
1481                         if(handler->keymap) {
1482                                 wmKeyMap *keymap= WM_keymap_active(wm, handler->keymap);
1483                                 wmKeyMapItem *kmi;
1484                                 
1485                                 if(!keymap->poll || keymap->poll(C)) {
1486                                         for(kmi= keymap->items.first; kmi; kmi= kmi->next) {
1487                                                 if(wm_eventmatch(event, kmi)) {
1488                                                         
1489                                                         event->keymap_idname= kmi->idname;      /* weak, but allows interactive callback to not use rawkey */
1490                                                         
1491                                                         action |= wm_handler_operator_call(C, handlers, handler, event, kmi->ptr);
1492                                                         if(action & WM_HANDLER_BREAK)  /* not always_pass here, it denotes removed handler */
1493                                                                 break;
1494                                                 }
1495                                         }
1496                                 }
1497                         }
1498                         else if(handler->ui_handle) {
1499                                 action |= wm_handler_ui_call(C, handler, event, always_pass);
1500                         }
1501                         else if(handler->type==WM_HANDLER_FILESELECT) {
1502                                 /* screen context changes here */
1503                                 action |= wm_handler_fileselect_call(C, handlers, handler, event);
1504                         }
1505                         else if(handler->dropboxes) {
1506                                 if(event->type==EVT_DROP) {
1507                                         wmDropBox *drop= handler->dropboxes->first;
1508                                         for(; drop; drop= drop->next) {
1509                                                 /* other drop custom types allowed */
1510                                                 if(event->custom==EVT_DATA_LISTBASE) {
1511                                                         ListBase *lb= (ListBase *)event->customdata;
1512                                                         wmDrag *drag;
1513                                                         
1514                                                         for(drag= lb->first; drag; drag= drag->next) {
1515                                                                 if(drop->poll(C, drag, event)) {
1516                                                                         
1517                                                                         drop->copy(drag, drop);
1518                                                                         
1519                                                                         /* free the drags before calling operator */
1520                                                                         BLI_freelistN(event->customdata);
1521                                                                         event->customdata= NULL;
1522                                                                         event->custom= 0;
1523                                                                         
1524                                                                         WM_operator_name_call(C, drop->ot->idname, drop->opcontext, drop->ptr);
1525                                                                         action |= WM_HANDLER_BREAK;
1526                                                                         
1527                                                                         /* XXX fileread case */
1528                                                                         if(CTX_wm_window(C)==NULL)
1529                                                                                 return action;
1530                                                                         
1531                                                                         /* escape from drag loop, got freed */
1532                                                                         break;
1533                                                                 }
1534                                                         }
1535                                                 }
1536                                         }
1537                                 }
1538                         }
1539                         else {
1540                                 /* modal, swallows all */
1541                                 action |= wm_handler_operator_call(C, handlers, handler, event, NULL);
1542                         }
1543
1544                         if(action & WM_HANDLER_BREAK) {
1545                                 if(always_pass)
1546                                         action &= ~WM_HANDLER_BREAK;
1547                                 else
1548                                         break;
1549                         }
1550                 }
1551                 
1552                 /* XXX fileread case, if the wm is freed then the handler's
1553                  * will have been too so the code below need not run. */
1554                 if(CTX_wm_window(C)==NULL) {
1555                         return action;
1556                 }
1557
1558                 /* XXX code this for all modal ops, and ensure free only happens here */
1559                 
1560                 /* modal ui handler can be tagged to be freed */ 
1561                 if(BLI_findindex(handlers, handler) != -1) { /* could be free'd already by regular modal ops */
1562                         if(handler->flag & WM_HANDLER_DO_FREE) {
1563                                 BLI_remlink(handlers, handler);
1564                                 wm_event_free_handler(handler);
1565                         }
1566                 }
1567         }
1568
1569         /* test for CLICK event */
1570         if (wm_action_not_handled(action) && event->val == KM_RELEASE) {
1571                 wmWindow *win = CTX_wm_window(C);
1572
1573                 if (win && win->eventstate->prevtype == event->type && win->eventstate->prevval == KM_PRESS) {
1574                         /* test for double click first,
1575                          * note1: this can be problematic because single click operators can get the
1576                          *   double click event but then with old mouse coords which is highly confusing,
1577                          *   so check for mouse moves too.
1578                          * note2: the first click event will be handled but still used to create a
1579                          *   double click event if clicking again quickly.
1580                          *   If no double click events are found it will fallback to a single click.
1581                          *   So a double click event can result in 2 successive single click calls
1582                          *   if its not handled by the keymap - campbell */
1583                         if (    (ABS(event->x - win->eventstate->prevclickx)) <= 2 &&
1584                                         (ABS(event->y - win->eventstate->prevclicky)) <= 2 &&
1585                                         ((PIL_check_seconds_timer() - win->eventstate->prevclicktime) * 1000 < U.dbl_click_time)
1586                         ) {
1587                                 event->val = KM_DBL_CLICK;
1588                                 /* removed this because in cases where we're this is used as a single click
1589                                  * event, this will give old coords, since the distance is checked above, using new coords should be ok. */
1590                                 //   event->x = win->eventstate->prevclickx;
1591                                 //   event->y = win->eventstate->prevclicky;
1592                                 action |= wm_handlers_do(C, event, handlers);
1593                         }
1594
1595                         if (wm_action_not_handled(action)) {
1596                                 event->val = KM_CLICK;
1597                                 action |= wm_handlers_do(C, event, handlers);
1598                         }
1599
1600
1601                         /* revert value if not handled */
1602                         if (wm_action_not_handled(action)) {
1603                                 event->val = KM_RELEASE;
1604                         }
1605                 }
1606         }
1607         
1608         if(action == (WM_HANDLER_BREAK|WM_HANDLER_MODAL))
1609                 wm_cursor_arrow_move(CTX_wm_window(C), event);
1610
1611         return action;
1612 }
1613
1614 static int wm_event_inside_i(wmEvent *event, rcti *rect)
1615 {
1616         if(wm_event_always_pass(event))
1617                 return 1;
1618         if(BLI_in_rcti(rect, event->x, event->y))
1619                 return 1;
1620         if(event->type==MOUSEMOVE) {
1621                 if( BLI_in_rcti(rect, event->prevx, event->prevy)) {
1622                         return 1;
1623                 }
1624                 return 0;
1625         }
1626         return 0;
1627 }
1628
1629 static ScrArea *area_event_inside(bContext *C, int x, int y)
1630 {
1631         bScreen *screen= CTX_wm_screen(C);
1632         ScrArea *sa;
1633         
1634         if(screen)
1635                 for(sa= screen->areabase.first; sa; sa= sa->next)
1636                         if(BLI_in_rcti(&sa->totrct, x, y))
1637                                 return sa;
1638         return NULL;
1639 }
1640
1641 static ARegion *region_event_inside(bContext *C, int x, int y)
1642 {
1643         bScreen *screen= CTX_wm_screen(C);
1644         ScrArea *area= CTX_wm_area(C);
1645         ARegion *ar;
1646         
1647         if(screen && area)
1648                 for(ar= area->regionbase.first; ar; ar= ar->next)
1649                         if(BLI_in_rcti(&ar->winrct, x, y))
1650                                 return ar;
1651         return NULL;
1652 }
1653
1654 static void wm_paintcursor_tag(bContext *C, wmPaintCursor *pc, ARegion *ar)
1655 {
1656         if(ar) {
1657                 for(; pc; pc= pc->next) {
1658                         if(pc->poll == NULL || pc->poll(C)) {
1659                                 wmWindow *win= CTX_wm_window(C);
1660                                 win->screen->do_draw_paintcursor= 1;
1661                                 wm_tag_redraw_overlay(win, ar);
1662                         }
1663                 }
1664         }
1665 }
1666
1667 /* called on mousemove, check updates for paintcursors */
1668 /* context was set on active area and region */
1669 static void wm_paintcursor_test(bContext *C, wmEvent *event)
1670 {
1671         wmWindowManager *wm= CTX_wm_manager(C);
1672         
1673         if(wm->paintcursors.first) {
1674                 ARegion *ar= CTX_wm_region(C);
1675                 
1676                 if(ar)
1677                         wm_paintcursor_tag(C, wm->paintcursors.first, ar);
1678                 
1679                 /* if previous position was not in current region, we have to set a temp new context */
1680                 if(ar==NULL || !BLI_in_rcti(&ar->winrct, event->prevx, event->prevy)) {
1681                         ScrArea *sa= CTX_wm_area(C);
1682                         
1683                         CTX_wm_area_set(C, area_event_inside(C, event->prevx, event->prevy));
1684                         CTX_wm_region_set(C, region_event_inside(C, event->prevx, event->prevy));
1685
1686                         wm_paintcursor_tag(C, wm->paintcursors.first, CTX_wm_region(C));
1687                         
1688                         CTX_wm_area_set(C, sa);
1689                         CTX_wm_region_set(C, ar);
1690                 }
1691         }
1692 }
1693
1694 static void wm_event_drag_test(wmWindowManager *wm, wmWindow *win, wmEvent *event)
1695 {
1696         if(wm->drags.first==NULL) return;
1697         
1698         if(event->type==MOUSEMOVE)
1699                 win->screen->do_draw_drag= 1;
1700         else if(event->type==ESCKEY) {
1701                 BLI_freelistN(&wm->drags);
1702                 win->screen->do_draw_drag= 1;
1703         }
1704         else if(event->type==LEFTMOUSE && event->val==KM_RELEASE) {
1705                 event->type= EVT_DROP;
1706                 
1707                 /* create customdata, first free existing */
1708                 if(event->customdata) {
1709                         if(event->customdatafree)
1710                                 MEM_freeN(event->customdata);
1711                 }
1712                 
1713                 event->custom= EVT_DATA_LISTBASE;
1714                 event->customdata= &wm->drags;
1715                 event->customdatafree= 1;
1716                 
1717                 /* clear drop icon */
1718                 win->screen->do_draw_drag= 1;
1719                 
1720                 /* restore cursor (disabled, see wm_dragdrop.c) */
1721                 // WM_cursor_restore(win);
1722         }
1723         
1724         /* overlap fails otherwise */
1725         if(win->screen->do_draw_drag)
1726                 if(win->drawmethod == USER_DRAW_OVERLAP)
1727                         win->screen->do_draw= 1;
1728         
1729 }
1730
1731 /* called in main loop */
1732 /* goes over entire hierarchy:  events -> window -> screen -> area -> region */
1733 void wm_event_do_handlers(bContext *C)
1734 {
1735         wmWindowManager *wm= CTX_wm_manager(C);
1736         wmWindow *win;
1737
1738         for(win= wm->windows.first; win; win= win->next) {
1739                 wmEvent *event;
1740                 
1741                 if( win->screen==NULL )
1742                         wm_event_free_all(win);
1743                 else {
1744                         Scene* scene = win->screen->scene;
1745                         
1746                         if(scene) {
1747                                 int playing = sound_scene_playing(win->screen->scene);
1748                                 
1749                                 if(playing != -1) {
1750                                         CTX_wm_window_set(C, win);
1751                                         CTX_wm_screen_set(C, win->screen);
1752                                         CTX_data_scene_set(C, scene);
1753                                         
1754                                         if(((playing == 1) && (!win->screen->animtimer)) || ((playing == 0) && (win->screen->animtimer))){
1755                                                 ED_screen_animation_play(C, -1, 1);
1756                                         }
1757                                         
1758                                         if(playing == 0) {
1759                                                 int ncfra = sound_sync_scene(scene) * (float)FPS + 0.5f;
1760                                                 if(ncfra != scene->r.cfra)      {
1761                                                         scene->r.cfra = ncfra;
1762                                                         ED_update_for_newframe(CTX_data_main(C), scene, win->screen, 1);
1763                                                         WM_event_add_notifier(C, NC_WINDOW, NULL);
1764                                                 }
1765                                         }
1766                                         
1767                                         CTX_data_scene_set(C, NULL);
1768                                         CTX_wm_screen_set(C, NULL);
1769                                         CTX_wm_window_set(C, NULL);
1770                                 }
1771                         }
1772                 }
1773                 
1774                 while( (event= win->queue.first) ) {
1775                         int action = WM_HANDLER_CONTINUE;
1776
1777                         if((G.f & G_DEBUG) && event && !ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE))
1778                                 printf("pass on evt %d val %d\n", event->type, event->val); 
1779                         
1780                         wm_eventemulation(event);
1781
1782                         CTX_wm_window_set(C, win);
1783                         
1784                         /* we let modal handlers get active area/region, also wm_paintcursor_test needs it */
1785                         CTX_wm_area_set(C, area_event_inside(C, event->x, event->y));
1786                         CTX_wm_region_set(C, region_event_inside(C, event->x, event->y));
1787                         
1788                         /* MVC demands to not draw in event handlers... but we need to leave it for ogl selecting etc */
1789                         wm_window_make_drawable(C, win);
1790                         
1791                         wm_region_mouse_co(C, event);
1792
1793                         /* first we do priority handlers, modal + some limited keymaps */
1794                         action |= wm_handlers_do(C, event, &win->modalhandlers);
1795                         
1796                         /* fileread case */
1797                         if(CTX_wm_window(C)==NULL)
1798                                 return;
1799                         
1800                         /* check dragging, creates new event or frees, adds draw tag */
1801                         wm_event_drag_test(wm, win, event);
1802                         
1803                         /* builtin tweak, if action is break it removes tweak */
1804                         wm_tweakevent_test(C, event, action);
1805
1806                         if((action & WM_HANDLER_BREAK) == 0) {
1807                                 ScrArea *sa;
1808                                 ARegion *ar;
1809                                 int doit= 0;
1810         
1811                                 /* Note: setting subwin active should be done here, after modal handlers have been done */
1812                                 if(event->type==MOUSEMOVE) {
1813                                         /* state variables in screen, cursors. Also used in wm_draw.c, fails for modal handlers though */
1814                                         ED_screen_set_subwinactive(C, event);   
1815                                         /* for regions having custom cursors */
1816                                         wm_paintcursor_test(C, event);
1817                                 }
1818                                 
1819                                 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
1820                                         if(wm_event_inside_i(event, &sa->totrct)) {
1821                                                 CTX_wm_area_set(C, sa);
1822
1823                                                 if((action & WM_HANDLER_BREAK) == 0) {
1824                                                         for(ar=sa->regionbase.first; ar; ar= ar->next) {
1825                                                                 if(wm_event_inside_i(event, &ar->winrct)) {
1826                                                                         CTX_wm_region_set(C, ar);
1827                                                                         
1828                                                                         /* call even on non mouse events, since the */
1829                                                                         wm_region_mouse_co(C, event);
1830
1831                                                                         /* does polls for drop regions and checks uibuts */
1832                                                                         /* need to be here to make sure region context is true */
1833                                                                         if(ELEM(event->type, MOUSEMOVE, EVT_DROP)) {
1834                                                                                 wm_drags_check_ops(C, event);
1835                                                                         }
1836                                                                         
1837                                                                         action |= wm_handlers_do(C, event, &ar->handlers);
1838
1839                                                                         /* fileread case (python), [#29489] */
1840                                                                         if(CTX_wm_window(C)==NULL)
1841                                                                                 return;
1842
1843                                                                         doit |= (BLI_in_rcti(&ar->winrct, event->x, event->y));
1844                                                                         
1845                                                                         if(action & WM_HANDLER_BREAK)
1846                                                                                 break;
1847                                                                 }
1848                                                         }
1849                                                 }
1850
1851                                                 CTX_wm_region_set(C, NULL);
1852
1853                                                 if((action & WM_HANDLER_BREAK) == 0) {
1854                                                         wm_region_mouse_co(C, event); /* only invalidates event->mval in this case */
1855                                                         action |= wm_handlers_do(C, event, &sa->handlers);
1856                                                 }
1857                                                 CTX_wm_area_set(C, NULL);
1858
1859                                                 /* NOTE: do not escape on WM_HANDLER_BREAK, mousemove needs handled for previous area */
1860                                         }
1861                                 }
1862                                 
1863                                 if((action & WM_HANDLER_BREAK) == 0) {
1864                                         /* also some non-modal handlers need active area/region */
1865                                         CTX_wm_area_set(C, area_event_inside(C, event->x, event->y));
1866                                         CTX_wm_region_set(C, region_event_inside(C, event->x, event->y));
1867
1868                                         wm_region_mouse_co(C, event);
1869
1870                                         action |= wm_handlers_do(C, event, &win->handlers);
1871
1872                                         /* fileread case */
1873                                         if(CTX_wm_window(C)==NULL)
1874                                                 return;
1875                                 }
1876
1877                                 /* XXX hrmf, this gives reliable previous mouse coord for area change, feels bad? 
1878                                    doing it on ghost queue gives errors when mousemoves go over area borders */
1879                                 if(doit && win->screen && win->screen->subwinactive != win->screen->mainwin) {
1880                                         win->eventstate->prevx= event->x;
1881                                         win->eventstate->prevy= event->y;
1882                                 }
1883                         }
1884                         
1885                         /* store last event for this window */
1886                         /* mousemove and timer events don't overwrite last type */
1887                         if (event->type != MOUSEMOVE && !ISTIMER(event->type)) {
1888                                 if (wm_action_not_handled(action)) {
1889                                         if (win->eventstate->prevtype == event->type) {
1890                                                 /* set click time on first click (press -> release) */
1891                                                 if (win->eventstate->prevval == KM_PRESS && event->val == KM_RELEASE) {
1892                                                         win->eventstate->prevclicktime = PIL_check_seconds_timer();
1893                                                         win->eventstate->prevclickx = event->x;
1894                                                         win->eventstate->prevclicky = event->y;
1895                                                 }
1896                                         } else {
1897                                                 /* reset click time if event type not the same */
1898                                                 win->eventstate->prevclicktime = 0;
1899                                         }
1900
1901                                         win->eventstate->prevval = event->val;
1902                                         win->eventstate->prevtype = event->type;
1903                                 } else if (event->val == KM_CLICK) { /* keep click for double click later */
1904                                         win->eventstate->prevtype = event->type;
1905                                         win->eventstate->prevval = event->val;
1906                                         win->eventstate->prevclicktime = PIL_check_seconds_timer();
1907                                         win->eventstate->prevclickx = event->x;
1908                                         win->eventstate->prevclicky = event->y;
1909                                 } else { /* reset if not */
1910                                         win->eventstate->prevtype = -1;
1911                                         win->eventstate->prevval = 0;
1912                                         win->eventstate->prevclicktime = 0;
1913                                 }
1914                         }
1915
1916                         /* unlink and free here, blender-quit then frees all */
1917                         BLI_remlink(&win->queue, event);
1918                         wm_event_free(event);
1919                         
1920                 }
1921                 
1922                 /* only add mousemove when queue was read entirely */
1923                 if(win->addmousemove && win->eventstate) {
1924                         wmEvent tevent= *(win->eventstate);
1925                         tevent.type= MOUSEMOVE;
1926                         tevent.prevx= tevent.x;
1927                         tevent.prevy= tevent.y;
1928                         wm_event_add(win, &tevent);
1929                         win->addmousemove= 0;
1930                 }
1931                 
1932                 CTX_wm_window_set(C, NULL);
1933         }
1934 }
1935
1936 /* ********** filesector handling ************ */
1937
1938 void WM_event_fileselect_event(bContext *C, void *ophandle, int eventval)
1939 {
1940         /* add to all windows! */
1941         wmWindow *win;
1942         
1943         for(win= CTX_wm_manager(C)->windows.first; win; win= win->next) {
1944                 wmEvent event= *win->eventstate;
1945                 
1946                 event.type= EVT_FILESELECT;
1947                 event.val= eventval;
1948                 event.customdata= ophandle;             // only as void pointer type check
1949
1950                 wm_event_add(win, &event);
1951         }
1952 }
1953
1954 /* operator is supposed to have a filled "path" property */
1955 /* optional property: filetype (XXX enum?) */
1956
1957 /* Idea is to keep a handler alive on window queue, owning the operator.
1958    The filewindow can send event to make it execute, thus ensuring
1959    executing happens outside of lower level queues, with UI refreshed. 
1960    Should also allow multiwin solutions */
1961
1962 void WM_event_add_fileselect(bContext *C, wmOperator *op)
1963 {
1964         wmEventHandler *handler, *handlernext;
1965         wmWindow *win= CTX_wm_window(C);
1966         int full= 1;    // XXX preset?
1967
1968         /* only allow 1 file selector open per window */
1969         for(handler= win->modalhandlers.first; handler; handler=handlernext) {
1970                 handlernext= handler->next;
1971                 
1972                 if(handler->type == WM_HANDLER_FILESELECT) {
1973                         if(handler->op)
1974                                 WM_operator_free(handler->op);
1975                         BLI_remlink(&win->modalhandlers, handler);
1976                         wm_event_free_handler(handler);
1977                 }
1978         }
1979         
1980         handler = MEM_callocN(sizeof(wmEventHandler), "fileselect handler");
1981         
1982         handler->type= WM_HANDLER_FILESELECT;
1983         handler->op= op;
1984         handler->op_area= CTX_wm_area(C);
1985         handler->op_region= CTX_wm_region(C);
1986         handler->filescreen= CTX_wm_screen(C);
1987         
1988         BLI_addhead(&win->modalhandlers, handler);
1989         
1990         /* check props once before invoking if check is available
1991          * ensures initial properties are valid */
1992         if(op->type->check) {
1993                 op->type->check(C, op); /* ignore return value */
1994         }
1995
1996         WM_event_fileselect_event(C, op, full?EVT_FILESELECT_FULL_OPEN:EVT_FILESELECT_OPEN);
1997 }
1998
1999 #if 0
2000 /* lets not expose struct outside wm? */
2001 static void WM_event_set_handler_flag(wmEventHandler *handler, int flag)
2002 {
2003         handler->flag= flag;
2004 }
2005 #endif
2006
2007 wmEventHandler *WM_event_add_modal_handler(bContext *C, wmOperator *op)
2008 {
2009         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event modal handler");
2010         wmWindow *win= CTX_wm_window(C);
2011         
2012         /* operator was part of macro */
2013         if(op->opm) {
2014                 /* give the mother macro to the handler */
2015                 handler->op= op->opm;
2016                 /* mother macro opm becomes the macro element */
2017                 handler->op->opm= op;
2018         }
2019         else
2020                 handler->op= op;
2021         
2022         handler->op_area= CTX_wm_area(C);               /* means frozen screen context for modal handlers! */
2023         handler->op_region= CTX_wm_region(C);
2024         
2025         BLI_addhead(&win->modalhandlers, handler);
2026
2027         return handler;
2028 }
2029
2030 wmEventHandler *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
2031 {
2032         wmEventHandler *handler;
2033
2034         if(!keymap) {
2035                 printf("WM_event_add_keymap_handler called with NULL keymap\n");
2036                 return NULL;
2037         }
2038
2039         /* only allow same keymap once */
2040         for(handler= handlers->first; handler; handler= handler->next)
2041                 if(handler->keymap==keymap)
2042                         return handler;
2043         
2044         handler= MEM_callocN(sizeof(wmEventHandler), "event keymap handler");
2045         BLI_addtail(handlers, handler);
2046         handler->keymap= keymap;
2047
2048         return handler;
2049 }
2050
2051 /* priorities not implemented yet, for time being just insert in begin of list */
2052 wmEventHandler *WM_event_add_keymap_handler_priority(ListBase *handlers, wmKeyMap *keymap, int UNUSED(priority))
2053 {
2054         wmEventHandler *handler;
2055         
2056         WM_event_remove_keymap_handler(handlers, keymap);
2057         
2058         handler= MEM_callocN(sizeof(wmEventHandler), "event keymap handler");
2059         BLI_addhead(handlers, handler);
2060         handler->keymap= keymap;
2061         
2062         return handler;
2063 }
2064
2065 wmEventHandler *WM_event_add_keymap_handler_bb(ListBase *handlers, wmKeyMap *keymap, rcti *bblocal, rcti *bbwin)
2066 {
2067         wmEventHandler *handler= WM_event_add_keymap_handler(handlers, keymap);
2068         
2069         if(handler) {
2070                 handler->bblocal= bblocal;
2071                 handler->bbwin= bbwin;
2072         }
2073         return handler;
2074 }
2075
2076 void WM_event_remove_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
2077 {
2078         wmEventHandler *handler;
2079         
2080         for(handler= handlers->first; handler; handler= handler->next) {
2081                 if(handler->keymap==keymap) {
2082                         BLI_remlink(handlers, handler);
2083                         wm_event_free_handler(handler);
2084                         break;
2085                 }
2086         }
2087 }
2088
2089 wmEventHandler *WM_event_add_ui_handler(const bContext *C, ListBase *handlers, wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata)
2090 {
2091         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event ui handler");
2092         handler->ui_handle= func;
2093         handler->ui_remove= remove;
2094         handler->ui_userdata= userdata;
2095         handler->ui_area= (C)? CTX_wm_area(C): NULL;
2096         handler->ui_region= (C)? CTX_wm_region(C): NULL;
2097         handler->ui_menu= (C)? CTX_wm_menu(C): NULL;
2098         
2099         BLI_addhead(handlers, handler);
2100         
2101         return handler;
2102 }
2103
2104 /* set "postpone" for win->modalhandlers, this is in a running for() loop in wm_handlers_do() */
2105 void WM_event_remove_ui_handler(ListBase *handlers, wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata, int postpone)
2106 {
2107         wmEventHandler *handler;
2108         
2109         for(handler= handlers->first; handler; handler= handler->next) {
2110                 if(handler->ui_handle == func && handler->ui_remove == remove && handler->ui_userdata == userdata) {
2111                         /* handlers will be freed in wm_handlers_do() */
2112                         if(postpone) {
2113                                 handler->flag |= WM_HANDLER_DO_FREE;
2114                         }
2115                         else {
2116                                 BLI_remlink(handlers, handler);
2117                                 wm_event_free_handler(handler);
2118                         }
2119                         break;
2120                 }
2121         }
2122 }
2123
2124 wmEventHandler *WM_event_add_dropbox_handler(ListBase *handlers, ListBase *dropboxes)
2125 {
2126         wmEventHandler *handler;
2127
2128         /* only allow same dropbox once */
2129         for(handler= handlers->first; handler; handler= handler->next)
2130                 if(handler->dropboxes==dropboxes)
2131                         return handler;
2132         
2133         handler= MEM_callocN(sizeof(wmEventHandler), "dropbox handler");
2134         
2135         /* dropbox stored static, no free or copy */
2136         handler->dropboxes= dropboxes;
2137         BLI_addhead(handlers, handler);
2138         
2139         return handler;
2140 }
2141
2142 /* XXX solution works, still better check the real cause (ton) */
2143 void WM_event_remove_area_handler(ListBase *handlers, void *area)
2144 {
2145         wmEventHandler *handler, *nexthandler;
2146
2147         for(handler = handlers->first; handler; handler= nexthandler) {
2148                 nexthandler = handler->next;
2149                 if (handler->type != WM_HANDLER_FILESELECT) {
2150                         if (handler->ui_area == area) {
2151                                 BLI_remlink(handlers, handler);
2152                                 wm_event_free_handler(handler);
2153                         }
2154                 }
2155         }
2156 }
2157
2158 #if 0
2159 static void WM_event_remove_handler(ListBase *handlers, wmEventHandler *handler)
2160 {
2161         BLI_remlink(handlers, handler);
2162         wm_event_free_handler(handler);
2163 }
2164 #endif
2165
2166 void WM_event_add_mousemove(bContext *C)
2167 {
2168         wmWindow *window= CTX_wm_window(C);
2169         
2170         window->addmousemove= 1;
2171 }
2172
2173 /* for modal callbacks, check configuration for how to interpret exit with tweaks  */
2174 int WM_modal_tweak_exit(wmEvent *evt, int tweak_event)
2175 {
2176         /* if the release-confirm userpref setting is enabled, 
2177          * tweak events can be cancelled when mouse is released
2178          */
2179         if (U.flag & USER_RELEASECONFIRM) {
2180                 /* option on, so can exit with km-release */
2181                 if (evt->val == KM_RELEASE) {
2182                         switch (tweak_event) {
2183                                 case EVT_TWEAK_L:
2184                                 case EVT_TWEAK_M:
2185                                 case EVT_TWEAK_R:
2186                                         return 1;
2187                         }
2188                 }
2189                 else {
2190                         /* if the initial event wasn't a tweak event then
2191                          * ignore USER_RELEASECONFIRM setting: see [#26756] */
2192                         if(ELEM3(tweak_event, EVT_TWEAK_L, EVT_TWEAK_M, EVT_TWEAK_R) == 0) {
2193                                 return 1;
2194                         }
2195                 }
2196         }
2197         else {
2198                 /* this is fine as long as not doing km-release, otherwise
2199                  * some items (i.e. markers) being tweaked may end up getting
2200                  * dropped all over
2201                  */
2202                 if (evt->val != KM_RELEASE)
2203                         return 1;
2204         }
2205         
2206         return 0;
2207 }
2208
2209 /* ********************* ghost stuff *************** */
2210
2211 static int convert_key(GHOST_TKey key) 
2212 {
2213         if (key>=GHOST_kKeyA && key<=GHOST_kKeyZ) {
2214                 return (AKEY + ((int) key - GHOST_kKeyA));
2215         } else if (key>=GHOST_kKey0 && key<=GHOST_kKey9) {
2216                 return (ZEROKEY + ((int) key - GHOST_kKey0));
2217         } else if (key>=GHOST_kKeyNumpad0 && key<=GHOST_kKeyNumpad9) {
2218                 return (PAD0 + ((int) key - GHOST_kKeyNumpad0));
2219         } else if (key>=GHOST_kKeyF1 && key<=GHOST_kKeyF19) {
2220                 return (F1KEY + ((int) key - GHOST_kKeyF1));
2221         } else {
2222                 switch (key) {
2223                         case GHOST_kKeyBackSpace:               return BACKSPACEKEY;
2224                         case GHOST_kKeyTab:                             return TABKEY;
2225                         case GHOST_kKeyLinefeed:                return LINEFEEDKEY;
2226                         case GHOST_kKeyClear:                   return 0;
2227                         case GHOST_kKeyEnter:                   return RETKEY;
2228                                 
2229                         case GHOST_kKeyEsc:                             return ESCKEY;
2230                         case GHOST_kKeySpace:                   return SPACEKEY;
2231                         case GHOST_kKeyQuote:                   return QUOTEKEY;
2232                         case GHOST_kKeyComma:                   return COMMAKEY;
2233                         case GHOST_kKeyMinus:                   return MINUSKEY;
2234                         case GHOST_kKeyPeriod:                  return PERIODKEY;
2235                         case GHOST_kKeySlash:                   return SLASHKEY;
2236                                 
2237                         case GHOST_kKeySemicolon:               return SEMICOLONKEY;
2238                         case GHOST_kKeyEqual:                   return EQUALKEY;
2239                                 
2240                         case GHOST_kKeyLeftBracket:             return LEFTBRACKETKEY;
2241                         case GHOST_kKeyRightBracket:    return RIGHTBRACKETKEY;
2242                         case GHOST_kKeyBackslash:               return BACKSLASHKEY;
2243                         case GHOST_kKeyAccentGrave:             return ACCENTGRAVEKEY;
2244                                 
2245                         case GHOST_kKeyLeftShift:               return LEFTSHIFTKEY;
2246                         case GHOST_kKeyRightShift:              return RIGHTSHIFTKEY;
2247                         case GHOST_kKeyLeftControl:             return LEFTCTRLKEY;
2248                         case GHOST_kKeyRightControl:    return RIGHTCTRLKEY;
2249                         case GHOST_kKeyOS:                              return OSKEY;
2250                         case GHOST_kKeyLeftAlt:                 return LEFTALTKEY;
2251                         case GHOST_kKeyRightAlt:                return RIGHTALTKEY;
2252                                 
2253                         case GHOST_kKeyCapsLock:                return CAPSLOCKKEY;
2254                         case GHOST_kKeyNumLock:                 return 0;
2255                         case GHOST_kKeyScrollLock:              return 0;
2256                                 
2257                         case GHOST_kKeyLeftArrow:               return LEFTARROWKEY;
2258                         case GHOST_kKeyRightArrow:              return RIGHTARROWKEY;
2259                         case GHOST_kKeyUpArrow:                 return UPARROWKEY;
2260                         case GHOST_kKeyDownArrow:               return DOWNARROWKEY;
2261                                 
2262                         case GHOST_kKeyPrintScreen:             return 0;
2263                         case GHOST_kKeyPause:                   return PAUSEKEY;
2264                                 
2265                         case GHOST_kKeyInsert:                  return INSERTKEY;
2266                         case GHOST_kKeyDelete:                  return DELKEY;
2267                         case GHOST_kKeyHome:                    return HOMEKEY;
2268                         case GHOST_kKeyEnd:                             return ENDKEY;
2269                         case GHOST_kKeyUpPage:                  return PAGEUPKEY;
2270                         case GHOST_kKeyDownPage:                return PAGEDOWNKEY;
2271                                 
2272                         case GHOST_kKeyNumpadPeriod:    return PADPERIOD;
2273                         case GHOST_kKeyNumpadEnter:             return PADENTER;
2274                         case GHOST_kKeyNumpadPlus:              return PADPLUSKEY;
2275                         case GHOST_kKeyNumpadMinus:             return PADMINUS;
2276                         case GHOST_kKeyNumpadAsterisk:  return PADASTERKEY;
2277                         case GHOST_kKeyNumpadSlash:             return PADSLASHKEY;
2278                                 
2279                         case GHOST_kKeyGrLess:              return GRLESSKEY; 
2280                         
2281                         case GHOST_kKeyMediaPlay:               return MEDIAPLAY;
2282                         case GHOST_kKeyMediaStop:               return MEDIASTOP;
2283                         case GHOST_kKeyMediaFirst:              return MEDIAFIRST;
2284                         case GHOST_kKeyMediaLast:               return MEDIALAST;
2285                         
2286                         default:
2287                                 return UNKNOWNKEY;      /* GHOST_kKeyUnknown */
2288                 }
2289         }
2290 }
2291
2292 /* adds customdata to event */
2293 static void update_tablet_data(wmWindow *win, wmEvent *event)
2294 {
2295         const GHOST_TabletData *td= GHOST_GetTabletData(win->ghostwin);
2296         
2297         /* if there's tablet data from an active tablet device then add it */
2298         if ((td != NULL) && td->Active != GHOST_kTabletModeNone) {
2299                 struct wmTabletData *wmtab= MEM_mallocN(sizeof(wmTabletData), "customdata tablet");
2300                 
2301                 wmtab->Active = (int)td->Active;
2302                 wmtab->Pressure = td->Pressure;
2303                 wmtab->Xtilt = td->Xtilt;
2304                 wmtab->Ytilt = td->Ytilt;
2305                 
2306                 event->custom= EVT_DATA_TABLET;
2307                 event->customdata= wmtab;
2308                 event->customdatafree= 1;
2309         } 
2310 }
2311
2312 /* adds customdata to event */
2313 static void attach_ndof_data(wmEvent* event, const GHOST_TEventNDOFMotionData* ghost)
2314 {
2315         wmNDOFMotionData* data = MEM_mallocN(sizeof(wmNDOFMotionData), "customdata NDOF");
2316
2317         data->tx = ghost->tx;
2318         data->ty = ghost->ty;
2319         data->tz = ghost->tz;
2320
2321         data->rx = ghost->rx;
2322         data->ry = ghost->ry;
2323         data->rz = ghost->rz;
2324
2325         data->dt = ghost->dt;
2326
2327         event->custom = EVT_DATA_NDOF_MOTION;
2328         event->customdata = data;
2329         event->customdatafree = 1;
2330 }
2331
2332 /* imperfect but probably usable... draw/enable drags to other windows */
2333 static wmWindow *wm_event_cursor_other_windows(wmWindowManager *wm, wmWindow *win, wmEvent *evt)
2334 {
2335         int mx= evt->x, my= evt->y;
2336         
2337         if(wm->windows.first== wm->windows.last)
2338                 return NULL;
2339         
2340         /* top window bar... */
2341         if(mx<0 || my<0 || mx>win->sizex || my>win->sizey+30) { 
2342                 wmWindow *owin;
2343                 wmEventHandler *handler;
2344                 
2345                 /* let's skip windows having modal handlers now */
2346                 /* potential XXX ugly... I wouldn't have added a modalhandlers list (introduced in rev 23331, ton) */
2347                 for(handler= win->modalhandlers.first; handler; handler= handler->next)
2348                         if(handler->ui_handle || handler->op)
2349                                 return NULL;
2350                 
2351                 /* to desktop space */
2352                 mx += (int)win->posx;
2353                 my += (int)win->posy;
2354                 
2355                 /* check other windows to see if it has mouse inside */
2356                 for(owin= wm->windows.first; owin; owin= owin->next) {
2357                         
2358                         if(owin!=win) {
2359                                 if(mx-owin->posx >= 0 && my-owin->posy >= 0 &&
2360                                    mx-owin->posx <= owin->sizex && my-owin->posy <= owin->sizey) {
2361                                         evt->x= mx - (int)owin->posx;
2362                                         evt->y= my - (int)owin->posy;
2363                                         
2364                                         return owin;
2365                                 }
2366                         }
2367                 }
2368         }
2369         return NULL;
2370 }
2371
2372 /* windows store own event queues, no bContext here */
2373 /* time is in 1000s of seconds, from ghost */
2374 void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int UNUSED(time), void *customdata)
2375 {
2376         wmWindow *owin;
2377         wmEvent event, *evt= win->eventstate;
2378         
2379         /* initialize and copy state (only mouse x y and modifiers) */
2380         event= *evt;
2381         
2382         switch (type) {
2383                 /* mouse move */
2384                 case GHOST_kEventCursorMove: {
2385                         if(win->active) {
2386                                 GHOST_TEventCursorData *cd= customdata;
2387                                 wmEvent *lastevent= win->queue.last;
2388                                 
2389 #if defined(__APPLE__) && defined(GHOST_COCOA)
2390                                 //Cocoa already uses coordinates with y=0 at bottom, and returns inwindow coordinates on mouse moved event
2391                                 evt->x= cd->x;
2392                                 evt->y= cd->y;
2393 #else
2394                                 int cx, cy;
2395                                 
2396                                 GHOST_ScreenToClient(win->ghostwin, cd->x, cd->y, &cx, &cy);
2397                                 evt->x= cx;
2398                                 evt->y= (win->sizey-1) - cy;
2399 #endif
2400                                 
2401                                 event.x= evt->x;
2402                                 event.y= evt->y;
2403
2404                                 event.type= MOUSEMOVE;
2405
2406                                 /* some painting operators want accurate mouse events, they can
2407                                    handle in between mouse move moves, others can happily ignore
2408                                    them for better performance */
2409                                 if(lastevent && lastevent->type == MOUSEMOVE)
2410                                         lastevent->type = INBETWEEN_MOUSEMOVE;
2411
2412                                 update_tablet_data(win, &event);
2413                                 wm_event_add(win, &event);
2414                                 
2415                                 /* also add to other window if event is there, this makes overdraws disappear nicely */
2416                                 /* it remaps mousecoord to other window in event */
2417                                 owin= wm_event_cursor_other_windows(wm, win, &event);
2418                                 if(owin) {
2419                                         wmEvent oevent= *(owin->eventstate);
2420                                         
2421                                         oevent.x=owin->eventstate->x= event.x;
2422                                         oevent.y=owin->eventstate->y= event.y;
2423                                         oevent.type= MOUSEMOVE;
2424                                         
2425                                         update_tablet_data(owin, &oevent);
2426                                         wm_event_add(owin, &oevent);
2427                                 }
2428                                 
2429                         }
2430                         break;
2431                 }
2432                 case GHOST_kEventTrackpad: {
2433                         GHOST_TEventTrackpadData * pd = customdata;
2434                         switch (pd->subtype) {
2435                                 case GHOST_kTrackpadEventMagnify:
2436                                         event.type = MOUSEZOOM;
2437                                         break;
2438                                 case GHOST_kTrackpadEventRotate:
2439                                         event.type = MOUSEROTATE;
2440                                         break;
2441                                 case GHOST_kTrackpadEventScroll:
2442                                 default:
2443                                         event.type= MOUSEPAN;
2444                                         break;
2445                         }
2446 #if defined(__APPLE__) && defined(GHOST_COCOA)
2447                         //Cocoa already uses coordinates with y=0 at bottom, and returns inwindow coordinates on mouse moved event
2448                         event.x= evt->x = pd->x;
2449                         event.y = evt->y = pd->y;
2450 #else
2451                         {
2452                         int cx, cy;
2453                         GHOST_ScreenToClient(win->ghostwin, pd->x, pd->y, &cx, &cy);
2454                         event.x= evt->x= cx;
2455                         event.y= evt->y= (win->sizey-1) - cy;
2456                         }
2457 #endif
2458                         // Use prevx/prevy so we can calculate the delta later
2459                         event.prevx= event.x - pd->deltaX;
2460                         event.prevy= event.y - pd->deltaY;
2461                         
2462                         update_tablet_data(win, &event);
2463                         wm_event_add(win, &event);
2464                         break;
2465                 }
2466                 /* mouse button */
2467                 case GHOST_kEventButtonDown:
2468                 case GHOST_kEventButtonUp: {
2469                         GHOST_TEventButtonData *bd= customdata;
2470                         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 */
2471                         
2472                         if (bd->button == GHOST_kButtonMaskLeft)
2473                                 event.type= LEFTMOUSE;
2474                         else if (bd->button == GHOST_kButtonMaskRight)
2475                                 event.type= RIGHTMOUSE;
2476                         else if (bd->button == GHOST_kButtonMaskButton4)
2477                                 event.type= BUTTON4MOUSE;
2478                         else if (bd->button == GHOST_kButtonMaskButton5)
2479                                 event.type= BUTTON5MOUSE;
2480                         else
2481                                 event.type= MIDDLEMOUSE;
2482                         
2483                         /* add to other window if event is there (not to both!) */
2484                         owin= wm_event_cursor_other_windows(wm, win, &event);
2485                         if(owin) {
2486                                 wmEvent oevent= *(owin->eventstate);
2487                                 
2488                                 oevent.x= event.x;
2489                                 oevent.y= event.y;
2490                                 oevent.type= event.type;
2491                                 oevent.val= event.val;
2492                                 
2493                                 update_tablet_data(owin, &oevent);
2494                                 wm_event_add(owin, &oevent);
2495                         }
2496                         else {
2497                                 update_tablet_data(win, &event);
2498                                 wm_event_add(win, &event);
2499                         }
2500                         
2501                         break;
2502                 }
2503                 /* keyboard */
2504                 case GHOST_kEventKeyDown:
2505                 case GHOST_kEventKeyUp: {
2506                         GHOST_TEventKeyData *kd= customdata;
2507                         event.type= convert_key(kd->key);
2508                         event.ascii= kd->ascii;
2509                         event.val= (type==GHOST_kEventKeyDown)?KM_PRESS:KM_RELEASE;
2510                         
2511                         /* exclude arrow keys, esc, etc from text input */
2512                         if(type==GHOST_kEventKeyUp || (event.ascii<32 && event.ascii>0))
2513                                 event.ascii= '\0';
2514                         
2515                         /* modifiers */
2516                         if (event.type==LEFTSHIFTKEY || event.type==RIGHTSHIFTKEY) {
2517                                 event.shift= evt->shift= (event.val==KM_PRESS);
2518                                 if(event.val==KM_PRESS && (evt->ctrl || evt->alt || evt->oskey))
2519                                    event.shift= evt->shift = 3;         // define?
2520                         } 
2521                         else if (event.type==LEFTCTRLKEY || event.type==RIGHTCTRLKEY) {
2522                                 event.ctrl= evt->ctrl= (event.val==KM_PRESS);
2523                                 if(event.val==KM_PRESS && (evt->shift || evt->alt || evt->oskey))
2524                                    event.ctrl= evt->ctrl = 3;           // define?
2525                         } 
2526                         else if (event.type==LEFTALTKEY || event.type==RIGHTALTKEY) {
2527                                 event.alt= evt->alt= (event.val==KM_PRESS);
2528                                 if(event.val==KM_PRESS && (evt->ctrl || evt->shift || evt->oskey))
2529                                    event.alt= evt->alt = 3;             // define?
2530                         } 
2531                         else if (event.type==OSKEY) {
2532                                 event.oskey= evt->oskey= (event.val==KM_PRESS);
2533                                 if(event.val==KM_PRESS && (evt->ctrl || evt->alt || evt->shift))
2534                                    event.oskey= evt->oskey = 3;         // define?
2535                         }
2536                         else {
2537                                 if(event.val==KM_PRESS && event.keymodifier==0)
2538                                         evt->keymodifier= event.type; /* only set in eventstate, for next event */
2539                                 else if(event.val==KM_RELEASE && event.keymodifier==event.type)
2540                                         event.keymodifier= evt->keymodifier= 0;
2541                         }
2542
2543                         /* this case happens on some systems that on holding a key pressed,
2544                            generate press events without release, we still want to keep the
2545                            modifier in win->eventstate, but for the press event of the same
2546                            key we don't want the key modifier */
2547                         if(event.keymodifier == event.type)
2548                                 event.keymodifier= 0;
2549                         
2550                         /* if test_break set, it catches this. XXX Keep global for now? */
2551                         if(event.type==ESCKEY)
2552                                 G.afbreek= 1;
2553                         
2554                         wm_event_add(win, &event);
2555                         
2556                         break;
2557                 }
2558                         
2559                 case GHOST_kEventWheel: {
2560                         GHOST_TEventWheelData* wheelData = customdata;
2561                         
2562                         if (wheelData->z > 0)
2563                                 event.type= WHEELUPMOUSE;
2564                         else
2565                                 event.type= WHEELDOWNMOUSE;
2566                         
2567                         event.val= KM_PRESS;
2568                         wm_event_add(win, &event);
2569                         
2570                         break;
2571                 }
2572                 case GHOST_kEventTimer: {
2573                         event.type= TIMER;
2574                         event.custom= EVT_DATA_TIMER;
2575                         event.customdata= customdata;
2576                         wm_event_add(win, &event);
2577
2578                         break;
2579                 }
2580
2581                 case GHOST_kEventNDOFMotion: {
2582                         event.type = NDOF_MOTION;
2583                         attach_ndof_data(&event, customdata);
2584                         wm_event_add(win, &event);
2585
2586                         break;
2587                 }
2588
2589                 case GHOST_kEventNDOFButton: {
2590                         GHOST_TEventNDOFButtonData* e = customdata;
2591
2592                         event.type = NDOF_BUTTON_NONE + e->button;
2593
2594                         switch (e->action) {
2595                                 case GHOST_kPress:
2596                                         event.val = KM_PRESS;
2597                                         break;
2598                                 case GHOST_kRelease:
2599                                         event.val = KM_RELEASE;
2600                                         break;
2601                                 }
2602
2603                         event.custom = 0;
2604                         event.customdata = NULL;
2605
2606                         wm_event_add(win, &event);
2607
2608                         break;
2609                 }
2610
2611                 case GHOST_kEventUnknown:
2612                 case GHOST_kNumEventTypes:
2613                         break;
2614
2615                 case GHOST_kEventWindowDeactivate: {
2616                         event.type= WINDEACTIVATE;
2617                         wm_event_add(win, &event);
2618
2619                         break;
2620                         
2621                 }
2622
2623         }
2624 }