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