ndof data change: operators can access values as vectors or components, as both are...
[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 aggressive with swallowing events, like scrollwheel */
344         /* I realize this is not extremely nice code... when UI gets keymaps it can be maybe smarter */
345         if(do_wheel_ui==0) {
346                 if(is_wheel)
347                         return WM_HANDLER_CONTINUE;
348                 else if(wm_event_always_pass(event)==0)
349                         do_wheel_ui= 1;
350         }
351         
352         /* we set context to where ui handler came from */
353         if(handler->ui_area) CTX_wm_area_set(C, handler->ui_area);
354         if(handler->ui_region) CTX_wm_region_set(C, handler->ui_region);
355         if(handler->ui_menu) CTX_wm_menu_set(C, handler->ui_menu);
356
357         retval= handler->ui_handle(C, event, handler->ui_userdata);
358
359         /* putting back screen context */
360         if((retval != WM_UI_HANDLER_BREAK) || always_pass) {
361                 CTX_wm_area_set(C, area);
362                 CTX_wm_region_set(C, region);
363                 CTX_wm_menu_set(C, menu);
364         }
365         else {
366                 /* this special cases is for areas and regions that get removed */
367                 CTX_wm_area_set(C, NULL);
368                 CTX_wm_region_set(C, NULL);
369                 CTX_wm_menu_set(C, NULL);
370         }
371         
372         if(retval == WM_UI_HANDLER_BREAK)
373                 return WM_HANDLER_BREAK;
374         
375         /* event not handled in UI, if wheel then we temporarily disable it */
376         if(is_wheel)
377                 do_wheel_ui= 0;
378         
379         return WM_HANDLER_CONTINUE;
380 }
381
382 static void wm_handler_ui_cancel(bContext *C)
383 {
384         wmWindow *win= CTX_wm_window(C);
385         ARegion *ar= CTX_wm_region(C);
386         wmEventHandler *handler, *nexthandler;
387
388         if(!ar)
389                 return;
390
391         for(handler= ar->handlers.first; handler; handler= nexthandler) {
392                 nexthandler= handler->next;
393
394                 if(handler->ui_handle) {
395                         wmEvent event= *(win->eventstate);
396                         event.type= EVT_BUT_CANCEL;
397                         handler->ui_handle(C, &event, handler->ui_userdata);
398                 }
399         }
400 }
401
402 /* ********************* operators ******************* */
403
404 int WM_operator_poll(bContext *C, wmOperatorType *ot)
405 {
406         wmOperatorTypeMacro *otmacro;
407         
408         for(otmacro= ot->macro.first; otmacro; otmacro= otmacro->next) {
409                 wmOperatorType *ot_macro= WM_operatortype_find(otmacro->idname, 0);
410                 
411                 if(0==WM_operator_poll(C, ot_macro))
412                         return 0;
413         }
414         
415         /* python needs operator type, so we added exception for it */
416         if(ot->pyop_poll)
417                 return ot->pyop_poll(C, ot);
418         else if(ot->poll)
419                 return ot->poll(C);
420
421         return 1;
422 }
423
424 /* sets up the new context and calls 'wm_operator_invoke()' with poll_only */
425 int WM_operator_poll_context(bContext *C, wmOperatorType *ot, int context)
426 {
427         return wm_operator_call_internal(C, ot, NULL, NULL, context, TRUE);
428 }
429
430 static void wm_operator_print(bContext *C, wmOperator *op)
431 {
432         /* context is needed for enum function */
433         char *buf = WM_operator_pystring(C, op->type, op->ptr, 1);
434         printf("%s\n", buf);
435         MEM_freeN(buf);
436 }
437
438 static void wm_operator_reports(bContext *C, wmOperator *op, int retval, int popup)
439 {
440         if(popup)
441                 if(op->reports->list.first)
442                         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                                 }
1293                                 else {
1294                                         sa = handler->op_area;
1295                                 }
1296                                         
1297                                 if(event->val==EVT_FILESELECT_OPEN) {
1298                                         ED_area_newspace(C, sa, SPACE_FILE); /* 'sa' is modified in-place */
1299                                 }
1300                                 else {
1301                                         sa= ED_screen_full_newspace(C, sa, SPACE_FILE); /* sets context */
1302                                 }
1303
1304                                 /* note, getting the 'sa' back from the context causes a nasty bug where the newly created
1305                                  * 'sa' != CTX_wm_area(C). removed the line below and set 'sa' in the 'if' above */
1306                                 /* sa = CTX_wm_area(C); */
1307
1308                                 /* settings for filebrowser, sfile is not operator owner but sends events */
1309                                 sfile= (SpaceFile*)sa->spacedata.first;
1310                                 sfile->op= handler->op;
1311
1312                                 ED_fileselect_set_params(sfile);
1313                                 
1314                                 action= WM_HANDLER_BREAK;
1315                         }
1316                         break;
1317                         
1318                 case EVT_FILESELECT_EXEC:
1319                 case EVT_FILESELECT_CANCEL:
1320                 case EVT_FILESELECT_EXTERNAL_CANCEL:
1321                         {
1322                                 /* XXX validate area and region? */
1323                                 bScreen *screen= CTX_wm_screen(C);
1324
1325                                 /* remlink now, for load file case before removing*/
1326                                 BLI_remlink(handlers, handler);
1327                                 
1328                                 if(event->val!=EVT_FILESELECT_EXTERNAL_CANCEL) {
1329                                         if(screen != handler->filescreen) {
1330                                                 ED_screen_full_prevspace(C, CTX_wm_area(C));
1331                                         }
1332                                         else {
1333                                                 ED_area_prevspace(C, CTX_wm_area(C));
1334                                         }
1335                                 }
1336                                 
1337                                 wm_handler_op_context(C, handler);
1338
1339                                 /* needed for uiPupMenuReports */
1340
1341                                 if(event->val==EVT_FILESELECT_EXEC) {
1342 #if 0                           // use REDALERT now
1343
1344                                         /* a bit weak, might become arg for WM_event_fileselect? */
1345                                         /* XXX also extension code in image-save doesnt work for this yet */
1346                                         if (RNA_struct_find_property(handler->op->ptr, "check_existing") && 
1347                                                         RNA_boolean_get(handler->op->ptr, "check_existing")) {
1348                                                 char *path= RNA_string_get_alloc(handler->op->ptr, "filepath", NULL, 0);
1349                                                 /* this gives ownership to pupmenu */
1350                                                 uiPupMenuSaveOver(C, handler->op, (path)? path: "");
1351                                                 if(path)
1352                                                         MEM_freeN(path);
1353                                         }
1354                                         else
1355 #endif
1356                                         {
1357                                                 int retval;
1358                                                 
1359                                                 if(handler->op->type->flag & OPTYPE_UNDO)
1360                                                         wm->op_undo_depth++;
1361
1362                                                 retval= handler->op->type->exec(C, handler->op);
1363
1364                                                 /* XXX check this carefully, CTX_wm_manager(C) == wm is a bit hackish */
1365                                                 if(handler->op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm)
1366                                                         wm->op_undo_depth--;
1367                                                 
1368                                                 if (retval & OPERATOR_FINISHED)
1369                                                         if(G.f & G_DEBUG)
1370                                                                 wm_operator_print(C, handler->op);
1371                                                 
1372                                                 /* XXX check this carefully, CTX_wm_manager(C) == wm is a bit hackish */
1373                                                 if(CTX_wm_manager(C) == wm && wm->op_undo_depth == 0)
1374                                                         if(handler->op->type->flag & OPTYPE_UNDO)
1375                                                                 ED_undo_push_op(C, handler->op);
1376
1377                                                 if(handler->op->reports->list.first) {
1378
1379                                                         /* FIXME, temp setting window, this is really bad!
1380                                                          * only have because lib linking errors need to be seen by users :(
1381                                                          * it can be removed without breaking anything but then no linking errors - campbell */
1382                                                         wmWindow *win_prev= CTX_wm_window(C);
1383                                                         if(win_prev==NULL)
1384                                                                 CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first);
1385
1386                                                         handler->op->reports->printlevel = RPT_WARNING;
1387                                                         uiPupMenuReports(C, handler->op->reports);
1388
1389                                                         /* XXX - copied from 'wm_operator_finished()' */
1390                                                         /* add reports to the global list, otherwise they are not seen */
1391                                                         BLI_movelisttolist(&CTX_wm_reports(C)->list, &handler->op->reports->list);
1392
1393                                                         CTX_wm_window_set(C, win_prev);
1394                                                 }
1395
1396                                                 WM_operator_free(handler->op);
1397                                         }
1398                                 }
1399                                 else {
1400                                         if(handler->op->type->cancel) {
1401                                                 if(handler->op->type->flag & OPTYPE_UNDO)
1402                                                         wm->op_undo_depth++;
1403
1404                                                 handler->op->type->cancel(C, handler->op);
1405
1406                                                 if(handler->op->type->flag & OPTYPE_UNDO)
1407                                                         wm->op_undo_depth--;
1408                                         }
1409
1410                                         WM_operator_free(handler->op);
1411                                 }
1412
1413                                 CTX_wm_area_set(C, NULL);
1414                                 
1415                                 wm_event_free_handler(handler);
1416                                 
1417                                 action= WM_HANDLER_BREAK;
1418                         }
1419                         break;
1420         }
1421         
1422         return action;
1423 }
1424
1425 static int handler_boundbox_test(wmEventHandler *handler, wmEvent *event)
1426 {
1427         if(handler->bbwin) {
1428                 if(handler->bblocal) {
1429                         rcti rect= *handler->bblocal;
1430                         BLI_translate_rcti(&rect, handler->bbwin->xmin, handler->bbwin->ymin);
1431
1432                         if(BLI_in_rcti(&rect, event->x, event->y))
1433                                 return 1;
1434                         else if(event->type==MOUSEMOVE && BLI_in_rcti(&rect, event->prevx, event->prevy))
1435                                 return 1;
1436                         else
1437                                 return 0;
1438                 }
1439                 else {
1440                         if(BLI_in_rcti(handler->bbwin, event->x, event->y))
1441                                 return 1;
1442                         else if(event->type==MOUSEMOVE && BLI_in_rcti(handler->bbwin, event->prevx, event->prevy))
1443                                 return 1;
1444                         else
1445                                 return 0;
1446                 }
1447         }
1448         return 1;
1449 }
1450
1451 static int wm_action_not_handled(int action)
1452 {
1453         return action == WM_HANDLER_CONTINUE || action == (WM_HANDLER_BREAK|WM_HANDLER_MODAL);
1454 }
1455
1456 static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
1457 {
1458         wmWindowManager *wm= CTX_wm_manager(C);
1459         wmEventHandler *handler, *nexthandler;
1460         int action= WM_HANDLER_CONTINUE;
1461         int always_pass;
1462
1463         if(handlers==NULL) return action;
1464
1465         /* modal handlers can get removed in this loop, we keep the loop this way */
1466         for(handler= handlers->first; handler; handler= nexthandler) {
1467                 
1468                 nexthandler= handler->next;
1469                 
1470                 /* during this loop, ui handlers for nested menus can tag multiple handlers free */
1471                 if(handler->flag & WM_HANDLER_DO_FREE);
1472                         /* optional boundbox */
1473                 else if(handler_boundbox_test(handler, event)) {
1474                         /* in advance to avoid access to freed event on window close */
1475                         always_pass= wm_event_always_pass(event);
1476                 
1477                         /* modal+blocking handler */
1478                         if(handler->flag & WM_HANDLER_BLOCKING)
1479                                 action |= WM_HANDLER_BREAK;
1480
1481                         if(handler->keymap) {
1482                                 wmKeyMap *keymap= WM_keymap_active(wm, handler->keymap);
1483                                 wmKeyMapItem *kmi;
1484                                 
1485                                 if(!keymap->poll || keymap->poll(C)) {
1486                                         for(kmi= keymap->items.first; kmi; kmi= kmi->next) {
1487                                                 if(wm_eventmatch(event, kmi)) {
1488                                                         
1489                                                         event->keymap_idname= kmi->idname;      /* weak, but allows interactive callback to not use rawkey */
1490                                                         
1491                                                         action |= wm_handler_operator_call(C, handlers, handler, event, kmi->ptr);
1492                                                         if(action & WM_HANDLER_BREAK)  /* not always_pass here, it denotes removed handler */
1493                                                                 break;
1494                                                 }
1495                                         }
1496                                 }
1497                         }
1498                         else if(handler->ui_handle) {
1499                                 action |= wm_handler_ui_call(C, handler, event, always_pass);
1500                         }
1501                         else if(handler->type==WM_HANDLER_FILESELECT) {
1502                                 /* screen context changes here */
1503                                 action |= wm_handler_fileselect_call(C, handlers, handler, event);
1504                         }
1505                         else if(handler->dropboxes) {
1506                                 if(event->type==EVT_DROP) {
1507                                         wmDropBox *drop= handler->dropboxes->first;
1508                                         for(; drop; drop= drop->next) {
1509                                                 /* other drop custom types allowed */
1510                                                 if(event->custom==EVT_DATA_LISTBASE) {
1511                                                         ListBase *lb= (ListBase *)event->customdata;
1512                                                         wmDrag *drag;
1513                                                         
1514                                                         for(drag= lb->first; drag; drag= drag->next) {
1515                                                                 if(drop->poll(C, drag, event)) {
1516                                                                         
1517                                                                         drop->copy(drag, drop);
1518                                                                         
1519                                                                         /* free the drags before calling operator */
1520                                                                         BLI_freelistN(event->customdata);
1521                                                                         event->customdata= NULL;
1522                                                                         event->custom= 0;
1523                                                                         
1524                                                                         WM_operator_name_call(C, drop->ot->idname, drop->opcontext, drop->ptr);
1525                                                                         action |= WM_HANDLER_BREAK;
1526                                                                         
1527                                                                         /* XXX fileread case */
1528                                                                         if(CTX_wm_window(C)==NULL)
1529                                                                                 return action;
1530                                                                         
1531                                                                         /* escape from drag loop, got freed */
1532                                                                         break;
1533                                                                 }
1534                                                         }
1535                                                 }
1536                                         }
1537                                 }
1538                         }
1539                         else {
1540                                 /* modal, swallows all */
1541                                 action |= wm_handler_operator_call(C, handlers, handler, event, NULL);
1542                         }
1543
1544                         if(action & WM_HANDLER_BREAK) {
1545                                 if(always_pass)
1546                                         action &= ~WM_HANDLER_BREAK;
1547                                 else
1548                                         break;
1549                         }
1550                 }
1551                 
1552                 /* XXX fileread case, if the wm is freed then the handler's
1553                  * will have been too so the code below need not run. */
1554                 if(CTX_wm_window(C)==NULL) {
1555                         return action;
1556                 }
1557
1558                 /* XXX code this for all modal ops, and ensure free only happens here */
1559                 
1560                 /* modal ui handler can be tagged to be freed */ 
1561                 if(BLI_findindex(handlers, handler) != -1) { /* could be free'd already by regular modal ops */
1562                         if(handler->flag & WM_HANDLER_DO_FREE) {
1563                                 BLI_remlink(handlers, handler);
1564                                 wm_event_free_handler(handler);
1565                         }
1566                 }
1567         }
1568
1569         /* test for CLICK event */
1570         if (wm_action_not_handled(action) && event->val == KM_RELEASE) {
1571                 wmWindow *win = CTX_wm_window(C);
1572
1573                 if (win && win->eventstate->prevtype == event->type && win->eventstate->prevval == KM_PRESS) {
1574                         /* test for double click first,
1575                          * note1: this can be problematic because single click operators can get the
1576                          *   double click event but then with old mouse coords which is highly confusing,
1577                          *   so check for mouse moves too.
1578                          * note2: the first click event will be handled but still used to create a
1579                          *   double click event if clicking again quickly.
1580                          *   If no double click events are found it will fallback to a single click.
1581                          *   So a double click event can result in 2 successive single click calls
1582                          *   if its not handled by the keymap - campbell */
1583                         if (    (ABS(event->x - win->eventstate->prevclickx)) <= 2 &&
1584                                         (ABS(event->y - win->eventstate->prevclicky)) <= 2 &&
1585                                         ((PIL_check_seconds_timer() - win->eventstate->prevclicktime) * 1000 < U.dbl_click_time)
1586                         ) {
1587                                 event->val = KM_DBL_CLICK;
1588                                 /* removed this because in cases where we're this is used as a single click
1589                                  * event, this will give old coords, since the distance is checked above, using new coords should be ok. */
1590                                 //   event->x = win->eventstate->prevclickx;
1591                                 //   event->y = win->eventstate->prevclicky;
1592                                 action |= wm_handlers_do(C, event, handlers);
1593                         }
1594
1595                         if (wm_action_not_handled(action)) {
1596                                 event->val = KM_CLICK;
1597                                 action |= wm_handlers_do(C, event, handlers);
1598                         }
1599
1600
1601                         /* revert value if not handled */
1602                         if (wm_action_not_handled(action)) {
1603                                 event->val = KM_RELEASE;
1604                         }
1605                 }
1606         }
1607         
1608         if(action == (WM_HANDLER_BREAK|WM_HANDLER_MODAL))
1609                 wm_cursor_arrow_move(CTX_wm_window(C), event);
1610
1611         return action;
1612 }
1613
1614 static int wm_event_inside_i(wmEvent *event, rcti *rect)
1615 {
1616         if(wm_event_always_pass(event))
1617                 return 1;
1618         if(BLI_in_rcti(rect, event->x, event->y))
1619                 return 1;
1620         if(event->type==MOUSEMOVE) {
1621                 if( BLI_in_rcti(rect, event->prevx, event->prevy)) {
1622                         return 1;
1623                 }
1624                 return 0;
1625         }
1626         return 0;
1627 }
1628
1629 static ScrArea *area_event_inside(bContext *C, int x, int y)
1630 {
1631         bScreen *screen= CTX_wm_screen(C);
1632         ScrArea *sa;
1633         
1634         if(screen)
1635                 for(sa= screen->areabase.first; sa; sa= sa->next)
1636                         if(BLI_in_rcti(&sa->totrct, x, y))
1637                                 return sa;
1638         return NULL;
1639 }
1640
1641 static ARegion *region_event_inside(bContext *C, int x, int y)
1642 {
1643         bScreen *screen= CTX_wm_screen(C);
1644         ScrArea *area= CTX_wm_area(C);
1645         ARegion *ar;
1646         
1647         if(screen && area)
1648                 for(ar= area->regionbase.first; ar; ar= ar->next)
1649                         if(BLI_in_rcti(&ar->winrct, x, y))
1650                                 return ar;
1651         return NULL;
1652 }
1653
1654 static void wm_paintcursor_tag(bContext *C, wmPaintCursor *pc, ARegion *ar)
1655 {
1656         if(ar) {
1657                 for(; pc; pc= pc->next) {
1658                         if(pc->poll == NULL || pc->poll(C)) {
1659                                 wmWindow *win= CTX_wm_window(C);
1660                                 win->screen->do_draw_paintcursor= 1;
1661                                 wm_tag_redraw_overlay(win, ar);
1662                         }
1663                 }
1664         }
1665 }
1666
1667 /* called on mousemove, check updates for paintcursors */
1668 /* context was set on active area and region */
1669 static void wm_paintcursor_test(bContext *C, wmEvent *event)
1670 {
1671         wmWindowManager *wm= CTX_wm_manager(C);
1672         
1673         if(wm->paintcursors.first) {
1674                 ARegion *ar= CTX_wm_region(C);
1675                 
1676                 if(ar)
1677                         wm_paintcursor_tag(C, wm->paintcursors.first, ar);
1678                 
1679                 /* if previous position was not in current region, we have to set a temp new context */
1680                 if(ar==NULL || !BLI_in_rcti(&ar->winrct, event->prevx, event->prevy)) {
1681                         ScrArea *sa= CTX_wm_area(C);
1682                         
1683                         CTX_wm_area_set(C, area_event_inside(C, event->prevx, event->prevy));
1684                         CTX_wm_region_set(C, region_event_inside(C, event->prevx, event->prevy));
1685
1686                         wm_paintcursor_tag(C, wm->paintcursors.first, CTX_wm_region(C));
1687                         
1688                         CTX_wm_area_set(C, sa);
1689                         CTX_wm_region_set(C, ar);
1690                 }
1691         }
1692 }
1693
1694 static void wm_event_drag_test(wmWindowManager *wm, wmWindow *win, wmEvent *event)
1695 {
1696         if(wm->drags.first==NULL) return;
1697         
1698         if(event->type==MOUSEMOVE)
1699                 win->screen->do_draw_drag= 1;
1700         else if(event->type==ESCKEY) {
1701                 BLI_freelistN(&wm->drags);
1702                 win->screen->do_draw_drag= 1;
1703         }
1704         else if(event->type==LEFTMOUSE && event->val==KM_RELEASE) {
1705                 event->type= EVT_DROP;
1706                 
1707                 /* create customdata, first free existing */
1708                 if(event->customdata) {
1709                         if(event->customdatafree)
1710                                 MEM_freeN(event->customdata);
1711                 }
1712                 
1713                 event->custom= EVT_DATA_LISTBASE;
1714                 event->customdata= &wm->drags;
1715                 event->customdatafree= 1;
1716                 
1717                 /* clear drop icon */
1718                 win->screen->do_draw_drag= 1;
1719                 
1720                 /* restore cursor (disabled, see wm_dragdrop.c) */
1721                 // WM_cursor_restore(win);
1722         }
1723         
1724         /* overlap fails otherwise */
1725         if(win->screen->do_draw_drag)
1726                 if(win->drawmethod == USER_DRAW_OVERLAP)
1727                         win->screen->do_draw= 1;
1728         
1729 }
1730
1731 /* called in main loop */
1732 /* goes over entire hierarchy:  events -> window -> screen -> area -> region */
1733 void wm_event_do_handlers(bContext *C)
1734 {
1735         wmWindowManager *wm= CTX_wm_manager(C);
1736         wmWindow *win;
1737
1738         /* update key configuration before handling events */
1739         WM_keyconfig_update(wm);
1740
1741         for(win= wm->windows.first; win; win= win->next) {
1742                 wmEvent *event;
1743                 
1744                 if( win->screen==NULL )
1745                         wm_event_free_all(win);
1746                 else {
1747                         Scene* scene = win->screen->scene;
1748                         
1749                         if(scene) {
1750                                 int playing = sound_scene_playing(win->screen->scene);
1751                                 
1752                                 if(playing != -1) {
1753                                         CTX_wm_window_set(C, win);
1754                                         CTX_wm_screen_set(C, win->screen);
1755                                         CTX_data_scene_set(C, scene);
1756                                         
1757                                         if(((playing == 1) && (!win->screen->animtimer)) || ((playing == 0) && (win->screen->animtimer))){
1758                                                 ED_screen_animation_play(C, -1, 1);
1759                                         }
1760                                         
1761                                         if(playing == 0) {
1762                                                 int ncfra = sound_sync_scene(scene) * (float)FPS + 0.5f;
1763                                                 if(ncfra != scene->r.cfra)      {
1764                                                         scene->r.cfra = ncfra;
1765                                                         ED_update_for_newframe(CTX_data_main(C), scene, win->screen, 1);
1766                                                         WM_event_add_notifier(C, NC_WINDOW, NULL);
1767                                                 }
1768                                         }
1769                                         
1770                                         CTX_data_scene_set(C, NULL);
1771                                         CTX_wm_screen_set(C, NULL);
1772                                         CTX_wm_window_set(C, NULL);
1773                                 }
1774                         }
1775                 }
1776                 
1777                 while( (event= win->queue.first) ) {
1778                         int action = WM_HANDLER_CONTINUE;
1779
1780                         if((G.f & G_DEBUG) && event && !ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE))
1781                                 printf("pass on evt %d val %d\n", event->type, event->val); 
1782                         
1783                         wm_eventemulation(event);
1784
1785                         CTX_wm_window_set(C, win);
1786                         
1787                         /* we let modal handlers get active area/region, also wm_paintcursor_test needs it */
1788                         CTX_wm_area_set(C, area_event_inside(C, event->x, event->y));
1789                         CTX_wm_region_set(C, region_event_inside(C, event->x, event->y));
1790                         
1791                         /* MVC demands to not draw in event handlers... but we need to leave it for ogl selecting etc */
1792                         wm_window_make_drawable(C, win);
1793                         
1794                         wm_region_mouse_co(C, event);
1795
1796                         /* first we do priority handlers, modal + some limited keymaps */
1797                         action |= wm_handlers_do(C, event, &win->modalhandlers);
1798                         
1799                         /* fileread case */
1800                         if(CTX_wm_window(C)==NULL)
1801                                 return;
1802                         
1803                         /* check dragging, creates new event or frees, adds draw tag */
1804                         wm_event_drag_test(wm, win, event);
1805                         
1806                         /* builtin tweak, if action is break it removes tweak */
1807                         wm_tweakevent_test(C, event, action);
1808
1809                         if((action & WM_HANDLER_BREAK) == 0) {
1810                                 ScrArea *sa;
1811                                 ARegion *ar;
1812                                 int doit= 0;
1813         
1814                                 /* Note: setting subwin active should be done here, after modal handlers have been done */
1815                                 if(event->type==MOUSEMOVE) {
1816                                         /* state variables in screen, cursors. Also used in wm_draw.c, fails for modal handlers though */
1817                                         ED_screen_set_subwinactive(C, event);   
1818                                         /* for regions having custom cursors */
1819                                         wm_paintcursor_test(C, event);
1820                                 }
1821                                 else if (event->type==NDOF_MOTION) {
1822                                         win->addmousemove = TRUE;
1823                                 }
1824
1825                                 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
1826                                         if(wm_event_inside_i(event, &sa->totrct)) {
1827                                                 CTX_wm_area_set(C, sa);
1828
1829                                                 if((action & WM_HANDLER_BREAK) == 0) {
1830                                                         for(ar=sa->regionbase.first; ar; ar= ar->next) {
1831                                                                 if(wm_event_inside_i(event, &ar->winrct)) {
1832                                                                         CTX_wm_region_set(C, ar);
1833                                                                         
1834                                                                         /* call even on non mouse events, since the */
1835                                                                         wm_region_mouse_co(C, event);
1836
1837                                                                         /* does polls for drop regions and checks uibuts */
1838                                                                         /* need to be here to make sure region context is true */
1839                                                                         if(ELEM(event->type, MOUSEMOVE, EVT_DROP)) {
1840                                                                                 wm_drags_check_ops(C, event);
1841                                                                         }
1842                                                                         
1843                                                                         action |= wm_handlers_do(C, event, &ar->handlers);
1844
1845                                                                         /* fileread case (python), [#29489] */
1846                                                                         if(CTX_wm_window(C)==NULL)
1847                                                                                 return;
1848
1849                                                                         doit |= (BLI_in_rcti(&ar->winrct, event->x, event->y));
1850                                                                         
1851                                                                         if(action & WM_HANDLER_BREAK)
1852                                                                                 break;
1853                                                                 }
1854                                                         }
1855                                                 }
1856
1857                                                 CTX_wm_region_set(C, NULL);
1858
1859                                                 if((action & WM_HANDLER_BREAK) == 0) {
1860                                                         wm_region_mouse_co(C, event); /* only invalidates event->mval in this case */
1861                                                         action |= wm_handlers_do(C, event, &sa->handlers);
1862                                                 }
1863                                                 CTX_wm_area_set(C, NULL);
1864
1865                                                 /* NOTE: do not escape on WM_HANDLER_BREAK, mousemove needs handled for previous area */
1866                                         }
1867                                 }
1868                                 
1869                                 if((action & WM_HANDLER_BREAK) == 0) {
1870                                         /* also some non-modal handlers need active area/region */
1871                                         CTX_wm_area_set(C, area_event_inside(C, event->x, event->y));
1872                                         CTX_wm_region_set(C, region_event_inside(C, event->x, event->y));
1873
1874                                         wm_region_mouse_co(C, event);
1875
1876                                         action |= wm_handlers_do(C, event, &win->handlers);
1877
1878                                         /* fileread case */
1879                                         if(CTX_wm_window(C)==NULL)
1880                                                 return;
1881                                 }
1882
1883                                 /* XXX hrmf, this gives reliable previous mouse coord for area change, feels bad? 
1884                                    doing it on ghost queue gives errors when mousemoves go over area borders */
1885                                 if(doit && win->screen && win->screen->subwinactive != win->screen->mainwin) {
1886                                         win->eventstate->prevx= event->x;
1887                                         win->eventstate->prevy= event->y;
1888                                         //printf("win->eventstate->prev = %d %d\n", event->x, event->y);
1889                                 }
1890                                 else
1891                                         ;//printf("not setting prev to %d %d\n", event->x, event->y);
1892                         }
1893                         
1894                         /* store last event for this window */
1895                         /* mousemove and timer events don't overwrite last type */
1896                         if (event->type != MOUSEMOVE && !ISTIMER(event->type)) {
1897                                 if (wm_action_not_handled(action)) {
1898                                         if (win->eventstate->prevtype == event->type) {
1899                                                 /* set click time on first click (press -> release) */
1900                                                 if (win->eventstate->prevval == KM_PRESS && event->val == KM_RELEASE) {
1901                                                         win->eventstate->prevclicktime = PIL_check_seconds_timer();
1902                                                         win->eventstate->prevclickx = event->x;
1903                                                         win->eventstate->prevclicky = event->y;
1904                                                 }
1905                                         } else {
1906                                                 /* reset click time if event type not the same */
1907                                                 win->eventstate->prevclicktime = 0;
1908                                         }
1909
1910                                         win->eventstate->prevval = event->val;
1911                                         win->eventstate->prevtype = event->type;
1912                                 } else if (event->val == KM_CLICK) { /* keep click for double click later */
1913                                         win->eventstate->prevtype = event->type;
1914                                         win->eventstate->prevval = event->val;
1915                                         win->eventstate->prevclicktime = PIL_check_seconds_timer();
1916                                         win->eventstate->prevclickx = event->x;
1917                                         win->eventstate->prevclicky = event->y;
1918                                 } else { /* reset if not */
1919                                         win->eventstate->prevtype = -1;
1920                                         win->eventstate->prevval = 0;
1921                                         win->eventstate->prevclicktime = 0;
1922                                 }
1923                         }
1924
1925                         /* unlink and free here, blender-quit then frees all */
1926                         BLI_remlink(&win->queue, event);
1927                         wm_event_free(event);
1928                         
1929                 }
1930                 
1931                 /* only add mousemove when queue was read entirely */
1932                 if(win->addmousemove && win->eventstate) {
1933                         wmEvent tevent= *(win->eventstate);
1934                         //printf("adding MOUSEMOVE %d %d\n", tevent.x, tevent.y);
1935                         tevent.type= MOUSEMOVE;
1936                         tevent.prevx= tevent.x;
1937                         tevent.prevy= tevent.y;
1938                         wm_event_add(win, &tevent);
1939                         win->addmousemove= 0;
1940                 }
1941                 
1942                 CTX_wm_window_set(C, NULL);
1943         }
1944
1945         /* update key configuration after handling events */
1946         WM_keyconfig_update(wm);
1947 }
1948
1949 /* ********** filesector handling ************ */
1950
1951 void WM_event_fileselect_event(bContext *C, void *ophandle, int eventval)
1952 {
1953         /* add to all windows! */
1954         wmWindow *win;
1955         
1956         for(win= CTX_wm_manager(C)->windows.first; win; win= win->next) {
1957                 wmEvent event= *win->eventstate;
1958                 
1959                 event.type= EVT_FILESELECT;
1960                 event.val= eventval;
1961                 event.customdata= ophandle;             // only as void pointer type check
1962
1963                 wm_event_add(win, &event);
1964         }
1965 }
1966
1967 /* operator is supposed to have a filled "path" property */
1968 /* optional property: filetype (XXX enum?) */
1969
1970 /* Idea is to keep a handler alive on window queue, owning the operator.
1971    The filewindow can send event to make it execute, thus ensuring
1972    executing happens outside of lower level queues, with UI refreshed. 
1973    Should also allow multiwin solutions */
1974
1975 void WM_event_add_fileselect(bContext *C, wmOperator *op)
1976 {
1977         wmEventHandler *handler, *handlernext;
1978         wmWindow *win= CTX_wm_window(C);
1979         int full= 1;    // XXX preset?
1980
1981         /* only allow 1 file selector open per window */
1982         for(handler= win->modalhandlers.first; handler; handler=handlernext) {
1983                 handlernext= handler->next;
1984                 
1985                 if(handler->type == WM_HANDLER_FILESELECT) {
1986                         if(handler->op)
1987                                 WM_operator_free(handler->op);
1988                         BLI_remlink(&win->modalhandlers, handler);
1989                         wm_event_free_handler(handler);
1990                 }
1991         }
1992         
1993         handler = MEM_callocN(sizeof(wmEventHandler), "fileselect handler");
1994         
1995         handler->type= WM_HANDLER_FILESELECT;
1996         handler->op= op;
1997         handler->op_area= CTX_wm_area(C);
1998         handler->op_region= CTX_wm_region(C);
1999         handler->filescreen= CTX_wm_screen(C);
2000         
2001         BLI_addhead(&win->modalhandlers, handler);
2002         
2003         /* check props once before invoking if check is available
2004          * ensures initial properties are valid */
2005         if(op->type->check) {
2006                 op->type->check(C, op); /* ignore return value */
2007         }
2008
2009         WM_event_fileselect_event(C, op, full?EVT_FILESELECT_FULL_OPEN:EVT_FILESELECT_OPEN);
2010 }
2011
2012 #if 0
2013 /* lets not expose struct outside wm? */
2014 static void WM_event_set_handler_flag(wmEventHandler *handler, int flag)
2015 {
2016         handler->flag= flag;
2017 }
2018 #endif
2019
2020 wmEventHandler *WM_event_add_modal_handler(bContext *C, wmOperator *op)
2021 {
2022         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event modal handler");
2023         wmWindow *win= CTX_wm_window(C);
2024         
2025         /* operator was part of macro */
2026         if(op->opm) {
2027                 /* give the mother macro to the handler */
2028                 handler->op= op->opm;
2029                 /* mother macro opm becomes the macro element */
2030                 handler->op->opm= op;
2031         }
2032         else
2033                 handler->op= op;
2034         
2035         handler->op_area= CTX_wm_area(C);               /* means frozen screen context for modal handlers! */
2036         handler->op_region= CTX_wm_region(C);
2037         
2038         BLI_addhead(&win->modalhandlers, handler);
2039
2040         return handler;
2041 }
2042
2043 wmEventHandler *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
2044 {
2045         wmEventHandler *handler;
2046
2047         if(!keymap) {
2048                 printf("WM_event_add_keymap_handler called with NULL keymap\n");
2049                 return NULL;
2050         }
2051
2052         /* only allow same keymap once */
2053         for(handler= handlers->first; handler; handler= handler->next)
2054                 if(handler->keymap==keymap)
2055                         return handler;
2056         
2057         handler= MEM_callocN(sizeof(wmEventHandler), "event keymap handler");
2058         BLI_addtail(handlers, handler);
2059         handler->keymap= keymap;
2060
2061         return handler;
2062 }
2063
2064 /* priorities not implemented yet, for time being just insert in begin of list */
2065 wmEventHandler *WM_event_add_keymap_handler_priority(ListBase *handlers, wmKeyMap *keymap, int UNUSED(priority))
2066 {
2067         wmEventHandler *handler;
2068         
2069         WM_event_remove_keymap_handler(handlers, keymap);
2070         
2071         handler= MEM_callocN(sizeof(wmEventHandler), "event keymap handler");
2072         BLI_addhead(handlers, handler);
2073         handler->keymap= keymap;
2074         
2075         return handler;
2076 }
2077
2078 wmEventHandler *WM_event_add_keymap_handler_bb(ListBase *handlers, wmKeyMap *keymap, rcti *bblocal, rcti *bbwin)
2079 {
2080         wmEventHandler *handler= WM_event_add_keymap_handler(handlers, keymap);
2081         
2082         if(handler) {
2083                 handler->bblocal= bblocal;
2084                 handler->bbwin= bbwin;
2085         }
2086         return handler;
2087 }
2088
2089 void WM_event_remove_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
2090 {
2091         wmEventHandler *handler;
2092         
2093         for(handler= handlers->first; handler; handler= handler->next) {
2094                 if(handler->keymap==keymap) {
2095                         BLI_remlink(handlers, handler);
2096                         wm_event_free_handler(handler);
2097                         break;
2098                 }
2099         }
2100 }
2101
2102 wmEventHandler *WM_event_add_ui_handler(const bContext *C, ListBase *handlers, wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata)
2103 {
2104         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event ui handler");
2105         handler->ui_handle= func;
2106         handler->ui_remove= remove;
2107         handler->ui_userdata= userdata;
2108         handler->ui_area= (C)? CTX_wm_area(C): NULL;
2109         handler->ui_region= (C)? CTX_wm_region(C): NULL;
2110         handler->ui_menu= (C)? CTX_wm_menu(C): NULL;
2111         
2112         BLI_addhead(handlers, handler);
2113         
2114         return handler;
2115 }
2116
2117 /* set "postpone" for win->modalhandlers, this is in a running for() loop in wm_handlers_do() */
2118 void WM_event_remove_ui_handler(ListBase *handlers, wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata, int postpone)
2119 {
2120         wmEventHandler *handler;
2121         
2122         for(handler= handlers->first; handler; handler= handler->next) {
2123                 if(handler->ui_handle == func && handler->ui_remove == remove && handler->ui_userdata == userdata) {
2124                         /* handlers will be freed in wm_handlers_do() */
2125                         if(postpone) {
2126                                 handler->flag |= WM_HANDLER_DO_FREE;
2127                         }
2128                         else {
2129                                 BLI_remlink(handlers, handler);
2130                                 wm_event_free_handler(handler);
2131                         }
2132                         break;
2133                 }
2134         }
2135 }
2136
2137 wmEventHandler *WM_event_add_dropbox_handler(ListBase *handlers, ListBase *dropboxes)
2138 {
2139         wmEventHandler *handler;
2140
2141         /* only allow same dropbox once */
2142         for(handler= handlers->first; handler; handler= handler->next)
2143                 if(handler->dropboxes==dropboxes)
2144                         return handler;
2145         
2146         handler= MEM_callocN(sizeof(wmEventHandler), "dropbox handler");
2147         
2148         /* dropbox stored static, no free or copy */
2149         handler->dropboxes= dropboxes;
2150         BLI_addhead(handlers, handler);
2151         
2152         return handler;
2153 }
2154
2155 /* XXX solution works, still better check the real cause (ton) */
2156 void WM_event_remove_area_handler(ListBase *handlers, void *area)
2157 {
2158         wmEventHandler *handler, *nexthandler;
2159
2160         for(handler = handlers->first; handler; handler= nexthandler) {
2161                 nexthandler = handler->next;
2162                 if (handler->type != WM_HANDLER_FILESELECT) {
2163                         if (handler->ui_area == area) {
2164                                 BLI_remlink(handlers, handler);
2165                                 wm_event_free_handler(handler);
2166                         }
2167                 }
2168         }
2169 }
2170
2171 #if 0
2172 static void WM_event_remove_handler(ListBase *handlers, wmEventHandler *handler)
2173 {
2174         BLI_remlink(handlers, handler);
2175         wm_event_free_handler(handler);
2176 }
2177 #endif
2178
2179 void WM_event_add_mousemove(bContext *C)
2180 {
2181         wmWindow *window= CTX_wm_window(C);
2182         
2183         window->addmousemove= 1;
2184 }
2185
2186 /* for modal callbacks, check configuration for how to interpret exit with tweaks  */
2187 int WM_modal_tweak_exit(wmEvent *evt, int tweak_event)
2188 {
2189         /* if the release-confirm userpref setting is enabled, 
2190          * tweak events can be cancelled when mouse is released
2191          */
2192         if (U.flag & USER_RELEASECONFIRM) {
2193                 /* option on, so can exit with km-release */
2194                 if (evt->val == KM_RELEASE) {
2195                         switch (tweak_event) {
2196                                 case EVT_TWEAK_L:
2197                                 case EVT_TWEAK_M:
2198                                 case EVT_TWEAK_R:
2199                                         return 1;
2200                         }
2201                 }
2202                 else {
2203                         /* if the initial event wasn't a tweak event then
2204                          * ignore USER_RELEASECONFIRM setting: see [#26756] */
2205                         if(ELEM3(tweak_event, EVT_TWEAK_L, EVT_TWEAK_M, EVT_TWEAK_R) == 0) {
2206                                 return 1;
2207                         }
2208                 }
2209         }
2210         else {
2211                 /* this is fine as long as not doing km-release, otherwise
2212                  * some items (i.e. markers) being tweaked may end up getting
2213                  * dropped all over
2214                  */
2215                 if (evt->val != KM_RELEASE)
2216                         return 1;
2217         }
2218         
2219         return 0;
2220 }
2221
2222 /* ********************* ghost stuff *************** */
2223
2224 static int convert_key(GHOST_TKey key) 
2225 {
2226         if (key>=GHOST_kKeyA && key<=GHOST_kKeyZ) {
2227                 return (AKEY + ((int) key - GHOST_kKeyA));
2228         } else if (key>=GHOST_kKey0 && key<=GHOST_kKey9) {
2229                 return (ZEROKEY + ((int) key - GHOST_kKey0));
2230         } else if (key>=GHOST_kKeyNumpad0 && key<=GHOST_kKeyNumpad9) {
2231                 return (PAD0 + ((int) key - GHOST_kKeyNumpad0));
2232         } else if (key>=GHOST_kKeyF1 && key<=GHOST_kKeyF19) {
2233                 return (F1KEY + ((int) key - GHOST_kKeyF1));
2234         } else {
2235                 switch (key) {
2236                         case GHOST_kKeyBackSpace:               return BACKSPACEKEY;
2237                         case GHOST_kKeyTab:                             return TABKEY;
2238                         case GHOST_kKeyLinefeed:                return LINEFEEDKEY;
2239                         case GHOST_kKeyClear:                   return 0;
2240                         case GHOST_kKeyEnter:                   return RETKEY;
2241                                 
2242                         case GHOST_kKeyEsc:                             return ESCKEY;
2243                         case GHOST_kKeySpace:                   return SPACEKEY;
2244                         case GHOST_kKeyQuote:                   return QUOTEKEY;
2245                         case GHOST_kKeyComma:                   return COMMAKEY;
2246                         case GHOST_kKeyMinus:                   return MINUSKEY;
2247                         case GHOST_kKeyPeriod:                  return PERIODKEY;
2248                         case GHOST_kKeySlash:                   return SLASHKEY;
2249                                 
2250                         case GHOST_kKeySemicolon:               return SEMICOLONKEY;
2251                         case GHOST_kKeyEqual:                   return EQUALKEY;
2252                                 
2253                         case GHOST_kKeyLeftBracket:             return LEFTBRACKETKEY;
2254                         case GHOST_kKeyRightBracket:    return RIGHTBRACKETKEY;
2255                         case GHOST_kKeyBackslash:               return BACKSLASHKEY;
2256                         case GHOST_kKeyAccentGrave:             return ACCENTGRAVEKEY;
2257                                 
2258                         case GHOST_kKeyLeftShift:               return LEFTSHIFTKEY;
2259                         case GHOST_kKeyRightShift:              return RIGHTSHIFTKEY;
2260                         case GHOST_kKeyLeftControl:             return LEFTCTRLKEY;
2261                         case GHOST_kKeyRightControl:    return RIGHTCTRLKEY;
2262                         case GHOST_kKeyOS:                              return OSKEY;
2263                         case GHOST_kKeyLeftAlt:                 return LEFTALTKEY;
2264                         case GHOST_kKeyRightAlt:                return RIGHTALTKEY;
2265                                 
2266                         case GHOST_kKeyCapsLock:                return CAPSLOCKKEY;
2267                         case GHOST_kKeyNumLock:                 return 0;
2268                         case GHOST_kKeyScrollLock:              return 0;
2269                                 
2270                         case GHOST_kKeyLeftArrow:               return LEFTARROWKEY;
2271                         case GHOST_kKeyRightArrow:              return RIGHTARROWKEY;
2272                         case GHOST_kKeyUpArrow:                 return UPARROWKEY;
2273                         case GHOST_kKeyDownArrow:               return DOWNARROWKEY;
2274                                 
2275                         case GHOST_kKeyPrintScreen:             return 0;
2276                         case GHOST_kKeyPause:                   return PAUSEKEY;
2277                                 
2278                         case GHOST_kKeyInsert:                  return INSERTKEY;
2279                         case GHOST_kKeyDelete:                  return DELKEY;
2280                         case GHOST_kKeyHome:                    return HOMEKEY;
2281                         case GHOST_kKeyEnd:                             return ENDKEY;
2282                         case GHOST_kKeyUpPage:                  return PAGEUPKEY;
2283                         case GHOST_kKeyDownPage:                return PAGEDOWNKEY;
2284                                 
2285                         case GHOST_kKeyNumpadPeriod:    return PADPERIOD;
2286                         case GHOST_kKeyNumpadEnter:             return PADENTER;
2287                         case GHOST_kKeyNumpadPlus:              return PADPLUSKEY;
2288                         case GHOST_kKeyNumpadMinus:             return PADMINUS;
2289                         case GHOST_kKeyNumpadAsterisk:  return PADASTERKEY;
2290                         case GHOST_kKeyNumpadSlash:             return PADSLASHKEY;
2291                                 
2292                         case GHOST_kKeyGrLess:              return GRLESSKEY; 
2293                         
2294                         case GHOST_kKeyMediaPlay:               return MEDIAPLAY;
2295                         case GHOST_kKeyMediaStop:               return MEDIASTOP;
2296                         case GHOST_kKeyMediaFirst:              return MEDIAFIRST;
2297                         case GHOST_kKeyMediaLast:               return MEDIALAST;
2298                         
2299                         default:
2300                                 return UNKNOWNKEY;      /* GHOST_kKeyUnknown */
2301                 }
2302         }
2303 }
2304
2305 /* adds customdata to event */
2306 static void update_tablet_data(wmWindow *win, wmEvent *event)
2307 {
2308         const GHOST_TabletData *td= GHOST_GetTabletData(win->ghostwin);
2309         
2310         /* if there's tablet data from an active tablet device then add it */
2311         if ((td != NULL) && td->Active != GHOST_kTabletModeNone) {
2312                 struct wmTabletData *wmtab= MEM_mallocN(sizeof(wmTabletData), "customdata tablet");
2313                 
2314                 wmtab->Active = (int)td->Active;
2315                 wmtab->Pressure = td->Pressure;
2316                 wmtab->Xtilt = td->Xtilt;
2317                 wmtab->Ytilt = td->Ytilt;
2318                 
2319                 event->custom= EVT_DATA_TABLET;
2320                 event->customdata= wmtab;
2321                 event->customdatafree= 1;
2322         } 
2323 }
2324
2325 /* adds customdata to event */
2326 static void attach_ndof_data(wmEvent* event, const GHOST_TEventNDOFMotionData* ghost)
2327 {
2328         wmNDOFMotionData* data = MEM_mallocN(sizeof(wmNDOFMotionData), "customdata NDOF");
2329
2330         const float s = U.ndof_sensitivity;
2331
2332         data->tx = s * ghost->tx;
2333
2334         data->rx = s * ghost->rx;
2335         data->rx = s * ghost->ry;
2336         data->rx = s * ghost->rz;
2337
2338         if (U.ndof_flag & NDOF_ZOOM_UPDOWN)
2339                 {
2340                 /* rotate so Y is where Z was */
2341                 data->ty = s * ghost->tz;
2342                 data->tz = s * ghost->ty;
2343                 /* maintain handed-ness? or just do what feels right? */
2344
2345                 /* should this affect rotation also?
2346                  * initial guess is 'yes', but get user feedback immediately!
2347                  */
2348 #if 0
2349                 /* after turning this on, my guess becomes 'no' */
2350                 data->ry = s * ghost->rz;
2351                 data->rz = s * ghost->ry;
2352 #endif
2353                 }
2354         else
2355                 {
2356                 data->ty = s * ghost->ty;
2357                 data->tz = s * ghost->tz;
2358                 }
2359
2360         data->dt = ghost->dt;
2361
2362         data->progress = (wmProgress) ghost->progress;
2363
2364         event->custom = EVT_DATA_NDOF_MOTION;
2365         event->customdata = data;
2366         event->customdatafree = 1;
2367 }
2368
2369 /* imperfect but probably usable... draw/enable drags to other windows */
2370 static wmWindow *wm_event_cursor_other_windows(wmWindowManager *wm, wmWindow *win, wmEvent *evt)
2371 {
2372         int mx= evt->x, my= evt->y;
2373         
2374         if(wm->windows.first== wm->windows.last)
2375                 return NULL;
2376         
2377         /* top window bar... */
2378         if(mx<0 || my<0 || mx>win->sizex || my>win->sizey+30) { 
2379                 wmWindow *owin;
2380                 wmEventHandler *handler;
2381                 
2382                 /* let's skip windows having modal handlers now */
2383                 /* potential XXX ugly... I wouldn't have added a modalhandlers list (introduced in rev 23331, ton) */
2384                 for(handler= win->modalhandlers.first; handler; handler= handler->next)
2385                         if(handler->ui_handle || handler->op)
2386                                 return NULL;
2387                 
2388                 /* to desktop space */
2389                 mx += (int)win->posx;
2390                 my += (int)win->posy;
2391                 
2392                 /* check other windows to see if it has mouse inside */
2393                 for(owin= wm->windows.first; owin; owin= owin->next) {
2394                         
2395                         if(owin!=win) {
2396                                 if(mx-owin->posx >= 0 && my-owin->posy >= 0 &&
2397                                    mx-owin->posx <= owin->sizex && my-owin->posy <= owin->sizey) {
2398                                         evt->x= mx - (int)owin->posx;
2399                                         evt->y= my - (int)owin->posy;
2400                                         
2401                                         return owin;
2402                                 }
2403                         }
2404                 }
2405         }
2406         return NULL;
2407 }
2408
2409 /* windows store own event queues, no bContext here */
2410 /* time is in 1000s of seconds, from ghost */
2411 void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int UNUSED(time), void *customdata)
2412 {
2413         wmWindow *owin;
2414         wmEvent event, *evt= win->eventstate;
2415
2416         /* initialize and copy state (only mouse x y and modifiers) */
2417         event= *evt;
2418         
2419         switch (type) {
2420                 /* mouse move */
2421                 case GHOST_kEventCursorMove: {
2422                         if(win->active) {
2423                                 GHOST_TEventCursorData *cd= customdata;
2424                                 wmEvent *lastevent= win->queue.last;
2425                                 int cx, cy;
2426                                 
2427                                 GHOST_ScreenToClient(win->ghostwin, cd->x, cd->y, &cx, &cy);
2428                                 evt->x= cx;
2429                                 evt->y= (win->sizey-1) - cy;
2430                                 
2431                                 event.x= evt->x;
2432                                 event.y= evt->y;
2433
2434                                 event.type= MOUSEMOVE;
2435
2436                                 /* some painting operators want accurate mouse events, they can
2437                                    handle in between mouse move moves, others can happily ignore
2438                                    them for better performance */
2439                                 if(lastevent && lastevent->type == MOUSEMOVE)
2440                                         lastevent->type = INBETWEEN_MOUSEMOVE;
2441
2442                                 update_tablet_data(win, &event);
2443                                 wm_event_add(win, &event);
2444
2445                                 //printf("sending MOUSEMOVE %d %d\n", event.x, event.y);
2446                                 
2447                                 /* also add to other window if event is there, this makes overdraws disappear nicely */
2448                                 /* it remaps mousecoord to other window in event */
2449                                 owin= wm_event_cursor_other_windows(wm, win, &event);
2450                                 if(owin) {
2451                                         wmEvent oevent= *(owin->eventstate);
2452                                         
2453                                         oevent.x=owin->eventstate->x= event.x;
2454                                         oevent.y=owin->eventstate->y= event.y;
2455                                         oevent.type= MOUSEMOVE;
2456                                         
2457                                         update_tablet_data(owin, &oevent);
2458                                         wm_event_add(owin, &oevent);
2459                                 }
2460                                 
2461                         }
2462                         break;
2463                 }
2464                 case GHOST_kEventTrackpad: {
2465                         GHOST_TEventTrackpadData * pd = customdata;
2466                         switch (pd->subtype) {
2467                                 case GHOST_kTrackpadEventMagnify:
2468                                         event.type = MOUSEZOOM;
2469                                         break;
2470                                 case GHOST_kTrackpadEventRotate:
2471                                         event.type = MOUSEROTATE;
2472                                         break;
2473                                 case GHOST_kTrackpadEventScroll:
2474                                 default:
2475                                         event.type= MOUSEPAN;
2476                                         break;
2477                         }
2478
2479                         {
2480                                 int cx, cy;
2481                                 GHOST_ScreenToClient(win->ghostwin, pd->x, pd->y, &cx, &cy);
2482                                 event.x= evt->x= cx;
2483                                 event.y= evt->y= (win->sizey-1) - cy;
2484                         }
2485
2486                         // Use prevx/prevy so we can calculate the delta later
2487                         event.prevx= event.x - pd->deltaX;
2488                         event.prevy= event.y - (-pd->deltaY);
2489                         
2490                         update_tablet_data(win, &event);
2491                         wm_event_add(win, &event);
2492                         break;
2493                 }
2494                 /* mouse button */
2495                 case GHOST_kEventButtonDown:
2496                 case GHOST_kEventButtonUp: {
2497                         GHOST_TEventButtonData *bd= customdata;
2498                         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 */
2499                         
2500                         if (bd->button == GHOST_kButtonMaskLeft)
2501                                 event.type= LEFTMOUSE;
2502                         else if (bd->button == GHOST_kButtonMaskRight)
2503                                 event.type= RIGHTMOUSE;
2504                         else if (bd->button == GHOST_kButtonMaskButton4)
2505                                 event.type= BUTTON4MOUSE;
2506                         else if (bd->button == GHOST_kButtonMaskButton5)
2507                                 event.type= BUTTON5MOUSE;
2508                         else
2509                                 event.type= MIDDLEMOUSE;
2510                         
2511                         if(win->active==0) {
2512                                 int cx, cy;
2513                                 
2514                                 /* entering window, update mouse pos. (ghost sends win-activate *after* the mouseclick in window!) */
2515                                 wm_get_cursor_position(win, &cx, &cy);
2516
2517                                 event.x= evt->x= cx;
2518                                 event.y= evt->y= cy;
2519                         }
2520                         
2521                         /* add to other window if event is there (not to both!) */
2522                         owin= wm_event_cursor_other_windows(wm, win, &event);
2523                         if(owin) {
2524                                 wmEvent oevent= *(owin->eventstate);
2525                                 
2526                                 oevent.x= event.x;
2527                                 oevent.y= event.y;
2528                                 oevent.type= event.type;
2529                                 oevent.val= event.val;
2530                                 
2531                                 update_tablet_data(owin, &oevent);
2532                                 wm_event_add(owin, &oevent);
2533                         }
2534                         else {
2535                                 update_tablet_data(win, &event);
2536                                 wm_event_add(win, &event);
2537                         }
2538                         
2539                         break;
2540                 }
2541                 /* keyboard */
2542                 case GHOST_kEventKeyDown:
2543                 case GHOST_kEventKeyUp: {
2544                         GHOST_TEventKeyData *kd= customdata;
2545                         event.type= convert_key(kd->key);
2546                         event.ascii= kd->ascii;
2547                         event.val= (type==GHOST_kEventKeyDown)?KM_PRESS:KM_RELEASE;
2548                         
2549                         /* exclude arrow keys, esc, etc from text input */
2550                         if(type==GHOST_kEventKeyUp || (event.ascii<32 && event.ascii>0))
2551                                 event.ascii= '\0';
2552                         
2553                         /* modifiers */
2554                         if (event.type==LEFTSHIFTKEY || event.type==RIGHTSHIFTKEY) {
2555                                 event.shift= evt->shift= (event.val==KM_PRESS);
2556                                 if(event.val==KM_PRESS && (evt->ctrl || evt->alt || evt->oskey))
2557                                    event.shift= evt->shift = 3;         // define?
2558                         } 
2559                         else if (event.type==LEFTCTRLKEY || event.type==RIGHTCTRLKEY) {
2560                                 event.ctrl= evt->ctrl= (event.val==KM_PRESS);
2561                                 if(event.val==KM_PRESS && (evt->shift || evt->alt || evt->oskey))
2562                                    event.ctrl= evt->ctrl = 3;           // define?
2563                         } 
2564                         else if (event.type==LEFTALTKEY || event.type==RIGHTALTKEY) {
2565                                 event.alt= evt->alt= (event.val==KM_PRESS);
2566                                 if(event.val==KM_PRESS && (evt->ctrl || evt->shift || evt->oskey))
2567                                    event.alt= evt->alt = 3;             // define?
2568                         } 
2569                         else if (event.type==OSKEY) {
2570                                 event.oskey= evt->oskey= (event.val==KM_PRESS);
2571                                 if(event.val==KM_PRESS && (evt->ctrl || evt->alt || evt->shift))
2572                                    event.oskey= evt->oskey = 3;         // define?
2573                         }
2574                         else {
2575                                 if(event.val==KM_PRESS && event.keymodifier==0)
2576                                         evt->keymodifier= event.type; /* only set in eventstate, for next event */
2577                                 else if(event.val==KM_RELEASE && event.keymodifier==event.type)
2578                                         event.keymodifier= evt->keymodifier= 0;
2579                         }
2580
2581                         /* this case happens on some systems that on holding a key pressed,
2582                            generate press events without release, we still want to keep the
2583                            modifier in win->eventstate, but for the press event of the same
2584                            key we don't want the key modifier */
2585                         if(event.keymodifier == event.type)
2586                                 event.keymodifier= 0;
2587                         
2588                         /* if test_break set, it catches this. XXX Keep global for now? */
2589                         if(event.type==ESCKEY)
2590                                 G.afbreek= 1;
2591                         
2592                         wm_event_add(win, &event);
2593                         
2594                         break;
2595                 }
2596                         
2597                 case GHOST_kEventWheel: {
2598                         GHOST_TEventWheelData* wheelData = customdata;
2599                         
2600                         if (wheelData->z > 0)
2601                                 event.type= WHEELUPMOUSE;
2602                         else
2603                                 event.type= WHEELDOWNMOUSE;
2604                         
2605                         event.val= KM_PRESS;
2606                         wm_event_add(win, &event);
2607                         
2608                         break;
2609                 }
2610                 case GHOST_kEventTimer: {
2611                         event.type= TIMER;
2612                         event.custom= EVT_DATA_TIMER;
2613                         event.customdata= customdata;
2614                         wm_event_add(win, &event);
2615
2616                         break;
2617                 }
2618
2619                 case GHOST_kEventNDOFMotion: {
2620                         event.type = NDOF_MOTION;
2621                         attach_ndof_data(&event, customdata);
2622                         wm_event_add(win, &event);
2623
2624                         //printf("sending NDOF_MOTION, prev = %d %d\n", event.x, event.y);
2625
2626                         break;
2627                 }
2628
2629                 case GHOST_kEventNDOFButton: {
2630                         GHOST_TEventNDOFButtonData* e = customdata;
2631
2632                         event.type = NDOF_BUTTON_NONE + e->button;
2633
2634                         switch (e->action) {
2635                                 case GHOST_kPress:
2636                                         event.val = KM_PRESS;
2637                                         break;
2638                                 case GHOST_kRelease:
2639                                         event.val = KM_RELEASE;
2640                                         break;
2641                                 }
2642
2643                         event.custom = 0;
2644                         event.customdata = NULL;
2645
2646                         wm_event_add(win, &event);
2647
2648                         break;
2649                 }
2650
2651                 case GHOST_kEventUnknown:
2652                 case GHOST_kNumEventTypes:
2653                         break;
2654
2655                 case GHOST_kEventWindowDeactivate: {
2656                         event.type= WINDEACTIVATE;
2657                         wm_event_add(win, &event);
2658
2659                         break;
2660                         
2661                 }
2662
2663         }
2664 }