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