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