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