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