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