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