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