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