4 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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.
20 * The Original Code is Copyright (C) 2007 Blender Foundation.
21 * All rights reserved.
24 * Contributor(s): Blender Foundation
26 * ***** END GPL LICENSE BLOCK *****
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"
38 #include "MEM_guardedalloc.h"
40 #include "GHOST_C-api.h"
42 #include "BLI_blenlib.h"
44 #include "BKE_blender.h"
45 #include "BKE_context.h"
46 #include "BKE_idprop.h"
47 #include "BKE_global.h"
48 #include "BKE_object.h"
49 #include "BKE_report.h"
50 #include "BKE_scene.h"
51 #include "BKE_utildefines.h"
52 #include "BKE_pointcache.h"
54 #include "ED_fileselect.h"
56 #include "ED_screen.h"
57 #include "ED_space_api.h"
60 #include "RNA_access.h"
62 #include "UI_interface.h"
67 #include "wm_window.h"
68 #include "wm_event_system.h"
69 #include "wm_event_types.h"
71 /* ************ event management ************** */
73 void wm_event_add(wmWindow *win, wmEvent *event_to_add)
75 wmEvent *event= MEM_callocN(sizeof(wmEvent), "event");
77 *event= *event_to_add;
78 BLI_addtail(&win->queue, event);
81 void wm_event_free(wmEvent *event)
83 if(event->customdata && event->customdatafree)
84 MEM_freeN(event->customdata);
88 void wm_event_free_all(wmWindow *win)
92 while((event= win->queue.first)) {
93 BLI_remlink(&win->queue, event);
98 /* ********************* notifiers, listeners *************** */
100 /* XXX: in future, which notifiers to send to other windows? */
101 void WM_event_add_notifier(const bContext *C, unsigned int type, void *reference)
103 wmNotifier *note= MEM_callocN(sizeof(wmNotifier), "notifier");
105 note->wm= CTX_wm_manager(C);
106 BLI_addtail(¬e->wm->queue, note);
108 note->window= CTX_wm_window(C);
111 note->swinid= CTX_wm_region(C)->swinid;
113 note->category= type & NOTE_CATEGORY;
114 note->data= type & NOTE_DATA;
115 note->subtype= type & NOTE_SUBTYPE;
116 note->action= type & NOTE_ACTION;
118 note->reference= reference;
121 static wmNotifier *wm_notifier_next(wmWindowManager *wm)
123 wmNotifier *note= wm->queue.first;
125 if(note) BLI_remlink(&wm->queue, note);
129 /* called in mainloop */
130 void wm_event_do_notifiers(bContext *C)
132 wmWindowManager *wm= CTX_wm_manager(C);
133 wmNotifier *note, *next;
139 /* cache & catch WM level notifiers, such as frame change, scene/screen set */
140 for(win= wm->windows.first; win; win= win->next) {
143 CTX_wm_window_set(C, win);
145 for(note= wm->queue.first; note; note= next) {
148 if(note->category==NC_WM) {
149 if( ELEM(note->data, ND_FILEREAD, ND_FILESAVE)) {
151 wm_window_title(wm, win);
153 else if(note->data==ND_DATACHANGED)
154 wm_window_title(wm, win);
156 if(note->window==win) {
157 if(note->category==NC_SCREEN) {
158 if(note->data==ND_SCREENBROWSE) {
159 ED_screen_set(C, note->reference); // XXX hrms, think this over!
160 printf("screen set %p\n", note->reference);
162 else if(note->data==ND_SCREENDELETE) {
163 ED_screen_delete(C, note->reference); // XXX hrms, think this over!
164 printf("screen delete %p\n", note->reference);
167 else if(note->category==NC_SCENE) {
168 if(note->data==ND_SCENEBROWSE) {
169 ED_screen_set_scene(C, note->reference); // XXX hrms, think this over!
170 printf("scene set %p\n", note->reference);
172 if(note->data==ND_SCENEDELETE) {
173 ED_screen_delete_scene(C, note->reference); // XXX hrms, think this over!
174 printf("scene delete %p\n", note->reference);
176 else if(note->data==ND_FRAME)
180 if(ELEM4(note->category, NC_SCENE, NC_OBJECT, NC_GEOM, NC_SCENE)) {
181 ED_info_stats_clear(CTX_data_scene(C));
182 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_INFO, NULL);
186 /* depsgraph gets called, might send more notifiers */
187 ED_update_for_newframe(C, 1);
191 /* the notifiers are sent without context, to keep it clean */
192 while( (note=wm_notifier_next(wm)) ) {
195 for(win= wm->windows.first; win; win= win->next) {
197 /* filter out notifiers */
198 if(note->category==NC_SCREEN && note->reference && note->reference!=win->screen);
199 else if(note->category==NC_SCENE && note->reference && note->reference!=win->screen->scene);
204 /* XXX context in notifiers? */
205 CTX_wm_window_set(C, win);
207 /* printf("notifier win %d screen %s cat %x\n", win->winid, win->screen->id.name+2, note->category); */
208 ED_screen_do_listen(win, note);
210 for(ar=win->screen->regionbase.first; ar; ar= ar->next) {
211 ED_region_do_listen(ar, note);
214 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
215 ED_area_do_listen(sa, note);
216 for(ar=sa->regionbase.first; ar; ar= ar->next) {
217 ED_region_do_listen(ar, note);
226 /* cached: editor refresh callbacks now, they get context */
227 for(win= wm->windows.first; win; win= win->next) {
228 Scene *sce, *scene= win->screen->scene;
232 CTX_wm_window_set(C, win);
233 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
235 CTX_wm_area_set(C, sa);
236 ED_area_do_refresh(C, sa);
240 if(G.rendering==0) { // XXX make lock in future, or separated derivedmesh users in scene
242 /* update all objects, ipos, matrices, displists, etc. Flags set by depgraph or manual,
243 no layer check here, gets correct flushed */
244 /* sets first, we allow per definition current scene to have dependencies on sets */
246 for(SETLOOPER(scene->set, base))
247 object_handle_update(scene, base->object);
250 for(base= scene->base.first; base; base= base->next) {
251 object_handle_update(scene, base->object);
254 BKE_ptcache_quick_cache_all(scene);
257 CTX_wm_window_set(C, NULL);
260 /* ********************* operators ******************* */
262 static int wm_operator_poll(bContext *C, wmOperatorType *ot)
264 wmOperatorTypeMacro *otmacro;
266 for(otmacro= ot->macro.first; otmacro; otmacro= otmacro->next) {
267 wmOperatorType *ot= WM_operatortype_find(otmacro->idname, 0);
269 if(0==wm_operator_poll(C, ot))
279 /* if repeat is true, it doesn't register again, nor does it free */
280 static int wm_operator_exec(bContext *C, wmOperator *op, int repeat)
282 int retval= OPERATOR_CANCELLED;
284 if(op==NULL || op->type==NULL)
287 if(0==wm_operator_poll(C, op->type))
291 retval= op->type->exec(C, op);
293 if(!(retval & OPERATOR_RUNNING_MODAL))
294 if(op->reports->list.first)
295 uiPupMenuReports(C, op->reports);
297 if(retval & OPERATOR_FINISHED) {
298 if(op->type->flag & OPTYPE_UNDO)
299 ED_undo_push_op(C, op);
302 if((op->type->flag & OPTYPE_REGISTER) || (G.f & G_DEBUG))
303 wm_operator_register(C, op);
305 WM_operator_free(op);
309 WM_operator_free(op);
315 /* for running operators with frozen context (modal handlers, menus) */
316 int WM_operator_call(bContext *C, wmOperator *op)
318 return wm_operator_exec(C, op, 0);
321 /* do this operator again, put here so it can share above code */
322 int WM_operator_repeat(bContext *C, wmOperator *op)
324 return wm_operator_exec(C, op, 1);
327 static wmOperator *wm_operator_create(wmWindowManager *wm, wmOperatorType *ot, PointerRNA *properties, ReportList *reports)
329 wmOperator *op= MEM_callocN(sizeof(wmOperator), ot->idname); /* XXX operatortype names are static still. for debug */
331 /* XXX adding new operator could be function, only happens here now */
333 BLI_strncpy(op->idname, ot->idname, OP_MAX_TYPENAME);
335 /* initialize properties, either copy or create */
336 op->ptr= MEM_callocN(sizeof(PointerRNA), "wmOperatorPtrRNA");
337 if(properties && properties->data) {
338 op->properties= IDP_CopyProperty(properties->data);
341 IDPropertyTemplate val = {0};
342 op->properties= IDP_New(IDP_GROUP, val, "wmOperatorProperties");
344 RNA_pointer_create(&wm->id, ot->srna, op->properties, op->ptr);
346 /* initialize error reports */
348 op->reports= reports; /* must be initialized already */
351 op->reports= MEM_mallocN(sizeof(ReportList), "wmOperatorReportList");
352 BKE_reports_init(op->reports, RPT_STORE|RPT_FREE);
355 /* recursive filling of operator macro list */
356 if(ot->macro.first) {
357 static wmOperator *motherop= NULL;
358 wmOperatorTypeMacro *otmacro;
360 /* ensure all ops are in execution order in 1 list */
364 for(otmacro= ot->macro.first; otmacro; otmacro= otmacro->next) {
365 wmOperatorType *otm= WM_operatortype_find(otmacro->idname, 0);
366 wmOperator *opm= wm_operator_create(wm, otm, otmacro->ptr, NULL);
368 BLI_addtail(&motherop->macro, opm);
369 opm->opm= motherop; /* pointer to mom, for modal() */
378 static void wm_operator_print(wmOperator *op)
380 char *buf = WM_operator_pystring(NULL, op->type, op->ptr, 1);
385 static void wm_region_mouse_co(bContext *C, wmEvent *event)
387 ARegion *ar= CTX_wm_region(C);
389 /* compatibility convention */
390 event->mval[0]= event->x - ar->winrct.xmin;
391 event->mval[1]= event->y - ar->winrct.ymin;
395 static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, PointerRNA *properties, ReportList *reports)
397 wmWindowManager *wm= CTX_wm_manager(C);
398 int retval= OPERATOR_PASS_THROUGH;
400 if(wm_operator_poll(C, ot)) {
401 wmOperator *op= wm_operator_create(wm, ot, properties, reports); /* if reports==NULL, theyll be initialized */
403 if((G.f & G_DEBUG) && event && event->type!=MOUSEMOVE)
404 printf("handle evt %d win %d op %s\n", event?event->type:0, CTX_wm_screen(C)->subwinactive, ot->idname);
406 if(op->type->invoke && event) {
407 wm_region_mouse_co(C, event);
408 retval= op->type->invoke(C, op, event);
410 else if(op->type->exec)
411 retval= op->type->exec(C, op);
413 printf("invalid operator call %s\n", ot->idname); /* debug, important to leave a while, should never happen */
415 if(!(retval & OPERATOR_RUNNING_MODAL)) {
416 if(op->reports->list.first) /* only show the report if the report list was not given in the function */
417 uiPupMenuReports(C, op->reports);
419 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 */
421 wm_operator_print(op);
424 if(retval & OPERATOR_FINISHED) {
425 if(ot->flag & OPTYPE_UNDO)
426 ED_undo_push_op(C, op);
428 if((ot->flag & OPTYPE_REGISTER) || (G.f & G_DEBUG))
429 wm_operator_register(C, op);
431 WM_operator_free(op);
433 else if(retval & OPERATOR_RUNNING_MODAL) {
434 /* grab cursor during blocking modal ops (X11) */
435 if(ot->flag & OPTYPE_BLOCKING)
436 WM_cursor_grab(CTX_wm_window(C), 1);
439 WM_operator_free(op);
445 /* WM_operator_name_call is the main accessor function
446 * this is for python to access since its done the operator lookup
448 * invokes operator in context */
449 static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, int context, PointerRNA *properties, ReportList *reports)
451 wmWindow *window= CTX_wm_window(C);
457 if(ot && C && window) {
458 event= window->eventstate;
461 case WM_OP_EXEC_REGION_WIN:
462 event= NULL; /* pass on without break */
463 case WM_OP_INVOKE_REGION_WIN:
465 /* forces operator to go to the region window, for header menus */
466 ARegion *ar= CTX_wm_region(C);
467 ScrArea *area= CTX_wm_area(C);
470 ARegion *ar1= area->regionbase.first;
471 for(; ar1; ar1= ar1->next)
472 if(ar1->regiontype==RGN_TYPE_WINDOW)
475 CTX_wm_region_set(C, ar1);
478 retval= wm_operator_invoke(C, ot, event, properties, reports);
480 /* set region back */
481 CTX_wm_region_set(C, ar);
485 case WM_OP_EXEC_AREA:
486 event= NULL; /* pass on without break */
487 case WM_OP_INVOKE_AREA:
489 /* remove region from context */
490 ARegion *ar= CTX_wm_region(C);
492 CTX_wm_region_set(C, NULL);
493 retval= wm_operator_invoke(C, ot, event, properties, reports);
494 CTX_wm_region_set(C, ar);
498 case WM_OP_EXEC_SCREEN:
499 event= NULL; /* pass on without break */
500 case WM_OP_INVOKE_SCREEN:
502 /* remove region + area from context */
503 ARegion *ar= CTX_wm_region(C);
504 ScrArea *area= CTX_wm_area(C);
506 CTX_wm_region_set(C, NULL);
507 CTX_wm_area_set(C, NULL);
508 retval= wm_operator_invoke(C, ot, event, properties, reports);
509 CTX_wm_region_set(C, ar);
510 CTX_wm_area_set(C, area);
514 case WM_OP_EXEC_DEFAULT:
515 event= NULL; /* pass on without break */
516 case WM_OP_INVOKE_DEFAULT:
517 return wm_operator_invoke(C, ot, event, properties, reports);
525 /* invokes operator in context */
526 int WM_operator_name_call(bContext *C, const char *opstring, int context, PointerRNA *properties)
528 wmOperatorType *ot= WM_operatortype_find(opstring, 0);
530 return wm_operator_call_internal(C, ot, context, properties, NULL);
535 /* Similar to WM_operator_name_call called with WM_OP_EXEC_DEFAULT context.
536 - wmOperatorType is used instead of operator name since python alredy has the operator type
537 - poll() must be called by python before this runs.
538 - reports can be passed to this function (so python can report them as exceptions)
540 int WM_operator_call_py(bContext *C, wmOperatorType *ot, int context, PointerRNA *properties, ReportList *reports)
542 int retval= OPERATOR_CANCELLED;
546 wmWindowManager *wm= CTX_wm_manager(C);
547 op= wm_operator_create(wm, ot, properties, reports);
550 retval= op->type->exec(C, op);
552 printf("error \"%s\" operator has no exec function, python cannot call it\n", op->type->name);
555 retval= wm_operator_call_internal(C, ot, context, properties, reports);
557 /* keep the reports around if needed later */
558 if (retval & OPERATOR_RUNNING_MODAL || ot->flag & OPTYPE_REGISTER)
560 reports->flag |= RPT_FREE;
567 /* ********************* handlers *************** */
569 /* future extra customadata free? */
570 static void wm_event_free_handler(wmEventHandler *handler)
575 /* only set context when area/region is part of screen */
576 static void wm_handler_op_context(bContext *C, wmEventHandler *handler)
578 bScreen *screen= CTX_wm_screen(C);
580 if(screen && handler->op) {
581 if(handler->op_area==NULL)
582 CTX_wm_area_set(C, NULL);
586 for(sa= screen->areabase.first; sa; sa= sa->next)
587 if(sa==handler->op_area)
590 /* when changing screen layouts with running modal handlers (like render display), this
591 is not an error to print */
592 if(handler->op==NULL)
593 printf("internal error: handler (%s) has invalid area\n", handler->op->type->idname);
597 CTX_wm_area_set(C, sa);
598 for(ar= sa->regionbase.first; ar; ar= ar->next)
599 if(ar==handler->op_region)
601 /* XXX no warning print here, after full-area and back regions are remade */
603 CTX_wm_region_set(C, ar);
609 /* called on exit or remove area, only here call cancel callback */
610 void WM_event_remove_handlers(bContext *C, ListBase *handlers)
612 wmEventHandler *handler;
614 /* C is zero on freeing database, modal handlers then already were freed */
615 while((handler=handlers->first)) {
616 BLI_remlink(handlers, handler);
619 if(handler->op->type->cancel) {
620 ScrArea *area= CTX_wm_area(C);
621 ARegion *region= CTX_wm_region(C);
623 wm_handler_op_context(C, handler);
625 handler->op->type->cancel(C, handler->op);
627 CTX_wm_area_set(C, area);
628 CTX_wm_region_set(C, region);
631 WM_operator_free(handler->op);
632 WM_cursor_grab(CTX_wm_window(C), 0);
634 else if(handler->ui_remove) {
635 ScrArea *area= CTX_wm_area(C);
636 ARegion *region= CTX_wm_region(C);
637 ARegion *menu= CTX_wm_menu(C);
639 if(handler->ui_area) CTX_wm_area_set(C, handler->ui_area);
640 if(handler->ui_region) CTX_wm_region_set(C, handler->ui_region);
641 if(handler->ui_menu) CTX_wm_menu_set(C, handler->ui_menu);
643 handler->ui_remove(C, handler->ui_userdata);
645 CTX_wm_area_set(C, area);
646 CTX_wm_region_set(C, region);
647 CTX_wm_menu_set(C, menu);
650 wm_event_free_handler(handler);
654 /* do userdef mappings */
655 static int wm_userdef_event_map(int kmitype)
659 if(U.flag & USER_LMOUSESELECT)
665 if(U.flag & USER_LMOUSESELECT)
671 if(U.uiflag & USER_WHEELZOOMDIR)
674 return WHEELDOWNMOUSE;
677 if(U.uiflag & USER_WHEELZOOMDIR)
678 return WHEELDOWNMOUSE;
683 if(U.flag & USER_LMOUSESELECT)
689 if(U.flag & USER_LMOUSESELECT)
698 static int wm_eventmatch(wmEvent *winevent, wmKeymapItem *kmi)
700 int kmitype= wm_userdef_event_map(kmi->type);
702 if(kmi->inactive) return 0;
704 /* exception for middlemouse emulation */
705 if((U.flag & USER_TWOBUTTONMOUSE) && (kmi->type == MIDDLEMOUSE)) {
706 if(winevent->type == LEFTMOUSE && winevent->alt) {
707 wmKeymapItem tmp= *kmi;
709 tmp.type= winevent->type;
710 tmp.alt= winevent->alt;
711 if(wm_eventmatch(winevent, &tmp))
716 /* the matching rules */
717 if(kmitype==KM_TEXTINPUT)
718 if(ISKEYBOARD(winevent->type) && winevent->ascii) return 1;
720 if(winevent->type!=kmitype) return 0;
723 if(winevent->val!=kmi->val) return 0;
725 /* modifiers also check bits, so it allows modifier order */
726 if(kmi->shift!=KM_ANY)
727 if(winevent->shift != kmi->shift && !(winevent->shift & kmi->shift)) return 0;
728 if(kmi->ctrl!=KM_ANY)
729 if(winevent->ctrl != kmi->ctrl && !(winevent->ctrl & kmi->ctrl)) return 0;
731 if(winevent->alt != kmi->alt && !(winevent->alt & kmi->alt)) return 0;
732 if(kmi->oskey!=KM_ANY)
733 if(winevent->oskey != kmi->oskey && !(winevent->oskey & kmi->oskey)) return 0;
736 if(winevent->keymodifier!=kmi->keymodifier) return 0;
738 /* key modifiers always check when event has it */
739 /* otherwise regular keypresses with keymodifier still work */
740 if(winevent->keymodifier)
741 if(ISKEYBOARD(winevent->type))
742 if(winevent->keymodifier!=kmi->keymodifier) return 0;
747 static int wm_event_always_pass(wmEvent *event)
749 /* some events we always pass on, to ensure proper communication */
750 return ELEM5(event->type, TIMER, TIMER0, TIMER1, TIMER2, TIMERJOBS);
753 /* operator exists */
754 static void wm_event_modalkeymap(wmOperator *op, wmEvent *event)
756 if(op->type->modalkeymap) {
759 for(kmi= op->type->modalkeymap->keymap.first; kmi; kmi= kmi->next) {
760 if(wm_eventmatch(event, kmi)) {
762 event->type= EVT_MODAL_MAP;
763 event->val= kmi->propvalue;
769 /* Warning: this function removes a modal handler, when finished */
770 static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHandler *handler, wmEvent *event, PointerRNA *properties)
772 int retval= OPERATOR_PASS_THROUGH;
774 /* derived, modal or blocking operator */
776 wmOperator *op= handler->op;
777 wmOperatorType *ot= op->type;
780 /* we set context to where modal handler came from */
781 ScrArea *area= CTX_wm_area(C);
782 ARegion *region= CTX_wm_region(C);
784 wm_handler_op_context(C, handler);
785 wm_region_mouse_co(C, event);
786 wm_event_modalkeymap(op, event);
788 retval= ot->modal(C, op, event);
790 /* putting back screen context, reval can pass trough after modal failures! */
791 if((retval & OPERATOR_PASS_THROUGH) || wm_event_always_pass(event)) {
792 CTX_wm_area_set(C, area);
793 CTX_wm_region_set(C, region);
796 /* this special cases is for areas and regions that get removed */
797 CTX_wm_area_set(C, NULL);
798 CTX_wm_region_set(C, NULL);
801 if(!(retval & OPERATOR_RUNNING_MODAL))
802 if(op->reports->list.first)
803 uiPupMenuReports(C, op->reports);
805 if (retval & OPERATOR_FINISHED) {
807 wm_operator_print(op); /* todo - this print may double up, might want to check more flags then the FINISHED */
810 if(retval & OPERATOR_FINISHED) {
811 if(ot->flag & OPTYPE_UNDO)
812 ED_undo_push_op(C, op);
814 if((ot->flag & OPTYPE_REGISTER) || (G.f & G_DEBUG))
815 wm_operator_register(C, op);
817 WM_operator_free(op);
820 else if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) {
821 WM_operator_free(op);
825 /* remove modal handler, operator itself should have been cancelled and freed */
826 if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) {
827 WM_cursor_grab(CTX_wm_window(C), 0);
829 BLI_remlink(handlers, handler);
830 wm_event_free_handler(handler);
832 /* prevent silly errors from operator users */
833 //retval &= ~OPERATOR_PASS_THROUGH;
838 printf("wm_handler_operator_call error\n");
841 wmOperatorType *ot= WM_operatortype_find(event->keymap_idname, 0);
844 retval= wm_operator_invoke(C, ot, event, properties, NULL);
847 if(retval & OPERATOR_PASS_THROUGH)
848 return WM_HANDLER_CONTINUE;
850 return WM_HANDLER_BREAK;
853 static int wm_handler_ui_call(bContext *C, wmEventHandler *handler, wmEvent *event)
855 ScrArea *area= CTX_wm_area(C);
856 ARegion *region= CTX_wm_region(C);
857 ARegion *menu= CTX_wm_menu(C);
858 int retval, always_pass;
860 /* we set context to where ui handler came from */
861 if(handler->ui_area) CTX_wm_area_set(C, handler->ui_area);
862 if(handler->ui_region) CTX_wm_region_set(C, handler->ui_region);
863 if(handler->ui_menu) CTX_wm_menu_set(C, handler->ui_menu);
865 /* in advance to avoid access to freed event on window close */
866 always_pass= wm_event_always_pass(event);
868 retval= handler->ui_handle(C, event, handler->ui_userdata);
870 /* putting back screen context */
871 if((retval != WM_UI_HANDLER_BREAK) || always_pass) {
872 CTX_wm_area_set(C, area);
873 CTX_wm_region_set(C, region);
874 CTX_wm_menu_set(C, menu);
877 /* this special cases is for areas and regions that get removed */
878 CTX_wm_area_set(C, NULL);
879 CTX_wm_region_set(C, NULL);
880 CTX_wm_menu_set(C, NULL);
883 if(retval == WM_UI_HANDLER_BREAK)
884 return WM_HANDLER_BREAK;
886 return WM_HANDLER_CONTINUE;
889 /* fileselect handlers are only in the window queue, so it's save to switch screens or area types */
890 static int wm_handler_fileselect_call(bContext *C, ListBase *handlers, wmEventHandler *handler, wmEvent *event)
893 int action= WM_HANDLER_CONTINUE;
895 if(event->type != EVT_FILESELECT)
897 if(handler->op != (wmOperator *)event->customdata)
901 case EVT_FILESELECT_OPEN:
902 case EVT_FILESELECT_FULL_OPEN:
904 if(event->val==EVT_FILESELECT_OPEN)
905 ED_area_newspace(C, handler->op_area, SPACE_FILE);
907 ED_screen_full_newspace(C, handler->op_area, SPACE_FILE);
909 /* settings for filebrowser, sfile is not operator owner but sends events */
910 sfile= (SpaceFile*)CTX_wm_space_data(C);
911 sfile->op= handler->op;
913 ED_fileselect_set_params(sfile);
915 action= WM_HANDLER_BREAK;
919 case EVT_FILESELECT_EXEC:
920 case EVT_FILESELECT_CANCEL:
922 /* XXX validate area and region? */
923 bScreen *screen= CTX_wm_screen(C);
924 char *path= RNA_string_get_alloc(handler->op->ptr, "path", NULL, 0);
926 if(screen != handler->filescreen)
927 ED_screen_full_prevspace(C);
929 ED_area_prevspace(C);
931 /* remlink now, for load file case */
932 BLI_remlink(handlers, handler);
934 if(event->val==EVT_FILESELECT_EXEC) {
935 wm_handler_op_context(C, handler);
937 /* a bit weak, might become arg for WM_event_fileselect? */
938 /* XXX also extension code in image-save doesnt work for this yet */
939 if(strncmp(handler->op->type->name, "Save", 4)==0) {
940 /* this gives ownership to pupmenu */
941 uiPupMenuSaveOver(C, handler->op, path);
944 int retval= handler->op->type->exec(C, handler->op);
946 if (retval & OPERATOR_FINISHED)
948 wm_operator_print(handler->op);
950 WM_operator_free(handler->op);
953 CTX_wm_area_set(C, NULL);
956 WM_operator_free(handler->op);
958 wm_event_free_handler(handler);
961 action= WM_HANDLER_BREAK;
969 static int handler_boundbox_test(wmEventHandler *handler, wmEvent *event)
972 if(handler->bblocal) {
973 rcti rect= *handler->bblocal;
974 BLI_translate_rcti(&rect, handler->bbwin->xmin, handler->bbwin->ymin);
976 if(BLI_in_rcti(&rect, event->x, event->y))
978 else if(event->type==MOUSEMOVE && BLI_in_rcti(&rect, event->prevx, event->prevy))
984 if(BLI_in_rcti(handler->bbwin, event->x, event->y))
986 else if(event->type==MOUSEMOVE && BLI_in_rcti(handler->bbwin, event->prevx, event->prevy))
995 static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
997 wmEventHandler *handler, *nexthandler;
998 int action= WM_HANDLER_CONTINUE;
1001 if(handlers==NULL) return action;
1003 /* modal handlers can get removed in this loop, we keep the loop this way */
1004 for(handler= handlers->first; handler; handler= nexthandler) {
1005 nexthandler= handler->next;
1007 /* optional boundbox */
1008 if(handler_boundbox_test(handler, event)) {
1009 /* in advance to avoid access to freed event on window close */
1010 always_pass= wm_event_always_pass(event);
1012 /* modal+blocking handler */
1013 if(handler->flag & WM_HANDLER_BLOCKING)
1014 action= WM_HANDLER_BREAK;
1016 if(handler->keymap) {
1019 for(kmi= handler->keymap->first; kmi; kmi= kmi->next) {
1020 if(wm_eventmatch(event, kmi)) {
1022 event->keymap_idname= kmi->idname; /* weak, but allows interactive callback to not use rawkey */
1024 action= wm_handler_operator_call(C, handlers, handler, event, kmi->ptr);
1025 if(action==WM_HANDLER_BREAK) /* not wm_event_always_pass(event) here, it denotes removed handler */
1030 else if(handler->ui_handle) {
1031 action= wm_handler_ui_call(C, handler, event);
1033 else if(handler->type==WM_HANDLER_FILESELECT) {
1034 /* screen context changes here */
1035 action= wm_handler_fileselect_call(C, handlers, handler, event);
1038 /* modal, swallows all */
1039 action= wm_handler_operator_call(C, handlers, handler, event, NULL);
1042 if(!always_pass && action==WM_HANDLER_BREAK)
1047 if(CTX_wm_window(C)==NULL)
1053 static int wm_event_inside_i(wmEvent *event, rcti *rect)
1055 if(BLI_in_rcti(rect, event->x, event->y))
1057 if(event->type==MOUSEMOVE) {
1058 if( BLI_in_rcti(rect, event->prevx, event->prevy)) {
1066 static ScrArea *area_event_inside(bContext *C, int x, int y)
1068 bScreen *screen= CTX_wm_screen(C);
1072 for(sa= screen->areabase.first; sa; sa= sa->next)
1073 if(BLI_in_rcti(&sa->totrct, x, y))
1078 static ARegion *region_event_inside(bContext *C, int x, int y)
1080 bScreen *screen= CTX_wm_screen(C);
1081 ScrArea *area= CTX_wm_area(C);
1085 for(ar= area->regionbase.first; ar; ar= ar->next)
1086 if(BLI_in_rcti(&ar->winrct, x, y))
1091 static void wm_paintcursor_tag(bContext *C, wmPaintCursor *pc, ARegion *ar)
1094 for(; pc; pc= pc->next) {
1096 wmWindow *win= CTX_wm_window(C);
1097 win->screen->do_draw_paintcursor= 1;
1099 if(win->drawmethod != USER_DRAW_TRIPLE)
1100 ED_region_tag_redraw(ar);
1106 /* called on mousemove, check updates for paintcursors */
1107 /* context was set on active area and region */
1108 static void wm_paintcursor_test(bContext *C, wmEvent *event)
1110 wmWindowManager *wm= CTX_wm_manager(C);
1112 if(wm->paintcursors.first) {
1113 ARegion *ar= CTX_wm_region(C);
1115 wm_paintcursor_tag(C, wm->paintcursors.first, ar);
1117 /* if previous position was not in current region, we have to set a temp new context */
1118 if(ar==NULL || !BLI_in_rcti(&ar->winrct, event->prevx, event->prevy)) {
1119 ScrArea *sa= CTX_wm_area(C);
1121 CTX_wm_area_set(C, area_event_inside(C, event->prevx, event->prevy));
1122 CTX_wm_region_set(C, region_event_inside(C, event->prevx, event->prevy));
1124 wm_paintcursor_tag(C, wm->paintcursors.first, CTX_wm_region(C));
1126 CTX_wm_area_set(C, sa);
1127 CTX_wm_region_set(C, ar);
1132 /* called in main loop */
1133 /* goes over entire hierarchy: events -> window -> screen -> area -> region */
1134 void wm_event_do_handlers(bContext *C)
1138 for(win= CTX_wm_manager(C)->windows.first; win; win= win->next) {
1141 if( win->screen==NULL )
1142 wm_event_free_all(win);
1144 while( (event= win->queue.first) ) {
1147 CTX_wm_window_set(C, win);
1149 /* we let modal handlers get active area/region, also wm_paintcursor_test needs it */
1150 CTX_wm_area_set(C, area_event_inside(C, event->x, event->y));
1151 CTX_wm_region_set(C, region_event_inside(C, event->x, event->y));
1153 /* MVC demands to not draw in event handlers... but we need to leave it for ogl selecting etc */
1154 wm_window_make_drawable(C, win);
1156 action= wm_handlers_do(C, event, &win->handlers);
1159 if(CTX_wm_window(C)==NULL) {
1163 /* builtin tweak, if action is break it removes tweak */
1164 if(!wm_event_always_pass(event))
1165 wm_tweakevent_test(C, event, action);
1167 if(wm_event_always_pass(event) || action==WM_HANDLER_CONTINUE) {
1172 /* XXX to solve, here screen handlers? */
1173 if(!wm_event_always_pass(event)) {
1174 if(event->type==MOUSEMOVE) {
1175 /* state variables in screen, cursors */
1176 ED_screen_set_subwinactive(win, event);
1177 /* for regions having custom cursors */
1178 wm_paintcursor_test(C, event);
1182 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
1183 if(wm_event_always_pass(event) || wm_event_inside_i(event, &sa->totrct)) {
1185 CTX_wm_area_set(C, sa);
1186 CTX_wm_region_set(C, NULL);
1187 action= wm_handlers_do(C, event, &sa->handlers);
1189 if(wm_event_always_pass(event) || action==WM_HANDLER_CONTINUE) {
1190 for(ar=sa->regionbase.first; ar; ar= ar->next) {
1191 if(wm_event_always_pass(event) || wm_event_inside_i(event, &ar->winrct)) {
1192 CTX_wm_region_set(C, ar);
1193 action= wm_handlers_do(C, event, &ar->handlers);
1195 doit |= (BLI_in_rcti(&ar->winrct, event->x, event->y));
1197 if(!wm_event_always_pass(event)) {
1198 if(action==WM_HANDLER_BREAK)
1204 /* NOTE: do not escape on WM_HANDLER_BREAK, mousemove needs handled for previous area */
1208 /* XXX hrmf, this gives reliable previous mouse coord for area change, feels bad?
1209 doing it on ghost queue gives errors when mousemoves go over area borders */
1210 if(doit && win->screen->subwinactive != win->screen->mainwin) {
1211 win->eventstate->prevx= event->x;
1212 win->eventstate->prevy= event->y;
1216 /* unlink and free here, blender-quit then frees all */
1217 BLI_remlink(&win->queue, event);
1218 wm_event_free(event);
1222 /* only add mousemove when queue was read entirely */
1223 if(win->addmousemove) {
1224 wmEvent event= *(win->eventstate);
1225 event.type= MOUSEMOVE;
1226 event.prevx= event.x;
1227 event.prevy= event.y;
1228 wm_event_add(win, &event);
1229 win->addmousemove= 0;
1232 CTX_wm_window_set(C, NULL);
1236 /* ********** filesector handling ************ */
1238 void WM_event_fileselect_event(bContext *C, void *ophandle, int eventval)
1240 /* add to all windows! */
1243 for(win= CTX_wm_manager(C)->windows.first; win; win= win->next) {
1244 wmEvent event= *win->eventstate;
1246 event.type= EVT_FILESELECT;
1247 event.val= eventval;
1248 event.customdata= ophandle; // only as void pointer type check
1250 wm_event_add(win, &event);
1254 /* operator is supposed to have a filled "path" property */
1255 /* optional property: filetype (XXX enum?) */
1257 /* Idea is to keep a handler alive on window queue, owning the operator.
1258 The filewindow can send event to make it execute, thus ensuring
1259 executing happens outside of lower level queues, with UI refreshed.
1260 Should also allow multiwin solutions */
1262 void WM_event_add_fileselect(bContext *C, wmOperator *op)
1264 wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "fileselect handler");
1265 wmWindow *win= CTX_wm_window(C);
1266 int full= 1; // XXX preset?
1268 handler->type= WM_HANDLER_FILESELECT;
1270 handler->op_area= CTX_wm_area(C);
1271 handler->op_region= CTX_wm_region(C);
1272 handler->filescreen= CTX_wm_screen(C);
1274 BLI_addhead(&win->handlers, handler);
1276 WM_event_fileselect_event(C, op, full?EVT_FILESELECT_FULL_OPEN:EVT_FILESELECT_OPEN);
1279 /* lets not expose struct outside wm? */
1280 void WM_event_set_handler_flag(wmEventHandler *handler, int flag)
1282 handler->flag= flag;
1285 wmEventHandler *WM_event_add_modal_handler(bContext *C, ListBase *handlers, wmOperator *op)
1287 wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event modal handler");
1289 /* operator was part of macro */
1291 /* give the mother macro to the handler */
1292 handler->op= op->opm;
1293 /* mother macro opm becomes the macro element */
1294 handler->op->opm= op;
1299 handler->op_area= CTX_wm_area(C); /* means frozen screen context for modal handlers! */
1300 handler->op_region= CTX_wm_region(C);
1302 BLI_addhead(handlers, handler);
1307 wmEventHandler *WM_event_add_keymap_handler(ListBase *handlers, ListBase *keymap)
1309 wmEventHandler *handler;
1311 /* only allow same keymap once */
1312 for(handler= handlers->first; handler; handler= handler->next)
1313 if(handler->keymap==keymap)
1316 handler= MEM_callocN(sizeof(wmEventHandler), "event keymap handler");
1317 BLI_addtail(handlers, handler);
1318 handler->keymap= keymap;
1323 /* priorities not implemented yet, for time being just insert in begin of list */
1324 wmEventHandler *WM_event_add_keymap_handler_priority(ListBase *handlers, ListBase *keymap, int priority)
1326 wmEventHandler *handler;
1328 WM_event_remove_keymap_handler(handlers, keymap);
1330 handler= MEM_callocN(sizeof(wmEventHandler), "event keymap handler");
1331 BLI_addhead(handlers, handler);
1332 handler->keymap= keymap;
1337 wmEventHandler *WM_event_add_keymap_handler_bb(ListBase *handlers, ListBase *keymap, rcti *bblocal, rcti *bbwin)
1339 wmEventHandler *handler= WM_event_add_keymap_handler(handlers, keymap);
1342 handler->bblocal= bblocal;
1343 handler->bbwin= bbwin;
1348 void WM_event_remove_keymap_handler(ListBase *handlers, ListBase *keymap)
1350 wmEventHandler *handler;
1352 for(handler= handlers->first; handler; handler= handler->next) {
1353 if(handler->keymap==keymap) {
1354 BLI_remlink(handlers, handler);
1355 wm_event_free_handler(handler);
1361 wmEventHandler *WM_event_add_ui_handler(const bContext *C, ListBase *handlers, wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata)
1363 wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event ui handler");
1364 handler->ui_handle= func;
1365 handler->ui_remove= remove;
1366 handler->ui_userdata= userdata;
1367 handler->ui_area= (C)? CTX_wm_area(C): NULL;
1368 handler->ui_region= (C)? CTX_wm_region(C): NULL;
1369 handler->ui_menu= (C)? CTX_wm_menu(C): NULL;
1371 BLI_addhead(handlers, handler);
1376 void WM_event_remove_ui_handler(ListBase *handlers, wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata)
1378 wmEventHandler *handler;
1380 for(handler= handlers->first; handler; handler= handler->next) {
1381 if(handler->ui_handle == func && handler->ui_remove == remove && handler->ui_userdata == userdata) {
1382 BLI_remlink(handlers, handler);
1383 wm_event_free_handler(handler);
1389 void WM_event_add_mousemove(bContext *C)
1391 wmWindow *window= CTX_wm_window(C);
1393 window->addmousemove= 1;
1396 /* for modal callbacks, check configuration for how to interpret exit with tweaks */
1397 int WM_modal_tweak_exit(wmEvent *evt, int tweak_event)
1399 /* user preset or keymap? dunno... */
1400 int tweak_modal= (U.flag & USER_DRAGIMMEDIATE)==0;
1402 switch(tweak_event) {
1406 if(evt->val==tweak_modal)
1409 /* this case is when modal callcback didnt get started with a tweak */
1417 /* ********************* ghost stuff *************** */
1419 static int convert_key(GHOST_TKey key)
1421 if (key>=GHOST_kKeyA && key<=GHOST_kKeyZ) {
1422 return (AKEY + ((int) key - GHOST_kKeyA));
1423 } else if (key>=GHOST_kKey0 && key<=GHOST_kKey9) {
1424 return (ZEROKEY + ((int) key - GHOST_kKey0));
1425 } else if (key>=GHOST_kKeyNumpad0 && key<=GHOST_kKeyNumpad9) {
1426 return (PAD0 + ((int) key - GHOST_kKeyNumpad0));
1427 } else if (key>=GHOST_kKeyF1 && key<=GHOST_kKeyF12) {
1428 return (F1KEY + ((int) key - GHOST_kKeyF1));
1431 case GHOST_kKeyBackSpace: return BACKSPACEKEY;
1432 case GHOST_kKeyTab: return TABKEY;
1433 case GHOST_kKeyLinefeed: return LINEFEEDKEY;
1434 case GHOST_kKeyClear: return 0;
1435 case GHOST_kKeyEnter: return RETKEY;
1437 case GHOST_kKeyEsc: return ESCKEY;
1438 case GHOST_kKeySpace: return SPACEKEY;
1439 case GHOST_kKeyQuote: return QUOTEKEY;
1440 case GHOST_kKeyComma: return COMMAKEY;
1441 case GHOST_kKeyMinus: return MINUSKEY;
1442 case GHOST_kKeyPeriod: return PERIODKEY;
1443 case GHOST_kKeySlash: return SLASHKEY;
1445 case GHOST_kKeySemicolon: return SEMICOLONKEY;
1446 case GHOST_kKeyEqual: return EQUALKEY;
1448 case GHOST_kKeyLeftBracket: return LEFTBRACKETKEY;
1449 case GHOST_kKeyRightBracket: return RIGHTBRACKETKEY;
1450 case GHOST_kKeyBackslash: return BACKSLASHKEY;
1451 case GHOST_kKeyAccentGrave: return ACCENTGRAVEKEY;
1453 case GHOST_kKeyLeftShift: return LEFTSHIFTKEY;
1454 case GHOST_kKeyRightShift: return RIGHTSHIFTKEY;
1455 case GHOST_kKeyLeftControl: return LEFTCTRLKEY;
1456 case GHOST_kKeyRightControl: return RIGHTCTRLKEY;
1457 case GHOST_kKeyCommand: return COMMANDKEY;
1458 case GHOST_kKeyLeftAlt: return LEFTALTKEY;
1459 case GHOST_kKeyRightAlt: return RIGHTALTKEY;
1461 case GHOST_kKeyCapsLock: return CAPSLOCKKEY;
1462 case GHOST_kKeyNumLock: return 0;
1463 case GHOST_kKeyScrollLock: return 0;
1465 case GHOST_kKeyLeftArrow: return LEFTARROWKEY;
1466 case GHOST_kKeyRightArrow: return RIGHTARROWKEY;
1467 case GHOST_kKeyUpArrow: return UPARROWKEY;
1468 case GHOST_kKeyDownArrow: return DOWNARROWKEY;
1470 case GHOST_kKeyPrintScreen: return 0;
1471 case GHOST_kKeyPause: return PAUSEKEY;
1473 case GHOST_kKeyInsert: return INSERTKEY;
1474 case GHOST_kKeyDelete: return DELKEY;
1475 case GHOST_kKeyHome: return HOMEKEY;
1476 case GHOST_kKeyEnd: return ENDKEY;
1477 case GHOST_kKeyUpPage: return PAGEUPKEY;
1478 case GHOST_kKeyDownPage: return PAGEDOWNKEY;
1480 case GHOST_kKeyNumpadPeriod: return PADPERIOD;
1481 case GHOST_kKeyNumpadEnter: return PADENTER;
1482 case GHOST_kKeyNumpadPlus: return PADPLUSKEY;
1483 case GHOST_kKeyNumpadMinus: return PADMINUS;
1484 case GHOST_kKeyNumpadAsterisk: return PADASTERKEY;
1485 case GHOST_kKeyNumpadSlash: return PADSLASHKEY;
1487 case GHOST_kKeyGrLess: return GRLESSKEY;
1490 return UNKNOWNKEY; /* GHOST_kKeyUnknown */
1495 /* adds customdata to event */
1496 static void update_tablet_data(wmWindow *win, wmEvent *event)
1498 const GHOST_TabletData *td= GHOST_GetTabletData(win->ghostwin);
1500 /* if there's tablet data from an active tablet device then add it */
1501 if ((td != NULL) && td->Active != GHOST_kTabletModeNone) {
1502 struct wmTabletData *wmtab= MEM_mallocN(sizeof(wmTabletData), "customdata tablet");
1504 wmtab->Active = (int)td->Active;
1505 wmtab->Pressure = td->Pressure;
1506 wmtab->Xtilt = td->Xtilt;
1507 wmtab->Ytilt = td->Ytilt;
1509 event->custom= EVT_DATA_TABLET;
1510 event->customdata= wmtab;
1511 event->customdatafree= 1;
1516 /* windows store own event queues, no bContext here */
1517 void wm_event_add_ghostevent(wmWindow *win, int type, void *customdata)
1519 wmEvent event, *evt= win->eventstate;
1521 /* initialize and copy state (only mouse x y and modifiers) */
1526 case GHOST_kEventCursorMove: {
1528 GHOST_TEventCursorData *cd= customdata;
1531 GHOST_ScreenToClient(win->ghostwin, cd->x, cd->y, &cx, &cy);
1533 event.type= MOUSEMOVE;
1534 event.x= evt->x= cx;
1535 event.y= evt->y= (win->sizey-1) - cy;
1537 update_tablet_data(win, &event);
1538 wm_event_add(win, &event);
1543 case GHOST_kEventButtonDown:
1544 case GHOST_kEventButtonUp: {
1545 GHOST_TEventButtonData *bd= customdata;
1546 event.val= (type==GHOST_kEventButtonDown);
1548 if (bd->button == GHOST_kButtonMaskLeft)
1549 event.type= LEFTMOUSE;
1550 else if (bd->button == GHOST_kButtonMaskRight)
1551 event.type= RIGHTMOUSE;
1553 event.type= MIDDLEMOUSE;
1555 update_tablet_data(win, &event);
1556 wm_event_add(win, &event);
1561 case GHOST_kEventKeyDown:
1562 case GHOST_kEventKeyUp: {
1563 GHOST_TEventKeyData *kd= customdata;
1564 event.type= convert_key(kd->key);
1565 event.ascii= kd->ascii;
1566 event.val= (type==GHOST_kEventKeyDown)?KM_PRESS:KM_RELEASE;
1568 /* exclude arrow keys, esc, etc from text input */
1569 if(type==GHOST_kEventKeyUp || (event.ascii<32 && event.ascii>14))
1573 if (event.type==LEFTSHIFTKEY || event.type==RIGHTSHIFTKEY) {
1574 event.shift= evt->shift= (event.val==KM_PRESS);
1575 if(event.val==KM_PRESS && (evt->ctrl || evt->alt || evt->oskey))
1576 event.shift= evt->shift = 3; // define?
1578 else if (event.type==LEFTCTRLKEY || event.type==RIGHTCTRLKEY) {
1579 event.ctrl= evt->ctrl= (event.val==KM_PRESS);
1580 if(event.val==KM_PRESS && (evt->shift || evt->alt || evt->oskey))
1581 event.ctrl= evt->ctrl = 3; // define?
1583 else if (event.type==LEFTALTKEY || event.type==RIGHTALTKEY) {
1584 event.alt= evt->alt= (event.val==KM_PRESS);
1585 if(event.val==KM_PRESS && (evt->ctrl || evt->shift || evt->oskey))
1586 event.alt= evt->alt = 3; // define?
1588 else if (event.type==COMMANDKEY) {
1589 event.oskey= evt->oskey= (event.val==KM_PRESS);
1590 if(event.val==KM_PRESS && (evt->ctrl || evt->alt || evt->shift))
1591 event.oskey= evt->oskey = 3; // define?
1594 if(event.val==KM_PRESS && event.keymodifier==0)
1595 evt->keymodifier= event.type; /* only set in eventstate, for next event */
1596 else if(event.val==KM_RELEASE && event.keymodifier==event.type)
1597 event.keymodifier= evt->keymodifier= 0;
1600 /* if test_break set, it catches this. XXX Keep global for now? */
1601 if(event.type==ESCKEY)
1604 wm_event_add(win, &event);
1609 case GHOST_kEventWheel: {
1610 GHOST_TEventWheelData* wheelData = customdata;
1612 if (wheelData->z > 0)
1613 event.type= WHEELUPMOUSE;
1615 event.type= WHEELDOWNMOUSE;
1617 event.val= KM_PRESS;
1618 wm_event_add(win, &event);
1622 case GHOST_kEventTimer: {
1624 event.custom= EVT_DATA_TIMER;
1625 event.customdata= customdata;
1626 wm_event_add(win, &event);
1631 case GHOST_kEventUnknown:
1632 case GHOST_kNumEventTypes: