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