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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 <stdio.h> // [mce] debug, remove when finished
34 #include "DNA_listBase.h"
35 #include "DNA_screen_types.h"
36 #include "DNA_scene_types.h"
37 #include "DNA_windowmanager_types.h"
38 #include "DNA_userdef_types.h"
40 #include "MEM_guardedalloc.h"
42 #include "GHOST_C-api.h"
44 #include "BLI_blenlib.h"
46 #include "BKE_blender.h"
47 #include "BKE_context.h"
48 #include "BKE_idprop.h"
49 #include "BKE_global.h"
51 #include "BKE_report.h"
52 #include "BKE_scene.h"
53 #include "BKE_screen.h"
54 #include "BKE_utildefines.h"
55 #include "BKE_sound.h"
57 #include "ED_fileselect.h"
59 #include "ED_screen.h"
62 #include "RNA_access.h"
64 #include "UI_interface.h"
71 #include "wm_window.h"
72 #include "wm_event_system.h"
73 #include "wm_event_types.h"
76 /* ************ event management ************** */
78 void wm_event_add(wmWindow *win, wmEvent *event_to_add)
80 wmEvent *event= MEM_callocN(sizeof(wmEvent), "event");
82 *event= *event_to_add;
83 BLI_addtail(&win->queue, event);
86 void wm_event_free(wmEvent *event)
88 if(event->customdata) {
89 if(event->customdatafree) {
90 /* note: pointer to listbase struct elsewhere */
91 if(event->custom==EVT_DATA_LISTBASE)
92 BLI_freelistN(event->customdata);
94 MEM_freeN(event->customdata);
100 void wm_event_free_all(wmWindow *win)
104 while((event= win->queue.first)) {
105 BLI_remlink(&win->queue, event);
106 wm_event_free(event);
110 /* ********************* notifiers, listeners *************** */
112 static int wm_test_duplicate_notifier(wmWindowManager *wm, unsigned int type, void *reference)
116 for(note=wm->queue.first; note; note=note->next)
117 if((note->category|note->data|note->subtype|note->action) == type && note->reference == reference)
123 /* XXX: in future, which notifiers to send to other windows? */
124 void WM_event_add_notifier(const bContext *C, unsigned int type, void *reference)
126 wmNotifier *note= MEM_callocN(sizeof(wmNotifier), "notifier");
128 note->wm= CTX_wm_manager(C);
129 BLI_addtail(¬e->wm->queue, note);
131 note->window= CTX_wm_window(C);
134 note->swinid= CTX_wm_region(C)->swinid;
136 note->category= type & NOTE_CATEGORY;
137 note->data= type & NOTE_DATA;
138 note->subtype= type & NOTE_SUBTYPE;
139 note->action= type & NOTE_ACTION;
141 note->reference= reference;
144 void WM_main_add_notifier(unsigned int type, void *reference)
147 wmWindowManager *wm= bmain->wm.first;
149 if(wm && !wm_test_duplicate_notifier(wm, type, reference)) {
150 wmNotifier *note= MEM_callocN(sizeof(wmNotifier), "notifier");
153 BLI_addtail(¬e->wm->queue, note);
155 note->category= type & NOTE_CATEGORY;
156 note->data= type & NOTE_DATA;
157 note->subtype= type & NOTE_SUBTYPE;
158 note->action= type & NOTE_ACTION;
160 note->reference= reference;
164 static wmNotifier *wm_notifier_next(wmWindowManager *wm)
166 wmNotifier *note= wm->queue.first;
168 if(note) BLI_remlink(&wm->queue, note);
172 /* called in mainloop */
173 void wm_event_do_notifiers(bContext *C)
175 wmWindowManager *wm= CTX_wm_manager(C);
176 wmNotifier *note, *next;
182 /* cache & catch WM level notifiers, such as frame change, scene/screen set */
183 for(win= wm->windows.first; win; win= win->next) {
186 CTX_wm_window_set(C, win);
188 for(note= wm->queue.first; note; note= next) {
191 if(note->category==NC_WM) {
192 if( ELEM(note->data, ND_FILEREAD, ND_FILESAVE)) {
194 wm_window_title(wm, win);
196 else if(note->data==ND_DATACHANGED)
197 wm_window_title(wm, win);
199 if(note->window==win) {
200 if(note->category==NC_SCREEN) {
201 if(note->data==ND_SCREENBROWSE) {
202 ED_screen_set(C, note->reference); // XXX hrms, think this over!
204 printf("screen set %p\n", note->reference);
206 else if(note->data==ND_SCREENDELETE) {
207 ED_screen_delete(C, note->reference); // XXX hrms, think this over!
209 printf("screen delete %p\n", note->reference);
214 if(note->window==win || (note->window == NULL && (note->reference == NULL || note->reference == CTX_data_scene(C)))) {
215 if(note->category==NC_SCENE) {
216 if(note->data==ND_SCENEBROWSE) {
217 ED_screen_set_scene(C, note->reference); // XXX hrms, think this over!
219 printf("scene set %p\n", note->reference);
221 else if(note->data==ND_FRAME)
224 if(note->action == NA_REMOVED) {
225 ED_screen_delete_scene(C, note->reference); // XXX hrms, think this over!
227 printf("scene delete %p\n", note->reference);
231 if(ELEM5(note->category, NC_SCENE, NC_OBJECT, NC_GEOM, NC_SCENE, NC_WM)) {
232 ED_info_stats_clear(CTX_data_scene(C));
233 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_INFO, NULL);
238 /* XXX, quick frame changes can cause a crash if framechange and rendering
239 * collide (happens on slow scenes), scene_update_for_newframe can be called
240 * twice which can depgraph update the same object at once */
243 /* depsgraph gets called, might send more notifiers */
244 ED_update_for_newframe(C, 1);
249 /* the notifiers are sent without context, to keep it clean */
250 while( (note=wm_notifier_next(wm)) ) {
253 for(win= wm->windows.first; win; win= win->next) {
255 /* filter out notifiers */
256 if(note->category==NC_SCREEN && note->reference && note->reference!=win->screen);
257 else if(note->category==NC_SCENE && note->reference && note->reference!=win->screen->scene);
262 /* XXX context in notifiers? */
263 CTX_wm_window_set(C, win);
265 /* printf("notifier win %d screen %s cat %x\n", win->winid, win->screen->id.name+2, note->category); */
266 ED_screen_do_listen(win, note);
268 for(ar=win->screen->regionbase.first; ar; ar= ar->next) {
269 ED_region_do_listen(ar, note);
272 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
273 ED_area_do_listen(sa, note);
274 for(ar=sa->regionbase.first; ar; ar= ar->next) {
275 ED_region_do_listen(ar, note);
284 /* cached: editor refresh callbacks now, they get context */
285 for(win= wm->windows.first; win; win= win->next) {
288 CTX_wm_window_set(C, win);
289 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
291 CTX_wm_area_set(C, sa);
292 ED_area_do_refresh(C, sa);
296 /* XXX make lock in future, or separated derivedmesh users in scene */
298 /* depsgraph & animation: update tagged datablocks */
299 scene_update_tagged(CTX_data_main(C), win->screen->scene);
302 CTX_wm_window_set(C, NULL);
305 /* ********************* ui handler ******************* */
307 static int wm_handler_ui_call(bContext *C, wmEventHandler *handler, wmEvent *event, int always_pass)
309 ScrArea *area= CTX_wm_area(C);
310 ARegion *region= CTX_wm_region(C);
311 ARegion *menu= CTX_wm_menu(C);
314 /* we set context to where ui handler came from */
315 if(handler->ui_area) CTX_wm_area_set(C, handler->ui_area);
316 if(handler->ui_region) CTX_wm_region_set(C, handler->ui_region);
317 if(handler->ui_menu) CTX_wm_menu_set(C, handler->ui_menu);
319 retval= handler->ui_handle(C, event, handler->ui_userdata);
321 /* putting back screen context */
322 if((retval != WM_UI_HANDLER_BREAK) || always_pass) {
323 CTX_wm_area_set(C, area);
324 CTX_wm_region_set(C, region);
325 CTX_wm_menu_set(C, menu);
328 /* this special cases is for areas and regions that get removed */
329 CTX_wm_area_set(C, NULL);
330 CTX_wm_region_set(C, NULL);
331 CTX_wm_menu_set(C, NULL);
334 if(retval == WM_UI_HANDLER_BREAK)
335 return WM_HANDLER_BREAK;
337 return WM_HANDLER_CONTINUE;
340 static void wm_handler_ui_cancel(bContext *C)
342 wmWindow *win= CTX_wm_window(C);
343 ARegion *ar= CTX_wm_region(C);
344 wmEventHandler *handler, *nexthandler;
349 for(handler= ar->handlers.first; handler; handler= nexthandler) {
350 nexthandler= handler->next;
352 if(handler->ui_handle) {
353 wmEvent event= *(win->eventstate);
354 event.type= EVT_BUT_CANCEL;
355 handler->ui_handle(C, &event, handler->ui_userdata);
360 /* ********************* operators ******************* */
362 int WM_operator_poll(bContext *C, wmOperatorType *ot)
364 wmOperatorTypeMacro *otmacro;
366 for(otmacro= ot->macro.first; otmacro; otmacro= otmacro->next) {
367 wmOperatorType *ot= WM_operatortype_find(otmacro->idname, 0);
369 if(0==WM_operator_poll(C, ot))
373 /* python needs operator type, so we added exception for it */
375 return ot->pyop_poll(C, ot);
382 static void wm_operator_print(wmOperator *op)
384 char *buf = WM_operator_pystring(NULL, op->type, op->ptr, 1);
389 static void wm_operator_reports(bContext *C, wmOperator *op, int retval, int popup)
391 wmWindowManager *wm = CTX_wm_manager(C);
392 ReportList *reports = CTX_wm_reports(C);
396 if(op->reports->list.first)
397 uiPupMenuReports(C, op->reports);
399 if(retval & OPERATOR_FINISHED) {
401 wm_operator_print(op); /* todo - this print may double up, might want to check more flags then the FINISHED */
403 if (op->type->flag & OPTYPE_REGISTER) {
404 /* Report the python string representation of the operator */
405 buf = WM_operator_pystring(C, op->type, op->ptr, 1);
406 BKE_report(CTX_wm_reports(C), RPT_OPERATOR, buf);
411 if (op->reports->list.first) {
412 ReportTimerInfo *rti;
414 /* add reports to the global list, otherwise they are not seen */
415 addlisttolist(&CTX_wm_reports(C)->list, &op->reports->list);
417 /* After adding reports to the global list, reset the report timer. */
418 WM_event_remove_timer(wm, NULL, reports->reporttimer);
420 /* Records time since last report was added */
421 reports->reporttimer= WM_event_add_timer(wm, CTX_wm_window(C), TIMER, 0.02);
423 rti = MEM_callocN(sizeof(ReportTimerInfo), "ReportTimerInfo");
424 reports->reporttimer->customdata = rti;
428 static void wm_operator_finished(bContext *C, wmOperator *op, int repeat)
430 wmWindowManager *wm= CTX_wm_manager(C);
432 op->customdata= NULL;
434 /* we don't want to do undo pushes for operators that are being
435 called from operators that already do an undo push. usually
436 this will happen for python operators that call C operators */
437 if(wm->op_undo_depth == 0)
438 if(op->type->flag & OPTYPE_UNDO)
439 ED_undo_push_op(C, op);
443 char *buf = WM_operator_pystring(C, op->type, op->ptr, 1);
444 BKE_report(CTX_wm_reports(C), RPT_OPERATOR, buf);
448 if((wm->op_undo_depth == 0) && (op->type->flag & OPTYPE_REGISTER))
449 wm_operator_register(C, op);
451 WM_operator_free(op);
455 /* if repeat is true, it doesn't register again, nor does it free */
456 static int wm_operator_exec(bContext *C, wmOperator *op, int repeat)
458 wmWindowManager *wm= CTX_wm_manager(C);
459 int retval= OPERATOR_CANCELLED;
461 if(op==NULL || op->type==NULL)
464 if(0==WM_operator_poll(C, op->type))
468 if(op->type->flag & OPTYPE_UNDO)
471 retval= op->type->exec(C, op);
473 if(op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm)
477 if (retval & (OPERATOR_FINISHED|OPERATOR_CANCELLED) && repeat == 0)
478 wm_operator_reports(C, op, retval, 0);
480 if(retval & OPERATOR_FINISHED)
481 wm_operator_finished(C, op, repeat);
483 WM_operator_free(op);
485 return retval | OPERATOR_HANDLED;
488 /* for running operators with frozen context (modal handlers, menus) */
489 int WM_operator_call(bContext *C, wmOperator *op)
491 return wm_operator_exec(C, op, 0);
494 /* do this operator again, put here so it can share above code */
495 int WM_operator_repeat(bContext *C, wmOperator *op)
497 return wm_operator_exec(C, op, 1);
500 static wmOperator *wm_operator_create(wmWindowManager *wm, wmOperatorType *ot, PointerRNA *properties, ReportList *reports)
502 wmOperator *op= MEM_callocN(sizeof(wmOperator), ot->idname); /* XXX operatortype names are static still. for debug */
504 /* XXX adding new operator could be function, only happens here now */
506 BLI_strncpy(op->idname, ot->idname, OP_MAX_TYPENAME);
508 /* initialize properties, either copy or create */
509 op->ptr= MEM_callocN(sizeof(PointerRNA), "wmOperatorPtrRNA");
510 if(properties && properties->data) {
511 op->properties= IDP_CopyProperty(properties->data);
514 IDPropertyTemplate val = {0};
515 op->properties= IDP_New(IDP_GROUP, val, "wmOperatorProperties");
517 RNA_pointer_create(&wm->id, ot->srna, op->properties, op->ptr);
519 /* initialize error reports */
521 op->reports= reports; /* must be initialized already */
524 op->reports= MEM_mallocN(sizeof(ReportList), "wmOperatorReportList");
525 BKE_reports_init(op->reports, RPT_STORE|RPT_FREE);
528 /* recursive filling of operator macro list */
529 if(ot->macro.first) {
530 static wmOperator *motherop= NULL;
531 wmOperatorTypeMacro *otmacro;
534 /* ensure all ops are in execution order in 1 list */
540 /* if properties exist, it will contain everything needed */
542 otmacro= ot->macro.first;
544 RNA_STRUCT_BEGIN(properties, prop) {
549 /* skip invalid properties */
550 if (strcmp(RNA_property_identifier(prop), otmacro->idname) == 0)
552 wmOperatorType *otm= WM_operatortype_find(otmacro->idname, 0);
553 PointerRNA someptr = RNA_property_pointer_get(properties, prop);
554 wmOperator *opm= wm_operator_create(wm, otm, &someptr, NULL);
556 IDP_ReplaceGroupInGroup(opm->properties, otmacro->properties);
558 BLI_addtail(&motherop->macro, opm);
559 opm->opm= motherop; /* pointer to mom, for modal() */
561 otmacro= otmacro->next;
566 for (otmacro = ot->macro.first; otmacro; otmacro = otmacro->next) {
567 wmOperatorType *otm= WM_operatortype_find(otmacro->idname, 0);
568 wmOperator *opm= wm_operator_create(wm, otm, otmacro->ptr, NULL);
570 BLI_addtail(&motherop->macro, opm);
571 opm->opm= motherop; /* pointer to mom, for modal() */
579 WM_operator_properties_sanitize(op->ptr, 0);
584 static void wm_region_mouse_co(bContext *C, wmEvent *event)
586 ARegion *ar= CTX_wm_region(C);
588 /* compatibility convention */
589 event->mval[0]= event->x - ar->winrct.xmin;
590 event->mval[1]= event->y - ar->winrct.ymin;
594 int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, PointerRNA *properties, ReportList *reports)
596 wmWindowManager *wm= CTX_wm_manager(C);
597 int retval= OPERATOR_PASS_THROUGH;
599 if(WM_operator_poll(C, ot)) {
600 wmOperator *op= wm_operator_create(wm, ot, properties, reports); /* if reports==NULL, theyll be initialized */
602 if((G.f & G_DEBUG) && event && event->type!=MOUSEMOVE)
603 printf("handle evt %d win %d op %s\n", event?event->type:0, CTX_wm_screen(C)->subwinactive, ot->idname);
605 if(op->type->invoke && event) {
606 wm_region_mouse_co(C, event);
608 if(op->type->flag & OPTYPE_UNDO)
611 retval= op->type->invoke(C, op, event);
613 if(op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm)
616 else if(op->type->exec) {
617 if(op->type->flag & OPTYPE_UNDO)
620 retval= op->type->exec(C, op);
622 if(op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm)
626 printf("invalid operator call %s\n", ot->idname); /* debug, important to leave a while, should never happen */
628 /* Note, if the report is given as an argument then assume the caller will deal with displaying them
629 * currently python only uses this */
630 if (!(retval & OPERATOR_HANDLED) && retval & (OPERATOR_FINISHED|OPERATOR_CANCELLED))
631 /* only show the report if the report list was not given in the function */
632 wm_operator_reports(C, op, retval, (reports==NULL));
634 if(retval & OPERATOR_HANDLED)
635 ; /* do nothing, wm_operator_exec() has been called somewhere */
636 else if(retval & OPERATOR_FINISHED) {
637 wm_operator_finished(C, op, 0);
639 else if(retval & OPERATOR_RUNNING_MODAL) {
640 /* grab cursor during blocking modal ops (X11)
641 * Also check for macro
643 if(ot->flag & OPTYPE_BLOCKING || (op->opm && op->opm->type->flag & OPTYPE_BLOCKING)) {
644 int bounds[4] = {-1,-1,-1,-1};
648 wrap = (U.uiflag & USER_CONTINUOUS_MOUSE) && ((op->opm->flag & OP_GRAB_POINTER) || (op->opm->type->flag & OPTYPE_GRAB_POINTER));
650 wrap = (U.uiflag & USER_CONTINUOUS_MOUSE) && ((op->flag & OP_GRAB_POINTER) || (ot->flag & OPTYPE_GRAB_POINTER));
654 ARegion *ar= CTX_wm_region(C);
656 bounds[0]= ar->winrct.xmin;
657 bounds[1]= ar->winrct.ymax;
658 bounds[2]= ar->winrct.xmax;
659 bounds[3]= ar->winrct.ymin;
663 WM_cursor_grab(CTX_wm_window(C), wrap, FALSE, bounds);
666 /* cancel UI handlers, typically tooltips that can hang around
667 while dragging the view or worse, that stay there permanently
668 after the modal operator has swallowed all events and passed
669 none to the UI handler */
670 wm_handler_ui_cancel(C);
673 WM_operator_free(op);
679 /* WM_operator_name_call is the main accessor function
680 * this is for python to access since its done the operator lookup
682 * invokes operator in context */
683 static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, int context, PointerRNA *properties, ReportList *reports)
685 wmWindow *window= CTX_wm_window(C);
693 case WM_OP_INVOKE_DEFAULT:
694 case WM_OP_INVOKE_REGION_WIN:
695 case WM_OP_INVOKE_AREA:
696 case WM_OP_INVOKE_SCREEN:
697 /* window is needed for invoke, cancel operator */
701 event= window->eventstate;
709 case WM_OP_EXEC_REGION_WIN:
710 case WM_OP_INVOKE_REGION_WIN:
711 case WM_OP_EXEC_REGION_CHANNELS:
712 case WM_OP_INVOKE_REGION_CHANNELS:
713 case WM_OP_EXEC_REGION_PREVIEW:
714 case WM_OP_INVOKE_REGION_PREVIEW:
716 /* forces operator to go to the region window/channels/preview, for header menus
717 * but we stay in the same region if we are already in one
719 ARegion *ar= CTX_wm_region(C);
720 ScrArea *area= CTX_wm_area(C);
721 int type = RGN_TYPE_WINDOW;
724 case WM_OP_EXEC_REGION_CHANNELS:
725 case WM_OP_INVOKE_REGION_CHANNELS:
726 type = RGN_TYPE_CHANNELS;
728 case WM_OP_EXEC_REGION_PREVIEW:
729 case WM_OP_INVOKE_REGION_PREVIEW:
730 type = RGN_TYPE_PREVIEW;
733 case WM_OP_EXEC_REGION_WIN:
734 case WM_OP_INVOKE_REGION_WIN:
736 type = RGN_TYPE_WINDOW;
740 if(!(ar && ar->regiontype == type) && area) {
741 ARegion *ar1= BKE_area_find_region_type(area, type);
743 CTX_wm_region_set(C, ar1);
746 retval= wm_operator_invoke(C, ot, event, properties, reports);
748 /* set region back */
749 CTX_wm_region_set(C, ar);
753 case WM_OP_EXEC_AREA:
754 case WM_OP_INVOKE_AREA:
756 /* remove region from context */
757 ARegion *ar= CTX_wm_region(C);
759 CTX_wm_region_set(C, NULL);
760 retval= wm_operator_invoke(C, ot, event, properties, reports);
761 CTX_wm_region_set(C, ar);
765 case WM_OP_EXEC_SCREEN:
766 case WM_OP_INVOKE_SCREEN:
768 /* remove region + area from context */
769 ARegion *ar= CTX_wm_region(C);
770 ScrArea *area= CTX_wm_area(C);
772 CTX_wm_region_set(C, NULL);
773 CTX_wm_area_set(C, NULL);
774 retval= wm_operator_invoke(C, ot, event, properties, reports);
775 CTX_wm_region_set(C, ar);
776 CTX_wm_area_set(C, area);
780 case WM_OP_EXEC_DEFAULT:
781 case WM_OP_INVOKE_DEFAULT:
782 return wm_operator_invoke(C, ot, event, properties, reports);
790 /* invokes operator in context */
791 int WM_operator_name_call(bContext *C, const char *opstring, int context, PointerRNA *properties)
793 wmOperatorType *ot= WM_operatortype_find(opstring, 0);
795 return wm_operator_call_internal(C, ot, context, properties, NULL);
800 /* Similar to WM_operator_name_call called with WM_OP_EXEC_DEFAULT context.
801 - wmOperatorType is used instead of operator name since python already has the operator type
802 - poll() must be called by python before this runs.
803 - reports can be passed to this function (so python can report them as exceptions)
805 int WM_operator_call_py(bContext *C, wmOperatorType *ot, int context, PointerRNA *properties, ReportList *reports)
807 int retval= OPERATOR_CANCELLED;
811 wmWindowManager *wm= CTX_wm_manager(C);
812 op= wm_operator_create(wm, ot, properties, reports);
814 if (op->type->exec) {
815 if(op->type->flag & OPTYPE_UNDO)
818 retval= op->type->exec(C, op);
820 if(op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm)
824 printf("error \"%s\" operator has no exec function, python cannot call it\n", op->type->name);
827 retval= wm_operator_call_internal(C, ot, context, properties, reports);
829 /* keep the reports around if needed later */
830 if (retval & OPERATOR_RUNNING_MODAL || ot->flag & OPTYPE_REGISTER)
832 reports->flag |= RPT_FREE;
839 /* ********************* handlers *************** */
841 /* future extra customadata free? */
842 void wm_event_free_handler(wmEventHandler *handler)
847 /* only set context when area/region is part of screen */
848 static void wm_handler_op_context(bContext *C, wmEventHandler *handler)
850 bScreen *screen= CTX_wm_screen(C);
852 if(screen && handler->op) {
853 if(handler->op_area==NULL)
854 CTX_wm_area_set(C, NULL);
858 for(sa= screen->areabase.first; sa; sa= sa->next)
859 if(sa==handler->op_area)
862 /* when changing screen layouts with running modal handlers (like render display), this
863 is not an error to print */
864 if(handler->op==NULL)
865 printf("internal error: handler (%s) has invalid area\n", handler->op->type->idname);
869 CTX_wm_area_set(C, sa);
870 for(ar= sa->regionbase.first; ar; ar= ar->next)
871 if(ar==handler->op_region)
873 /* XXX no warning print here, after full-area and back regions are remade */
875 CTX_wm_region_set(C, ar);
881 /* called on exit or remove area, only here call cancel callback */
882 void WM_event_remove_handlers(bContext *C, ListBase *handlers)
884 wmEventHandler *handler;
885 wmWindowManager *wm= CTX_wm_manager(C);
887 /* C is zero on freeing database, modal handlers then already were freed */
888 while((handler=handlers->first)) {
889 BLI_remlink(handlers, handler);
892 if(handler->op->type->cancel) {
893 ScrArea *area= CTX_wm_area(C);
894 ARegion *region= CTX_wm_region(C);
896 wm_handler_op_context(C, handler);
898 if(handler->op->type->flag & OPTYPE_UNDO)
901 handler->op->type->cancel(C, handler->op);
903 if(handler->op->type->flag & OPTYPE_UNDO)
906 CTX_wm_area_set(C, area);
907 CTX_wm_region_set(C, region);
910 WM_cursor_ungrab(CTX_wm_window(C));
911 WM_operator_free(handler->op);
913 else if(handler->ui_remove) {
914 ScrArea *area= CTX_wm_area(C);
915 ARegion *region= CTX_wm_region(C);
916 ARegion *menu= CTX_wm_menu(C);
918 if(handler->ui_area) CTX_wm_area_set(C, handler->ui_area);
919 if(handler->ui_region) CTX_wm_region_set(C, handler->ui_region);
920 if(handler->ui_menu) CTX_wm_menu_set(C, handler->ui_menu);
922 handler->ui_remove(C, handler->ui_userdata);
924 CTX_wm_area_set(C, area);
925 CTX_wm_region_set(C, region);
926 CTX_wm_menu_set(C, menu);
929 wm_event_free_handler(handler);
933 /* do userdef mappings */
934 int WM_userdef_event_map(int kmitype)
938 if(U.flag & USER_LMOUSESELECT)
944 if(U.flag & USER_LMOUSESELECT)
950 if(U.uiflag & USER_WHEELZOOMDIR)
953 return WHEELDOWNMOUSE;
956 if(U.uiflag & USER_WHEELZOOMDIR)
957 return WHEELDOWNMOUSE;
962 if(U.flag & USER_LMOUSESELECT)
968 if(U.flag & USER_LMOUSESELECT)
977 static void wm_eventemulation(wmEvent *event)
979 static int mmb_emulated = 0; /* this should be in a data structure somwhere */
981 /* middlemouse emulation */
982 if(U.flag & USER_TWOBUTTONMOUSE) {
983 if(event->type == LEFTMOUSE && (event->alt || mmb_emulated == KM_PRESS)) {
984 event->type = MIDDLEMOUSE;
986 mmb_emulated = event->val;
991 /* rightmouse emulation */
992 if(U.flag & USER_TWOBUTTONMOUSE) {
993 if(event->type == LEFTMOUSE && (event->oskey || mmb_emulated == KM_PRESS)) {
994 event->type = RIGHTMOUSE;
996 mmb_emulated = event->val;
1001 /* numpad emulation */
1002 if(U.flag & USER_NONUMPAD) {
1003 switch(event->type) {
1004 case ZEROKEY: event->type = PAD0; break;
1005 case ONEKEY: event->type = PAD1; break;
1006 case TWOKEY: event->type = PAD2; break;
1007 case THREEKEY: event->type = PAD3; break;
1008 case FOURKEY: event->type = PAD4; break;
1009 case FIVEKEY: event->type = PAD5; break;
1010 case SIXKEY: event->type = PAD6; break;
1011 case SEVENKEY: event->type = PAD7; break;
1012 case EIGHTKEY: event->type = PAD8; break;
1013 case NINEKEY: event->type = PAD9; break;
1014 case MINUSKEY: event->type = PADMINUS; break;
1015 case EQUALKEY: event->type = PADPLUSKEY; break;
1016 case BACKSLASHKEY: event->type = PADSLASHKEY; break;
1021 static int wm_eventmatch(wmEvent *winevent, wmKeyMapItem *kmi)
1023 int kmitype= WM_userdef_event_map(kmi->type);
1025 if(kmi->flag & KMI_INACTIVE) return 0;
1027 /* the matching rules */
1028 if(kmitype==KM_TEXTINPUT)
1029 if(ISTEXTINPUT(winevent->type) && winevent->ascii) return 1;
1031 if(winevent->type!=kmitype) return 0;
1033 if(kmi->val!=KM_ANY)
1034 if(winevent->val!=kmi->val) return 0;
1036 /* modifiers also check bits, so it allows modifier order */
1037 if(kmi->shift!=KM_ANY)
1038 if(winevent->shift != kmi->shift && !(winevent->shift & kmi->shift)) return 0;
1039 if(kmi->ctrl!=KM_ANY)
1040 if(winevent->ctrl != kmi->ctrl && !(winevent->ctrl & kmi->ctrl)) return 0;
1041 if(kmi->alt!=KM_ANY)
1042 if(winevent->alt != kmi->alt && !(winevent->alt & kmi->alt)) return 0;
1043 if(kmi->oskey!=KM_ANY)
1044 if(winevent->oskey != kmi->oskey && !(winevent->oskey & kmi->oskey)) return 0;
1046 if(kmi->keymodifier)
1047 if(winevent->keymodifier!=kmi->keymodifier) return 0;
1049 /* key modifiers always check when event has it */
1050 /* otherwise regular keypresses with keymodifier still work */
1051 if(winevent->keymodifier)
1052 if(ISTEXTINPUT(winevent->type))
1053 if(winevent->keymodifier!=kmi->keymodifier) return 0;
1058 static int wm_event_always_pass(wmEvent *event)
1060 /* some events we always pass on, to ensure proper communication */
1061 return ISTIMER(event->type) || (event->type == WINDEACTIVATE);
1064 /* operator exists */
1065 static void wm_event_modalkeymap(const bContext *C, wmOperator *op, wmEvent *event)
1067 /* support for modal keymap in macros */
1071 if(op->type->modalkeymap) {
1072 wmKeyMap *keymap= WM_keymap_active(CTX_wm_manager(C), op->type->modalkeymap);
1075 for(kmi= keymap->items.first; kmi; kmi= kmi->next) {
1076 if(wm_eventmatch(event, kmi)) {
1077 event->type= EVT_MODAL_MAP;
1078 event->val= kmi->propvalue;
1084 /* Warning: this function removes a modal handler, when finished */
1085 static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHandler *handler, wmEvent *event, PointerRNA *properties)
1087 int retval= OPERATOR_PASS_THROUGH;
1089 /* derived, modal or blocking operator */
1091 wmOperator *op= handler->op;
1092 wmOperatorType *ot= op->type;
1095 /* we set context to where modal handler came from */
1096 wmWindowManager *wm= CTX_wm_manager(C);
1097 ScrArea *area= CTX_wm_area(C);
1098 ARegion *region= CTX_wm_region(C);
1100 wm_handler_op_context(C, handler);
1101 wm_region_mouse_co(C, event);
1102 wm_event_modalkeymap(C, op, event);
1104 if(ot->flag & OPTYPE_UNDO)
1105 wm->op_undo_depth++;
1107 retval= ot->modal(C, op, event);
1109 if(ot->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm)
1110 wm->op_undo_depth--;
1112 /* putting back screen context, reval can pass trough after modal failures! */
1113 if((retval & OPERATOR_PASS_THROUGH) || wm_event_always_pass(event)) {
1114 CTX_wm_area_set(C, area);
1115 CTX_wm_region_set(C, region);
1118 /* this special cases is for areas and regions that get removed */
1119 CTX_wm_area_set(C, NULL);
1120 CTX_wm_region_set(C, NULL);
1123 if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED))
1124 wm_operator_reports(C, op, retval, 0);
1126 if(retval & OPERATOR_FINISHED) {
1127 wm_operator_finished(C, op, 0);
1130 else if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) {
1131 WM_operator_free(op);
1135 /* remove modal handler, operator itself should have been cancelled and freed */
1136 if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) {
1137 WM_cursor_ungrab(CTX_wm_window(C));
1139 BLI_remlink(handlers, handler);
1140 wm_event_free_handler(handler);
1142 /* prevent silly errors from operator users */
1143 //retval &= ~OPERATOR_PASS_THROUGH;
1147 printf("wm_handler_operator_call error\n");
1150 wmOperatorType *ot= WM_operatortype_find(event->keymap_idname, 0);
1153 retval= wm_operator_invoke(C, ot, event, properties, NULL);
1156 /* Finished and pass through flag as handled */
1157 if(retval == (OPERATOR_FINISHED|OPERATOR_PASS_THROUGH))
1158 return WM_HANDLER_HANDLED;
1160 /* Modal unhandled, break */
1161 if(retval == (OPERATOR_PASS_THROUGH|OPERATOR_RUNNING_MODAL))
1162 return (WM_HANDLER_BREAK|WM_HANDLER_MODAL);
1164 if(retval & OPERATOR_PASS_THROUGH)
1165 return WM_HANDLER_CONTINUE;
1167 return WM_HANDLER_BREAK;
1170 /* fileselect handlers are only in the window queue, so it's save to switch screens or area types */
1171 static int wm_handler_fileselect_call(bContext *C, ListBase *handlers, wmEventHandler *handler, wmEvent *event)
1173 wmWindowManager *wm= CTX_wm_manager(C);
1175 int action= WM_HANDLER_CONTINUE;
1177 if(event->type != EVT_FILESELECT)
1179 if(handler->op != (wmOperator *)event->customdata)
1182 switch(event->val) {
1183 case EVT_FILESELECT_OPEN:
1184 case EVT_FILESELECT_FULL_OPEN:
1188 /* sa can be null when window A is active, but mouse is over window B */
1189 /* in this case, open file select in original window A */
1190 if (handler->op_area == NULL) {
1191 bScreen *screen = CTX_wm_screen(C);
1192 sa = (ScrArea *)screen->areabase.first;
1194 sa = handler->op_area;
1196 if(event->val==EVT_FILESELECT_OPEN)
1197 ED_area_newspace(C, sa, SPACE_FILE);
1199 ED_screen_full_newspace(C, sa, SPACE_FILE); /* sets context */
1201 /* settings for filebrowser, sfile is not operator owner but sends events */
1202 sa = CTX_wm_area(C);
1203 sfile= (SpaceFile*)sa->spacedata.first;
1204 sfile->op= handler->op;
1206 ED_fileselect_set_params(sfile);
1208 action= WM_HANDLER_BREAK;
1212 case EVT_FILESELECT_EXEC:
1213 case EVT_FILESELECT_CANCEL:
1215 /* XXX validate area and region? */
1216 bScreen *screen= CTX_wm_screen(C);
1218 if(screen != handler->filescreen)
1219 ED_screen_full_prevspace(C, CTX_wm_area(C));
1221 ED_area_prevspace(C, CTX_wm_area(C));
1223 /* remlink now, for load file case */
1224 BLI_remlink(handlers, handler);
1226 wm_handler_op_context(C, handler);
1228 /* needed for uiPupMenuReports */
1230 if(event->val==EVT_FILESELECT_EXEC) {
1231 /* a bit weak, might become arg for WM_event_fileselect? */
1232 /* XXX also extension code in image-save doesnt work for this yet */
1233 if (RNA_struct_find_property(handler->op->ptr, "check_existing") &&
1234 RNA_boolean_get(handler->op->ptr, "check_existing")) {
1235 char *path= RNA_string_get_alloc(handler->op->ptr, "filepath", NULL, 0);
1236 /* this gives ownership to pupmenu */
1237 uiPupMenuSaveOver(C, handler->op, (path)? path: "");
1244 if(handler->op->type->flag & OPTYPE_UNDO)
1245 wm->op_undo_depth++;
1247 retval= handler->op->type->exec(C, handler->op);
1249 if(handler->op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm)
1250 wm->op_undo_depth--;
1252 if (retval & OPERATOR_FINISHED)
1254 wm_operator_print(handler->op);
1256 if(wm->op_undo_depth == 0)
1257 if(handler->op->type->flag & OPTYPE_UNDO)
1258 ED_undo_push_op(C, handler->op);
1260 if(handler->op->reports->list.first) {
1262 /* FIXME, temp setting window, this is really bad!
1263 * only have because lib linking errors need to be seen by users :(
1264 * it can be removed without breaking anything but then no linking errors - campbell */
1265 wmWindow *win_prev= CTX_wm_window(C);
1267 CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first);
1269 handler->op->reports->printlevel = RPT_WARNING;
1270 uiPupMenuReports(C, handler->op->reports);
1272 /* XXX - copied from 'wm_operator_finished()' */
1273 /* add reports to the global list, otherwise they are not seen */
1274 addlisttolist(&CTX_wm_reports(C)->list, &handler->op->reports->list);
1276 CTX_wm_window_set(C, win_prev);
1279 WM_operator_free(handler->op);
1283 if(handler->op->type->cancel) {
1284 if(handler->op->type->flag & OPTYPE_UNDO)
1285 wm->op_undo_depth++;
1287 handler->op->type->cancel(C, handler->op);
1289 if(handler->op->type->flag & OPTYPE_UNDO)
1290 wm->op_undo_depth--;
1293 WM_operator_free(handler->op);
1296 CTX_wm_area_set(C, NULL);
1298 wm_event_free_handler(handler);
1300 action= WM_HANDLER_BREAK;
1308 static int handler_boundbox_test(wmEventHandler *handler, wmEvent *event)
1310 if(handler->bbwin) {
1311 if(handler->bblocal) {
1312 rcti rect= *handler->bblocal;
1313 BLI_translate_rcti(&rect, handler->bbwin->xmin, handler->bbwin->ymin);
1315 if(BLI_in_rcti(&rect, event->x, event->y))
1317 else if(event->type==MOUSEMOVE && BLI_in_rcti(&rect, event->prevx, event->prevy))
1323 if(BLI_in_rcti(handler->bbwin, event->x, event->y))
1325 else if(event->type==MOUSEMOVE && BLI_in_rcti(handler->bbwin, event->prevx, event->prevy))
1334 static int wm_action_not_handled(int action)
1336 return action == WM_HANDLER_CONTINUE || action == (WM_HANDLER_BREAK|WM_HANDLER_MODAL);
1339 static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
1341 wmWindowManager *wm= CTX_wm_manager(C);
1342 wmEventHandler *handler, *nexthandler;
1343 int action= WM_HANDLER_CONTINUE;
1346 if(handlers==NULL) return action;
1348 /* modal handlers can get removed in this loop, we keep the loop this way */
1349 for(handler= handlers->first; handler; handler= nexthandler) {
1350 nexthandler= handler->next;
1352 /* optional boundbox */
1353 if(handler_boundbox_test(handler, event)) {
1354 /* in advance to avoid access to freed event on window close */
1355 always_pass= wm_event_always_pass(event);
1357 /* modal+blocking handler */
1358 if(handler->flag & WM_HANDLER_BLOCKING)
1359 action |= WM_HANDLER_BREAK;
1361 if(handler->keymap) {
1362 wmKeyMap *keymap= WM_keymap_active(wm, handler->keymap);
1365 if(!keymap->poll || keymap->poll(C)) {
1366 for(kmi= keymap->items.first; kmi; kmi= kmi->next) {
1367 if(wm_eventmatch(event, kmi)) {
1369 event->keymap_idname= kmi->idname; /* weak, but allows interactive callback to not use rawkey */
1371 action |= wm_handler_operator_call(C, handlers, handler, event, kmi->ptr);
1372 if(action & WM_HANDLER_BREAK) /* not always_pass here, it denotes removed handler */
1378 else if(handler->ui_handle) {
1379 action |= wm_handler_ui_call(C, handler, event, always_pass);
1381 else if(handler->type==WM_HANDLER_FILESELECT) {
1382 /* screen context changes here */
1383 action |= wm_handler_fileselect_call(C, handlers, handler, event);
1385 else if(handler->dropboxes) {
1386 if(event->type==EVT_DROP) {
1387 wmDropBox *drop= handler->dropboxes->first;
1388 for(; drop; drop= drop->next) {
1389 /* other drop custom types allowed */
1390 if(event->custom==EVT_DATA_LISTBASE) {
1391 ListBase *lb= (ListBase *)event->customdata;
1393 for(drag= lb->first; drag; drag= drag->next) {
1394 if(drop->poll(C, drag, event)) {
1395 drop->copy(drag, drop);
1397 wm_operator_invoke(C, drop->ot, event, drop->ptr, NULL);
1398 action |= WM_HANDLER_BREAK;
1406 /* modal, swallows all */
1407 action |= wm_handler_operator_call(C, handlers, handler, event, NULL);
1410 if(action & WM_HANDLER_BREAK) {
1412 action &= ~WM_HANDLER_BREAK;
1419 if(CTX_wm_window(C)==NULL)
1423 /* test for CLICK event */
1424 if (wm_action_not_handled(action) && event->val == KM_RELEASE) {
1425 wmWindow *win = CTX_wm_window(C);
1427 if (win && win->eventstate->prevtype == event->type && win->eventstate->prevval == KM_PRESS) {
1428 /* test for double click first */
1429 if ((PIL_check_seconds_timer() - win->eventstate->prevclicktime) * 1000 < U.dbl_click_time) {
1430 event->val = KM_DBL_CLICK;
1431 event->x = win->eventstate->prevclickx;
1432 event->y = win->eventstate->prevclicky;
1433 action |= wm_handlers_do(C, event, handlers);
1436 if (wm_action_not_handled(action)) {
1437 event->val = KM_CLICK;
1438 action |= wm_handlers_do(C, event, handlers);
1441 /* revert value if not handled */
1442 if (wm_action_not_handled(action)) {
1443 event->val = KM_RELEASE;
1451 static int wm_event_inside_i(wmEvent *event, rcti *rect)
1453 if(wm_event_always_pass(event))
1455 if(BLI_in_rcti(rect, event->x, event->y))
1457 if(event->type==MOUSEMOVE) {
1458 if( BLI_in_rcti(rect, event->prevx, event->prevy)) {
1466 static ScrArea *area_event_inside(bContext *C, int x, int y)
1468 bScreen *screen= CTX_wm_screen(C);
1472 for(sa= screen->areabase.first; sa; sa= sa->next)
1473 if(BLI_in_rcti(&sa->totrct, x, y))
1478 static ARegion *region_event_inside(bContext *C, int x, int y)
1480 bScreen *screen= CTX_wm_screen(C);
1481 ScrArea *area= CTX_wm_area(C);
1485 for(ar= area->regionbase.first; ar; ar= ar->next)
1486 if(BLI_in_rcti(&ar->winrct, x, y))
1491 static void wm_paintcursor_tag(bContext *C, wmPaintCursor *pc, ARegion *ar)
1494 for(; pc; pc= pc->next) {
1495 if(pc->poll == NULL || pc->poll(C)) {
1496 wmWindow *win= CTX_wm_window(C);
1497 win->screen->do_draw_paintcursor= 1;
1498 wm_tag_redraw_overlay(win, ar);
1504 /* called on mousemove, check updates for paintcursors */
1505 /* context was set on active area and region */
1506 static void wm_paintcursor_test(bContext *C, wmEvent *event)
1508 wmWindowManager *wm= CTX_wm_manager(C);
1510 if(wm->paintcursors.first) {
1511 ARegion *ar= CTX_wm_region(C);
1513 wm_paintcursor_tag(C, wm->paintcursors.first, ar);
1515 /* if previous position was not in current region, we have to set a temp new context */
1516 if(ar==NULL || !BLI_in_rcti(&ar->winrct, event->prevx, event->prevy)) {
1517 ScrArea *sa= CTX_wm_area(C);
1519 CTX_wm_area_set(C, area_event_inside(C, event->prevx, event->prevy));
1520 CTX_wm_region_set(C, region_event_inside(C, event->prevx, event->prevy));
1522 wm_paintcursor_tag(C, wm->paintcursors.first, CTX_wm_region(C));
1524 CTX_wm_area_set(C, sa);
1525 CTX_wm_region_set(C, ar);
1530 static void wm_event_drag_test(wmWindowManager *wm, wmWindow *win, wmEvent *event)
1532 if(wm->drags.first==NULL) return;
1534 if(event->type==MOUSEMOVE)
1535 win->screen->do_draw_drag= 1;
1536 else if(event->type==ESCKEY) {
1537 BLI_freelistN(&wm->drags);
1538 win->screen->do_draw_drag= 1;
1540 else if(event->type==LEFTMOUSE && event->val==KM_RELEASE) {
1541 event->type= EVT_DROP;
1543 /* create customdata, first free existing */
1544 if(event->customdata) {
1545 if(event->customdatafree)
1546 MEM_freeN(event->customdata);
1549 event->custom= EVT_DATA_LISTBASE;
1550 event->customdata= &wm->drags;
1551 event->customdatafree= 1;
1553 /* clear drop icon */
1554 win->screen->do_draw_drag= 1;
1556 /* restore cursor (disabled, see wm_dragdrop.c) */
1557 // WM_cursor_restore(win);
1560 /* overlap fails otherwise */
1561 if(win->screen->do_draw_drag)
1562 if(win->drawmethod == USER_DRAW_OVERLAP)
1563 win->screen->do_draw= 1;
1567 /* called in main loop */
1568 /* goes over entire hierarchy: events -> window -> screen -> area -> region */
1569 void wm_event_do_handlers(bContext *C)
1571 wmWindowManager *wm= CTX_wm_manager(C);
1574 for(win= wm->windows.first; win; win= win->next) {
1577 if( win->screen==NULL )
1578 wm_event_free_all(win);
1580 Scene* scene = win->screen->scene;
1583 int playing = sound_scene_playing(win->screen->scene);
1586 CTX_wm_window_set(C, win);
1587 CTX_wm_screen_set(C, win->screen);
1588 CTX_data_scene_set(C, scene);
1590 if(((playing == 1) && (!win->screen->animtimer)) || ((playing == 0) && (win->screen->animtimer))){
1591 ED_screen_animation_play(C, -1, 1);
1595 int ncfra = sound_sync_scene(scene) * FPS + 0.5;
1596 if(ncfra != scene->r.cfra) {
1597 scene->r.cfra = ncfra;
1598 ED_update_for_newframe(C, 1);
1599 WM_event_add_notifier(C, NC_WINDOW, NULL);
1603 CTX_data_scene_set(C, NULL);
1604 CTX_wm_screen_set(C, NULL);
1605 CTX_wm_window_set(C, NULL);
1610 while( (event= win->queue.first) ) {
1611 int action = WM_HANDLER_CONTINUE;
1613 if((G.f & G_DEBUG) && event && !ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE))
1614 printf("pass on evt %d val %d\n", event->type, event->val);
1616 wm_eventemulation(event);
1618 CTX_wm_window_set(C, win);
1620 /* we let modal handlers get active area/region, also wm_paintcursor_test needs it */
1621 CTX_wm_area_set(C, area_event_inside(C, event->x, event->y));
1622 CTX_wm_region_set(C, region_event_inside(C, event->x, event->y));
1624 /* MVC demands to not draw in event handlers... but we need to leave it for ogl selecting etc */
1625 wm_window_make_drawable(C, win);
1627 /* first we do priority handlers, modal + some limited keymaps */
1628 action |= wm_handlers_do(C, event, &win->modalhandlers);
1631 if(CTX_wm_window(C)==NULL)
1634 /* check dragging, creates new event or frees, adds draw tag */
1635 wm_event_drag_test(wm, win, event);
1637 /* builtin tweak, if action is break it removes tweak */
1638 wm_tweakevent_test(C, event, action);
1640 if((action & WM_HANDLER_BREAK) == 0) {
1645 /* XXX to solve, here screen handlers? */
1646 if(event->type==MOUSEMOVE) {
1647 /* state variables in screen, cursors */
1648 ED_screen_set_subwinactive(win, event);
1649 /* for regions having custom cursors */
1650 wm_paintcursor_test(C, event);
1653 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
1654 if(wm_event_inside_i(event, &sa->totrct)) {
1655 CTX_wm_area_set(C, sa);
1657 if((action & WM_HANDLER_BREAK) == 0) {
1658 for(ar=sa->regionbase.first; ar; ar= ar->next) {
1659 if(wm_event_inside_i(event, &ar->winrct)) {
1660 CTX_wm_region_set(C, ar);
1662 /* does polls for drop regions and checks uibuts */
1663 /* need to be here to make sure region context is true */
1664 if(ELEM(event->type, MOUSEMOVE, EVT_DROP)) {
1665 wm_region_mouse_co(C, event);
1666 wm_drags_check_ops(C, event);
1669 action |= wm_handlers_do(C, event, &ar->handlers);
1671 doit |= (BLI_in_rcti(&ar->winrct, event->x, event->y));
1673 if(action & WM_HANDLER_BREAK)
1679 CTX_wm_region_set(C, NULL);
1681 if((action & WM_HANDLER_BREAK) == 0)
1682 action |= wm_handlers_do(C, event, &sa->handlers);
1684 CTX_wm_area_set(C, NULL);
1686 /* NOTE: do not escape on WM_HANDLER_BREAK, mousemove needs handled for previous area */
1690 if((action & WM_HANDLER_BREAK) == 0) {
1691 /* also some non-modal handlers need active area/region */
1692 CTX_wm_area_set(C, area_event_inside(C, event->x, event->y));
1693 CTX_wm_region_set(C, region_event_inside(C, event->x, event->y));
1695 action |= wm_handlers_do(C, event, &win->handlers);
1698 if(CTX_wm_window(C)==NULL)
1702 /* XXX hrmf, this gives reliable previous mouse coord for area change, feels bad?
1703 doing it on ghost queue gives errors when mousemoves go over area borders */
1704 if(doit && win->screen && win->screen->subwinactive != win->screen->mainwin) {
1705 win->eventstate->prevx= event->x;
1706 win->eventstate->prevy= event->y;
1710 /* store last event for this window */
1711 /* mousemove and timer events don't overwrite last type */
1712 if (event->type != MOUSEMOVE && !ISTIMER(event->type)) {
1713 if (wm_action_not_handled(action)) {
1714 if (win->eventstate->prevtype == event->type) {
1715 /* set click time on first click (press -> release) */
1716 if (win->eventstate->prevval == KM_PRESS && event->val == KM_RELEASE) {
1717 win->eventstate->prevclicktime = PIL_check_seconds_timer();
1718 win->eventstate->prevclickx = event->x;
1719 win->eventstate->prevclicky = event->y;
1722 /* reset click time if event type not the same */
1723 win->eventstate->prevclicktime = 0;
1726 win->eventstate->prevval = event->val;
1727 win->eventstate->prevtype = event->type;
1728 } else if (event->val == KM_CLICK) { /* keep click for double click later */
1729 win->eventstate->prevtype = event->type;
1730 win->eventstate->prevval = event->val;
1731 win->eventstate->prevclicktime = PIL_check_seconds_timer();
1732 win->eventstate->prevclickx = event->x;
1733 win->eventstate->prevclicky = event->y;
1734 } else { /* reset if not */
1735 win->eventstate->prevtype = -1;
1736 win->eventstate->prevval = 0;
1737 win->eventstate->prevclicktime = 0;
1741 /* unlink and free here, blender-quit then frees all */
1742 BLI_remlink(&win->queue, event);
1743 wm_event_free(event);
1747 /* only add mousemove when queue was read entirely */
1748 if(win->addmousemove && win->eventstate) {
1749 wmEvent event= *(win->eventstate);
1750 event.type= MOUSEMOVE;
1751 event.prevx= event.x;
1752 event.prevy= event.y;
1753 wm_event_add(win, &event);
1754 win->addmousemove= 0;
1757 CTX_wm_window_set(C, NULL);
1761 /* ********** filesector handling ************ */
1763 void WM_event_fileselect_event(bContext *C, void *ophandle, int eventval)
1765 /* add to all windows! */
1768 for(win= CTX_wm_manager(C)->windows.first; win; win= win->next) {
1769 wmEvent event= *win->eventstate;
1771 event.type= EVT_FILESELECT;
1772 event.val= eventval;
1773 event.customdata= ophandle; // only as void pointer type check
1775 wm_event_add(win, &event);
1779 /* operator is supposed to have a filled "path" property */
1780 /* optional property: filetype (XXX enum?) */
1782 /* Idea is to keep a handler alive on window queue, owning the operator.
1783 The filewindow can send event to make it execute, thus ensuring
1784 executing happens outside of lower level queues, with UI refreshed.
1785 Should also allow multiwin solutions */
1787 void WM_event_add_fileselect(bContext *C, wmOperator *op)
1789 wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "fileselect handler");
1790 wmWindow *win= CTX_wm_window(C);
1791 int full= 1; // XXX preset?
1793 handler->type= WM_HANDLER_FILESELECT;
1795 handler->op_area= CTX_wm_area(C);
1796 handler->op_region= CTX_wm_region(C);
1797 handler->filescreen= CTX_wm_screen(C);
1799 BLI_addhead(&win->modalhandlers, handler);
1801 WM_event_fileselect_event(C, op, full?EVT_FILESELECT_FULL_OPEN:EVT_FILESELECT_OPEN);
1804 /* lets not expose struct outside wm? */
1805 void WM_event_set_handler_flag(wmEventHandler *handler, int flag)
1807 handler->flag= flag;
1810 wmEventHandler *WM_event_add_modal_handler(bContext *C, wmOperator *op)
1812 wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event modal handler");
1813 wmWindow *win= CTX_wm_window(C);
1815 /* operator was part of macro */
1817 /* give the mother macro to the handler */
1818 handler->op= op->opm;
1819 /* mother macro opm becomes the macro element */
1820 handler->op->opm= op;
1825 handler->op_area= CTX_wm_area(C); /* means frozen screen context for modal handlers! */
1826 handler->op_region= CTX_wm_region(C);
1828 BLI_addhead(&win->modalhandlers, handler);
1833 wmEventHandler *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
1835 wmEventHandler *handler;
1838 printf("WM_event_add_keymap_handler called with NULL keymap\n");
1842 /* only allow same keymap once */
1843 for(handler= handlers->first; handler; handler= handler->next)
1844 if(handler->keymap==keymap)
1847 handler= MEM_callocN(sizeof(wmEventHandler), "event keymap handler");
1848 BLI_addtail(handlers, handler);
1849 handler->keymap= keymap;
1854 /* priorities not implemented yet, for time being just insert in begin of list */
1855 wmEventHandler *WM_event_add_keymap_handler_priority(ListBase *handlers, wmKeyMap *keymap, int priority)
1857 wmEventHandler *handler;
1859 WM_event_remove_keymap_handler(handlers, keymap);
1861 handler= MEM_callocN(sizeof(wmEventHandler), "event keymap handler");
1862 BLI_addhead(handlers, handler);
1863 handler->keymap= keymap;
1868 wmEventHandler *WM_event_add_keymap_handler_bb(ListBase *handlers, wmKeyMap *keymap, rcti *bblocal, rcti *bbwin)
1870 wmEventHandler *handler= WM_event_add_keymap_handler(handlers, keymap);
1873 handler->bblocal= bblocal;
1874 handler->bbwin= bbwin;
1879 void WM_event_remove_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
1881 wmEventHandler *handler;
1883 for(handler= handlers->first; handler; handler= handler->next) {
1884 if(handler->keymap==keymap) {
1885 BLI_remlink(handlers, handler);
1886 wm_event_free_handler(handler);
1892 wmEventHandler *WM_event_add_ui_handler(const bContext *C, ListBase *handlers, wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata)
1894 wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event ui handler");
1895 handler->ui_handle= func;
1896 handler->ui_remove= remove;
1897 handler->ui_userdata= userdata;
1898 handler->ui_area= (C)? CTX_wm_area(C): NULL;
1899 handler->ui_region= (C)? CTX_wm_region(C): NULL;
1900 handler->ui_menu= (C)? CTX_wm_menu(C): NULL;
1902 BLI_addhead(handlers, handler);
1907 void WM_event_remove_ui_handler(ListBase *handlers, wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata)
1909 wmEventHandler *handler;
1911 for(handler= handlers->first; handler; handler= handler->next) {
1912 if(handler->ui_handle == func && handler->ui_remove == remove && handler->ui_userdata == userdata) {
1913 BLI_remlink(handlers, handler);
1914 wm_event_free_handler(handler);
1920 wmEventHandler *WM_event_add_dropbox_handler(ListBase *handlers, ListBase *dropboxes)
1922 wmEventHandler *handler;
1924 /* only allow same dropbox once */
1925 for(handler= handlers->first; handler; handler= handler->next)
1926 if(handler->dropboxes==dropboxes)
1929 handler= MEM_callocN(sizeof(wmEventHandler), "dropbox handler");
1931 /* dropbox stored static, no free or copy */
1932 handler->dropboxes= dropboxes;
1933 BLI_addhead(handlers, handler);
1938 /* XXX solution works, still better check the real cause (ton) */
1939 void WM_event_remove_area_handler(ListBase *handlers, void *area)
1941 wmEventHandler *handler, *nexthandler;
1943 for(handler = handlers->first; handler; handler= nexthandler) {
1944 nexthandler = handler->next;
1945 if (handler->type != WM_HANDLER_FILESELECT) {
1946 if (handler->ui_area == area) {
1947 BLI_remlink(handlers, handler);
1948 wm_event_free_handler(handler);
1954 void WM_event_remove_handler(ListBase *handlers, wmEventHandler *handler)
1956 BLI_remlink(handlers, handler);
1957 wm_event_free_handler(handler);
1960 void WM_event_add_mousemove(bContext *C)
1962 wmWindow *window= CTX_wm_window(C);
1964 window->addmousemove= 1;
1967 /* for modal callbacks, check configuration for how to interpret exit with tweaks */
1968 int WM_modal_tweak_exit(wmEvent *evt, int tweak_event)
1970 /* user preset or keymap? dunno... */
1972 int tweak_modal= (U.flag & USER_RELEASECONFIRM)==0;
1974 switch(tweak_event) {
1978 if(evt->val==tweak_modal)
1981 /* this case is when modal callcback didnt get started with a tweak */
1988 /* ********************* ghost stuff *************** */
1990 static int convert_key(GHOST_TKey key)
1992 if (key>=GHOST_kKeyA && key<=GHOST_kKeyZ) {
1993 return (AKEY + ((int) key - GHOST_kKeyA));
1994 } else if (key>=GHOST_kKey0 && key<=GHOST_kKey9) {
1995 return (ZEROKEY + ((int) key - GHOST_kKey0));
1996 } else if (key>=GHOST_kKeyNumpad0 && key<=GHOST_kKeyNumpad9) {
1997 return (PAD0 + ((int) key - GHOST_kKeyNumpad0));
1998 } else if (key>=GHOST_kKeyF1 && key<=GHOST_kKeyF19) {
1999 return (F1KEY + ((int) key - GHOST_kKeyF1));
2002 case GHOST_kKeyBackSpace: return BACKSPACEKEY;
2003 case GHOST_kKeyTab: return TABKEY;
2004 case GHOST_kKeyLinefeed: return LINEFEEDKEY;
2005 case GHOST_kKeyClear: return 0;
2006 case GHOST_kKeyEnter: return RETKEY;
2008 case GHOST_kKeyEsc: return ESCKEY;
2009 case GHOST_kKeySpace: return SPACEKEY;
2010 case GHOST_kKeyQuote: return QUOTEKEY;
2011 case GHOST_kKeyComma: return COMMAKEY;
2012 case GHOST_kKeyMinus: return MINUSKEY;
2013 case GHOST_kKeyPeriod: return PERIODKEY;
2014 case GHOST_kKeySlash: return SLASHKEY;
2016 case GHOST_kKeySemicolon: return SEMICOLONKEY;
2017 case GHOST_kKeyEqual: return EQUALKEY;
2019 case GHOST_kKeyLeftBracket: return LEFTBRACKETKEY;
2020 case GHOST_kKeyRightBracket: return RIGHTBRACKETKEY;
2021 case GHOST_kKeyBackslash: return BACKSLASHKEY;
2022 case GHOST_kKeyAccentGrave: return ACCENTGRAVEKEY;
2024 case GHOST_kKeyLeftShift: return LEFTSHIFTKEY;
2025 case GHOST_kKeyRightShift: return RIGHTSHIFTKEY;
2026 case GHOST_kKeyLeftControl: return LEFTCTRLKEY;
2027 case GHOST_kKeyRightControl: return RIGHTCTRLKEY;
2028 case GHOST_kKeyCommand: return COMMANDKEY;
2029 case GHOST_kKeyLeftAlt: return LEFTALTKEY;
2030 case GHOST_kKeyRightAlt: return RIGHTALTKEY;
2032 case GHOST_kKeyCapsLock: return CAPSLOCKKEY;
2033 case GHOST_kKeyNumLock: return 0;
2034 case GHOST_kKeyScrollLock: return 0;
2036 case GHOST_kKeyLeftArrow: return LEFTARROWKEY;
2037 case GHOST_kKeyRightArrow: return RIGHTARROWKEY;
2038 case GHOST_kKeyUpArrow: return UPARROWKEY;
2039 case GHOST_kKeyDownArrow: return DOWNARROWKEY;
2041 case GHOST_kKeyPrintScreen: return 0;
2042 case GHOST_kKeyPause: return PAUSEKEY;
2044 case GHOST_kKeyInsert: return INSERTKEY;
2045 case GHOST_kKeyDelete: return DELKEY;
2046 case GHOST_kKeyHome: return HOMEKEY;
2047 case GHOST_kKeyEnd: return ENDKEY;
2048 case GHOST_kKeyUpPage: return PAGEUPKEY;
2049 case GHOST_kKeyDownPage: return PAGEDOWNKEY;
2051 case GHOST_kKeyNumpadPeriod: return PADPERIOD;
2052 case GHOST_kKeyNumpadEnter: return PADENTER;
2053 case GHOST_kKeyNumpadPlus: return PADPLUSKEY;
2054 case GHOST_kKeyNumpadMinus: return PADMINUS;
2055 case GHOST_kKeyNumpadAsterisk: return PADASTERKEY;
2056 case GHOST_kKeyNumpadSlash: return PADSLASHKEY;
2058 case GHOST_kKeyGrLess: return GRLESSKEY;
2061 return UNKNOWNKEY; /* GHOST_kKeyUnknown */
2067 /* adds customdata to event */
2068 static void update_tablet_data(wmWindow *win, wmEvent *event)
2070 const GHOST_TabletData *td= GHOST_GetTabletData(win->ghostwin);
2072 /* if there's tablet data from an active tablet device then add it */
2073 if ((td != NULL) && td->Active != GHOST_kTabletModeNone) {
2074 struct wmTabletData *wmtab= MEM_mallocN(sizeof(wmTabletData), "customdata tablet");
2076 wmtab->Active = (int)td->Active;
2077 wmtab->Pressure = td->Pressure;
2078 wmtab->Xtilt = td->Xtilt;
2079 wmtab->Ytilt = td->Ytilt;
2081 event->custom= EVT_DATA_TABLET;
2082 event->customdata= wmtab;
2083 event->customdatafree= 1;
2088 /* adds customdata to event */
2089 static void attach_tablet_data(wmEvent* event, const GHOST_TabletData* ghost)
2091 if (ghost->Active != GHOST_kTabletModeNone)
2093 wmTabletData* data = MEM_mallocN(sizeof(wmTabletData), "customdata tablet");
2095 data->Active = ghost->Active;
2096 data->Pressure = ghost->Pressure;
2097 data->Xtilt = ghost->Xtilt;
2098 data->Ytilt = ghost->Ytilt;
2100 event->custom = EVT_DATA_TABLET;
2101 event->customdata = data;
2102 event->customdatafree = 1;
2104 printf("+ pressure = %.2f tilt = %.2f %2f\n", data->Pressure, data->Xtilt, data->Ytilt);
2108 /* adds customdata to event */
2109 static void attach_ndof_data(wmEvent* event, const GHOST_TEventNDOFMotionData* ghost)
2111 wmNDOFMotionData* data = MEM_mallocN(sizeof(wmNDOFMotionData), "customdata NDOF");
2113 data->tx = ghost->tx;
2114 data->ty = ghost->ty;
2115 data->tz = ghost->tz;
2117 data->rx = ghost->rx;
2118 data->ry = ghost->ry;
2119 data->rz = ghost->rz;
2121 data->dt = ghost->dt;
2123 event->custom = EVT_DATA_NDOF_MOTION;
2124 event->customdata = data;
2125 event->customdatafree = 1;
2128 /* imperfect but probably usable... draw/enable drags to other windows */
2129 static wmWindow *wm_event_cursor_other_windows(wmWindowManager *wm, wmWindow *win, wmEvent *evt)
2131 short mx= evt->x, my= evt->y;
2133 if(wm->windows.first== wm->windows.last)
2136 /* top window bar... */
2137 if(mx<0 || my<0 || mx>win->sizex || my>win->sizey+30) {
2139 wmEventHandler *handler;
2141 /* let's skip windows having modal handlers now */
2142 /* potential XXX ugly... I wouldn't have added a modalhandlers list (introduced in rev 23331, ton) */
2143 for(handler= win->modalhandlers.first; handler; handler= handler->next)
2144 if(handler->ui_handle || handler->op)
2147 /* to desktop space */
2151 /* check other windows to see if it has mouse inside */
2152 for(owin= wm->windows.first; owin; owin= owin->next) {
2155 if(mx-owin->posx >= 0 && my-owin->posy >= 0 &&
2156 mx-owin->posx <= owin->sizex && my-owin->posy <= owin->sizey) {
2157 evt->x= mx-owin->posx;
2158 evt->y= my-owin->posy;
2168 /* windows store own event queues, no bContext here */
2169 /* time is in 1000s of seconds (or milliseconds?), from ghost */
2170 void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int time, void *customdata)
2173 wmEvent event, *evt= win->eventstate;
2175 /* initialize and copy state (only mouse x y and modifiers) */
2180 case GHOST_kEventCursorMove: {
2182 GHOST_TEventCursorData *cd= customdata;
2183 wmEvent *lastevent= win->queue.last;
2185 #if defined(__APPLE__) && defined(GHOST_COCOA)
2186 //Cocoa already uses coordinates with y=0 at bottom, and returns inwindow coordinates on mouse moved event
2192 GHOST_ScreenToClient(win->ghostwin, cd->x, cd->y, &cx, &cy);
2194 evt->y= (win->sizey-1) - cy;
2200 event.type= MOUSEMOVE;
2202 /* some painting operators want accurate mouse events, they can
2203 handle inbetween mouse move moves, others can happily ignore
2204 them for better performance */
2205 if(lastevent && lastevent->type == MOUSEMOVE)
2206 lastevent->type = INBETWEEN_MOUSEMOVE;
2208 attach_tablet_data(&event, &(cd->tablet));
2209 // update_tablet_data(win, &event);
2210 wm_event_add(win, &event);
2212 /* also add to other window if event is there, this makes overdraws disappear nicely */
2213 /* it remaps mousecoord to other window in event */
2214 owin= wm_event_cursor_other_windows(wm, win, &event);
2216 wmEvent oevent= *(owin->eventstate);
2218 oevent.x=owin->eventstate->x= event.x;
2219 oevent.y=owin->eventstate->y= event.y;
2220 oevent.type= MOUSEMOVE;
2222 // update_tablet_data(owin, &oevent);
2223 wm_event_add(owin, &oevent);
2228 case GHOST_kEventTrackpad: {
2229 GHOST_TEventTrackpadData * pd = customdata;
2230 switch (pd->subtype) {
2231 case GHOST_kTrackpadEventMagnify:
2232 event.type = MOUSEZOOM;
2234 case GHOST_kTrackpadEventRotate:
2235 event.type = MOUSEROTATE;
2237 case GHOST_kTrackpadEventScroll:
2239 event.type= MOUSEPAN;
2242 #if defined(__APPLE__) && defined(GHOST_COCOA)
2243 //Cocoa already uses coordinates with y=0 at bottom, and returns inwindow coordinates on mouse moved event
2244 event.x= evt->x = pd->x;
2245 event.y = evt->y = pd->y;
2249 GHOST_ScreenToClient(win->ghostwin, pd->x, pd->y, &cx, &cy);
2250 event.x= evt->x= cx;
2251 event.y= evt->y= (win->sizey-1) - cy;
2254 // Use prevx/prevy so we can calculate the delta later
2255 event.prevx= event.x - pd->deltaX;
2256 event.prevy= event.y - pd->deltaY;
2258 // [mce] tablet never sends trackpad events.
2259 // update_tablet_data(win, &event);
2260 wm_event_add(win, &event);
2264 case GHOST_kEventButtonDown:
2265 case GHOST_kEventButtonUp: {
2266 GHOST_TEventButtonData *bd= customdata;
2267 event.val= (type==GHOST_kEventButtonDown) ? KM_PRESS:KM_RELEASE; /* Note!, this starts as 0/1 but later is converted to KM_PRESS/KM_RELEASE by tweak */
2269 if (bd->button == GHOST_kButtonMaskLeft)
2270 event.type= LEFTMOUSE;
2271 else if (bd->button == GHOST_kButtonMaskRight)
2272 event.type= RIGHTMOUSE;
2273 else if (bd->button == GHOST_kButtonMaskButton4)
2274 event.type= BUTTON4MOUSE;
2275 else if (bd->button == GHOST_kButtonMaskButton5)
2276 event.type= BUTTON5MOUSE;
2278 event.type= MIDDLEMOUSE;
2280 /* add to other window if event is there (not to both!) */
2281 owin= wm_event_cursor_other_windows(wm, win, &event);
2283 wmEvent oevent= *(owin->eventstate);
2287 oevent.type= event.type;
2288 oevent.val= event.val;
2290 attach_tablet_data(&oevent, &(bd->tablet));
2291 // update_tablet_data(owin, &oevent);
2292 wm_event_add(owin, &oevent);
2295 attach_tablet_data(&event, &(bd->tablet));
2296 // update_tablet_data(win, &event);
2297 wm_event_add(win, &event);
2303 case GHOST_kEventKeyDown:
2304 case GHOST_kEventKeyUp: {
2305 GHOST_TEventKeyData *kd= customdata;
2306 event.type= convert_key(kd->key);
2307 event.ascii= kd->ascii;
2308 event.val= (type==GHOST_kEventKeyDown)?KM_PRESS:KM_RELEASE;
2310 /* exclude arrow keys, esc, etc from text input */
2311 if(type==GHOST_kEventKeyUp || (event.ascii<32 && event.ascii>0))
2315 if (event.type==LEFTSHIFTKEY || event.type==RIGHTSHIFTKEY) {
2316 event.shift= evt->shift= (event.val==KM_PRESS);
2317 if(event.val==KM_PRESS && (evt->ctrl || evt->alt || evt->oskey))
2318 event.shift= evt->shift = 3; // define?
2320 else if (event.type==LEFTCTRLKEY || event.type==RIGHTCTRLKEY) {
2321 event.ctrl= evt->ctrl= (event.val==KM_PRESS);
2322 if(event.val==KM_PRESS && (evt->shift || evt->alt || evt->oskey))
2323 event.ctrl= evt->ctrl = 3; // define?
2325 else if (event.type==LEFTALTKEY || event.type==RIGHTALTKEY) {
2326 event.alt= evt->alt= (event.val==KM_PRESS);
2327 if(event.val==KM_PRESS && (evt->ctrl || evt->shift || evt->oskey))
2328 event.alt= evt->alt = 3; // define?
2330 else if (event.type==COMMANDKEY) {
2331 event.oskey= evt->oskey= (event.val==KM_PRESS);
2332 if(event.val==KM_PRESS && (evt->ctrl || evt->alt || evt->shift))
2333 event.oskey= evt->oskey = 3; // define?
2336 if(event.val==KM_PRESS && event.keymodifier==0)
2337 evt->keymodifier= event.type; /* only set in eventstate, for next event */
2338 else if(event.val==KM_RELEASE && event.keymodifier==event.type)
2339 event.keymodifier= evt->keymodifier= 0;
2342 /* this case happens on some systems that on holding a key pressed,
2343 generate press events without release, we still want to keep the
2344 modifier in win->eventstate, but for the press event of the same
2345 key we don't want the key modifier */
2346 if(event.keymodifier == event.type)
2347 event.keymodifier= 0;
2349 /* if test_break set, it catches this. XXX Keep global for now? */
2350 if(event.type==ESCKEY)
2353 wm_event_add(win, &event);
2358 case GHOST_kEventWheel: {
2359 GHOST_TEventWheelData* wheelData = customdata;
2361 if (wheelData->z > 0)
2362 event.type= WHEELUPMOUSE;
2364 event.type= WHEELDOWNMOUSE;
2366 event.val= KM_PRESS;
2367 wm_event_add(win, &event);
2372 case GHOST_kEventTimer: {
2374 event.custom= EVT_DATA_TIMER;
2375 event.customdata= customdata;
2376 wm_event_add(win, &event);
2381 case GHOST_kEventNDOFMotion: {
2382 event.type = NDOF_MOTION;
2383 attach_ndof_data(&event, customdata);
2384 wm_event_add(win, &event);
2389 case GHOST_kEventNDOFButton: {
2390 GHOST_TEventNDOFButtonData* e = customdata;
2392 event.type = NDOF_BUTTON_NONE + e->button;
2394 switch (e->action) {
2396 event.val = KM_PRESS;
2398 case GHOST_kRelease:
2399 event.val = KM_RELEASE;
2404 event.customdata = NULL;
2406 wm_event_add(win, &event);
2411 case GHOST_kEventUnknown:
2412 case GHOST_kNumEventTypes:
2415 case GHOST_kEventWindowDeactivate: {
2416 event.type= WINDEACTIVATE;
2417 wm_event_add(win, &event);