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