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