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