Multitouch trackpad 2 fingers gestures implementation
[blender-staging.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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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 #include <stdlib.h>
30 #include <string.h>
31
32 #include "DNA_listBase.h"
33 #include "DNA_screen_types.h"
34 #include "DNA_scene_types.h"
35 #include "DNA_windowmanager_types.h"
36 #include "DNA_userdef_types.h"
37
38 #include "MEM_guardedalloc.h"
39
40 #include "GHOST_C-api.h"
41
42 #include "BLI_blenlib.h"
43
44 #include "BKE_blender.h"
45 #include "BKE_context.h"
46 #include "BKE_idprop.h"
47 #include "BKE_global.h"
48 #include "BKE_main.h"
49 #include "BKE_report.h"
50 #include "BKE_scene.h"
51 #include "BKE_utildefines.h"
52
53 #include "ED_fileselect.h"
54 #include "ED_info.h"
55 #include "ED_screen.h"
56 #include "ED_space_api.h"
57 #include "ED_util.h"
58
59 #include "RNA_access.h"
60
61 #include "UI_interface.h"
62
63 #include "PIL_time.h"
64
65 #include "WM_api.h"
66 #include "WM_types.h"
67 #include "wm.h"
68 #include "wm_window.h"
69 #include "wm_event_system.h"
70 #include "wm_event_types.h"
71
72 /* ************ event management ************** */
73
74 void wm_event_add(wmWindow *win, wmEvent *event_to_add)
75 {
76         wmEvent *event= MEM_callocN(sizeof(wmEvent), "event");
77         
78         *event= *event_to_add;
79         BLI_addtail(&win->queue, event);
80 }
81
82 void wm_event_free(wmEvent *event)
83 {
84         if(event->customdata && event->customdatafree)
85                 MEM_freeN(event->customdata);
86         MEM_freeN(event);
87 }
88
89 void wm_event_free_all(wmWindow *win)
90 {
91         wmEvent *event;
92         
93         while((event= win->queue.first)) {
94                 BLI_remlink(&win->queue, event);
95                 wm_event_free(event);
96         }
97 }
98
99 /* ********************* notifiers, listeners *************** */
100
101 /* XXX: in future, which notifiers to send to other windows? */
102 void WM_event_add_notifier(const bContext *C, unsigned int type, void *reference)
103 {
104         wmNotifier *note= MEM_callocN(sizeof(wmNotifier), "notifier");
105         
106         note->wm= CTX_wm_manager(C);
107         BLI_addtail(&note->wm->queue, note);
108         
109         note->window= CTX_wm_window(C);
110         
111         if(CTX_wm_region(C))
112                 note->swinid= CTX_wm_region(C)->swinid;
113         
114         note->category= type & NOTE_CATEGORY;
115         note->data= type & NOTE_DATA;
116         note->subtype= type & NOTE_SUBTYPE;
117         note->action= type & NOTE_ACTION;
118         
119         note->reference= reference;
120 }
121
122 void WM_main_add_notifier(unsigned int type, void *reference)
123 {
124         Main *bmain= G.main;
125         wmWindowManager *wm= bmain->wm.first;
126
127         if(wm) {
128                 wmNotifier *note= MEM_callocN(sizeof(wmNotifier), "notifier");
129                 
130                 note->wm= wm;
131                 BLI_addtail(&note->wm->queue, note);
132                 
133                 note->category= type & NOTE_CATEGORY;
134                 note->data= type & NOTE_DATA;
135                 note->subtype= type & NOTE_SUBTYPE;
136                 note->action= type & NOTE_ACTION;
137                 
138                 note->reference= reference;
139         }
140 }
141
142 static wmNotifier *wm_notifier_next(wmWindowManager *wm)
143 {
144         wmNotifier *note= wm->queue.first;
145         
146         if(note) BLI_remlink(&wm->queue, note);
147         return note;
148 }
149
150 /* called in mainloop */
151 void wm_event_do_notifiers(bContext *C)
152 {
153         wmWindowManager *wm= CTX_wm_manager(C);
154         wmNotifier *note, *next;
155         wmWindow *win;
156         
157         if(wm==NULL)
158                 return;
159         
160         /* cache & catch WM level notifiers, such as frame change, scene/screen set */
161         for(win= wm->windows.first; win; win= win->next) {
162                 int do_anim= 0;
163                 
164                 CTX_wm_window_set(C, win);
165                 
166                 for(note= wm->queue.first; note; note= next) {
167                         next= note->next;
168
169                         if(note->category==NC_WM) {
170                                 if( ELEM(note->data, ND_FILEREAD, ND_FILESAVE)) {
171                                         wm->file_saved= 1;
172                                         wm_window_title(wm, win);
173                                 }
174                                 else if(note->data==ND_DATACHANGED)
175                                         wm_window_title(wm, win);
176                         }
177                         if(note->window==win) {
178                                 if(note->category==NC_SCREEN) {
179                                         if(note->data==ND_SCREENBROWSE) {
180                                                 ED_screen_set(C, note->reference);      // XXX hrms, think this over!
181                                                 if(G.f & G_DEBUG)
182                                                         printf("screen set %p\n", note->reference);
183                                         }
184                                         else if(note->data==ND_SCREENDELETE) {
185                                                 ED_screen_delete(C, note->reference);   // XXX hrms, think this over!
186                                                 if(G.f & G_DEBUG)
187                                                         printf("screen delete %p\n", note->reference);
188                                         }
189                                 }
190                                 else if(note->category==NC_SCENE) {
191                                         if(note->data==ND_SCENEBROWSE) {
192                                                 ED_screen_set_scene(C, note->reference);        // XXX hrms, think this over!
193                                                 if(G.f & G_DEBUG)
194                                                         printf("scene set %p\n", note->reference);
195                                         }
196                                         if(note->data==ND_SCENEDELETE) {
197                                                 ED_screen_delete_scene(C, note->reference);     // XXX hrms, think this over!
198                                                 if(G.f & G_DEBUG)
199                                                         printf("scene delete %p\n", note->reference);
200                                         }
201                                         else if(note->data==ND_FRAME)
202                                                 do_anim= 1;
203                                 }
204                         }
205                         if(ELEM4(note->category, NC_SCENE, NC_OBJECT, NC_GEOM, NC_SCENE)) {
206                                 ED_info_stats_clear(CTX_data_scene(C));
207                                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_INFO, NULL);
208                         }
209                 }
210                 if(do_anim) {
211                         /* depsgraph gets called, might send more notifiers */
212                         ED_update_for_newframe(C, 1);
213                 }
214         }
215         
216         /* the notifiers are sent without context, to keep it clean */
217         while( (note=wm_notifier_next(wm)) ) {
218                 wmWindow *win;
219                 
220                 for(win= wm->windows.first; win; win= win->next) {
221                         
222                         /* filter out notifiers */
223                         if(note->category==NC_SCREEN && note->reference && note->reference!=win->screen);
224                         else if(note->category==NC_SCENE && note->reference && note->reference!=win->screen->scene);
225                         else {
226                                 ScrArea *sa;
227                                 ARegion *ar;
228
229                                 /* XXX context in notifiers? */
230                                 CTX_wm_window_set(C, win);
231
232                                 /* printf("notifier win %d screen %s cat %x\n", win->winid, win->screen->id.name+2, note->category); */
233                                 ED_screen_do_listen(win, note);
234
235                                 for(ar=win->screen->regionbase.first; ar; ar= ar->next) {
236                                         ED_region_do_listen(ar, note);
237                                 }
238                                 
239                                 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
240                                         ED_area_do_listen(sa, note);
241                                         for(ar=sa->regionbase.first; ar; ar= ar->next) {
242                                                 ED_region_do_listen(ar, note);
243                                         }
244                                 }
245                         }
246                 }
247                 
248                 MEM_freeN(note);
249         }
250         
251         /* cached: editor refresh callbacks now, they get context */
252         for(win= wm->windows.first; win; win= win->next) {
253                 ScrArea *sa;
254                 
255                 CTX_wm_window_set(C, win);
256                 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
257                         if(sa->do_refresh) {
258                                 CTX_wm_area_set(C, sa);
259                                 ED_area_do_refresh(C, sa);
260                         }
261                 }
262                 
263                 /* XXX make lock in future, or separated derivedmesh users in scene */
264                 if(!G.rendering)
265                         /* depsgraph & animation: update tagged datablocks */
266                         scene_update_tagged(win->screen->scene);
267         }
268
269         CTX_wm_window_set(C, NULL);
270 }
271
272 /* ********************* operators ******************* */
273
274 int WM_operator_poll(bContext *C, wmOperatorType *ot)
275 {
276         wmOperatorTypeMacro *otmacro;
277         
278         for(otmacro= ot->macro.first; otmacro; otmacro= otmacro->next) {
279                 wmOperatorType *ot= WM_operatortype_find(otmacro->idname, 0);
280                 
281                 if(0==WM_operator_poll(C, ot))
282                         return 0;
283         }
284         
285         /* python needs operator type, so we added exception for it */
286         if(ot->pyop_poll)
287                 return ot->pyop_poll(C, ot);
288         else if(ot->poll)
289                 return ot->poll(C);
290
291         return 1;
292 }
293
294 /* if repeat is true, it doesn't register again, nor does it free */
295 static int wm_operator_exec(bContext *C, wmOperator *op, int repeat)
296 {
297         int retval= OPERATOR_CANCELLED;
298         
299         if(op==NULL || op->type==NULL)
300                 return retval;
301         
302         if(0==WM_operator_poll(C, op->type))
303                 return retval;
304         
305         if(op->type->exec)
306                 retval= op->type->exec(C, op);
307         
308         if(retval & (OPERATOR_FINISHED|OPERATOR_CANCELLED))
309                 if(op->reports->list.first)
310                         uiPupMenuReports(C, op->reports);
311         
312         if(retval & OPERATOR_FINISHED) {
313                 op->customdata= NULL;
314
315                 if(op->type->flag & OPTYPE_UNDO)
316                         ED_undo_push_op(C, op);
317                 
318                 if(repeat==0) {
319                         if(G.f & G_DEBUG) {
320                                 char *buf = WM_operator_pystring(C, op->type, op->ptr, 1);
321                                 BKE_report(CTX_wm_reports(C), RPT_OPERATOR, buf);
322                                 MEM_freeN(buf);
323                         }
324
325                         if((op->type->flag & OPTYPE_REGISTER))
326                                 wm_operator_register(C, op);
327                         else
328                                 WM_operator_free(op);
329                 }
330         }
331         else if(repeat==0)
332                 WM_operator_free(op);
333         
334         return retval;
335         
336 }
337
338 /* for running operators with frozen context (modal handlers, menus) */
339 int WM_operator_call(bContext *C, wmOperator *op)
340 {
341         return wm_operator_exec(C, op, 0);
342 }
343
344 /* do this operator again, put here so it can share above code */
345 int WM_operator_repeat(bContext *C, wmOperator *op)
346 {
347         return wm_operator_exec(C, op, 1);
348 }
349
350 static wmOperator *wm_operator_create(wmWindowManager *wm, wmOperatorType *ot, PointerRNA *properties, ReportList *reports)
351 {
352         wmOperator *op= MEM_callocN(sizeof(wmOperator), ot->idname);    /* XXX operatortype names are static still. for debug */
353         
354         /* XXX adding new operator could be function, only happens here now */
355         op->type= ot;
356         BLI_strncpy(op->idname, ot->idname, OP_MAX_TYPENAME);
357         
358         /* initialize properties, either copy or create */
359         op->ptr= MEM_callocN(sizeof(PointerRNA), "wmOperatorPtrRNA");
360         if(properties && properties->data) {
361                 op->properties= IDP_CopyProperty(properties->data);
362         }
363         else {
364                 IDPropertyTemplate val = {0};
365                 op->properties= IDP_New(IDP_GROUP, val, "wmOperatorProperties");
366         }
367         RNA_pointer_create(&wm->id, ot->srna, op->properties, op->ptr);
368
369         /* initialize error reports */
370         if (reports) {
371                 op->reports= reports; /* must be initialized already */
372         }
373         else {
374                 op->reports= MEM_mallocN(sizeof(ReportList), "wmOperatorReportList");
375                 BKE_reports_init(op->reports, RPT_STORE|RPT_FREE);
376         }
377         
378         /* recursive filling of operator macro list */
379         if(ot->macro.first) {
380                 static wmOperator *motherop= NULL;
381                 wmOperatorTypeMacro *otmacro;
382                 int root = 0;
383                 
384                 /* ensure all ops are in execution order in 1 list */
385                 if(motherop==NULL) {
386                         motherop = op;
387                         root = 1;
388                 }
389                 
390                 for(otmacro= ot->macro.first; otmacro; otmacro= otmacro->next) {
391                         wmOperatorType *otm= WM_operatortype_find(otmacro->idname, 0);
392                         wmOperator *opm= wm_operator_create(wm, otm, otmacro->ptr, NULL);
393                         
394                         IDP_ReplaceGroupInGroup(opm->properties, motherop->properties);
395
396                         BLI_addtail(&motherop->macro, opm);
397                         opm->opm= motherop; /* pointer to mom, for modal() */
398                 }
399                 
400                 if (root)
401                         motherop= NULL;
402         }
403         
404         return op;
405 }
406
407 static void wm_operator_print(wmOperator *op)
408 {
409         char *buf = WM_operator_pystring(NULL, op->type, op->ptr, 1);
410         printf("%s\n", buf);
411         MEM_freeN(buf);
412 }
413
414 static void wm_region_mouse_co(bContext *C, wmEvent *event)
415 {
416         ARegion *ar= CTX_wm_region(C);
417         if(ar) {
418                 /* compatibility convention */
419                 event->mval[0]= event->x - ar->winrct.xmin;
420                 event->mval[1]= event->y - ar->winrct.ymin;
421         }
422 }
423
424 static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, PointerRNA *properties, ReportList *reports)
425 {
426         wmWindowManager *wm= CTX_wm_manager(C);
427         int retval= OPERATOR_PASS_THROUGH;
428
429         if(WM_operator_poll(C, ot)) {
430                 wmOperator *op= wm_operator_create(wm, ot, properties, reports); /* if reports==NULL, theyll be initialized */
431                 
432                 if((G.f & G_DEBUG) && event && event->type!=MOUSEMOVE)
433                         printf("handle evt %d win %d op %s\n", event?event->type:0, CTX_wm_screen(C)->subwinactive, ot->idname); 
434                 
435                 if(op->type->invoke && event) {
436                         wm_region_mouse_co(C, event);
437                         retval= op->type->invoke(C, op, event);
438                 }
439                 else if(op->type->exec)
440                         retval= op->type->exec(C, op);
441                 else
442                         printf("invalid operator call %s\n", ot->idname); /* debug, important to leave a while, should never happen */
443
444                 /* Note, if the report is given as an argument then assume the caller will deal with displaying them
445                  * currently python only uses this */
446                 if((retval & (OPERATOR_FINISHED|OPERATOR_CANCELLED)) && reports==NULL)
447                         if(op->reports->list.first) /* only show the report if the report list was not given in the function */
448                                 uiPupMenuReports(C, op->reports);
449                 
450                 if (retval & OPERATOR_FINISHED) { /* todo - this may conflict with the other wm_operator_print, if theres ever 2 prints for 1 action will may need to add modal check here */
451                         if(G.f & G_DEBUG)
452                                 wm_operator_print(op);
453                 }
454
455                 if(retval & OPERATOR_FINISHED) {
456                         op->customdata= NULL;
457
458                         if(ot->flag & OPTYPE_UNDO)
459                                 ED_undo_push_op(C, op);
460                         
461                         if(G.f & G_DEBUG) {
462                                 char *buf = WM_operator_pystring(C, op->type, op->ptr, 1);
463                                 BKE_report(CTX_wm_reports(C), RPT_OPERATOR, buf);
464                                 MEM_freeN(buf);
465                         }
466                         
467                         if((ot->flag & OPTYPE_REGISTER))
468                                 wm_operator_register(C, op);
469                         else
470                                 WM_operator_free(op);
471                 }
472                 else if(retval & OPERATOR_RUNNING_MODAL) {
473                         /* grab cursor during blocking modal ops (X11)
474                          * Also check for macro
475                          * */
476                         if(ot->flag & OPTYPE_BLOCKING || (op->opm && op->opm->type->flag & OPTYPE_BLOCKING)) {
477                                 int bounds[4] = {-1,-1,-1,-1};
478                                 int wrap;
479
480                                 if (op->opm) {
481                                         wrap = (U.uiflag & USER_CONTINUOUS_MOUSE) && ((op->opm->flag & OP_GRAB_POINTER) || (op->opm->type->flag & OPTYPE_GRAB_POINTER));
482                                 } else {
483                                         wrap = (U.uiflag & USER_CONTINUOUS_MOUSE) && ((op->flag & OP_GRAB_POINTER) || (ot->flag & OPTYPE_GRAB_POINTER));
484                                 }
485
486                                 if(wrap) {
487                                         ARegion *ar= CTX_wm_region(C);
488                                         if(ar) {
489                                                 bounds[0]= ar->winrct.xmin;
490                                                 bounds[1]= ar->winrct.ymax;
491                                                 bounds[2]= ar->winrct.xmax;
492                                                 bounds[3]= ar->winrct.ymin;
493                                         }
494                                 }
495
496                                 WM_cursor_grab(CTX_wm_window(C), wrap, FALSE, bounds);
497                         }
498                 }
499                 else
500                         WM_operator_free(op);
501         }
502
503         return retval;
504 }
505
506 /* WM_operator_name_call is the main accessor function
507  * this is for python to access since its done the operator lookup
508  * 
509  * invokes operator in context */
510 static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, int context, PointerRNA *properties, ReportList *reports)
511 {
512         wmWindow *window= CTX_wm_window(C);
513         wmEvent *event;
514         
515         int retval;
516
517         /* dummie test */
518         if(ot && C) {
519                 switch(context) {
520                         case WM_OP_INVOKE_DEFAULT:
521                         case WM_OP_INVOKE_REGION_WIN:
522                         case WM_OP_INVOKE_AREA:
523                         case WM_OP_INVOKE_SCREEN:
524                                 /* window is needed for invoke, cancel operator */
525                                 if (window == NULL)
526                                         return 0;
527                                 else
528                                         event= window->eventstate;
529                                 break;
530                         default:
531                                 event = NULL;
532                 }
533
534                 switch(context) {
535                         
536                         case WM_OP_EXEC_REGION_WIN:
537                         case WM_OP_INVOKE_REGION_WIN: 
538                         {
539                                 /* forces operator to go to the region window, for header menus */
540                                 ARegion *ar= CTX_wm_region(C);
541                                 ScrArea *area= CTX_wm_area(C);
542                                 
543                                 if(area) {
544                                         ARegion *ar1= area->regionbase.first;
545                                         for(; ar1; ar1= ar1->next)
546                                                 if(ar1->regiontype==RGN_TYPE_WINDOW)
547                                                         break;
548                                         if(ar1)
549                                                 CTX_wm_region_set(C, ar1);
550                                 }
551                                 
552                                 retval= wm_operator_invoke(C, ot, event, properties, reports);
553                                 
554                                 /* set region back */
555                                 CTX_wm_region_set(C, ar);
556                                 
557                                 return retval;
558                         }
559                         case WM_OP_EXEC_AREA:
560                         case WM_OP_INVOKE_AREA:
561                         {
562                                         /* remove region from context */
563                                 ARegion *ar= CTX_wm_region(C);
564
565                                 CTX_wm_region_set(C, NULL);
566                                 retval= wm_operator_invoke(C, ot, event, properties, reports);
567                                 CTX_wm_region_set(C, ar);
568
569                                 return retval;
570                         }
571                         case WM_OP_EXEC_SCREEN:
572                         case WM_OP_INVOKE_SCREEN:
573                         {
574                                 /* remove region + area from context */
575                                 ARegion *ar= CTX_wm_region(C);
576                                 ScrArea *area= CTX_wm_area(C);
577
578                                 CTX_wm_region_set(C, NULL);
579                                 CTX_wm_area_set(C, NULL);
580                                 retval= wm_operator_invoke(C, ot, event, properties, reports);
581                                 CTX_wm_region_set(C, ar);
582                                 CTX_wm_area_set(C, area);
583
584                                 return retval;
585                         }
586                         case WM_OP_EXEC_DEFAULT:
587                         case WM_OP_INVOKE_DEFAULT:
588                                 return wm_operator_invoke(C, ot, event, properties, reports);
589                 }
590         }
591         
592         return 0;
593 }
594
595
596 /* invokes operator in context */
597 int WM_operator_name_call(bContext *C, const char *opstring, int context, PointerRNA *properties)
598 {
599         wmOperatorType *ot= WM_operatortype_find(opstring, 0);
600         if(ot)
601                 return wm_operator_call_internal(C, ot, context, properties, NULL);
602
603         return 0;
604 }
605
606 /* Similar to WM_operator_name_call called with WM_OP_EXEC_DEFAULT context.
607    - wmOperatorType is used instead of operator name since python alredy has the operator type
608    - poll() must be called by python before this runs.
609    - reports can be passed to this function (so python can report them as exceptions)
610 */
611 int WM_operator_call_py(bContext *C, wmOperatorType *ot, int context, PointerRNA *properties, ReportList *reports)
612 {
613         int retval= OPERATOR_CANCELLED;
614
615 #if 0
616         wmOperator *op;
617         wmWindowManager *wm=    CTX_wm_manager(C);
618         op= wm_operator_create(wm, ot, properties, reports);
619
620         if (op->type->exec)
621                 retval= op->type->exec(C, op);
622         else
623                 printf("error \"%s\" operator has no exec function, python cannot call it\n", op->type->name);
624 #endif
625
626         retval= wm_operator_call_internal(C, ot, context, properties, reports);
627         
628         /* keep the reports around if needed later */
629         if (retval & OPERATOR_RUNNING_MODAL || ot->flag & OPTYPE_REGISTER)
630         {
631                 reports->flag |= RPT_FREE;
632         }
633         
634         return retval;
635 }
636
637
638 /* ********************* handlers *************** */
639
640 /* future extra customadata free? */
641 void wm_event_free_handler(wmEventHandler *handler)
642 {
643         MEM_freeN(handler);
644 }
645
646 /* only set context when area/region is part of screen */
647 static void wm_handler_op_context(bContext *C, wmEventHandler *handler)
648 {
649         bScreen *screen= CTX_wm_screen(C);
650         
651         if(screen && handler->op) {
652                 if(handler->op_area==NULL)
653                         CTX_wm_area_set(C, NULL);
654                 else {
655                         ScrArea *sa;
656                         
657                         for(sa= screen->areabase.first; sa; sa= sa->next)
658                                 if(sa==handler->op_area)
659                                         break;
660                         if(sa==NULL) {
661                                 /* when changing screen layouts with running modal handlers (like render display), this
662                                    is not an error to print */
663                                 if(handler->op==NULL)
664                                         printf("internal error: handler (%s) has invalid area\n", handler->op->type->idname);
665                         }
666                         else {
667                                 ARegion *ar;
668                                 CTX_wm_area_set(C, sa);
669                                 for(ar= sa->regionbase.first; ar; ar= ar->next)
670                                         if(ar==handler->op_region)
671                                                 break;
672                                 /* XXX no warning print here, after full-area and back regions are remade */
673                                 if(ar)
674                                         CTX_wm_region_set(C, ar);
675                         }
676                 }
677         }
678 }
679
680 /* called on exit or remove area, only here call cancel callback */
681 void WM_event_remove_handlers(bContext *C, ListBase *handlers)
682 {
683         wmEventHandler *handler;
684         
685         /* C is zero on freeing database, modal handlers then already were freed */
686         while((handler=handlers->first)) {
687                 BLI_remlink(handlers, handler);
688                 
689                 if(handler->op) {
690                         if(handler->op->type->cancel) {
691                                 ScrArea *area= CTX_wm_area(C);
692                                 ARegion *region= CTX_wm_region(C);
693                                 
694                                 wm_handler_op_context(C, handler);
695
696                                 handler->op->type->cancel(C, handler->op);
697
698                                 CTX_wm_area_set(C, area);
699                                 CTX_wm_region_set(C, region);
700                         }
701
702                         WM_cursor_ungrab(CTX_wm_window(C));
703                         WM_operator_free(handler->op);
704                 }
705                 else if(handler->ui_remove) {
706                         ScrArea *area= CTX_wm_area(C);
707                         ARegion *region= CTX_wm_region(C);
708                         ARegion *menu= CTX_wm_menu(C);
709                         
710                         if(handler->ui_area) CTX_wm_area_set(C, handler->ui_area);
711                         if(handler->ui_region) CTX_wm_region_set(C, handler->ui_region);
712                         if(handler->ui_menu) CTX_wm_menu_set(C, handler->ui_menu);
713
714                         handler->ui_remove(C, handler->ui_userdata);
715
716                         CTX_wm_area_set(C, area);
717                         CTX_wm_region_set(C, region);
718                         CTX_wm_menu_set(C, menu);
719                 }
720
721                 wm_event_free_handler(handler);
722         }
723 }
724
725 /* do userdef mappings */
726 int WM_userdef_event_map(int kmitype)
727 {
728         switch(kmitype) {
729                 case SELECTMOUSE:
730                         if(U.flag & USER_LMOUSESELECT)
731                                 return LEFTMOUSE;
732                         else
733                                 return RIGHTMOUSE;
734                         
735                 case ACTIONMOUSE:
736                         if(U.flag & USER_LMOUSESELECT)
737                                 return RIGHTMOUSE;
738                         else
739                                 return LEFTMOUSE;
740                         
741                 case WHEELOUTMOUSE:
742                         if(U.uiflag & USER_WHEELZOOMDIR)
743                                 return WHEELUPMOUSE;
744                         else
745                                 return WHEELDOWNMOUSE;
746                         
747                 case WHEELINMOUSE:
748                         if(U.uiflag & USER_WHEELZOOMDIR)
749                                 return WHEELDOWNMOUSE;
750                         else
751                                 return WHEELUPMOUSE;
752                         
753                 case EVT_TWEAK_A:
754                         if(U.flag & USER_LMOUSESELECT)
755                                 return EVT_TWEAK_R;
756                         else
757                                 return EVT_TWEAK_L;
758                         
759                 case EVT_TWEAK_S:
760                         if(U.flag & USER_LMOUSESELECT)
761                                 return EVT_TWEAK_L;
762                         else
763                                 return EVT_TWEAK_R;
764         }
765         
766         return kmitype;
767 }
768
769 static int wm_eventmatch(wmEvent *winevent, wmKeyMapItem *kmi)
770 {
771         int kmitype= WM_userdef_event_map(kmi->type);
772
773         if(kmi->flag & KMI_INACTIVE) return 0;
774
775         /* exception for middlemouse emulation */
776         if((U.flag & USER_TWOBUTTONMOUSE) && (kmi->type == MIDDLEMOUSE)) {
777                 if(winevent->type == LEFTMOUSE && winevent->alt) {
778                         wmKeyMapItem tmp= *kmi;
779
780                         tmp.type= winevent->type;
781                         tmp.alt= winevent->alt;
782                         if(wm_eventmatch(winevent, &tmp))
783                                 return 1;
784                 }
785         }
786         /* exception for numpad emulation */
787         else if(U.flag & USER_NONUMPAD) {
788                 wmKeyMapItem tmp= *kmi;
789
790                 switch(kmi->type) {
791                         case PAD0: tmp.type = ZEROKEY; break;
792                         case PAD1: tmp.type = ONEKEY; break;
793                         case PAD2: tmp.type = TWOKEY; break;
794                         case PAD3: tmp.type = THREEKEY; break;
795                         case PAD4: tmp.type = FOURKEY; break;
796                         case PAD5: tmp.type = FIVEKEY; break;
797                         case PAD6: tmp.type = SIXKEY; break;
798                         case PAD7: tmp.type = SEVENKEY; break;
799                         case PAD8: tmp.type = EIGHTKEY; break;
800                         case PAD9: tmp.type = NINEKEY; break;
801                         case PADMINUS: tmp.type = MINUSKEY; break;
802                         case PADPLUSKEY: tmp.type = EQUALKEY; break;
803                         case PADSLASHKEY: tmp.type = BACKSLASHKEY; break;
804                 }
805
806                 if(tmp.type != kmi->type)
807                         if(wm_eventmatch(winevent, &tmp))
808                                 return 1;
809         }
810
811         /* the matching rules */
812         if(kmitype==KM_TEXTINPUT)
813                 if(ISTEXTINPUT(winevent->type) && winevent->ascii) return 1;
814         if(kmitype!=KM_ANY)
815                 if(winevent->type!=kmitype) return 0;
816         
817         if(kmi->val!=KM_ANY)
818                 if(winevent->val!=kmi->val) return 0;
819         
820         /* modifiers also check bits, so it allows modifier order */
821         if(kmi->shift!=KM_ANY)
822                 if(winevent->shift != kmi->shift && !(winevent->shift & kmi->shift)) return 0;
823         if(kmi->ctrl!=KM_ANY)
824                 if(winevent->ctrl != kmi->ctrl && !(winevent->ctrl & kmi->ctrl)) return 0;
825         if(kmi->alt!=KM_ANY)
826                 if(winevent->alt != kmi->alt && !(winevent->alt & kmi->alt)) return 0;
827         if(kmi->oskey!=KM_ANY)
828                 if(winevent->oskey != kmi->oskey && !(winevent->oskey & kmi->oskey)) return 0;
829         
830         if(kmi->keymodifier)
831                 if(winevent->keymodifier!=kmi->keymodifier) return 0;
832                 
833         /* key modifiers always check when event has it */
834         /* otherwise regular keypresses with keymodifier still work */
835         if(winevent->keymodifier)
836                 if(ISTEXTINPUT(winevent->type)) 
837                         if(winevent->keymodifier!=kmi->keymodifier) return 0;
838         
839         return 1;
840 }
841
842 static int wm_event_always_pass(wmEvent *event)
843 {
844         /* some events we always pass on, to ensure proper communication */
845         return ISTIMER(event->type) || (event->type == WINDEACTIVATE);
846 }
847
848 /* operator exists */
849 static void wm_event_modalkeymap(const bContext *C, wmOperator *op, wmEvent *event)
850 {
851         /* support for modal keymap in macros */
852         if (op->opm)
853                 op = op->opm;
854
855         if(op->type->modalkeymap) {
856                 wmKeyMap *keymap= WM_keymap_active(CTX_wm_manager(C), op->type->modalkeymap);
857                 wmKeyMapItem *kmi;
858
859                 for(kmi= keymap->items.first; kmi; kmi= kmi->next) {
860                         if(wm_eventmatch(event, kmi)) {
861                                         
862                                 event->type= EVT_MODAL_MAP;
863                                 event->val= kmi->propvalue;
864                         }
865                 }
866         }
867 }
868
869 /* Warning: this function removes a modal handler, when finished */
870 static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHandler *handler, wmEvent *event, PointerRNA *properties)
871 {
872         int retval= OPERATOR_PASS_THROUGH;
873         
874         /* derived, modal or blocking operator */
875         if(handler->op) {
876                 wmOperator *op= handler->op;
877                 wmOperatorType *ot= op->type;
878
879                 if(ot->modal) {
880                         /* we set context to where modal handler came from */
881                         ScrArea *area= CTX_wm_area(C);
882                         ARegion *region= CTX_wm_region(C);
883                         
884                         wm_handler_op_context(C, handler);
885                         wm_region_mouse_co(C, event);
886                         wm_event_modalkeymap(C, op, event);
887                         
888                         retval= ot->modal(C, op, event);
889
890                         /* putting back screen context, reval can pass trough after modal failures! */
891                         if((retval & OPERATOR_PASS_THROUGH) || wm_event_always_pass(event)) {
892                                 CTX_wm_area_set(C, area);
893                                 CTX_wm_region_set(C, region);
894                         }
895                         else {
896                                 /* this special cases is for areas and regions that get removed */
897                                 CTX_wm_area_set(C, NULL);
898                                 CTX_wm_region_set(C, NULL);
899                         }
900
901                         if(retval & (OPERATOR_FINISHED|OPERATOR_CANCELLED))
902                                 if(op->reports->list.first)
903                                         uiPupMenuReports(C, op->reports);
904
905                         if (retval & OPERATOR_FINISHED) {
906                                 if(G.f & G_DEBUG)
907                                         wm_operator_print(op); /* todo - this print may double up, might want to check more flags then the FINISHED */
908                         }                       
909
910                         if(retval & OPERATOR_FINISHED) {
911                                 op->customdata= NULL;
912
913                                 if(ot->flag & OPTYPE_UNDO)
914                                         ED_undo_push_op(C, op);
915                                 
916                                 if(G.f & G_DEBUG) {
917                                         char *buf = WM_operator_pystring(C, op->type, op->ptr, 1);
918                                         BKE_report(CTX_wm_reports(C), RPT_OPERATOR, buf);
919                                         MEM_freeN(buf);
920                                 }
921                                 
922                                 if((ot->flag & OPTYPE_REGISTER))
923                                         wm_operator_register(C, op);
924                                 else
925                                         WM_operator_free(op);
926                                 handler->op= NULL;
927                         }
928                         else if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) {
929                                 WM_operator_free(op);
930                                 handler->op= NULL;
931                         }
932                         
933                         /* remove modal handler, operator itself should have been cancelled and freed */
934                         if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) {
935                                 WM_cursor_ungrab(CTX_wm_window(C));
936
937                                 BLI_remlink(handlers, handler);
938                                 wm_event_free_handler(handler);
939                                 
940                                 /* prevent silly errors from operator users */
941                                 //retval &= ~OPERATOR_PASS_THROUGH;
942                         }
943                         
944                 }
945                 else
946                         printf("wm_handler_operator_call error\n");
947         }
948         else {
949                 wmOperatorType *ot= WM_operatortype_find(event->keymap_idname, 0);
950
951                 if(ot)
952                         retval= wm_operator_invoke(C, ot, event, properties, NULL);
953         }
954
955         /* Finished and pass through flag as handled */
956         if(retval == (OPERATOR_FINISHED|OPERATOR_PASS_THROUGH))
957                 return WM_HANDLER_HANDLED;
958
959         /* Modal unhandled, break */
960         if(retval == (OPERATOR_PASS_THROUGH|OPERATOR_RUNNING_MODAL))
961                 return (WM_HANDLER_BREAK|WM_HANDLER_MODAL);
962
963         if(retval & OPERATOR_PASS_THROUGH)
964                 return WM_HANDLER_CONTINUE;
965
966         return WM_HANDLER_BREAK;
967 }
968
969 static int wm_handler_ui_call(bContext *C, wmEventHandler *handler, wmEvent *event)
970 {
971         ScrArea *area= CTX_wm_area(C);
972         ARegion *region= CTX_wm_region(C);
973         ARegion *menu= CTX_wm_menu(C);
974         int retval, always_pass;
975                         
976         /* we set context to where ui handler came from */
977         if(handler->ui_area) CTX_wm_area_set(C, handler->ui_area);
978         if(handler->ui_region) CTX_wm_region_set(C, handler->ui_region);
979         if(handler->ui_menu) CTX_wm_menu_set(C, handler->ui_menu);
980
981         /* in advance to avoid access to freed event on window close */
982         always_pass= wm_event_always_pass(event);
983
984         retval= handler->ui_handle(C, event, handler->ui_userdata);
985
986         /* putting back screen context */
987         if((retval != WM_UI_HANDLER_BREAK) || always_pass) {
988                 CTX_wm_area_set(C, area);
989                 CTX_wm_region_set(C, region);
990                 CTX_wm_menu_set(C, menu);
991         }
992         else {
993                 /* this special cases is for areas and regions that get removed */
994                 CTX_wm_area_set(C, NULL);
995                 CTX_wm_region_set(C, NULL);
996                 CTX_wm_menu_set(C, NULL);
997         }
998
999         if(retval == WM_UI_HANDLER_BREAK)
1000                 return WM_HANDLER_BREAK;
1001
1002         return WM_HANDLER_CONTINUE;
1003 }
1004
1005 /* fileselect handlers are only in the window queue, so it's save to switch screens or area types */
1006 static int wm_handler_fileselect_call(bContext *C, ListBase *handlers, wmEventHandler *handler, wmEvent *event)
1007 {
1008         SpaceFile *sfile;
1009         int action= WM_HANDLER_CONTINUE;
1010         
1011         if(event->type != EVT_FILESELECT)
1012                 return action;
1013         if(handler->op != (wmOperator *)event->customdata)
1014                 return action;
1015         
1016         switch(event->val) {
1017                 case EVT_FILESELECT_OPEN: 
1018                 case EVT_FILESELECT_FULL_OPEN: 
1019                         {       
1020                                 ScrArea *sa;
1021                                 
1022                                 /* sa can be null when window A is active, but mouse is over window B */
1023                                 /* in this case, open file select in original window A */
1024                                 if (handler->op_area == NULL) {
1025                                         bScreen *screen = CTX_wm_screen(C);
1026                                         sa = (ScrArea *)screen->areabase.first;
1027                                 } else
1028                                         sa = handler->op_area;
1029                                         
1030                                 if(event->val==EVT_FILESELECT_OPEN)
1031                                         ED_area_newspace(C, sa, SPACE_FILE);
1032                                 else
1033                                         ED_screen_full_newspace(C, sa, SPACE_FILE);     /* sets context */
1034                                 
1035                                 /* settings for filebrowser, sfile is not operator owner but sends events */
1036                                 sa = CTX_wm_area(C);
1037                                 sfile= (SpaceFile*)sa->spacedata.first;
1038                                 sfile->op= handler->op;
1039
1040                                 ED_fileselect_set_params(sfile);
1041                                 
1042                                 action= WM_HANDLER_BREAK;
1043                         }
1044                         break;
1045                         
1046                 case EVT_FILESELECT_EXEC:
1047                 case EVT_FILESELECT_CANCEL:
1048                         {
1049                                 /* XXX validate area and region? */
1050                                 bScreen *screen= CTX_wm_screen(C);
1051                                 char *path= RNA_string_get_alloc(handler->op->ptr, "path", NULL, 0);
1052                                 
1053                                 if(screen != handler->filescreen)
1054                                         ED_screen_full_prevspace(C, CTX_wm_area(C));
1055                                 else
1056                                         ED_area_prevspace(C, CTX_wm_area(C));
1057                                 
1058                                 /* remlink now, for load file case */
1059                                 BLI_remlink(handlers, handler);
1060                                 
1061                                 wm_handler_op_context(C, handler);
1062
1063                                 if(event->val==EVT_FILESELECT_EXEC) {
1064                                         /* a bit weak, might become arg for WM_event_fileselect? */
1065                                         /* XXX also extension code in image-save doesnt work for this yet */
1066                                         if(strncmp(handler->op->type->name, "Save", 4)==0) {
1067                                                 /* this gives ownership to pupmenu */
1068                                                 uiPupMenuSaveOver(C, handler->op, (path)? path: "");
1069                                         }
1070                                         else {
1071                                                 int retval= handler->op->type->exec(C, handler->op);
1072                                                 
1073                                                 if (retval & OPERATOR_FINISHED)
1074                                                         if(G.f & G_DEBUG)
1075                                                                 wm_operator_print(handler->op);
1076                                                 
1077                                                 WM_operator_free(handler->op);
1078                                         }
1079                                 }
1080                                 else {
1081                                         if(handler->op->type->cancel)
1082                                                 handler->op->type->cancel(C, handler->op);
1083
1084                                         WM_operator_free(handler->op);
1085                                 }
1086
1087                                 CTX_wm_area_set(C, NULL);
1088                                 
1089                                 wm_event_free_handler(handler);
1090                                 if(path)
1091                                         MEM_freeN(path);
1092                                 
1093                                 action= WM_HANDLER_BREAK;
1094                         }
1095                         break;
1096         }
1097         
1098         return action;
1099 }
1100
1101 static int handler_boundbox_test(wmEventHandler *handler, wmEvent *event)
1102 {
1103         if(handler->bbwin) {
1104                 if(handler->bblocal) {
1105                         rcti rect= *handler->bblocal;
1106                         BLI_translate_rcti(&rect, handler->bbwin->xmin, handler->bbwin->ymin);
1107
1108                         if(BLI_in_rcti(&rect, event->x, event->y))
1109                                 return 1;
1110                         else if(event->type==MOUSEMOVE && BLI_in_rcti(&rect, event->prevx, event->prevy))
1111                                 return 1;
1112                         else
1113                                 return 0;
1114                 }
1115                 else {
1116                         if(BLI_in_rcti(handler->bbwin, event->x, event->y))
1117                                 return 1;
1118                         else if(event->type==MOUSEMOVE && BLI_in_rcti(handler->bbwin, event->prevx, event->prevy))
1119                                 return 1;
1120                         else
1121                                 return 0;
1122                 }
1123         }
1124         return 1;
1125 }
1126
1127 static int wm_action_not_handled(int action)
1128 {
1129         return action == WM_HANDLER_CONTINUE || action == (WM_HANDLER_BREAK|WM_HANDLER_MODAL);
1130 }
1131
1132 static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
1133 {
1134         wmWindowManager *wm= CTX_wm_manager(C);
1135         wmEventHandler *handler, *nexthandler;
1136         int action= WM_HANDLER_CONTINUE;
1137         int always_pass;
1138
1139         if(handlers==NULL) return action;
1140
1141         /* modal handlers can get removed in this loop, we keep the loop this way */
1142         for(handler= handlers->first; handler; handler= nexthandler) {
1143                 nexthandler= handler->next;
1144
1145                 /* optional boundbox */
1146                 if(handler_boundbox_test(handler, event)) {
1147                         /* in advance to avoid access to freed event on window close */
1148                         always_pass= wm_event_always_pass(event);
1149                 
1150                         /* modal+blocking handler */
1151                         if(handler->flag & WM_HANDLER_BLOCKING)
1152                                 action |= WM_HANDLER_BREAK;
1153
1154                         if(handler->keymap) {
1155                                 wmKeyMap *keymap= WM_keymap_active(wm, handler->keymap);
1156                                 wmKeyMapItem *kmi;
1157                                 
1158                                 if(!keymap->poll || keymap->poll(C)) {
1159                                         for(kmi= keymap->items.first; kmi; kmi= kmi->next) {
1160                                                 if(wm_eventmatch(event, kmi)) {
1161                                                         
1162                                                         event->keymap_idname= kmi->idname;      /* weak, but allows interactive callback to not use rawkey */
1163                                                         
1164                                                         action |= wm_handler_operator_call(C, handlers, handler, event, kmi->ptr);
1165                                                         if(action & WM_HANDLER_BREAK)  /* not always_pass here, it denotes removed handler */
1166                                                                 break;
1167                                                 }
1168                                         }
1169                                 }
1170                         }
1171                         else if(handler->ui_handle) {
1172                                 action |= wm_handler_ui_call(C, handler, event);
1173                         }
1174                         else if(handler->type==WM_HANDLER_FILESELECT) {
1175                                 /* screen context changes here */
1176                                 action |= wm_handler_fileselect_call(C, handlers, handler, event);
1177                         }
1178                         else {
1179                                 /* modal, swallows all */
1180                                 action |= wm_handler_operator_call(C, handlers, handler, event, NULL);
1181                         }
1182
1183                         if(action & WM_HANDLER_BREAK) {
1184                                 if(always_pass)
1185                                         action &= ~WM_HANDLER_BREAK;
1186                                 else
1187                                         break;
1188                         }
1189                 }
1190                 
1191                 /* fileread case */
1192                 if(CTX_wm_window(C)==NULL)
1193                         return action;
1194         }
1195
1196         /* test for CLICK event */
1197         if (wm_action_not_handled(action) && event->val == KM_RELEASE) {
1198                 wmWindow *win = CTX_wm_window(C);
1199
1200                 if (win && win->eventstate->prevtype == event->type && win->eventstate->prevval == KM_PRESS) {
1201                         /* test for double click first */
1202                         if ((PIL_check_seconds_timer() - win->eventstate->prevclicktime) * 1000 < U.dbl_click_time) {
1203                                 event->val = KM_DBL_CLICK;
1204                                 action |= wm_handlers_do(C, event, handlers);
1205                         }
1206
1207                         if (wm_action_not_handled(action)) {
1208                                 event->val = KM_CLICK;
1209                                 action |= wm_handlers_do(C, event, handlers);
1210                         }
1211
1212
1213                         /* revert value if not handled */
1214                         if (wm_action_not_handled(action)) {
1215                                 event->val = KM_RELEASE;
1216                         }
1217                 }
1218         }
1219
1220         return action;
1221 }
1222
1223 static int wm_event_inside_i(wmEvent *event, rcti *rect)
1224 {
1225         if(wm_event_always_pass(event))
1226                 return 1;
1227         if(BLI_in_rcti(rect, event->x, event->y))
1228            return 1;
1229         if(event->type==MOUSEMOVE) {
1230                 if( BLI_in_rcti(rect, event->prevx, event->prevy)) {
1231                         return 1;
1232                 }
1233                 return 0;
1234         }
1235         return 0;
1236 }
1237
1238 static ScrArea *area_event_inside(bContext *C, int x, int y)
1239 {
1240         bScreen *screen= CTX_wm_screen(C);
1241         ScrArea *sa;
1242         
1243         if(screen)
1244                 for(sa= screen->areabase.first; sa; sa= sa->next)
1245                         if(BLI_in_rcti(&sa->totrct, x, y))
1246                                 return sa;
1247         return NULL;
1248 }
1249
1250 static ARegion *region_event_inside(bContext *C, int x, int y)
1251 {
1252         bScreen *screen= CTX_wm_screen(C);
1253         ScrArea *area= CTX_wm_area(C);
1254         ARegion *ar;
1255         
1256         if(screen && area)
1257                 for(ar= area->regionbase.first; ar; ar= ar->next)
1258                         if(BLI_in_rcti(&ar->winrct, x, y))
1259                                 return ar;
1260         return NULL;
1261 }
1262
1263 static void wm_paintcursor_tag(bContext *C, wmPaintCursor *pc, ARegion *ar)
1264 {
1265         if(ar) {
1266                 for(; pc; pc= pc->next) {
1267                         if(pc->poll(C)) {
1268                                 wmWindow *win= CTX_wm_window(C);
1269                                 win->screen->do_draw_paintcursor= 1;
1270
1271                                 if(win->drawmethod != USER_DRAW_TRIPLE)
1272                                         ED_region_tag_redraw(ar);
1273                         }
1274                 }
1275         }
1276 }
1277
1278 /* called on mousemove, check updates for paintcursors */
1279 /* context was set on active area and region */
1280 static void wm_paintcursor_test(bContext *C, wmEvent *event)
1281 {
1282         wmWindowManager *wm= CTX_wm_manager(C);
1283         
1284         if(wm->paintcursors.first) {
1285                 ARegion *ar= CTX_wm_region(C);
1286                 if(ar)
1287                         wm_paintcursor_tag(C, wm->paintcursors.first, ar);
1288                 
1289                 /* if previous position was not in current region, we have to set a temp new context */
1290                 if(ar==NULL || !BLI_in_rcti(&ar->winrct, event->prevx, event->prevy)) {
1291                         ScrArea *sa= CTX_wm_area(C);
1292                         
1293                         CTX_wm_area_set(C, area_event_inside(C, event->prevx, event->prevy));
1294                         CTX_wm_region_set(C, region_event_inside(C, event->prevx, event->prevy));
1295
1296                         wm_paintcursor_tag(C, wm->paintcursors.first, CTX_wm_region(C));
1297                         
1298                         CTX_wm_area_set(C, sa);
1299                         CTX_wm_region_set(C, ar);
1300                 }
1301         }
1302 }
1303
1304 /* called in main loop */
1305 /* goes over entire hierarchy:  events -> window -> screen -> area -> region */
1306 void wm_event_do_handlers(bContext *C)
1307 {
1308         wmWindow *win;
1309
1310         for(win= CTX_wm_manager(C)->windows.first; win; win= win->next) {
1311                 wmEvent *event;
1312                 
1313                 if( win->screen==NULL )
1314                         wm_event_free_all(win);
1315                 
1316                 while( (event= win->queue.first) ) {
1317                         int action = WM_HANDLER_CONTINUE;
1318
1319                         CTX_wm_window_set(C, win);
1320                         
1321                         /* we let modal handlers get active area/region, also wm_paintcursor_test needs it */
1322                         CTX_wm_area_set(C, area_event_inside(C, event->x, event->y));
1323                         CTX_wm_region_set(C, region_event_inside(C, event->x, event->y));
1324                         
1325                         /* MVC demands to not draw in event handlers... but we need to leave it for ogl selecting etc */
1326                         wm_window_make_drawable(C, win);
1327                         
1328                         /* first we do priority handlers, modal + some limited keymaps */
1329                         action |= wm_handlers_do(C, event, &win->modalhandlers);
1330                         
1331                         /* fileread case */
1332                         if(CTX_wm_window(C)==NULL)
1333                                 return;
1334                         
1335                         /* builtin tweak, if action is break it removes tweak */
1336                         wm_tweakevent_test(C, event, action);
1337
1338                         if((action & WM_HANDLER_BREAK) == 0) {
1339                                 ScrArea *sa;
1340                                 ARegion *ar;
1341                                 int doit= 0;
1342                                 
1343                                 /* XXX to solve, here screen handlers? */
1344                                 if(event->type==MOUSEMOVE) {
1345                                         /* state variables in screen, cursors */
1346                                         ED_screen_set_subwinactive(win, event); 
1347                                         /* for regions having custom cursors */
1348                                         wm_paintcursor_test(C, event);
1349                                 }
1350
1351                                 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
1352                                         if(wm_event_inside_i(event, &sa->totrct)) {
1353                                                 CTX_wm_area_set(C, sa);
1354
1355                                                 if((action & WM_HANDLER_BREAK) == 0) {
1356                                                         for(ar=sa->regionbase.first; ar; ar= ar->next) {
1357                                                                 if(wm_event_inside_i(event, &ar->winrct)) {
1358                                                                         CTX_wm_region_set(C, ar);
1359                                                                         action |= wm_handlers_do(C, event, &ar->handlers);
1360
1361                                                                         doit |= (BLI_in_rcti(&ar->winrct, event->x, event->y));
1362                                                                         
1363                                                                         if(action & WM_HANDLER_BREAK)
1364                                                                                 break;
1365                                                                 }
1366                                                         }
1367                                                 }
1368
1369                                                 CTX_wm_region_set(C, NULL);
1370
1371                                                 if((action & WM_HANDLER_BREAK) == 0)
1372                                                         action |= wm_handlers_do(C, event, &sa->handlers);
1373
1374                                                 CTX_wm_area_set(C, NULL);
1375
1376                                                 /* NOTE: do not escape on WM_HANDLER_BREAK, mousemove needs handled for previous area */
1377                                         }
1378                                 }
1379                                 
1380                                 if((action & WM_HANDLER_BREAK) == 0) {
1381                                         /* also some non-modal handlers need active area/region */
1382                                         CTX_wm_area_set(C, area_event_inside(C, event->x, event->y));
1383                                         CTX_wm_region_set(C, region_event_inside(C, event->x, event->y));
1384
1385                                         action |= wm_handlers_do(C, event, &win->handlers);
1386
1387                                         /* fileread case */
1388                                         if(CTX_wm_window(C)==NULL)
1389                                                 return;
1390                                 }
1391
1392                                 /* XXX hrmf, this gives reliable previous mouse coord for area change, feels bad? 
1393                                    doing it on ghost queue gives errors when mousemoves go over area borders */
1394                                 if(doit && win->screen && win->screen->subwinactive != win->screen->mainwin) {
1395                                         win->eventstate->prevx= event->x;
1396                                         win->eventstate->prevy= event->y;
1397                                 }
1398                         }
1399                         
1400                         /* store last event for this window */
1401                         /* mousemove and timer events don't overwrite last type */
1402                         if (event->type != MOUSEMOVE && !ISTIMER(event->type)) {
1403                                 if (wm_action_not_handled(action)) {
1404                                         if (win->eventstate->prevtype == event->type) {
1405                                                 /* set click time on first click (press -> release) */
1406                                                 if (win->eventstate->prevval == KM_PRESS && event->val == KM_RELEASE) {
1407                                                         win->eventstate->prevclicktime = PIL_check_seconds_timer();
1408                                                 }
1409                                         } else {
1410                                                 /* reset click time if event type not the same */
1411                                                 win->eventstate->prevclicktime = 0;
1412                                         }
1413
1414                                         win->eventstate->prevval = event->val;
1415                                         win->eventstate->prevtype = event->type;
1416                                 } else if (event->val == KM_CLICK) { /* keep click for double click later */
1417                                         win->eventstate->prevtype = event->type;
1418                                         win->eventstate->prevval = event->val;
1419                                         win->eventstate->prevclicktime = PIL_check_seconds_timer();
1420                                 } else { /* reset if not */
1421                                         win->eventstate->prevtype = -1;
1422                                         win->eventstate->prevval = 0;
1423                                         win->eventstate->prevclicktime = 0;
1424                                 }
1425                         }
1426
1427                         /* unlink and free here, blender-quit then frees all */
1428                         BLI_remlink(&win->queue, event);
1429                         wm_event_free(event);
1430                         
1431                 }
1432                 
1433                 /* only add mousemove when queue was read entirely */
1434                 if(win->addmousemove && win->eventstate) {
1435                         wmEvent event= *(win->eventstate);
1436                         event.type= MOUSEMOVE;
1437                         event.prevx= event.x;
1438                         event.prevy= event.y;
1439                         wm_event_add(win, &event);
1440                         win->addmousemove= 0;
1441                 }
1442                 
1443                 CTX_wm_window_set(C, NULL);
1444         }
1445 }
1446
1447 /* ********** filesector handling ************ */
1448
1449 void WM_event_fileselect_event(bContext *C, void *ophandle, int eventval)
1450 {
1451         /* add to all windows! */
1452         wmWindow *win;
1453         
1454         for(win= CTX_wm_manager(C)->windows.first; win; win= win->next) {
1455                 wmEvent event= *win->eventstate;
1456                 
1457                 event.type= EVT_FILESELECT;
1458                 event.val= eventval;
1459                 event.customdata= ophandle;             // only as void pointer type check
1460
1461                 wm_event_add(win, &event);
1462         }
1463 }
1464
1465 /* operator is supposed to have a filled "path" property */
1466 /* optional property: filetype (XXX enum?) */
1467
1468 /* Idea is to keep a handler alive on window queue, owning the operator.
1469    The filewindow can send event to make it execute, thus ensuring
1470    executing happens outside of lower level queues, with UI refreshed. 
1471    Should also allow multiwin solutions */
1472
1473 void WM_event_add_fileselect(bContext *C, wmOperator *op)
1474 {
1475         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "fileselect handler");
1476         wmWindow *win= CTX_wm_window(C);
1477         int full= 1;    // XXX preset?
1478         
1479         handler->type= WM_HANDLER_FILESELECT;
1480         handler->op= op;
1481         handler->op_area= CTX_wm_area(C);
1482         handler->op_region= CTX_wm_region(C);
1483         handler->filescreen= CTX_wm_screen(C);
1484         
1485         BLI_addhead(&win->modalhandlers, handler);
1486         
1487         WM_event_fileselect_event(C, op, full?EVT_FILESELECT_FULL_OPEN:EVT_FILESELECT_OPEN);
1488 }
1489
1490 /* lets not expose struct outside wm? */
1491 void WM_event_set_handler_flag(wmEventHandler *handler, int flag)
1492 {
1493         handler->flag= flag;
1494 }
1495
1496 wmEventHandler *WM_event_add_modal_handler(bContext *C, wmOperator *op)
1497 {
1498         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event modal handler");
1499         wmWindow *win= CTX_wm_window(C);
1500         
1501         /* operator was part of macro */
1502         if(op->opm) {
1503                 /* give the mother macro to the handler */
1504                 handler->op= op->opm;
1505                 /* mother macro opm becomes the macro element */
1506                 handler->op->opm= op;
1507         }
1508         else
1509                 handler->op= op;
1510         
1511         handler->op_area= CTX_wm_area(C);               /* means frozen screen context for modal handlers! */
1512         handler->op_region= CTX_wm_region(C);
1513         
1514         BLI_addhead(&win->modalhandlers, handler);
1515
1516         return handler;
1517 }
1518
1519 wmEventHandler *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
1520 {
1521         wmEventHandler *handler;
1522
1523         if(!keymap) {
1524                 printf("WM_event_add_keymap_handler called with NULL keymap\n");
1525                 return NULL;
1526         }
1527
1528         /* only allow same keymap once */
1529         for(handler= handlers->first; handler; handler= handler->next)
1530                 if(handler->keymap==keymap)
1531                         return handler;
1532         
1533         handler= MEM_callocN(sizeof(wmEventHandler), "event keymap handler");
1534         BLI_addtail(handlers, handler);
1535         handler->keymap= keymap;
1536
1537         return handler;
1538 }
1539
1540 /* priorities not implemented yet, for time being just insert in begin of list */
1541 wmEventHandler *WM_event_add_keymap_handler_priority(ListBase *handlers, wmKeyMap *keymap, int priority)
1542 {
1543         wmEventHandler *handler;
1544         
1545         WM_event_remove_keymap_handler(handlers, keymap);
1546         
1547         handler= MEM_callocN(sizeof(wmEventHandler), "event keymap handler");
1548         BLI_addhead(handlers, handler);
1549         handler->keymap= keymap;
1550         
1551         return handler;
1552 }
1553
1554 wmEventHandler *WM_event_add_keymap_handler_bb(ListBase *handlers, wmKeyMap *keymap, rcti *bblocal, rcti *bbwin)
1555 {
1556         wmEventHandler *handler= WM_event_add_keymap_handler(handlers, keymap);
1557         
1558         if(handler) {
1559                 handler->bblocal= bblocal;
1560                 handler->bbwin= bbwin;
1561         }
1562         return handler;
1563 }
1564
1565 void WM_event_remove_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
1566 {
1567         wmEventHandler *handler;
1568         
1569         for(handler= handlers->first; handler; handler= handler->next) {
1570                 if(handler->keymap==keymap) {
1571                         BLI_remlink(handlers, handler);
1572                         wm_event_free_handler(handler);
1573                         break;
1574                 }
1575         }
1576 }
1577
1578 wmEventHandler *WM_event_add_ui_handler(const bContext *C, ListBase *handlers, wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata)
1579 {
1580         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event ui handler");
1581         handler->ui_handle= func;
1582         handler->ui_remove= remove;
1583         handler->ui_userdata= userdata;
1584         handler->ui_area= (C)? CTX_wm_area(C): NULL;
1585         handler->ui_region= (C)? CTX_wm_region(C): NULL;
1586         handler->ui_menu= (C)? CTX_wm_menu(C): NULL;
1587         
1588         BLI_addhead(handlers, handler);
1589         
1590         return handler;
1591 }
1592
1593 void WM_event_remove_ui_handler(ListBase *handlers, wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata)
1594 {
1595         wmEventHandler *handler;
1596         
1597         for(handler= handlers->first; handler; handler= handler->next) {
1598                 if(handler->ui_handle == func && handler->ui_remove == remove && handler->ui_userdata == userdata) {
1599                         BLI_remlink(handlers, handler);
1600                         wm_event_free_handler(handler);
1601                         break;
1602                 }
1603         }
1604 }
1605
1606 void WM_event_add_mousemove(bContext *C)
1607 {
1608         wmWindow *window= CTX_wm_window(C);
1609         
1610         window->addmousemove= 1;
1611 }
1612
1613 /* for modal callbacks, check configuration for how to interpret exit with tweaks  */
1614 int WM_modal_tweak_exit(wmEvent *evt, int tweak_event)
1615 {
1616         /* user preset or keymap? dunno... */
1617         int tweak_modal= (U.flag & USER_DRAGIMMEDIATE)==0;
1618         
1619         switch(tweak_event) {
1620                 case EVT_TWEAK_L:
1621                 case EVT_TWEAK_M:
1622                 case EVT_TWEAK_R:
1623                         if(evt->val==tweak_modal)
1624                                 return 1;
1625                 default:
1626                         /* this case is when modal callcback didnt get started with a tweak */
1627                         if(evt->val)
1628                                 return 1;
1629         }
1630         return 0;
1631 }
1632
1633
1634 /* ********************* ghost stuff *************** */
1635
1636 static int convert_key(GHOST_TKey key) 
1637 {
1638         if (key>=GHOST_kKeyA && key<=GHOST_kKeyZ) {
1639                 return (AKEY + ((int) key - GHOST_kKeyA));
1640         } else if (key>=GHOST_kKey0 && key<=GHOST_kKey9) {
1641                 return (ZEROKEY + ((int) key - GHOST_kKey0));
1642         } else if (key>=GHOST_kKeyNumpad0 && key<=GHOST_kKeyNumpad9) {
1643                 return (PAD0 + ((int) key - GHOST_kKeyNumpad0));
1644         } else if (key>=GHOST_kKeyF1 && key<=GHOST_kKeyF12) {
1645                 return (F1KEY + ((int) key - GHOST_kKeyF1));
1646         } else {
1647                 switch (key) {
1648                         case GHOST_kKeyBackSpace:               return BACKSPACEKEY;
1649                         case GHOST_kKeyTab:                             return TABKEY;
1650                         case GHOST_kKeyLinefeed:                return LINEFEEDKEY;
1651                         case GHOST_kKeyClear:                   return 0;
1652                         case GHOST_kKeyEnter:                   return RETKEY;
1653                                 
1654                         case GHOST_kKeyEsc:                             return ESCKEY;
1655                         case GHOST_kKeySpace:                   return SPACEKEY;
1656                         case GHOST_kKeyQuote:                   return QUOTEKEY;
1657                         case GHOST_kKeyComma:                   return COMMAKEY;
1658                         case GHOST_kKeyMinus:                   return MINUSKEY;
1659                         case GHOST_kKeyPeriod:                  return PERIODKEY;
1660                         case GHOST_kKeySlash:                   return SLASHKEY;
1661                                 
1662                         case GHOST_kKeySemicolon:               return SEMICOLONKEY;
1663                         case GHOST_kKeyEqual:                   return EQUALKEY;
1664                                 
1665                         case GHOST_kKeyLeftBracket:             return LEFTBRACKETKEY;
1666                         case GHOST_kKeyRightBracket:    return RIGHTBRACKETKEY;
1667                         case GHOST_kKeyBackslash:               return BACKSLASHKEY;
1668                         case GHOST_kKeyAccentGrave:             return ACCENTGRAVEKEY;
1669                                 
1670                         case GHOST_kKeyLeftShift:               return LEFTSHIFTKEY;
1671                         case GHOST_kKeyRightShift:              return RIGHTSHIFTKEY;
1672                         case GHOST_kKeyLeftControl:             return LEFTCTRLKEY;
1673                         case GHOST_kKeyRightControl:    return RIGHTCTRLKEY;
1674                         case GHOST_kKeyCommand:                 return COMMANDKEY;
1675                         case GHOST_kKeyLeftAlt:                 return LEFTALTKEY;
1676                         case GHOST_kKeyRightAlt:                return RIGHTALTKEY;
1677                                 
1678                         case GHOST_kKeyCapsLock:                return CAPSLOCKKEY;
1679                         case GHOST_kKeyNumLock:                 return 0;
1680                         case GHOST_kKeyScrollLock:              return 0;
1681                                 
1682                         case GHOST_kKeyLeftArrow:               return LEFTARROWKEY;
1683                         case GHOST_kKeyRightArrow:              return RIGHTARROWKEY;
1684                         case GHOST_kKeyUpArrow:                 return UPARROWKEY;
1685                         case GHOST_kKeyDownArrow:               return DOWNARROWKEY;
1686                                 
1687                         case GHOST_kKeyPrintScreen:             return 0;
1688                         case GHOST_kKeyPause:                   return PAUSEKEY;
1689                                 
1690                         case GHOST_kKeyInsert:                  return INSERTKEY;
1691                         case GHOST_kKeyDelete:                  return DELKEY;
1692                         case GHOST_kKeyHome:                    return HOMEKEY;
1693                         case GHOST_kKeyEnd:                             return ENDKEY;
1694                         case GHOST_kKeyUpPage:                  return PAGEUPKEY;
1695                         case GHOST_kKeyDownPage:                return PAGEDOWNKEY;
1696                                 
1697                         case GHOST_kKeyNumpadPeriod:    return PADPERIOD;
1698                         case GHOST_kKeyNumpadEnter:             return PADENTER;
1699                         case GHOST_kKeyNumpadPlus:              return PADPLUSKEY;
1700                         case GHOST_kKeyNumpadMinus:             return PADMINUS;
1701                         case GHOST_kKeyNumpadAsterisk:  return PADASTERKEY;
1702                         case GHOST_kKeyNumpadSlash:             return PADSLASHKEY;
1703                                 
1704                         case GHOST_kKeyGrLess:              return GRLESSKEY; 
1705                                 
1706                         default:
1707                                 return UNKNOWNKEY;      /* GHOST_kKeyUnknown */
1708                 }
1709         }
1710 }
1711
1712 /* adds customdata to event */
1713 static void update_tablet_data(wmWindow *win, wmEvent *event)
1714 {
1715         const GHOST_TabletData *td= GHOST_GetTabletData(win->ghostwin);
1716         
1717         /* if there's tablet data from an active tablet device then add it */
1718         if ((td != NULL) && td->Active != GHOST_kTabletModeNone) {
1719                 struct wmTabletData *wmtab= MEM_mallocN(sizeof(wmTabletData), "customdata tablet");
1720                 
1721                 wmtab->Active = (int)td->Active;
1722                 wmtab->Pressure = td->Pressure;
1723                 wmtab->Xtilt = td->Xtilt;
1724                 wmtab->Ytilt = td->Ytilt;
1725                 
1726                 event->custom= EVT_DATA_TABLET;
1727                 event->customdata= wmtab;
1728                 event->customdatafree= 1;
1729         } 
1730 }
1731
1732
1733 /* windows store own event queues, no bContext here */
1734 void wm_event_add_ghostevent(wmWindow *win, int type, void *customdata)
1735 {
1736         wmEvent event, *evt= win->eventstate;
1737         
1738         /* initialize and copy state (only mouse x y and modifiers) */
1739         event= *evt;
1740         
1741         switch (type) {
1742                 /* mouse move */
1743                 case GHOST_kEventCursorMove: {
1744                         if(win->active) {
1745                                 GHOST_TEventCursorData *cd= customdata;
1746 #if defined(__APPLE__) && defined(GHOST_COCOA)
1747                                 //Cocoa already uses coordinates with y=0 at bottom, and returns inwindow coordinates on mouse moved event
1748                                 event.type= MOUSEMOVE;
1749                                 event.x= evt->x = cd->x;
1750                                 event.y = evt->y = cd->y;
1751 #else
1752                                 int cx, cy;
1753                                 GHOST_ScreenToClient(win->ghostwin, cd->x, cd->y, &cx, &cy);
1754                                 event.type= MOUSEMOVE;
1755                                 event.x= evt->x= cx;
1756                                 event.y= evt->y= (win->sizey-1) - cy;
1757 #endif
1758                                 update_tablet_data(win, &event);
1759                                 wm_event_add(win, &event);
1760                         }
1761                         break;
1762                 }
1763                 case GHOST_kEventTrackpad: {
1764                         if (win->active) {
1765                                 GHOST_TEventTrackpadData * pd = customdata;
1766                                 switch (pd->subtype) {
1767                                         case GHOST_kTrackpadEventMagnify:
1768                                                 event.type = MOUSEZOOM;
1769                                                 break;
1770                                         case GHOST_kTrackpadEventRotate:
1771                                                 event.type = MOUSEROTATE;
1772                                                 break;
1773                                         case GHOST_kTrackpadEventScroll:
1774                                         default:
1775                                                 event.type= MOUSEPAN;
1776                                                 break;
1777                                 }
1778 #if defined(__APPLE__) && defined(GHOST_COCOA)
1779                                 //Cocoa already uses coordinates with y=0 at bottom, and returns inwindow coordinates on mouse moved event
1780                                 event.x= evt->x = pd->x;
1781                                 event.y = evt->y = pd->y;
1782 #else
1783                                 int cx, cy;
1784                                 GHOST_ScreenToClient(win->ghostwin, pd->x, pd->y, &cx, &cy);
1785                                 event.x= evt->x= cx;
1786                                 event.y= evt->y= (win->sizey-1) - cy;
1787 #endif
1788                                 // Use prevx/prevy so we can calculate the delta later
1789                                 event.prevx= event.x - pd->deltaX;
1790                                 event.prevy= event.y - pd->deltaY;
1791                                 
1792                                 update_tablet_data(win, &event);
1793                                 wm_event_add(win, &event);
1794                         }                       
1795                         break;
1796                 }
1797                 /* mouse button */
1798                 case GHOST_kEventButtonDown:
1799                 case GHOST_kEventButtonUp: {
1800                         GHOST_TEventButtonData *bd= customdata;
1801                         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 */
1802                         
1803                         if (bd->button == GHOST_kButtonMaskLeft)
1804                                 event.type= LEFTMOUSE;
1805                         else if (bd->button == GHOST_kButtonMaskRight)
1806                                 event.type= RIGHTMOUSE;
1807                         else if (bd->button == GHOST_kButtonMaskButton4)
1808                                 event.type= BUTTON4MOUSE;
1809                         else if (bd->button == GHOST_kButtonMaskButton5)
1810                                 event.type= BUTTON5MOUSE;
1811                         else
1812                                 event.type= MIDDLEMOUSE;
1813                         
1814                         update_tablet_data(win, &event);
1815                         wm_event_add(win, &event);
1816                         
1817                         break;
1818                 }
1819                 /* keyboard */
1820                 case GHOST_kEventKeyDown:
1821                 case GHOST_kEventKeyUp: {
1822                         GHOST_TEventKeyData *kd= customdata;
1823                         event.type= convert_key(kd->key);
1824                         event.ascii= kd->ascii;
1825                         event.val= (type==GHOST_kEventKeyDown)?KM_PRESS:KM_RELEASE;
1826                         
1827                         /* exclude arrow keys, esc, etc from text input */
1828                         if(type==GHOST_kEventKeyUp || (event.ascii<32 && event.ascii>0))
1829                                 event.ascii= '\0';
1830                         
1831                         /* modifiers */
1832                         if (event.type==LEFTSHIFTKEY || event.type==RIGHTSHIFTKEY) {
1833                                 event.shift= evt->shift= (event.val==KM_PRESS);
1834                                 if(event.val==KM_PRESS && (evt->ctrl || evt->alt || evt->oskey))
1835                                    event.shift= evt->shift = 3;         // define?
1836                         } 
1837                         else if (event.type==LEFTCTRLKEY || event.type==RIGHTCTRLKEY) {
1838                                 event.ctrl= evt->ctrl= (event.val==KM_PRESS);
1839                                 if(event.val==KM_PRESS && (evt->shift || evt->alt || evt->oskey))
1840                                    event.ctrl= evt->ctrl = 3;           // define?
1841                         } 
1842                         else if (event.type==LEFTALTKEY || event.type==RIGHTALTKEY) {
1843                                 event.alt= evt->alt= (event.val==KM_PRESS);
1844                                 if(event.val==KM_PRESS && (evt->ctrl || evt->shift || evt->oskey))
1845                                    event.alt= evt->alt = 3;             // define?
1846                         } 
1847                         else if (event.type==COMMANDKEY) {
1848                                 event.oskey= evt->oskey= (event.val==KM_PRESS);
1849                                 if(event.val==KM_PRESS && (evt->ctrl || evt->alt || evt->shift))
1850                                    event.oskey= evt->oskey = 3;         // define?
1851                         }
1852                         else {
1853                                 if(event.val==KM_PRESS && event.keymodifier==0)
1854                                         evt->keymodifier= event.type; /* only set in eventstate, for next event */
1855                                 else if(event.val==KM_RELEASE && event.keymodifier==event.type)
1856                                         event.keymodifier= evt->keymodifier= 0;
1857                         }
1858
1859                         /* this case happens on some systems that on holding a key pressed,
1860                            generate press events without release, we still want to keep the
1861                            modifier in win->eventstate, but for the press event of the same
1862                            key we don't want the key modifier */
1863                         if(event.keymodifier == event.type)
1864                                 event.keymodifier= 0;
1865                         
1866                         /* if test_break set, it catches this. XXX Keep global for now? */
1867                         if(event.type==ESCKEY)
1868                                 G.afbreek= 1;
1869
1870                         wm_event_add(win, &event);
1871                         
1872                         break;
1873                 }
1874                         
1875                 case GHOST_kEventWheel: {
1876                         GHOST_TEventWheelData* wheelData = customdata;
1877                         
1878                         if (wheelData->z > 0)
1879                                 event.type= WHEELUPMOUSE;
1880                         else
1881                                 event.type= WHEELDOWNMOUSE;
1882                         
1883                         event.val= KM_PRESS;
1884                         wm_event_add(win, &event);
1885                         
1886                         break;
1887                 }
1888                 case GHOST_kEventTimer: {
1889                         event.type= TIMER;
1890                         event.custom= EVT_DATA_TIMER;
1891                         event.customdata= customdata;
1892                         wm_event_add(win, &event);
1893
1894                         break;
1895                 }
1896
1897                 case GHOST_kEventUnknown:
1898                 case GHOST_kNumEventTypes:
1899                         break;
1900
1901                 case GHOST_kEventWindowDeactivate: {
1902                         event.type= WINDEACTIVATE;
1903                         wm_event_add(win, &event);
1904
1905                         break;
1906                 }
1907
1908         }
1909 }