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