2.5
[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., 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_windowmanager_types.h"
35 #include "DNA_userdef_types.h"  /* U.flag & TWOBUTTONMOUSE */
36
37 #include "MEM_guardedalloc.h"
38
39 #include "GHOST_C-api.h"
40
41 #include "BLI_blenlib.h"
42
43 #include "BKE_blender.h"
44 #include "BKE_context.h"
45 #include "BKE_idprop.h"
46 #include "BKE_global.h"
47 #include "BKE_report.h"
48 #include "BKE_utildefines.h"
49
50 #include "ED_screen.h"
51 #include "ED_space_api.h"
52 #include "ED_anim_api.h"
53
54 #include "RNA_access.h"
55
56 #include "UI_interface.h"
57
58 #include "WM_api.h"
59 #include "WM_types.h"
60 #include "wm.h"
61 #include "wm_window.h"
62 #include "wm_event_system.h"
63 #include "wm_event_types.h"
64
65 /* ************ event management ************** */
66
67 void wm_event_add(wmWindow *win, wmEvent *event_to_add)
68 {
69         wmEvent *event= MEM_callocN(sizeof(wmEvent), "event");
70         
71         *event= *event_to_add;
72         BLI_addtail(&win->queue, event);
73 }
74
75 wmEvent *wm_event_next(wmWindow *win)
76 {
77         wmEvent *event= win->queue.first;
78
79         if(event) BLI_remlink(&win->queue, event);
80         return event;
81 }
82
83 static void wm_event_free(wmEvent *event)
84 {
85         if(event->customdata && event->customdatafree)
86                 MEM_freeN(event->customdata);
87         MEM_freeN(event);
88 }
89
90 void wm_event_free_all(wmWindow *win)
91 {
92         wmEvent *event;
93         
94         while((event= win->queue.first)) {
95                 BLI_remlink(&win->queue, event);
96                 wm_event_free(event);
97         }
98 }
99
100 /* ********************* notifiers, listeners *************** */
101
102 /* XXX: in future, which notifiers to send to other windows? */
103 void WM_event_add_notifier(bContext *C, unsigned int type, void *reference)
104 {
105         wmNotifier *note= MEM_callocN(sizeof(wmNotifier), "notifier");
106         
107         note->wm= CTX_wm_manager(C);
108         BLI_addtail(&note->wm->queue, note);
109         
110         note->window= CTX_wm_window(C);
111         
112         if(CTX_wm_region(C))
113                 note->swinid= CTX_wm_region(C)->swinid;
114         
115         note->category= type & NOTE_CATEGORY;
116         note->data= type & NOTE_DATA;
117         note->subtype= type & NOTE_SUBTYPE;
118         note->action= type & NOTE_ACTION;
119         
120         note->reference= reference;
121 }
122
123 static wmNotifier *wm_notifier_next(wmWindowManager *wm)
124 {
125         wmNotifier *note= wm->queue.first;
126         
127         if(note) BLI_remlink(&wm->queue, note);
128         return note;
129 }
130
131 /* called in mainloop */
132 void wm_event_do_notifiers(bContext *C)
133 {
134         wmWindowManager *wm= CTX_wm_manager(C);
135         wmNotifier *note;
136         wmWindow *win;
137         
138         /* cache & catch WM level notifiers, such as frame change */
139         /* XXX todo, multiwindow scenes */
140         for(win= wm->windows.first; win; win= win->next) {
141                 int do_anim= 0;
142                 
143                 for(note= wm->queue.first; note; note= note->next) {
144                         if(note->window==win)
145                                 if(note->category==NC_SCENE)
146                                         if(note->data==ND_FRAME)
147                                                 do_anim= 1;
148                 }
149                 if(do_anim) {
150                         /* depsgraph gets called, might send more notifiers */
151                         CTX_wm_window_set(C, win);
152                         ED_update_for_newframe(C, 1);
153                 }
154         }
155         
156         /* the notifiers are sent without context, to keep it clean */
157         while( (note=wm_notifier_next(wm)) ) {
158                 wmWindow *win;
159                 
160                 for(win= wm->windows.first; win; win= win->next) {
161                         ScrArea *sa;
162                         ARegion *ar;
163
164                         /* XXX context in notifiers? */
165                         CTX_wm_window_set(C, win);
166
167                         /* printf("notifier win %d screen %s\n", win->winid, win->screen->id.name+2); */
168                         ED_screen_do_listen(win, note);
169
170                         for(ar=win->screen->regionbase.first; ar; ar= ar->next) {
171                                 ED_region_do_listen(ar, note);
172                         }
173                         
174                         for(sa= win->screen->areabase.first; sa; sa= sa->next) {
175                                 ED_area_do_listen(sa, note);
176                                 for(ar=sa->regionbase.first; ar; ar= ar->next) {
177                                         ED_region_do_listen(ar, note);
178                                 }
179                         }
180                 }
181                 
182                 CTX_wm_window_set(C, NULL);
183                 
184                 MEM_freeN(note);
185         }
186         
187         /* cached: editor refresh callbacks now, they get context */
188         for(win= wm->windows.first; win; win= win->next) {
189                 ScrArea *sa;
190                 CTX_wm_window_set(C, win);
191                 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
192                         if(sa->do_refresh) {
193                                 CTX_wm_area_set(C, sa);
194                                 ED_area_do_refresh(C, sa);
195                         }
196                 }
197                 CTX_wm_area_set(C, NULL);
198         }
199         CTX_wm_window_set(C, NULL);
200 }
201
202 /* ********************* drawing, swap ****************** */
203
204 static void wm_paintcursor_draw(bContext *C)
205 {
206         wmWindowManager *wm= CTX_wm_manager(C);
207         
208         if(wm->paintcursors.first) {
209                 wmWindow *win= CTX_wm_window(C);
210                 wmPaintCursor *pc;
211                 
212                 for(pc= wm->paintcursors.first; pc; pc= pc->next) {
213                         if(pc->poll(C)) {
214                                 ARegion *ar= CTX_wm_region(C);
215                                 pc->draw(C, win->eventstate->x - ar->winrct.xmin, win->eventstate->y - ar->winrct.ymin);
216                         }
217                 }
218         }
219 }
220
221 static void wm_window_swap_exchange(bContext *C, wmWindow *win)
222 {
223         ARegion *ar;
224         ScrArea *sa;
225         
226         if(win->screen->swap==WIN_FRONT_OK) {
227                 ED_screen_draw(win);
228                 win->screen->swap= WIN_EQUAL;
229         }
230         else if(win->screen->swap==WIN_BACK_OK) {
231                 win->screen->swap= WIN_FRONT_OK;
232         }
233         
234         for(sa= win->screen->areabase.first; sa; sa= sa->next) {
235                 
236                 CTX_wm_area_set(C, sa);
237                 
238                 for(ar=sa->regionbase.first; ar; ar= ar->next) {
239                         if(ar->swinid) {
240                                 if(ar->swap == WIN_BACK_OK) {
241                                         ar->swap = WIN_FRONT_OK;
242                                 }
243                                 else if(ar->swap == WIN_FRONT_OK) {
244                                         CTX_wm_region_set(C, ar);
245                                         
246                                         ED_region_do_draw(C, ar);
247                                         if(win->screen->subwinactive==ar->swinid)
248                                                 wm_paintcursor_draw(C);
249                                         
250                                         ar->swap = WIN_EQUAL;
251                                         
252                                         CTX_wm_region_set(C, NULL);
253                                         printf("draws swap exchange %d\n", ar->swinid);
254                                 }
255                         }
256                 }
257                 
258                 CTX_wm_area_set(C, NULL);
259         }
260         
261         wm_window_swap_buffers(win);
262 }
263
264 /* mark area-regions to redraw if overlapped with rect */
265 static void wm_flush_regions_down(bScreen *screen, rcti *dirty)
266 {
267         ScrArea *sa;
268         ARegion *ar;
269
270         for(sa= screen->areabase.first; sa; sa= sa->next)
271                 for(ar= sa->regionbase.first; ar; ar= ar->next)
272                         if(BLI_isect_rcti(dirty, &ar->winrct, NULL))
273                                 ar->do_draw= 1;
274 }
275
276 /* mark menu-regions to redraw if overlapped with rect */
277 static void wm_flush_regions_up(bScreen *screen, rcti *dirty)
278 {
279         ARegion *ar;
280         
281         for(ar= screen->regionbase.first; ar; ar= ar->next)
282                 if(BLI_isect_rcti(dirty, &ar->winrct, NULL))
283                         ar->do_draw= 1;
284 }
285
286
287 /* all the overlay management, menus, actionzones, region tabs, etc */
288 static void wm_flush_draw_update(bContext *C)
289 {
290         ScrArea *sa;
291         ARegion *ar;
292         bScreen *screen= CTX_wm_screen(C);
293         
294         if(screen->regionbase.first) {
295                 /* flush redraws of area-regions up to menus */
296                 for(sa= screen->areabase.first; sa; sa= sa->next)
297                         for(ar= sa->regionbase.first; ar; ar= ar->next)
298                                 if(ar->swinid && ar->do_draw)
299                                         wm_flush_regions_up(screen, &ar->winrct);
300                 
301                 /* flush overlapping menus */
302                 for(ar= screen->regionbase.last; ar; ar= ar->prev)
303                         if(ar->swinid && ar->do_draw)
304                                 wm_flush_regions_up(screen, &ar->winrct);
305                 
306                 
307                 /* flush redraws of menus down to areas */
308                 for(ar= screen->regionbase.last; ar; ar= ar->prev)
309                         if(ar->swinid && ar->do_draw)
310                                 wm_flush_regions_down(screen, &ar->winrct);
311         }       
312         
313         /* sets redraws for Azones, future region tabs, etc */
314         ED_area_overdraw_flush(C);
315 }
316
317 /* quick test to prevent changing window drawable */
318 static int wm_draw_update_test_window(wmWindow *win)
319 {
320         ScrArea *sa;
321         ARegion *ar;
322         
323         if(win->screen->do_refresh)
324                 return 1;
325         if(win->screen->do_draw)
326                 return 1;
327         if(win->screen->do_gesture)
328                 return 1;
329         
330         for(ar= win->screen->regionbase.first; ar; ar= ar->next)
331                 if(ar->swinid && ar->do_draw)
332                         return 1;
333                 
334         for(sa= win->screen->areabase.first; sa; sa= sa->next)
335                 for(ar=sa->regionbase.first; ar; ar= ar->next)
336                         if(ar->swinid && ar->do_draw)
337                                 return 1;
338
339         return 0;
340 }
341
342 void wm_draw_update(bContext *C)
343 {
344         wmWindowManager *wm= CTX_wm_manager(C);
345         wmWindow *win;
346         
347         for(win= wm->windows.first; win; win= win->next) {
348                 if(wm_draw_update_test_window(win)) {
349                         ScrArea *sa;
350                         ARegion *ar;
351
352                         CTX_wm_window_set(C, win);
353                         
354                         /* sets context window+screen */
355                         wm_window_make_drawable(C, win);
356                         
357                         /* notifiers for screen redraw */
358                         if(win->screen->do_refresh)
359                                 ED_screen_refresh(wm, win);
360                         
361                         /* flush draw updates for multiple layers */
362                         wm_flush_draw_update(C);
363
364                         for(sa= win->screen->areabase.first; sa; sa= sa->next) {
365                                 
366                                 CTX_wm_area_set(C, sa);
367                                 
368                                 for(ar=sa->regionbase.first; ar; ar= ar->next) {
369                                         
370                                         if(ar->swinid && ar->do_draw) {
371                                                 CTX_wm_region_set(C, ar);
372                                                 
373                                                 ED_region_do_draw(C, ar);
374                                                 if(win->screen->subwinactive==ar->swinid)
375                                                         wm_paintcursor_draw(C);
376                                                 
377                                                 CTX_wm_region_set(C, NULL);
378                                         }
379                                 }
380                                 
381                                 CTX_wm_area_set(C, NULL);
382                         }
383                         
384                         /* move this here so we can do area 'overlay' drawing */
385                         if(win->screen->do_draw)
386                                 ED_screen_draw(win);
387                         
388                         ED_area_overdraw(C);
389
390                         /* regions are menus here */
391                         for(ar=win->screen->regionbase.first; ar; ar= ar->next) {
392                                 CTX_wm_region_set(C, ar);
393                                 
394                                 if(ar->swinid && ar->do_draw)
395                                         ED_region_do_draw(C, ar);
396
397                                 CTX_wm_region_set(C, NULL);
398                         }
399                         
400                         if(win->screen->do_gesture)
401                                 wm_gesture_draw(win);
402
403                         if(G.f & G_SWAP_EXCHANGE)
404                                 wm_window_swap_exchange(C, win);
405                         else 
406                                 wm_window_swap_buffers(win);
407
408                         CTX_wm_window_set(C, NULL);
409                 }
410         }
411 }
412
413 /* ********************* operators ******************* */
414
415 static void WM_operator_print(wmOperator *op)
416 {
417         char *buf = WM_operator_pystring(op);
418         printf("%s\n", buf);
419         MEM_freeN(buf);
420 }
421
422 /* for running operators with frozen context (modal handlers, menus) */
423 int WM_operator_call(bContext *C, wmOperator *op)
424 {
425         int retval= OPERATOR_CANCELLED;
426         
427         if(op->type->exec)
428                 retval= op->type->exec(C, op);
429
430         if(!(retval & OPERATOR_RUNNING_MODAL))
431                 if(op->reports->list.first)
432                         uiPupmenuReports(C, op->reports);
433         
434         if((retval & OPERATOR_FINISHED) && (op->type->flag & OPTYPE_REGISTER)) {
435                 wm_operator_register(CTX_wm_manager(C), op);
436         }
437         else
438                 WM_operator_free(op);
439
440         return retval;
441 }
442
443 static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, PointerRNA *properties, ReportList *reports)
444 {
445         wmWindowManager *wm= CTX_wm_manager(C);
446         int retval= OPERATOR_PASS_THROUGH;
447
448         if(ot->poll==NULL || ot->poll(C)) {
449                 wmOperator *op= MEM_callocN(sizeof(wmOperator), ot->idname);    /* XXX operatortype names are static still. for debug */
450
451                 /* XXX adding new operator could be function, only happens here now */
452                 op->type= ot;
453                 BLI_strncpy(op->idname, ot->idname, OP_MAX_TYPENAME);
454                 
455                 /* initialize properties, either copy or create */
456                 op->ptr= MEM_callocN(sizeof(PointerRNA), "wmOperatorPtrRNA");
457                 if(properties && properties->data) {
458                         op->properties= IDP_CopyProperty(properties->data);
459                 }
460                 else {
461                         IDPropertyTemplate val = {0};
462                         op->properties= IDP_New(IDP_GROUP, val, "wmOperatorProperties");
463                 }
464                 RNA_pointer_create(&wm->id, ot->srna, op->properties, op->ptr);
465
466                 /* initialize error reports */
467                 if (reports) {
468                         op->reports= reports; /* must be initialized alredy */
469                 }
470                 else {
471                         op->reports= MEM_mallocN(sizeof(ReportList), "wmOperatorReportList");
472                         BKE_reports_init(op->reports, RPT_STORE);
473                 }
474
475                 if(op->type->invoke && event)
476                         retval= (*op->type->invoke)(C, op, event);
477                 else if(op->type->exec)
478                         retval= op->type->exec(C, op);
479                 else
480                         printf("invalid operator call %s\n", ot->idname); /* debug, important to leave a while, should never happen */
481
482                 if(G.f & G_DEBUG)
483                         WM_operator_print(op);
484
485                 if(!(retval & OPERATOR_RUNNING_MODAL))
486                         if(reports==NULL && op->reports->list.first) /* only show the report if the report list was not given in the function */
487                                 uiPupmenuReports(C, op->reports);
488
489                 if((retval & OPERATOR_FINISHED) && (ot->flag & OPTYPE_REGISTER)) {
490                         wm_operator_register(wm, op);
491                 }
492                 else if(!(retval & OPERATOR_RUNNING_MODAL)) {
493                         if (reports)
494                                 op->reports= NULL; /* dont let the operator free reports passed to this function */
495                         WM_operator_free(op);
496                 }
497         }
498
499         return retval;
500 }
501
502 /* invokes operator in context */
503 int WM_operator_name_call(bContext *C, const char *opstring, int context, PointerRNA *properties, ReportList *reports)
504 {
505         wmOperatorType *ot= WM_operatortype_find(opstring);
506         wmWindow *window= CTX_wm_window(C);
507         wmEvent *event;
508         
509         int retval;
510
511         /* dummie test */
512         if(ot && C && window) {
513                 event= window->eventstate;
514                 switch(context) {
515                         
516                         case WM_OP_EXEC_REGION_WIN:
517                                 event= NULL;    /* pass on without break */
518                         case WM_OP_INVOKE_REGION_WIN: 
519                         {
520                                 /* forces operator to go to the region window, for header menus */
521                                 ARegion *ar= CTX_wm_region(C);
522                                 ScrArea *area= CTX_wm_area(C);
523                                 
524                                 if(area) {
525                                         ARegion *ar1= area->regionbase.first;
526                                         for(; ar1; ar1= ar1->next)
527                                                 if(ar1->regiontype==RGN_TYPE_WINDOW)
528                                                         break;
529                                         if(ar1)
530                                                 CTX_wm_region_set(C, ar1);
531                                 }
532                                 
533                                 retval= wm_operator_invoke(C, ot, event, properties, reports);
534                                 
535                                 /* set region back */
536                                 CTX_wm_region_set(C, ar);
537                                 
538                                 return retval;
539                         }
540                         case WM_OP_EXEC_AREA:
541                                 event= NULL;    /* pass on without break */
542                         case WM_OP_INVOKE_AREA:
543                         {
544                                         /* remove region from context */
545                                 ARegion *ar= CTX_wm_region(C);
546
547                                 CTX_wm_region_set(C, NULL);
548                                 retval= wm_operator_invoke(C, ot, event, properties, reports);
549                                 CTX_wm_region_set(C, ar);
550
551                                 return retval;
552                         }
553                         case WM_OP_EXEC_SCREEN:
554                                 event= NULL;    /* pass on without break */
555                         case WM_OP_INVOKE_SCREEN:
556                         {
557                                 /* remove region + area from context */
558                                 ARegion *ar= CTX_wm_region(C);
559                                 ScrArea *area= CTX_wm_area(C);
560
561                                 CTX_wm_region_set(C, NULL);
562                                 CTX_wm_area_set(C, NULL);
563                                 retval= wm_operator_invoke(C, ot, window->eventstate, properties, reports);
564                                 CTX_wm_region_set(C, ar);
565                                 CTX_wm_area_set(C, area);
566
567                                 return retval;
568                         }
569                         case WM_OP_EXEC_DEFAULT:
570                                 event= NULL;    /* pass on without break */
571                         case WM_OP_INVOKE_DEFAULT:
572                                 return wm_operator_invoke(C, ot, event, properties, reports);
573                 }
574         }
575         
576         return 0;
577 }
578
579 /* ********************* handlers *************** */
580
581 /* not handler itself, is called by UI to move handlers to other queues, so don't close modal ones */
582 static void wm_event_free_handler(wmEventHandler *handler)
583 {
584         
585 }
586
587 /* called on exit or remove area, only here call cancel callback */
588 void WM_event_remove_handlers(bContext *C, ListBase *handlers)
589 {
590         wmEventHandler *handler;
591         
592         /* C is zero on freeing database, modal handlers then already were freed */
593         while((handler=handlers->first)) {
594                 BLI_remlink(handlers, handler);
595                 
596                 if(handler->op) {
597                         if(handler->op->type->cancel) {
598                                 ScrArea *area= CTX_wm_area(C);
599                                 ARegion *region= CTX_wm_region(C);
600                                 
601                                 CTX_wm_area_set(C, handler->op_area);
602                                 CTX_wm_region_set(C, handler->op_region);
603
604                                 handler->op->type->cancel(C, handler->op);
605
606                                 CTX_wm_area_set(C, area);
607                                 CTX_wm_region_set(C, region);
608                         }
609
610                         WM_operator_free(handler->op);
611                 }
612                 else if(handler->ui_remove) {
613                         ScrArea *area= CTX_wm_area(C);
614                         ARegion *region= CTX_wm_region(C);
615                         
616                         if(handler->ui_area) CTX_wm_area_set(C, handler->ui_area);
617                         if(handler->ui_region) CTX_wm_region_set(C, handler->ui_region);
618
619                         handler->ui_remove(C, handler->ui_userdata);
620
621                         CTX_wm_area_set(C, area);
622                         CTX_wm_region_set(C, region);
623                 }
624
625                 wm_event_free_handler(handler);
626                 MEM_freeN(handler);
627         }
628 }
629
630 /* do userdef mappings */
631 static int wm_userdef_event_map(int kmitype)
632 {
633         switch(kmitype) {
634                 case SELECTMOUSE:
635                         if(U.flag & USER_LMOUSESELECT)
636                                 return LEFTMOUSE;
637                         else
638                                 return RIGHTMOUSE;
639                         
640                 case ACTIONMOUSE:
641                         if(U.flag & USER_LMOUSESELECT)
642                                 return RIGHTMOUSE;
643                         else
644                                 return LEFTMOUSE;
645                         
646                 case WHEELOUTMOUSE:
647                         if(U.uiflag & USER_WHEELZOOMDIR)
648                                 return WHEELUPMOUSE;
649                         else
650                                 return WHEELDOWNMOUSE;
651                         
652                 case WHEELINMOUSE:
653                         if(U.uiflag & USER_WHEELZOOMDIR)
654                                 return WHEELDOWNMOUSE;
655                         else
656                                 return WHEELUPMOUSE;
657                         
658                 case EVT_TWEAK_A:
659                         if(U.flag & USER_LMOUSESELECT)
660                                 return EVT_TWEAK_R;
661                         else
662                                 return EVT_TWEAK_L;
663                         
664                 case EVT_TWEAK_S:
665                         if(U.flag & USER_LMOUSESELECT)
666                                 return EVT_TWEAK_L;
667                         else
668                                 return EVT_TWEAK_R;
669         }
670         
671         return kmitype;
672 }
673
674 static int wm_eventmatch(wmEvent *winevent, wmKeymapItem *kmi)
675 {
676         int kmitype= wm_userdef_event_map(kmi->type);
677         
678         /* the matching rules */
679         if(winevent->type!=kmitype) return 0;
680         
681         if(kmi->val!=KM_ANY)
682                 if(winevent->val!=kmi->val) return 0;
683         if(kmi->shift!=KM_ANY)
684                 if(winevent->shift!=kmi->shift) return 0;
685         if(kmi->ctrl!=KM_ANY)
686                 if(winevent->ctrl!=kmi->ctrl) return 0;
687         if(kmi->alt!=KM_ANY)
688                 if(winevent->alt!=kmi->alt) return 0;
689         if(kmi->oskey!=KM_ANY)
690                 if(winevent->oskey!=kmi->oskey) return 0;
691         if(kmi->keymodifier)
692                 if(winevent->keymodifier!=kmi->keymodifier) return 0;
693         
694         
695         return 1;
696 }
697
698 static int wm_event_always_pass(wmEvent *event)
699 {
700         /* some events we always pass on, to ensure proper communication */
701         return ELEM4(event->type, TIMER, TIMER0, TIMER1, TIMER2);
702 }
703
704 /* Warning: this function removes a modal handler, when finished */
705 static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHandler *handler, wmEvent *event, PointerRNA *properties)
706 {
707         int retval= OPERATOR_PASS_THROUGH;
708         
709         /* derived, modal or blocking operator */
710         if(handler->op) {
711                 wmOperator *op= handler->op;
712                 wmOperatorType *ot= op->type;
713
714                 if(ot->modal) {
715                         /* we set context to where modal handler came from */
716                         ScrArea *area= CTX_wm_area(C);
717                         ARegion *region= CTX_wm_region(C);
718                         
719                         CTX_wm_area_set(C, handler->op_area);
720                         CTX_wm_region_set(C, handler->op_region);
721                         
722                         retval= ot->modal(C, op, event);
723
724                         /* putting back screen context */
725                         if((retval & OPERATOR_PASS_THROUGH) || wm_event_always_pass(event)) {
726                                 CTX_wm_area_set(C, area);
727                                 CTX_wm_region_set(C, region);
728                         }
729                         else {
730                                 /* this special cases is for areas and regions that get removed */
731                                 CTX_wm_area_set(C, NULL);
732                                 CTX_wm_region_set(C, NULL);
733                         }
734
735                         if(!(retval & OPERATOR_RUNNING_MODAL))
736                                 if(op->reports->list.first)
737                                         uiPupmenuReports(C, op->reports);
738                         
739                         if((retval & OPERATOR_FINISHED) && (ot->flag & OPTYPE_REGISTER)) {
740                                 wm_operator_register(CTX_wm_manager(C), op);
741                                 handler->op= NULL;
742                         }
743                         else if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) {
744                                 WM_operator_free(op);
745                                 handler->op= NULL;
746                         }
747                         
748                         /* remove modal handler, operator itself should have been cancelled and freed */
749                         if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) {
750                                 BLI_remlink(handlers, handler);
751                                 wm_event_free_handler(handler);
752                                 MEM_freeN(handler);
753                                 
754                                 /* prevent silly errors from operator users */
755                                 retval &= ~OPERATOR_PASS_THROUGH;
756                         }
757                         
758                 }
759                 else
760                         printf("wm_handler_operator_call error\n");
761         }
762         else {
763                 wmOperatorType *ot= WM_operatortype_find(event->keymap_idname);
764
765                 if(ot)
766                         retval= wm_operator_invoke(C, ot, event, properties, NULL);
767         }
768
769         if(retval & OPERATOR_PASS_THROUGH)
770                 return WM_HANDLER_CONTINUE;
771
772         return WM_HANDLER_BREAK;
773 }
774
775 static int wm_handler_ui_call(bContext *C, wmEventHandler *handler, wmEvent *event)
776 {
777         ScrArea *area= CTX_wm_area(C);
778         ARegion *region= CTX_wm_region(C);
779         int retval;
780                         
781         /* we set context to where ui handler came from */
782         if(handler->ui_area) CTX_wm_area_set(C, handler->ui_area);
783         if(handler->ui_region) CTX_wm_region_set(C, handler->ui_region);
784
785         retval= handler->ui_handle(C, event, handler->ui_userdata);
786
787         /* putting back screen context */
788         if((retval != WM_UI_HANDLER_BREAK) || wm_event_always_pass(event)) {
789                 CTX_wm_area_set(C, area);
790                 CTX_wm_region_set(C, region);
791         }
792         else {
793                 /* this special cases is for areas and regions that get removed */
794                 CTX_wm_area_set(C, NULL);
795                 CTX_wm_region_set(C, NULL);
796         }
797
798         if(retval == WM_UI_HANDLER_BREAK)
799                 return WM_HANDLER_BREAK;
800
801         return WM_HANDLER_CONTINUE;
802 }
803
804 static int handler_boundbox_test(wmEventHandler *handler, wmEvent *event)
805 {
806         if(handler->bbwin) {
807                 if(handler->bblocal) {
808                         rcti rect= *handler->bblocal;
809                         BLI_translate_rcti(&rect, handler->bbwin->xmin, handler->bbwin->ymin);
810                         return BLI_in_rcti(&rect, event->x, event->y);
811                 }
812                 else 
813                         return BLI_in_rcti(handler->bbwin, event->x, event->y);
814         }
815         return 1;
816 }
817
818 static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
819 {
820         wmEventHandler *handler, *nexthandler;
821         int action= WM_HANDLER_CONTINUE;
822
823         if(handlers==NULL) return action;
824         
825         /* modal handlers can get removed in this loop, we keep the loop this way */
826         for(handler= handlers->first; handler; handler= nexthandler) {
827                 nexthandler= handler->next;
828
829                 /* optional boundbox */
830                 if(handler_boundbox_test(handler, event)) {
831                 
832                         /* modal+blocking handler */
833                         if(handler->flag & WM_HANDLER_BLOCKING)
834                                 action= WM_HANDLER_BREAK;
835
836                         if(handler->keymap) {
837                                 wmKeymapItem *kmi;
838                                 
839                                 for(kmi= handler->keymap->first; kmi; kmi= kmi->next) {
840                                         if(wm_eventmatch(event, kmi)) {
841                                                 if((G.f & G_DEBUG) && event->type!=MOUSEMOVE)
842                                                         printf("handle evt %d win %d op %s\n", event->type, CTX_wm_screen(C)->subwinactive, kmi->idname); 
843                                                 
844                                                 event->keymap_idname= kmi->idname;      /* weak, but allows interactive callback to not use rawkey */
845                                                 
846                                                 action= wm_handler_operator_call(C, handlers, handler, event, kmi->ptr);
847                                                 if(action==WM_HANDLER_BREAK)  /* not wm_event_always_pass(event) here, it denotes removed handler */
848                                                         break;
849                                         }
850                                 }
851                         }
852                         else if(handler->ui_handle) {
853                                 action= wm_handler_ui_call(C, handler, event);
854                         }
855                         else {
856                                 /* modal, swallows all */
857                                 action= wm_handler_operator_call(C, handlers, handler, event, NULL);
858                         }
859
860                         if(!wm_event_always_pass(event) && action==WM_HANDLER_BREAK)
861                                 break;
862                 }
863                 
864         }
865         return action;
866 }
867
868 static int wm_event_inside_i(wmEvent *event, rcti *rect)
869 {
870         if(BLI_in_rcti(rect, event->x, event->y))
871            return 1;
872         if(event->type==MOUSEMOVE) {
873                 if( BLI_in_rcti(rect, event->prevx, event->prevy)) {
874                         return 1;
875                 }
876                 return 0;
877         }
878         return 0;
879 }
880
881 static ScrArea *area_event_inside(bContext *C, int x, int y)
882 {
883         bScreen *screen= CTX_wm_screen(C);
884         ScrArea *sa;
885         
886         if(screen)
887                 for(sa= screen->areabase.first; sa; sa= sa->next)
888                         if(BLI_in_rcti(&sa->totrct, x, y))
889                                 return sa;
890         return NULL;
891 }
892
893 static ARegion *region_event_inside(bContext *C, int x, int y)
894 {
895         bScreen *screen= CTX_wm_screen(C);
896         ScrArea *area= CTX_wm_area(C);
897         ARegion *ar;
898         
899         if(screen && area)
900                 for(ar= area->regionbase.first; ar; ar= ar->next)
901                         if(BLI_in_rcti(&ar->winrct, x, y))
902                                 return ar;
903         return NULL;
904 }
905
906 static void wm_paintcursor_tag(bContext *C, wmPaintCursor *pc, ARegion *ar)
907 {
908         if(ar)
909                 for(; pc; pc= pc->next) 
910                         if(pc->poll(C))
911                                 ED_region_tag_redraw(ar);
912 }
913
914 /* called on mousemove, check updates for paintcursors */
915 /* context was set on active area and region */
916 static void wm_paintcursor_test(bContext *C, wmEvent *event)
917 {
918         wmWindowManager *wm= CTX_wm_manager(C);
919         
920         if(wm->paintcursors.first) {
921                 ARegion *ar= CTX_wm_region(C);
922                 if(ar)
923                         wm_paintcursor_tag(C, wm->paintcursors.first, ar);
924                 
925                 /* if previous position was not in current region, we have to set a temp new context */
926                 if(ar==NULL || !BLI_in_rcti(&ar->winrct, event->prevx, event->prevy)) {
927                         ScrArea *sa= CTX_wm_area(C);
928                         
929                         CTX_wm_area_set(C, area_event_inside(C, event->prevx, event->prevy));
930                         CTX_wm_region_set(C, region_event_inside(C, event->prevx, event->prevy));
931
932                         wm_paintcursor_tag(C, wm->paintcursors.first, CTX_wm_region(C));
933                         
934                         CTX_wm_area_set(C, sa);
935                         CTX_wm_region_set(C, ar);
936                 }
937         }
938 }
939
940 /* called in main loop */
941 /* goes over entire hierarchy:  events -> window -> screen -> area -> region */
942 void wm_event_do_handlers(bContext *C)
943 {
944         wmWindow *win;
945
946         for(win= CTX_wm_manager(C)->windows.first; win; win= win->next) {
947                 wmEvent *event;
948                 
949                 if( win->screen==NULL )
950                         wm_event_free_all(win);
951                 
952                 while( (event=wm_event_next(win)) ) {
953                         int action;
954
955                         CTX_wm_window_set(C, win);
956                         /* we let modal handlers get active area/region, also wm_paintcursor_test needs it */
957                         CTX_wm_area_set(C, area_event_inside(C, event->x, event->y));
958                         CTX_wm_region_set(C, region_event_inside(C, event->x, event->y));
959                         
960                         /* MVC demands to not draw in event handlers... but we need to leave it for ogl selecting etc */
961                         wm_window_make_drawable(C, win);
962                         
963                         action= wm_handlers_do(C, event, &win->handlers);
964                         
965                         if(wm_event_always_pass(event) || action==WM_HANDLER_CONTINUE) {
966                                 ScrArea *sa;
967                                 ARegion *ar;
968                                 int doit= 0;
969                                 
970                                 /* XXX to solve, here screen handlers? */
971                                 if(event->type==MOUSEMOVE) {
972                                         ED_screen_set_subwinactive(win, event); /* state variables in screen, cursors */
973                                         wm_paintcursor_test(C, event);
974                                 }
975                                 
976                                 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
977                                         if(wm_event_always_pass(event) || wm_event_inside_i(event, &sa->totrct)) {
978                                                 
979                                                 CTX_wm_area_set(C, sa);
980                                                 CTX_wm_region_set(C, NULL);
981                                                 action= wm_handlers_do(C, event, &sa->handlers);
982
983                                                 if(wm_event_always_pass(event) || action==WM_HANDLER_CONTINUE) {
984                                                         for(ar=sa->regionbase.first; ar; ar= ar->next) {
985                                                                 if(wm_event_always_pass(event) || wm_event_inside_i(event, &ar->winrct)) {
986                                                                         CTX_wm_region_set(C, ar);
987                                                                         action= wm_handlers_do(C, event, &ar->handlers);
988
989                                                                         doit |= (BLI_in_rcti(&ar->winrct, event->x, event->y));
990                                                                         
991                                                                         if(!wm_event_always_pass(event)) {
992                                                                                 if(action==WM_HANDLER_BREAK)
993                                                                                         break;
994                                                                         }
995                                                                 }
996                                                         }
997                                                 }
998                                                 /* NOTE: do not escape on WM_HANDLER_BREAK, mousemove needs handled for previous area */
999                                         }
1000                                 }
1001                                 /* XXX hrmf, this gives reliable previous mouse coord for area change, feels bad? 
1002                                    doing it on ghost queue gives errors when mousemoves go over area borders */
1003                                 if(doit && win->screen->subwinactive != win->screen->mainwin) {
1004                                         win->eventstate->prevx= event->x;
1005                                         win->eventstate->prevy= event->y;
1006                                 }
1007                         }
1008                         wm_event_free(event);
1009                         
1010                         CTX_wm_window_set(C, NULL);
1011                         CTX_wm_area_set(C, NULL);
1012                         CTX_wm_region_set(C, NULL);
1013                 }
1014         }
1015 }
1016
1017 /* lets not expose struct outside wm? */
1018 void WM_event_set_handler_flag(wmEventHandler *handler, int flag)
1019 {
1020         handler->flag= flag;
1021 }
1022
1023 wmEventHandler *WM_event_add_modal_handler(bContext *C, ListBase *handlers, wmOperator *op)
1024 {
1025         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event modal handler");
1026         handler->op= op;
1027         handler->op_area= CTX_wm_area(C);               /* means frozen screen context for modal handlers! */
1028         handler->op_region= CTX_wm_region(C);
1029         
1030         BLI_addhead(handlers, handler);
1031
1032         return handler;
1033 }
1034
1035 wmEventHandler *WM_event_add_keymap_handler(ListBase *handlers, ListBase *keymap)
1036 {
1037         wmEventHandler *handler;
1038         
1039         /* only allow same keymap once */
1040         for(handler= handlers->first; handler; handler= handler->next)
1041                 if(handler->keymap==keymap)
1042                         return handler;
1043
1044         handler= MEM_callocN(sizeof(wmEventHandler), "event keymap handler");
1045         BLI_addtail(handlers, handler);
1046         handler->keymap= keymap;
1047
1048         return handler;
1049 }
1050
1051 wmEventHandler *WM_event_add_keymap_handler_bb(ListBase *handlers, ListBase *keymap, rcti *bblocal, rcti *bbwin)
1052 {
1053         wmEventHandler *handler= WM_event_add_keymap_handler(handlers, keymap);
1054         handler->bblocal= bblocal;
1055         handler->bbwin= bbwin;
1056         
1057         return handler;
1058 }
1059
1060 void WM_event_remove_keymap_handler(ListBase *handlers, ListBase *keymap)
1061 {
1062         wmEventHandler *handler;
1063         
1064         for(handler= handlers->first; handler; handler= handler->next) {
1065                 if(handler->keymap==keymap) {
1066                         BLI_remlink(handlers, handler);
1067                         wm_event_free_handler(handler);
1068                         MEM_freeN(handler);
1069                         break;
1070                 }
1071         }
1072 }
1073
1074 wmEventHandler *WM_event_add_ui_handler(bContext *C, ListBase *handlers, wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata)
1075 {
1076         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event ui handler");
1077         handler->ui_handle= func;
1078         handler->ui_remove= remove;
1079         handler->ui_userdata= userdata;
1080         handler->ui_area= (C)? CTX_wm_area(C): NULL;
1081         handler->ui_region= (C)? CTX_wm_region(C): NULL;
1082         
1083         BLI_addhead(handlers, handler);
1084         
1085         return handler;
1086 }
1087
1088 void WM_event_remove_ui_handler(ListBase *handlers, wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata)
1089 {
1090         wmEventHandler *handler;
1091         
1092         for(handler= handlers->first; handler; handler= handler->next) {
1093                 if(handler->ui_handle == func && handler->ui_remove == remove && handler->ui_userdata == userdata) {
1094                         BLI_remlink(handlers, handler);
1095                         wm_event_free_handler(handler);
1096                         MEM_freeN(handler);
1097                         break;
1098                 }
1099         }
1100 }
1101
1102 void WM_event_add_mousemove(bContext *C)
1103 {
1104         wmWindow *window= CTX_wm_window(C);
1105         wmEvent event= *(window->eventstate);
1106         event.type= MOUSEMOVE;
1107         event.prevx= event.x;
1108         event.prevy= event.y;
1109         wm_event_add(window, &event);
1110 }
1111
1112 /* for modal callbacks, check configuration for how to interpret exit with tweaks  */
1113 int WM_modal_tweak_exit(wmEvent *evt, int tweak_event)
1114 {
1115         /* user preset?? dunno... */
1116         int tweak_modal= 1;
1117         
1118         switch(tweak_event) {
1119                 case EVT_TWEAK_L:
1120                 case EVT_TWEAK_M:
1121                 case EVT_TWEAK_R:
1122                         if(evt->val==tweak_modal)
1123                                 return 1;
1124                 default:
1125                         /* this case is when modal callcback didnt get started with a tweak */
1126                         if(evt->val)
1127                                 return 1;
1128         }
1129         return 0;
1130 }
1131
1132
1133 /* ********************* ghost stuff *************** */
1134
1135 static int convert_key(GHOST_TKey key) 
1136 {
1137         if (key>=GHOST_kKeyA && key<=GHOST_kKeyZ) {
1138                 return (AKEY + ((int) key - GHOST_kKeyA));
1139         } else if (key>=GHOST_kKey0 && key<=GHOST_kKey9) {
1140                 return (ZEROKEY + ((int) key - GHOST_kKey0));
1141         } else if (key>=GHOST_kKeyNumpad0 && key<=GHOST_kKeyNumpad9) {
1142                 return (PAD0 + ((int) key - GHOST_kKeyNumpad0));
1143         } else if (key>=GHOST_kKeyF1 && key<=GHOST_kKeyF12) {
1144                 return (F1KEY + ((int) key - GHOST_kKeyF1));
1145         } else {
1146                 switch (key) {
1147                         case GHOST_kKeyBackSpace:               return BACKSPACEKEY;
1148                         case GHOST_kKeyTab:                             return TABKEY;
1149                         case GHOST_kKeyLinefeed:                return LINEFEEDKEY;
1150                         case GHOST_kKeyClear:                   return 0;
1151                         case GHOST_kKeyEnter:                   return RETKEY;
1152                                 
1153                         case GHOST_kKeyEsc:                             return ESCKEY;
1154                         case GHOST_kKeySpace:                   return SPACEKEY;
1155                         case GHOST_kKeyQuote:                   return QUOTEKEY;
1156                         case GHOST_kKeyComma:                   return COMMAKEY;
1157                         case GHOST_kKeyMinus:                   return MINUSKEY;
1158                         case GHOST_kKeyPeriod:                  return PERIODKEY;
1159                         case GHOST_kKeySlash:                   return SLASHKEY;
1160                                 
1161                         case GHOST_kKeySemicolon:               return SEMICOLONKEY;
1162                         case GHOST_kKeyEqual:                   return EQUALKEY;
1163                                 
1164                         case GHOST_kKeyLeftBracket:             return LEFTBRACKETKEY;
1165                         case GHOST_kKeyRightBracket:    return RIGHTBRACKETKEY;
1166                         case GHOST_kKeyBackslash:               return BACKSLASHKEY;
1167                         case GHOST_kKeyAccentGrave:             return ACCENTGRAVEKEY;
1168                                 
1169                         case GHOST_kKeyLeftShift:               return LEFTSHIFTKEY;
1170                         case GHOST_kKeyRightShift:              return RIGHTSHIFTKEY;
1171                         case GHOST_kKeyLeftControl:             return LEFTCTRLKEY;
1172                         case GHOST_kKeyRightControl:    return RIGHTCTRLKEY;
1173                         case GHOST_kKeyCommand:                 return COMMANDKEY;
1174                         case GHOST_kKeyLeftAlt:                 return LEFTALTKEY;
1175                         case GHOST_kKeyRightAlt:                return RIGHTALTKEY;
1176                                 
1177                         case GHOST_kKeyCapsLock:                return CAPSLOCKKEY;
1178                         case GHOST_kKeyNumLock:                 return 0;
1179                         case GHOST_kKeyScrollLock:              return 0;
1180                                 
1181                         case GHOST_kKeyLeftArrow:               return LEFTARROWKEY;
1182                         case GHOST_kKeyRightArrow:              return RIGHTARROWKEY;
1183                         case GHOST_kKeyUpArrow:                 return UPARROWKEY;
1184                         case GHOST_kKeyDownArrow:               return DOWNARROWKEY;
1185                                 
1186                         case GHOST_kKeyPrintScreen:             return 0;
1187                         case GHOST_kKeyPause:                   return PAUSEKEY;
1188                                 
1189                         case GHOST_kKeyInsert:                  return INSERTKEY;
1190                         case GHOST_kKeyDelete:                  return DELKEY;
1191                         case GHOST_kKeyHome:                    return HOMEKEY;
1192                         case GHOST_kKeyEnd:                             return ENDKEY;
1193                         case GHOST_kKeyUpPage:                  return PAGEUPKEY;
1194                         case GHOST_kKeyDownPage:                return PAGEDOWNKEY;
1195                                 
1196                         case GHOST_kKeyNumpadPeriod:    return PADPERIOD;
1197                         case GHOST_kKeyNumpadEnter:             return PADENTER;
1198                         case GHOST_kKeyNumpadPlus:              return PADPLUSKEY;
1199                         case GHOST_kKeyNumpadMinus:             return PADMINUS;
1200                         case GHOST_kKeyNumpadAsterisk:  return PADASTERKEY;
1201                         case GHOST_kKeyNumpadSlash:             return PADSLASHKEY;
1202                                 
1203                         case GHOST_kKeyGrLess:              return GRLESSKEY; 
1204                                 
1205                         default:
1206                                 return UNKNOWNKEY;      /* GHOST_kKeyUnknown */
1207                 }
1208         }
1209 }
1210
1211 /* adds customdata to event */
1212 static void update_tablet_data(wmWindow *win, wmEvent *event)
1213 {
1214         const GHOST_TabletData *td= GHOST_GetTabletData(win->ghostwin);
1215         
1216         /* if there's tablet data from an active tablet device then add it */
1217         if ((td != NULL) && td->Active) {
1218                 struct wmTabletData *wmtab= MEM_mallocN(sizeof(wmTabletData), "customdata tablet");
1219                 
1220                 wmtab->Active = td->Active;
1221                 wmtab->Pressure = td->Pressure;
1222                 wmtab->Xtilt = td->Xtilt;
1223                 wmtab->Ytilt = td->Ytilt;
1224                 
1225                 event->custom= EVT_DATA_TABLET;
1226                 event->customdata= wmtab;
1227                 event->customdatafree= 1;
1228         } 
1229 }
1230
1231
1232 /* windows store own event queues, no bContext here */
1233 void wm_event_add_ghostevent(wmWindow *win, int type, void *customdata)
1234 {
1235         wmEvent event, *evt= win->eventstate;
1236         
1237         /* initialize and copy state (only mouse x y and modifiers) */
1238         event= *evt;
1239         
1240         switch (type) {
1241                 /* mouse move */
1242                 case GHOST_kEventCursorMove: {
1243                         if(win->active) {
1244                                 GHOST_TEventCursorData *cd= customdata;
1245                                 int cx, cy;
1246
1247                                 GHOST_ScreenToClient(win->ghostwin, cd->x, cd->y, &cx, &cy);
1248                                 
1249                                 event.type= MOUSEMOVE;
1250                                 event.x= evt->x= cx;
1251                                 event.y= evt->y= (win->sizey-1) - cy;
1252                                 
1253                                 update_tablet_data(win, &event);
1254                                 wm_event_add(win, &event);
1255                         }
1256                         break;
1257                 }
1258                 /* mouse button */
1259                 case GHOST_kEventButtonDown:
1260                 case GHOST_kEventButtonUp: {
1261                         GHOST_TEventButtonData *bd= customdata;
1262                         event.val= (type==GHOST_kEventButtonDown);
1263                         
1264                         if (bd->button == GHOST_kButtonMaskLeft)
1265                                 event.type= LEFTMOUSE;
1266                         else if (bd->button == GHOST_kButtonMaskRight)
1267                                 event.type= RIGHTMOUSE;
1268                         else
1269                                 event.type= MIDDLEMOUSE;
1270                         
1271                         if(event.val)
1272                                 event.keymodifier= evt->keymodifier= event.type;
1273                         else
1274                                 event.keymodifier= evt->keymodifier= 0;
1275                         
1276                         update_tablet_data(win, &event);
1277                         wm_event_add(win, &event);
1278                         
1279                         break;
1280                 }
1281                 /* keyboard */
1282                 case GHOST_kEventKeyDown:
1283                 case GHOST_kEventKeyUp: {
1284                         GHOST_TEventKeyData *kd= customdata;
1285                         event.type= convert_key(kd->key);
1286                         event.ascii= kd->ascii;
1287                         event.val= (type==GHOST_kEventKeyDown); /* XXX eventmatch uses defines, bad code... */
1288                         
1289                         /* modifiers */
1290                         if (event.type==LEFTSHIFTKEY || event.type==RIGHTSHIFTKEY) {
1291                                 event.shift= evt->shift= event.val;
1292                         } else if (event.type==LEFTCTRLKEY || event.type==RIGHTCTRLKEY) {
1293                                 event.ctrl= evt->ctrl= event.val;
1294                         } else if (event.type==LEFTALTKEY || event.type==RIGHTALTKEY) {
1295                                 event.alt= evt->alt= event.val;
1296                         } else if (event.type==COMMANDKEY) {
1297                                 event.oskey= evt->oskey= event.val;
1298                         }
1299                         
1300                         /* if test_break set, it catches this. Keep global for now? */
1301                         if(event.type==ESCKEY)
1302                                 G.afbreek= 1;
1303                         
1304                         wm_event_add(win, &event);
1305                         
1306                         break;
1307                 }
1308                         
1309                 case GHOST_kEventWheel: {
1310                         GHOST_TEventWheelData* wheelData = customdata;
1311                         
1312                         if (wheelData->z > 0)
1313                                 event.type= WHEELUPMOUSE;
1314                         else
1315                                 event.type= WHEELDOWNMOUSE;
1316                         
1317                         event.val= KM_PRESS;
1318                         wm_event_add(win, &event);
1319                         
1320                         break;
1321                 }
1322                 case GHOST_kEventTimer: {
1323                         event.type= TIMER;
1324                         event.custom= EVT_DATA_TIMER;
1325                         event.customdata= customdata;
1326                         wm_event_add(win, &event);
1327
1328                         break;
1329                 }
1330
1331                 case GHOST_kEventUnknown:
1332                 case GHOST_kNumEventTypes:
1333                         break;
1334         }
1335 }
1336