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