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