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