- fix for error with utf8 textinput for buttons
[blender.git] / source / blender / windowmanager / intern / wm_event_system.c
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2007 Blender Foundation.
21  * All rights reserved.
22  *
23  * 
24  * Contributor(s): Blender Foundation
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 /** \file blender/windowmanager/intern/wm_event_system.c
30  *  \ingroup wm
31  */
32
33
34 #include <stdlib.h>
35 #include <string.h>
36
37 #include "DNA_listBase.h"
38 #include "DNA_screen_types.h"
39 #include "DNA_scene_types.h"
40 #include "DNA_windowmanager_types.h"
41 #include "DNA_userdef_types.h"
42
43 #include "MEM_guardedalloc.h"
44
45 #include "GHOST_C-api.h"
46
47 #include "BLI_blenlib.h"
48 #include "BLI_utildefines.h"
49 #include "BLI_math.h"
50
51 #include "BKE_blender.h"
52 #include "BKE_context.h"
53 #include "BKE_idprop.h"
54 #include "BKE_global.h"
55 #include "BKE_main.h"
56 #include "BKE_report.h"
57 #include "BKE_scene.h"
58 #include "BKE_screen.h"
59
60 #include "BKE_sound.h"
61
62 #include "ED_fileselect.h"
63 #include "ED_info.h"
64 #include "ED_screen.h"
65 #include "ED_view3d.h"
66 #include "ED_util.h"
67
68 #include "RNA_access.h"
69
70 #include "UI_interface.h"
71
72 #include "PIL_time.h"
73
74 #include "WM_api.h"
75 #include "WM_types.h"
76 #include "wm.h"
77 #include "wm_window.h"
78 #include "wm_event_system.h"
79 #include "wm_event_types.h"
80 #include "wm_draw.h"
81
82 #ifndef NDEBUG
83 #  include "RNA_enum_types.h"
84 #endif
85
86 static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA *properties, ReportList *reports, short context, short poll_only);
87
88 /* ************ event management ************** */
89
90 void wm_event_add(wmWindow *win, wmEvent *event_to_add)
91 {
92         wmEvent *event= MEM_callocN(sizeof(wmEvent), "wmEvent");
93         
94         *event= *event_to_add;
95         BLI_addtail(&win->queue, event);
96 }
97
98 void wm_event_free(wmEvent *event)
99 {
100         if(event->customdata) {
101                 if(event->customdatafree) {
102                         /* note: pointer to listbase struct elsewhere */
103                         if(event->custom==EVT_DATA_LISTBASE)
104                                 BLI_freelistN(event->customdata);
105                         else
106                                 MEM_freeN(event->customdata);
107                 }
108         }
109         MEM_freeN(event);
110 }
111
112 void wm_event_free_all(wmWindow *win)
113 {
114         wmEvent *event;
115         
116         while((event= win->queue.first)) {
117                 BLI_remlink(&win->queue, event);
118                 wm_event_free(event);
119         }
120 }
121
122 /* ********************* notifiers, listeners *************** */
123
124 static int wm_test_duplicate_notifier(wmWindowManager *wm, unsigned int type, void *reference)
125 {
126         wmNotifier *note;
127
128         for(note=wm->queue.first; note; note=note->next)
129                 if((note->category|note->data|note->subtype|note->action) == type && note->reference == reference)
130                         return 1;
131         
132         return 0;
133 }
134
135 /* XXX: in future, which notifiers to send to other windows? */
136 void WM_event_add_notifier(const bContext *C, unsigned int type, void *reference)
137 {
138         wmNotifier *note= MEM_callocN(sizeof(wmNotifier), "notifier");
139         
140         note->wm= CTX_wm_manager(C);
141         BLI_addtail(&note->wm->queue, note);
142         
143         note->window= CTX_wm_window(C);
144         
145         if(CTX_wm_region(C))
146                 note->swinid= CTX_wm_region(C)->swinid;
147         
148         note->category= type & NOTE_CATEGORY;
149         note->data= type & NOTE_DATA;
150         note->subtype= type & NOTE_SUBTYPE;
151         note->action= type & NOTE_ACTION;
152         
153         note->reference= reference;
154 }
155
156 void WM_main_add_notifier(unsigned int type, void *reference)
157 {
158         Main *bmain= G.main;
159         wmWindowManager *wm= bmain->wm.first;
160
161         if(wm && !wm_test_duplicate_notifier(wm, type, reference)) {
162                 wmNotifier *note= MEM_callocN(sizeof(wmNotifier), "notifier");
163                 
164                 note->wm= wm;
165                 BLI_addtail(&note->wm->queue, note);
166                 
167                 note->category= type & NOTE_CATEGORY;
168                 note->data= type & NOTE_DATA;
169                 note->subtype= type & NOTE_SUBTYPE;
170                 note->action= type & NOTE_ACTION;
171                 
172                 note->reference= reference;
173         }
174 }
175
176 static wmNotifier *wm_notifier_next(wmWindowManager *wm)
177 {
178         wmNotifier *note= wm->queue.first;
179         
180         if(note) BLI_remlink(&wm->queue, note);
181         return note;
182 }
183
184 /* called in mainloop */
185 void wm_event_do_notifiers(bContext *C)
186 {
187         wmWindowManager *wm= CTX_wm_manager(C);
188         wmNotifier *note, *next;
189         wmWindow *win;
190         unsigned int win_combine_v3d_datamask= 0;
191         
192         if(wm==NULL)
193                 return;
194         
195         /* cache & catch WM level notifiers, such as frame change, scene/screen set */
196         for(win= wm->windows.first; win; win= win->next) {
197                 int do_anim= 0;
198                 
199                 CTX_wm_window_set(C, win);
200                 
201                 for(note= wm->queue.first; note; note= next) {
202                         next= note->next;
203
204                         if(note->category==NC_WM) {
205                                 if( ELEM(note->data, ND_FILEREAD, ND_FILESAVE)) {
206                                         wm->file_saved= 1;
207                                         wm_window_title(wm, win);
208                                 }
209                                 else if(note->data==ND_DATACHANGED)
210                                         wm_window_title(wm, win);
211                         }
212                         if(note->window==win) {
213                                 if(note->category==NC_SCREEN) {
214                                         if(note->data==ND_SCREENBROWSE) {
215                                                 ED_screen_set(C, note->reference);      // XXX hrms, think this over!
216                                                 if(G.f & G_DEBUG)
217                                                         printf("screen set %p\n", note->reference);
218                                         }
219                                         else if(note->data==ND_SCREENDELETE) {
220                                                 ED_screen_delete(C, note->reference);   // XXX hrms, think this over!
221                                                 if(G.f & G_DEBUG)
222                                                         printf("screen delete %p\n", note->reference);
223                                         }
224                                 }
225                         }
226
227                         if(note->window==win || (note->window == NULL && (note->reference == NULL || note->reference == CTX_data_scene(C)))) {
228                                 if(note->category==NC_SCENE) {
229                                         if(note->data==ND_SCENEBROWSE) {
230                                                 ED_screen_set_scene(C, note->reference);        // XXX hrms, think this over!
231                                                 if(G.f & G_DEBUG)
232                                                         printf("scene set %p\n", note->reference);
233                                         }
234                                         else if(note->data==ND_FRAME)
235                                                 do_anim= 1;
236                                         
237                                         if(note->action == NA_REMOVED) {
238                                                 ED_screen_delete_scene(C, note->reference);     // XXX hrms, think this over!
239                                                 if(G.f & G_DEBUG)
240                                                         printf("scene delete %p\n", note->reference);
241                                         }
242                                                 
243                                 }
244                         }
245                         if(ELEM5(note->category, NC_SCENE, NC_OBJECT, NC_GEOM, NC_SCENE, NC_WM)) {
246                                 ED_info_stats_clear(CTX_data_scene(C));
247                                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_INFO, NULL);
248                         }
249                 }
250                 if(do_anim) {
251
252                         /* XXX, quick frame changes can cause a crash if framechange and rendering
253                          * collide (happens on slow scenes), scene_update_for_newframe can be called
254                          * twice which can depgraph update the same object at once */
255                         if(!G.rendering) {
256
257                                 /* depsgraph gets called, might send more notifiers */
258                                 ED_update_for_newframe(CTX_data_main(C), win->screen->scene, win->screen, 1);
259                         }
260                 }
261         }
262         
263         /* the notifiers are sent without context, to keep it clean */
264         while( (note=wm_notifier_next(wm)) ) {
265                 for(win= wm->windows.first; win; win= win->next) {
266                         
267                         /* filter out notifiers */
268                         if(note->category==NC_SCREEN && note->reference && note->reference!=win->screen);
269                         else if(note->category==NC_SCENE && note->reference && note->reference!=win->screen->scene);
270                         else {
271                                 ScrArea *sa;
272                                 ARegion *ar;
273
274                                 /* XXX context in notifiers? */
275                                 CTX_wm_window_set(C, win);
276
277                                 /* printf("notifier win %d screen %s cat %x\n", win->winid, win->screen->id.name+2, note->category); */
278                                 ED_screen_do_listen(C, note);
279
280                                 for(ar=win->screen->regionbase.first; ar; ar= ar->next) {
281                                         ED_region_do_listen(ar, note);
282                                 }
283                                 
284                                 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
285                                         ED_area_do_listen(sa, note);
286                                         for(ar=sa->regionbase.first; ar; ar= ar->next) {
287                                                 ED_region_do_listen(ar, note);
288                                         }
289                                 }
290                         }
291                 }
292                 
293                 MEM_freeN(note);
294         }
295         
296         /* combine datamasks so 1 win doesn't disable UV's in another [#26448] */
297         for(win= wm->windows.first; win; win= win->next) {
298                 win_combine_v3d_datamask |= ED_viewedit_datamask(win->screen);
299         }
300
301         /* cached: editor refresh callbacks now, they get context */
302         for(win= wm->windows.first; win; win= win->next) {
303                 ScrArea *sa;
304                 
305                 CTX_wm_window_set(C, win);
306                 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
307                         if(sa->do_refresh) {
308                                 CTX_wm_area_set(C, sa);
309                                 ED_area_do_refresh(C, sa);
310                         }
311                 }
312                 
313                 /* XXX make lock in future, or separated derivedmesh users in scene */
314                 if(!G.rendering) {
315                         /* depsgraph & animation: update tagged datablocks */
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(CTX_data_main(C), 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                         /* store last event for this window */
1963                         /* mousemove and timer events don't overwrite last type */
1964                         if (!ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE) && !ISTIMER(event->type)) {
1965                                 if (wm_action_not_handled(action)) {
1966                                         if (win->eventstate->prevtype == event->type) {
1967                                                 /* set click time on first click (press -> release) */
1968                                                 if (win->eventstate->prevval == KM_PRESS && event->val == KM_RELEASE) {
1969                                                         win->eventstate->prevclicktime = PIL_check_seconds_timer();
1970                                                         win->eventstate->prevclickx = event->x;
1971                                                         win->eventstate->prevclicky = event->y;
1972                                                 }
1973                                         } else {
1974                                                 /* reset click time if event type not the same */
1975                                                 win->eventstate->prevclicktime = 0;
1976                                         }
1977
1978                                         win->eventstate->prevval = event->val;
1979                                         win->eventstate->prevtype = event->type;
1980                                 } else if (event->val == KM_CLICK) { /* keep click for double click later */
1981                                         win->eventstate->prevtype = event->type;
1982                                         win->eventstate->prevval = event->val;
1983                                         win->eventstate->prevclicktime = PIL_check_seconds_timer();
1984                                         win->eventstate->prevclickx = event->x;
1985                                         win->eventstate->prevclicky = event->y;
1986                                 } else { /* reset if not */
1987                                         win->eventstate->prevtype = -1;
1988                                         win->eventstate->prevval = 0;
1989                                         win->eventstate->prevclicktime = 0;
1990                                 }
1991                         }
1992
1993                         /* unlink and free here, blender-quit then frees all */
1994                         BLI_remlink(&win->queue, event);
1995                         wm_event_free(event);
1996                         
1997                 }
1998                 
1999                 /* only add mousemove when queue was read entirely */
2000                 if(win->addmousemove && win->eventstate) {
2001                         wmEvent tevent= *(win->eventstate);
2002                         //printf("adding MOUSEMOVE %d %d\n", tevent.x, tevent.y);
2003                         tevent.type= MOUSEMOVE;
2004                         tevent.prevx= tevent.x;
2005                         tevent.prevy= tevent.y;
2006                         wm_event_add(win, &tevent);
2007                         win->addmousemove= 0;
2008                 }
2009                 
2010                 CTX_wm_window_set(C, NULL);
2011         }
2012
2013         /* update key configuration after handling events */
2014         WM_keyconfig_update(wm);
2015 }
2016
2017 /* ********** filesector handling ************ */
2018
2019 void WM_event_fileselect_event(bContext *C, void *ophandle, int eventval)
2020 {
2021         /* add to all windows! */
2022         wmWindow *win;
2023         
2024         for(win= CTX_wm_manager(C)->windows.first; win; win= win->next) {
2025                 wmEvent event= *win->eventstate;
2026                 
2027                 event.type= EVT_FILESELECT;
2028                 event.val= eventval;
2029                 event.customdata= ophandle;             // only as void pointer type check
2030
2031                 wm_event_add(win, &event);
2032         }
2033 }
2034
2035 /* operator is supposed to have a filled "path" property */
2036 /* optional property: filetype (XXX enum?) */
2037
2038 /* Idea is to keep a handler alive on window queue, owning the operator.
2039    The filewindow can send event to make it execute, thus ensuring
2040    executing happens outside of lower level queues, with UI refreshed. 
2041    Should also allow multiwin solutions */
2042
2043 void WM_event_add_fileselect(bContext *C, wmOperator *op)
2044 {
2045         wmEventHandler *handler, *handlernext;
2046         wmWindow *win= CTX_wm_window(C);
2047         int full= 1;    // XXX preset?
2048
2049         /* only allow 1 file selector open per window */
2050         for(handler= win->modalhandlers.first; handler; handler=handlernext) {
2051                 handlernext= handler->next;
2052                 
2053                 if(handler->type == WM_HANDLER_FILESELECT) {
2054                         if(handler->op)
2055                                 WM_operator_free(handler->op);
2056                         BLI_remlink(&win->modalhandlers, handler);
2057                         wm_event_free_handler(handler);
2058                 }
2059         }
2060         
2061         handler = MEM_callocN(sizeof(wmEventHandler), "fileselect handler");
2062         
2063         handler->type= WM_HANDLER_FILESELECT;
2064         handler->op= op;
2065         handler->op_area= CTX_wm_area(C);
2066         handler->op_region= CTX_wm_region(C);
2067         handler->filescreen= CTX_wm_screen(C);
2068         
2069         BLI_addhead(&win->modalhandlers, handler);
2070         
2071         /* check props once before invoking if check is available
2072          * ensures initial properties are valid */
2073         if(op->type->check) {
2074                 op->type->check(C, op); /* ignore return value */
2075         }
2076
2077         WM_event_fileselect_event(C, op, full?EVT_FILESELECT_FULL_OPEN:EVT_FILESELECT_OPEN);
2078 }
2079
2080 #if 0
2081 /* lets not expose struct outside wm? */
2082 static void WM_event_set_handler_flag(wmEventHandler *handler, int flag)
2083 {
2084         handler->flag= flag;
2085 }
2086 #endif
2087
2088 wmEventHandler *WM_event_add_modal_handler(bContext *C, wmOperator *op)
2089 {
2090         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event modal handler");
2091         wmWindow *win= CTX_wm_window(C);
2092         
2093         /* operator was part of macro */
2094         if(op->opm) {
2095                 /* give the mother macro to the handler */
2096                 handler->op= op->opm;
2097                 /* mother macro opm becomes the macro element */
2098                 handler->op->opm= op;
2099         }
2100         else
2101                 handler->op= op;
2102         
2103         handler->op_area= CTX_wm_area(C);               /* means frozen screen context for modal handlers! */
2104         handler->op_region= CTX_wm_region(C);
2105         
2106         BLI_addhead(&win->modalhandlers, handler);
2107
2108         return handler;
2109 }
2110
2111 wmEventHandler *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
2112 {
2113         wmEventHandler *handler;
2114
2115         if(!keymap) {
2116                 printf("WM_event_add_keymap_handler called with NULL keymap\n");
2117                 return NULL;
2118         }
2119
2120         /* only allow same keymap once */
2121         for(handler= handlers->first; handler; handler= handler->next)
2122                 if(handler->keymap==keymap)
2123                         return handler;
2124         
2125         handler= MEM_callocN(sizeof(wmEventHandler), "event keymap handler");
2126         BLI_addtail(handlers, handler);
2127         handler->keymap= keymap;
2128
2129         return handler;
2130 }
2131
2132 /* priorities not implemented yet, for time being just insert in begin of list */
2133 wmEventHandler *WM_event_add_keymap_handler_priority(ListBase *handlers, wmKeyMap *keymap, int UNUSED(priority))
2134 {
2135         wmEventHandler *handler;
2136         
2137         WM_event_remove_keymap_handler(handlers, keymap);
2138         
2139         handler= MEM_callocN(sizeof(wmEventHandler), "event keymap handler");
2140         BLI_addhead(handlers, handler);
2141         handler->keymap= keymap;
2142         
2143         return handler;
2144 }
2145
2146 wmEventHandler *WM_event_add_keymap_handler_bb(ListBase *handlers, wmKeyMap *keymap, rcti *bblocal, rcti *bbwin)
2147 {
2148         wmEventHandler *handler= WM_event_add_keymap_handler(handlers, keymap);
2149         
2150         if(handler) {
2151                 handler->bblocal= bblocal;
2152                 handler->bbwin= bbwin;
2153         }
2154         return handler;
2155 }
2156
2157 void WM_event_remove_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
2158 {
2159         wmEventHandler *handler;
2160         
2161         for(handler= handlers->first; handler; handler= handler->next) {
2162                 if(handler->keymap==keymap) {
2163                         BLI_remlink(handlers, handler);
2164                         wm_event_free_handler(handler);
2165                         break;
2166                 }
2167         }
2168 }
2169
2170 wmEventHandler *WM_event_add_ui_handler(const bContext *C, ListBase *handlers, wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata)
2171 {
2172         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event ui handler");
2173         handler->ui_handle= func;
2174         handler->ui_remove= remove;
2175         handler->ui_userdata= userdata;
2176         handler->ui_area= (C)? CTX_wm_area(C): NULL;
2177         handler->ui_region= (C)? CTX_wm_region(C): NULL;
2178         handler->ui_menu= (C)? CTX_wm_menu(C): NULL;
2179         
2180         BLI_addhead(handlers, handler);
2181         
2182         return handler;
2183 }
2184
2185 /* set "postpone" for win->modalhandlers, this is in a running for() loop in wm_handlers_do() */
2186 void WM_event_remove_ui_handler(ListBase *handlers, wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata, int postpone)
2187 {
2188         wmEventHandler *handler;
2189         
2190         for(handler= handlers->first; handler; handler= handler->next) {
2191                 if(handler->ui_handle == func && handler->ui_remove == remove && handler->ui_userdata == userdata) {
2192                         /* handlers will be freed in wm_handlers_do() */
2193                         if(postpone) {
2194                                 handler->flag |= WM_HANDLER_DO_FREE;
2195                         }
2196                         else {
2197                                 BLI_remlink(handlers, handler);
2198                                 wm_event_free_handler(handler);
2199                         }
2200                         break;
2201                 }
2202         }
2203 }
2204
2205 wmEventHandler *WM_event_add_dropbox_handler(ListBase *handlers, ListBase *dropboxes)
2206 {
2207         wmEventHandler *handler;
2208
2209         /* only allow same dropbox once */
2210         for(handler= handlers->first; handler; handler= handler->next)
2211                 if(handler->dropboxes==dropboxes)
2212                         return handler;
2213         
2214         handler= MEM_callocN(sizeof(wmEventHandler), "dropbox handler");
2215         
2216         /* dropbox stored static, no free or copy */
2217         handler->dropboxes= dropboxes;
2218         BLI_addhead(handlers, handler);
2219         
2220         return handler;
2221 }
2222
2223 /* XXX solution works, still better check the real cause (ton) */
2224 void WM_event_remove_area_handler(ListBase *handlers, void *area)
2225 {
2226         wmEventHandler *handler, *nexthandler;
2227
2228         for(handler = handlers->first; handler; handler= nexthandler) {
2229                 nexthandler = handler->next;
2230                 if (handler->type != WM_HANDLER_FILESELECT) {
2231                         if (handler->ui_area == area) {
2232                                 BLI_remlink(handlers, handler);
2233                                 wm_event_free_handler(handler);
2234                         }
2235                 }
2236         }
2237 }
2238
2239 #if 0
2240 static void WM_event_remove_handler(ListBase *handlers, wmEventHandler *handler)
2241 {
2242         BLI_remlink(handlers, handler);
2243         wm_event_free_handler(handler);
2244 }
2245 #endif
2246
2247 void WM_event_add_mousemove(bContext *C)
2248 {
2249         wmWindow *window= CTX_wm_window(C);
2250         
2251         window->addmousemove= 1;
2252 }
2253
2254 /* for modal callbacks, check configuration for how to interpret exit with tweaks  */
2255 int WM_modal_tweak_exit(wmEvent *evt, int tweak_event)
2256 {
2257         /* if the release-confirm userpref setting is enabled, 
2258          * tweak events can be cancelled when mouse is released
2259          */
2260         if (U.flag & USER_RELEASECONFIRM) {
2261                 /* option on, so can exit with km-release */
2262                 if (evt->val == KM_RELEASE) {
2263                         switch (tweak_event) {
2264                                 case EVT_TWEAK_L:
2265                                 case EVT_TWEAK_M:
2266                                 case EVT_TWEAK_R:
2267                                         return 1;
2268                         }
2269                 }
2270                 else {
2271                         /* if the initial event wasn't a tweak event then
2272                          * ignore USER_RELEASECONFIRM setting: see [#26756] */
2273                         if(ELEM3(tweak_event, EVT_TWEAK_L, EVT_TWEAK_M, EVT_TWEAK_R) == 0) {
2274                                 return 1;
2275                         }
2276                 }
2277         }
2278         else {
2279                 /* this is fine as long as not doing km-release, otherwise
2280                  * some items (i.e. markers) being tweaked may end up getting
2281                  * dropped all over
2282                  */
2283                 if (evt->val != KM_RELEASE)
2284                         return 1;
2285         }
2286         
2287         return 0;
2288 }
2289
2290 /* ********************* ghost stuff *************** */
2291
2292 static int convert_key(GHOST_TKey key) 
2293 {
2294         if (key>=GHOST_kKeyA && key<=GHOST_kKeyZ) {
2295                 return (AKEY + ((int) key - GHOST_kKeyA));
2296         } else if (key>=GHOST_kKey0 && key<=GHOST_kKey9) {
2297                 return (ZEROKEY + ((int) key - GHOST_kKey0));
2298         } else if (key>=GHOST_kKeyNumpad0 && key<=GHOST_kKeyNumpad9) {
2299                 return (PAD0 + ((int) key - GHOST_kKeyNumpad0));
2300         } else if (key>=GHOST_kKeyF1 && key<=GHOST_kKeyF19) {
2301                 return (F1KEY + ((int) key - GHOST_kKeyF1));
2302         } else {
2303                 switch (key) {
2304                         case GHOST_kKeyBackSpace:               return BACKSPACEKEY;
2305                         case GHOST_kKeyTab:                             return TABKEY;
2306                         case GHOST_kKeyLinefeed:                return LINEFEEDKEY;
2307                         case GHOST_kKeyClear:                   return 0;
2308                         case GHOST_kKeyEnter:                   return RETKEY;
2309                                 
2310                         case GHOST_kKeyEsc:                             return ESCKEY;
2311                         case GHOST_kKeySpace:                   return SPACEKEY;
2312                         case GHOST_kKeyQuote:                   return QUOTEKEY;
2313                         case GHOST_kKeyComma:                   return COMMAKEY;
2314                         case GHOST_kKeyMinus:                   return MINUSKEY;
2315                         case GHOST_kKeyPeriod:                  return PERIODKEY;
2316                         case GHOST_kKeySlash:                   return SLASHKEY;
2317                                 
2318                         case GHOST_kKeySemicolon:               return SEMICOLONKEY;
2319                         case GHOST_kKeyEqual:                   return EQUALKEY;
2320                                 
2321                         case GHOST_kKeyLeftBracket:             return LEFTBRACKETKEY;
2322                         case GHOST_kKeyRightBracket:    return RIGHTBRACKETKEY;
2323                         case GHOST_kKeyBackslash:               return BACKSLASHKEY;
2324                         case GHOST_kKeyAccentGrave:             return ACCENTGRAVEKEY;
2325                                 
2326                         case GHOST_kKeyLeftShift:               return LEFTSHIFTKEY;
2327                         case GHOST_kKeyRightShift:              return RIGHTSHIFTKEY;
2328                         case GHOST_kKeyLeftControl:             return LEFTCTRLKEY;
2329                         case GHOST_kKeyRightControl:    return RIGHTCTRLKEY;
2330                         case GHOST_kKeyOS:                              return OSKEY;
2331                         case GHOST_kKeyLeftAlt:                 return LEFTALTKEY;
2332                         case GHOST_kKeyRightAlt:                return RIGHTALTKEY;
2333                                 
2334                         case GHOST_kKeyCapsLock:                return CAPSLOCKKEY;
2335                         case GHOST_kKeyNumLock:                 return 0;
2336                         case GHOST_kKeyScrollLock:              return 0;
2337                                 
2338                         case GHOST_kKeyLeftArrow:               return LEFTARROWKEY;
2339                         case GHOST_kKeyRightArrow:              return RIGHTARROWKEY;
2340                         case GHOST_kKeyUpArrow:                 return UPARROWKEY;
2341                         case GHOST_kKeyDownArrow:               return DOWNARROWKEY;
2342                                 
2343                         case GHOST_kKeyPrintScreen:             return 0;
2344                         case GHOST_kKeyPause:                   return PAUSEKEY;
2345                                 
2346                         case GHOST_kKeyInsert:                  return INSERTKEY;
2347                         case GHOST_kKeyDelete:                  return DELKEY;
2348                         case GHOST_kKeyHome:                    return HOMEKEY;
2349                         case GHOST_kKeyEnd:                             return ENDKEY;
2350                         case GHOST_kKeyUpPage:                  return PAGEUPKEY;
2351                         case GHOST_kKeyDownPage:                return PAGEDOWNKEY;
2352                                 
2353                         case GHOST_kKeyNumpadPeriod:    return PADPERIOD;
2354                         case GHOST_kKeyNumpadEnter:             return PADENTER;
2355                         case GHOST_kKeyNumpadPlus:              return PADPLUSKEY;
2356                         case GHOST_kKeyNumpadMinus:             return PADMINUS;
2357                         case GHOST_kKeyNumpadAsterisk:  return PADASTERKEY;
2358                         case GHOST_kKeyNumpadSlash:             return PADSLASHKEY;
2359                                 
2360                         case GHOST_kKeyGrLess:              return GRLESSKEY; 
2361                         
2362                         case GHOST_kKeyMediaPlay:               return MEDIAPLAY;
2363                         case GHOST_kKeyMediaStop:               return MEDIASTOP;
2364                         case GHOST_kKeyMediaFirst:              return MEDIAFIRST;
2365                         case GHOST_kKeyMediaLast:               return MEDIALAST;
2366                         
2367                         default:
2368                                 return UNKNOWNKEY;      /* GHOST_kKeyUnknown */
2369                 }
2370         }
2371 }
2372
2373 /* adds customdata to event */
2374 static void update_tablet_data(wmWindow *win, wmEvent *event)
2375 {
2376         const GHOST_TabletData *td= GHOST_GetTabletData(win->ghostwin);
2377         
2378         /* if there's tablet data from an active tablet device then add it */
2379         if ((td != NULL) && td->Active != GHOST_kTabletModeNone) {
2380                 struct wmTabletData *wmtab= MEM_mallocN(sizeof(wmTabletData), "customdata tablet");
2381                 
2382                 wmtab->Active = (int)td->Active;
2383                 wmtab->Pressure = td->Pressure;
2384                 wmtab->Xtilt = td->Xtilt;
2385                 wmtab->Ytilt = td->Ytilt;
2386                 
2387                 event->custom= EVT_DATA_TABLET;
2388                 event->customdata= wmtab;
2389                 event->customdatafree= 1;
2390         } 
2391 }
2392
2393 /* adds customdata to event */
2394 static void attach_ndof_data(wmEvent* event, const GHOST_TEventNDOFMotionData* ghost)
2395 {
2396         wmNDOFMotionData* data = MEM_mallocN(sizeof(wmNDOFMotionData), "customdata NDOF");
2397
2398         const float s = U.ndof_sensitivity;
2399
2400         data->tx = s * ghost->tx;
2401
2402         data->rx = s * ghost->rx;
2403         data->ry = s * ghost->ry;
2404         data->rz = s * ghost->rz;
2405
2406         if (U.ndof_flag & NDOF_ZOOM_UPDOWN)
2407                 {
2408                 /* rotate so Y is where Z was */
2409                 data->ty = s * ghost->tz;
2410                 data->tz = s * ghost->ty;
2411                 /* maintain handed-ness? or just do what feels right? */
2412
2413                 /* should this affect rotation also?
2414                  * initial guess is 'yes', but get user feedback immediately!
2415                  */
2416 #if 0
2417                 /* after turning this on, my guess becomes 'no' */
2418                 data->ry = s * ghost->rz;
2419                 data->rz = s * ghost->ry;
2420 #endif
2421                 }
2422         else
2423                 {
2424                 data->ty = s * ghost->ty;
2425                 data->tz = s * ghost->tz;
2426                 }
2427
2428         data->dt = ghost->dt;
2429
2430         data->progress = (wmProgress) ghost->progress;
2431
2432         event->custom = EVT_DATA_NDOF_MOTION;
2433         event->customdata = data;
2434         event->customdatafree = 1;
2435 }
2436
2437 /* imperfect but probably usable... draw/enable drags to other windows */
2438 static wmWindow *wm_event_cursor_other_windows(wmWindowManager *wm, wmWindow *win, wmEvent *evt)
2439 {
2440         int mx= evt->x, my= evt->y;
2441         
2442         if(wm->windows.first== wm->windows.last)
2443                 return NULL;
2444         
2445         /* top window bar... */
2446         if(mx<0 || my<0 || mx>win->sizex || my>win->sizey+30) { 
2447                 wmWindow *owin;
2448                 wmEventHandler *handler;
2449                 
2450                 /* let's skip windows having modal handlers now */
2451                 /* potential XXX ugly... I wouldn't have added a modalhandlers list (introduced in rev 23331, ton) */
2452                 for(handler= win->modalhandlers.first; handler; handler= handler->next)
2453                         if(handler->ui_handle || handler->op)
2454                                 return NULL;
2455                 
2456                 /* to desktop space */
2457                 mx += (int)win->posx;
2458                 my += (int)win->posy;
2459                 
2460                 /* check other windows to see if it has mouse inside */
2461                 for(owin= wm->windows.first; owin; owin= owin->next) {
2462                         
2463                         if(owin!=win) {
2464                                 if(mx-owin->posx >= 0 && my-owin->posy >= 0 &&
2465                                    mx-owin->posx <= owin->sizex && my-owin->posy <= owin->sizey) {
2466                                         evt->x= mx - (int)owin->posx;
2467                                         evt->y= my - (int)owin->posy;
2468                                         
2469                                         return owin;
2470                                 }
2471                         }
2472                 }
2473         }
2474         return NULL;
2475 }
2476
2477 /* windows store own event queues, no bContext here */
2478 /* time is in 1000s of seconds, from ghost */
2479 void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int UNUSED(time), void *customdata)
2480 {
2481         wmWindow *owin;
2482         wmEvent event, *evt= win->eventstate;
2483
2484         /* initialize and copy state (only mouse x y and modifiers) */
2485         event= *evt;
2486         
2487         switch (type) {
2488                 /* mouse move */
2489                 case GHOST_kEventCursorMove: {
2490                         if(win->active) {
2491                                 GHOST_TEventCursorData *cd= customdata;
2492                                 wmEvent *lastevent= win->queue.last;
2493                                 int cx, cy;
2494                                 
2495                                 GHOST_ScreenToClient(win->ghostwin, cd->x, cd->y, &cx, &cy);
2496                                 evt->x= cx;
2497                                 evt->y= (win->sizey-1) - cy;
2498                                 
2499                                 event.x= evt->x;
2500                                 event.y= evt->y;
2501
2502                                 event.type= MOUSEMOVE;
2503
2504                                 /* some painting operators want accurate mouse events, they can
2505                                    handle in between mouse move moves, others can happily ignore
2506                                    them for better performance */
2507                                 if(lastevent && lastevent->type == MOUSEMOVE)
2508                                         lastevent->type = INBETWEEN_MOUSEMOVE;
2509
2510                                 update_tablet_data(win, &event);
2511                                 wm_event_add(win, &event);
2512
2513                                 //printf("sending MOUSEMOVE %d %d\n", event.x, event.y);
2514                                 
2515                                 /* also add to other window if event is there, this makes overdraws disappear nicely */
2516                                 /* it remaps mousecoord to other window in event */
2517                                 owin= wm_event_cursor_other_windows(wm, win, &event);
2518                                 if(owin) {
2519                                         wmEvent oevent= *(owin->eventstate);
2520                                         
2521                                         oevent.x=owin->eventstate->x= event.x;
2522                                         oevent.y=owin->eventstate->y= event.y;
2523                                         oevent.type= MOUSEMOVE;
2524                                         
2525                                         update_tablet_data(owin, &oevent);
2526                                         wm_event_add(owin, &oevent);
2527                                 }
2528                                 
2529                         }
2530                         break;
2531                 }
2532                 case GHOST_kEventTrackpad: {
2533                         GHOST_TEventTrackpadData * pd = customdata;
2534                         switch (pd->subtype) {
2535                                 case GHOST_kTrackpadEventMagnify:
2536                                         event.type = MOUSEZOOM;
2537                                         break;
2538                                 case GHOST_kTrackpadEventRotate:
2539                                         event.type = MOUSEROTATE;
2540                                         break;
2541                                 case GHOST_kTrackpadEventScroll:
2542                                 default:
2543                                         event.type= MOUSEPAN;
2544                                         break;
2545                         }
2546
2547                         {
2548                                 int cx, cy;
2549                                 GHOST_ScreenToClient(win->ghostwin, pd->x, pd->y, &cx, &cy);
2550                                 event.x= evt->x= cx;
2551                                 event.y= evt->y= (win->sizey-1) - cy;
2552                         }
2553
2554                         // Use prevx/prevy so we can calculate the delta later
2555                         event.prevx= event.x - pd->deltaX;
2556                         event.prevy= event.y - (-pd->deltaY);
2557                         
2558                         update_tablet_data(win, &event);
2559                         wm_event_add(win, &event);
2560                         break;
2561                 }
2562                 /* mouse button */
2563                 case GHOST_kEventButtonDown:
2564                 case GHOST_kEventButtonUp: {
2565                         GHOST_TEventButtonData *bd= customdata;
2566                         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 */
2567                         
2568                         if (bd->button == GHOST_kButtonMaskLeft)
2569                                 event.type= LEFTMOUSE;
2570                         else if (bd->button == GHOST_kButtonMaskRight)
2571                                 event.type= RIGHTMOUSE;
2572                         else if (bd->button == GHOST_kButtonMaskButton4)
2573                                 event.type= BUTTON4MOUSE;
2574                         else if (bd->button == GHOST_kButtonMaskButton5)
2575                                 event.type= BUTTON5MOUSE;
2576                         else
2577                                 event.type= MIDDLEMOUSE;
2578                         
2579                         if(win->active==0) {
2580                                 int cx, cy;
2581                                 
2582                                 /* entering window, update mouse pos. (ghost sends win-activate *after* the mouseclick in window!) */
2583                                 wm_get_cursor_position(win, &cx, &cy);
2584
2585                                 event.x= evt->x= cx;
2586                                 event.y= evt->y= cy;
2587                         }
2588                         
2589                         /* add to other window if event is there (not to both!) */
2590                         owin= wm_event_cursor_other_windows(wm, win, &event);
2591                         if(owin) {
2592                                 wmEvent oevent= *(owin->eventstate);
2593                                 
2594                                 oevent.x= event.x;
2595                                 oevent.y= event.y;
2596                                 oevent.type= event.type;
2597                                 oevent.val= event.val;
2598                                 
2599                                 update_tablet_data(owin, &oevent);
2600                                 wm_event_add(owin, &oevent);
2601                         }
2602                         else {
2603                                 update_tablet_data(win, &event);
2604                                 wm_event_add(win, &event);
2605                         }
2606                         
2607                         break;
2608                 }
2609                 /* keyboard */
2610                 case GHOST_kEventKeyDown:
2611                 case GHOST_kEventKeyUp: {
2612                         GHOST_TEventKeyData *kd= customdata;
2613                         event.type= convert_key(kd->key);
2614                         event.ascii= kd->ascii;
2615                         memcpy(event.utf8_buf, kd->utf8_buf,sizeof(event.utf8_buf));/* might be not null terminated*/
2616                         event.val= (type==GHOST_kEventKeyDown)?KM_PRESS:KM_RELEASE;
2617                         
2618                         /* exclude arrow keys, esc, etc from text input */
2619                         if(type==GHOST_kEventKeyUp) {
2620                                 event.ascii= '\0';
2621
2622                                 /* ghost should do this already for key up */
2623                                 if (event.utf8_buf[0]) {
2624                                         printf("%s: ghost on you're platform is misbehaving, utf8 events on key up!\n", __func__);
2625                                 }
2626                                 event.utf8_buf[0]= '\0';
2627                         }
2628                         else if (event.ascii<32 && event.ascii > 0) {
2629                                 event.ascii= '\0';
2630                                 /* TODO. should this also zero utf8?, dont for now, campbell */
2631                         }
2632
2633                         if (event.utf8_buf[0]) {
2634                                 if (BLI_str_utf8_size(event.utf8_buf) == -1) {
2635                                         printf("%s: ghost detected an invalid unicode character '%d'!\n", __func__, (int)(unsigned char)event.utf8_buf[0]);
2636                                         event.utf8_buf[0]= '\0';
2637                                 }
2638                         }
2639
2640                         /* modifiers */
2641                         /* assigning both first and second is strange - campbell */
2642                         switch(event.type) {
2643                         case LEFTSHIFTKEY: case RIGHTSHIFTKEY:
2644                                 event.shift= evt->shift= (event.val==KM_PRESS) ? ((evt->ctrl || evt->alt || evt->oskey) ? (KM_MOD_FIRST | KM_MOD_SECOND) : KM_MOD_FIRST) : FALSE;
2645                                 break;
2646                         case LEFTCTRLKEY: case RIGHTCTRLKEY:
2647                                 event.ctrl= evt->ctrl= (event.val==KM_PRESS) ? ((evt->shift || evt->alt || evt->oskey) ? (KM_MOD_FIRST | KM_MOD_SECOND) : KM_MOD_FIRST) : FALSE;
2648                                 break;
2649                         case LEFTALTKEY: case RIGHTALTKEY:
2650                                 event.alt= evt->alt= (event.val==KM_PRESS) ? ((evt->ctrl || evt->shift || evt->oskey) ? (KM_MOD_FIRST | KM_MOD_SECOND) : KM_MOD_FIRST) : FALSE;
2651                                 break;
2652                         case OSKEY:
2653                                 event.oskey= evt->oskey= (event.val==KM_PRESS) ? ((evt->ctrl || evt->alt || evt->shift) ? (KM_MOD_FIRST | KM_MOD_SECOND) : KM_MOD_FIRST) : FALSE;
2654                                 break;
2655                         default:
2656                                 if(event.val==KM_PRESS && event.keymodifier==0)
2657                                         evt->keymodifier= event.type; /* only set in eventstate, for next event */
2658                                 else if(event.val==KM_RELEASE && event.keymodifier==event.type)
2659                                         event.keymodifier= evt->keymodifier= 0;
2660                                 break;
2661                         }
2662
2663                         /* this case happens on some systems that on holding a key pressed,
2664                            generate press events without release, we still want to keep the
2665                            modifier in win->eventstate, but for the press event of the same
2666                            key we don't want the key modifier */
2667                         if(event.keymodifier == event.type)
2668                                 event.keymodifier= 0;
2669                         
2670                         /* if test_break set, it catches this. XXX Keep global for now? */
2671                         if(event.type==ESCKEY)
2672                                 G.afbreek= 1;
2673                         
2674                         wm_event_add(win, &event);
2675                         
2676                         break;
2677                 }
2678                         
2679                 case GHOST_kEventWheel: {
2680                         GHOST_TEventWheelData* wheelData = customdata;
2681                         
2682                         if (wheelData->z > 0)
2683                                 event.type= WHEELUPMOUSE;
2684                         else
2685                                 event.type= WHEELDOWNMOUSE;
2686                         
2687                         event.val= KM_PRESS;
2688                         wm_event_add(win, &event);
2689                         
2690                         break;
2691                 }
2692                 case GHOST_kEventTimer: {
2693                         event.type= TIMER;
2694                         event.custom= EVT_DATA_TIMER;
2695                         event.customdata= customdata;
2696                         wm_event_add(win, &event);
2697
2698                         break;
2699                 }
2700
2701                 case GHOST_kEventNDOFMotion: {
2702                         event.type = NDOF_MOTION;
2703                         attach_ndof_data(&event, customdata);
2704                         wm_event_add(win, &event);
2705
2706                         //printf("sending NDOF_MOTION, prev = %d %d\n", event.x, event.y);
2707
2708                         break;
2709                 }
2710
2711                 case GHOST_kEventNDOFButton: {
2712                         GHOST_TEventNDOFButtonData* e = customdata;
2713
2714                         event.type = NDOF_BUTTON_NONE + e->button;
2715
2716                         switch (e->action) {
2717                                 case GHOST_kPress:
2718                                         event.val = KM_PRESS;
2719                                         break;
2720                                 case GHOST_kRelease:
2721                                         event.val = KM_RELEASE;
2722                                         break;
2723                                 }
2724
2725                         event.custom = 0;
2726                         event.customdata = NULL;
2727
2728                         wm_event_add(win, &event);
2729
2730                         break;
2731                 }
2732
2733                 case GHOST_kEventUnknown:
2734                 case GHOST_kNumEventTypes:
2735                         break;
2736
2737                 case GHOST_kEventWindowDeactivate: {
2738                         event.type= WINDEACTIVATE;
2739                         wm_event_add(win, &event);
2740
2741                         break;
2742                         
2743                 }
2744