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