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_windowmanager_types.h"
35 #include "DNA_userdef_types.h" /* U.flag & TWOBUTTONMOUSE */
37 #include "MEM_guardedalloc.h"
39 #include "GHOST_C-api.h"
41 #include "BLI_blenlib.h"
43 #include "BKE_blender.h"
44 #include "BKE_global.h"
46 #include "ED_screen.h"
52 #include "wm_window.h"
53 #include "wm_event_system.h"
54 #include "wm_event_types.h"
56 /* ************ event management ************** */
58 static void wm_event_add(wmWindow *win, wmEvent *event_to_add)
60 wmEvent *event= MEM_callocN(sizeof(wmEvent), "event");
62 *event= *event_to_add;
63 BLI_addtail(&win->queue, event);
66 wmEvent *wm_event_next(wmWindow *win)
68 wmEvent *event= win->queue.first;
70 if(event) BLI_remlink(&win->queue, event);
74 static void wm_event_free(wmEvent *event)
76 if(event->customdata) MEM_freeN(event->customdata);
80 void wm_event_free_all(wmWindow *win)
84 while((event= win->queue.first)) {
85 BLI_remlink(&win->queue, event);
90 /* ********************* notifiers, listeners *************** */
92 /* win and swinid are optional context limitors */
93 void WM_event_add_notifier(wmWindowManager *wm, wmWindow *window, int swinid, int type, int value)
95 wmNotifier *note= MEM_callocN(sizeof(wmNotifier), "notifier");
97 BLI_addtail(&wm->queue, note);
100 note->swinid= swinid;
105 static wmNotifier *wm_notifier_next(wmWindowManager *wm)
107 wmNotifier *note= wm->queue.first;
109 if(note) BLI_remlink(&wm->queue, note);
113 /* called in mainloop */
114 void wm_event_do_notifiers(bContext *C)
118 while( (note=wm_notifier_next(C->wm)) ) {
121 for(win= C->wm->windows.first; win; win= win->next) {
124 if(note->window && note->window!=win)
126 if(win->screen==NULL)
128 printf("notifier win %d screen %s\n", win->winid, win->screen->id.name+2);
129 ED_screen_do_listen(win->screen, note);
131 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
132 ARegion *ar= sa->regionbase.first;
134 for(; ar; ar= ar->next) {
135 if(note->swinid && note->swinid!=ar->swinid)
137 ED_region_do_listen(ar, note);
145 /* quick test to prevent changing window drawable */
146 static int wm_draw_update_test_window(wmWindow *win)
150 if(win->screen->do_refresh)
152 if(win->screen->do_draw)
155 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
156 ARegion *ar= sa->regionbase.first;
158 for(; ar; ar= ar->next) {
159 /* cached notifiers */
162 if(ar->swinid && ar->do_draw)
169 void wm_draw_update(bContext *C)
173 for(win= C->wm->windows.first; win; win= win->next) {
174 if(wm_draw_update_test_window(win)) {
177 /* sets context window+screen */
178 wm_window_make_drawable(C, win);
180 /* notifiers for screen redraw */
181 if(win->screen->do_refresh)
182 ED_screen_refresh(C->wm, win);
183 if(win->screen->do_draw)
186 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
187 ARegion *ar= sa->regionbase.first;
190 for(; ar; ar= ar->next) {
191 hasdrawn |= ar->do_draw;
193 /* cached notifiers */
195 ED_region_do_refresh(C, ar);
197 if(ar->swinid && ar->do_draw)
198 ED_region_do_draw(C, ar);
201 wm_window_swap_buffers(win);
206 /* ********************* handlers *************** */
208 /* not handler itself */
209 static void wm_event_free_handler(wmEventHandler *handler)
212 MEM_freeN(handler->op);
215 void wm_event_free_handlers(ListBase *lb)
217 wmEventHandler *handler;
219 for(handler= lb->first; handler; handler= handler->next)
220 wm_event_free_handler(handler);
225 static int wm_eventmatch(wmEvent *winevent, wmKeymapItem *km)
227 if(winevent->type!=km->type) return 0;
229 if(km->val) /* KM_PRESS, KM_RELEASE */
230 if(winevent->val!=km->val-1) return 0;
232 if(winevent->shift!=km->shift) return 0;
233 if(winevent->ctrl!=km->ctrl) return 0;
234 if(winevent->alt!=km->alt) return 0;
235 if(winevent->oskey!=km->oskey) return 0;
237 if(winevent->keymodifier!=km->keymodifier) return 0;
239 /* optional boundbox */
244 static int wm_handler_operator_call(bContext *C, wmEventHandler *handler, wmEvent *event)
248 /* derived, modal or blocking operator */
250 if(handler->op->type->modal)
251 retval= handler->op->type->modal(C, handler->op, event);
253 printf("wm_handler_operator_call error\n");
256 wmOperatorType *ot= WM_operatortype_find(event->keymap_idname);
258 if(ot->poll==NULL || ot->poll(C)) {
259 /* operator on stack, register or new modal handle malloc-copies */
262 memset(&op, 0, sizeof(wmOperator));
266 retval= (*op.type->invoke)(C, &op, event);
267 else if(&op.type->exec)
268 retval= op.type->exec(C, &op);
270 if( ot->flag & OPTYPE_REGISTER)
271 wm_operator_register(C->wm, &op);
276 return WM_HANDLER_BREAK;
278 return WM_HANDLER_CONTINUE;
281 static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
283 wmEventHandler *handler;
284 int action= WM_HANDLER_CONTINUE;
286 if(handlers==NULL) return action;
288 for(handler= handlers->first; handler; handler= handler->next) {
289 if(handler->keymap) {
292 for(km= handler->keymap->first; km; km= km->next) {
293 if(wm_eventmatch(event, km)) {
295 if(event->type!=MOUSEMOVE)
296 printf("handle evt %d win %d op %s\n", event->type, C->window->winid, km->idname);
298 event->keymap_idname= km->idname; /* weak, but allows interactive callback to not use rawkey */
300 action= wm_handler_operator_call(C, handler, event);
303 if(action==WM_HANDLER_BREAK)
307 /* modal, swallows all */
308 action= wm_handler_operator_call(C, handler, event);
311 /* modal+blocking handler */
312 if(handler->flag & WM_HANDLER_BLOCKING)
313 action= WM_HANDLER_BREAK;
318 static int wm_event_inside_i(wmEvent *event, rcti *rect)
320 return BLI_in_rcti(rect, event->x, event->y);
324 /* called in main loop */
325 /* goes over entire hierarchy: events -> window -> screen -> area -> region */
326 void wm_event_do_handlers(bContext *C)
330 for(win= C->wm->windows.first; win; win= win->next) {
333 if( win->screen==NULL )
334 wm_event_free_all(win);
336 while( (event=wm_event_next(win)) ) {
339 /* MVC demands to not draw in event handlers... for now we leave it */
340 /* it also updates context (win, screen) */
341 wm_window_make_drawable(C, win);
343 action= wm_handlers_do(C, event, &win->handlers);
345 if(action==WM_HANDLER_CONTINUE) {
346 ScrArea *sa= win->screen->areabase.first;
348 for(; sa; sa= sa->next) {
349 if(wm_event_inside_i(event, &sa->totrct)) {
352 action= wm_handlers_do(C, event, &sa->handlers);
353 if(action==WM_HANDLER_CONTINUE) {
354 ARegion *ar= sa->regionbase.first;
356 for(; ar; ar= ar->next) {
357 if(wm_event_inside_i(event, &ar->winrct)) {
359 action= wm_handlers_do(C, event, &ar->handlers);
360 if(action==WM_HANDLER_BREAK)
365 if(action==WM_HANDLER_BREAK)
370 wm_event_free(event);
375 /* lets not expose struct outside wm? */
376 void WM_event_set_handler_flag(wmEventHandler *handler, int flag)
381 wmEventHandler *WM_event_add_modal_handler(ListBase *handlers, wmOperator *op)
383 /* debug test; operator not in registry */
384 if(op->type->flag & OPTYPE_REGISTER) {
385 printf("error: handler (%s) cannot be modal, was registered\n", op->type->idname);
388 wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event handler");
389 wmOperator *opc= MEM_mallocN(sizeof(wmOperator), "operator modal");
391 BLI_addhead(handlers, handler);
400 void WM_event_remove_modal_handler(ListBase *handlers, wmOperator *op)
402 wmEventHandler *handler;
404 for(handler= handlers->first; handler; handler= handler->next) {
405 if(handler->op==op) {
406 BLI_remlink(handlers, handler);
407 wm_event_free_handler(handler);
414 wmEventHandler *WM_event_add_keymap_handler(ListBase *keymap, ListBase *handlers)
416 wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event handler");
418 BLI_addtail(handlers, handler);
419 handler->keymap= keymap;
425 /* ********************* ghost stuff *************** */
427 static int convert_key(GHOST_TKey key)
429 if (key>=GHOST_kKeyA && key<=GHOST_kKeyZ) {
430 return (AKEY + ((int) key - GHOST_kKeyA));
431 } else if (key>=GHOST_kKey0 && key<=GHOST_kKey9) {
432 return (ZEROKEY + ((int) key - GHOST_kKey0));
433 } else if (key>=GHOST_kKeyNumpad0 && key<=GHOST_kKeyNumpad9) {
434 return (PAD0 + ((int) key - GHOST_kKeyNumpad0));
435 } else if (key>=GHOST_kKeyF1 && key<=GHOST_kKeyF12) {
436 return (F1KEY + ((int) key - GHOST_kKeyF1));
439 case GHOST_kKeyBackSpace: return BACKSPACEKEY;
440 case GHOST_kKeyTab: return TABKEY;
441 case GHOST_kKeyLinefeed: return LINEFEEDKEY;
442 case GHOST_kKeyClear: return 0;
443 case GHOST_kKeyEnter: return RETKEY;
445 case GHOST_kKeyEsc: return ESCKEY;
446 case GHOST_kKeySpace: return SPACEKEY;
447 case GHOST_kKeyQuote: return QUOTEKEY;
448 case GHOST_kKeyComma: return COMMAKEY;
449 case GHOST_kKeyMinus: return MINUSKEY;
450 case GHOST_kKeyPeriod: return PERIODKEY;
451 case GHOST_kKeySlash: return SLASHKEY;
453 case GHOST_kKeySemicolon: return SEMICOLONKEY;
454 case GHOST_kKeyEqual: return EQUALKEY;
456 case GHOST_kKeyLeftBracket: return LEFTBRACKETKEY;
457 case GHOST_kKeyRightBracket: return RIGHTBRACKETKEY;
458 case GHOST_kKeyBackslash: return BACKSLASHKEY;
459 case GHOST_kKeyAccentGrave: return ACCENTGRAVEKEY;
461 case GHOST_kKeyLeftShift: return LEFTSHIFTKEY;
462 case GHOST_kKeyRightShift: return RIGHTSHIFTKEY;
463 case GHOST_kKeyLeftControl: return LEFTCTRLKEY;
464 case GHOST_kKeyRightControl: return RIGHTCTRLKEY;
465 case GHOST_kKeyCommand: return COMMANDKEY;
466 case GHOST_kKeyLeftAlt: return LEFTALTKEY;
467 case GHOST_kKeyRightAlt: return RIGHTALTKEY;
469 case GHOST_kKeyCapsLock: return CAPSLOCKKEY;
470 case GHOST_kKeyNumLock: return 0;
471 case GHOST_kKeyScrollLock: return 0;
473 case GHOST_kKeyLeftArrow: return LEFTARROWKEY;
474 case GHOST_kKeyRightArrow: return RIGHTARROWKEY;
475 case GHOST_kKeyUpArrow: return UPARROWKEY;
476 case GHOST_kKeyDownArrow: return DOWNARROWKEY;
478 case GHOST_kKeyPrintScreen: return 0;
479 case GHOST_kKeyPause: return PAUSEKEY;
481 case GHOST_kKeyInsert: return INSERTKEY;
482 case GHOST_kKeyDelete: return DELKEY;
483 case GHOST_kKeyHome: return HOMEKEY;
484 case GHOST_kKeyEnd: return ENDKEY;
485 case GHOST_kKeyUpPage: return PAGEUPKEY;
486 case GHOST_kKeyDownPage: return PAGEDOWNKEY;
488 case GHOST_kKeyNumpadPeriod: return PADPERIOD;
489 case GHOST_kKeyNumpadEnter: return PADENTER;
490 case GHOST_kKeyNumpadPlus: return PADPLUSKEY;
491 case GHOST_kKeyNumpadMinus: return PADMINUS;
492 case GHOST_kKeyNumpadAsterisk: return PADASTERKEY;
493 case GHOST_kKeyNumpadSlash: return PADSLASHKEY;
495 case GHOST_kKeyGrLess: return GRLESSKEY;
498 return UNKNOWNKEY; /* GHOST_kKeyUnknown */
503 /* adds customdata to event */
504 static void update_tablet_data(wmWindow *win, wmEvent *event)
506 const GHOST_TabletData *td= GHOST_GetTabletData(win->ghostwin);
508 /* if there's tablet data from an active tablet device then add it */
509 if ((td != NULL) && td->Active) {
510 struct wmTabletData *wmtab= MEM_mallocN(sizeof(wmTabletData), "customdata tablet");
512 wmtab->Active = td->Active;
513 wmtab->Pressure = td->Pressure;
514 wmtab->Xtilt = td->Xtilt;
515 wmtab->Ytilt = td->Ytilt;
517 event->custom= EVT_TABLET;
518 event->customdata= wmtab;
523 /* windows store own event queues, no bContext here */
524 void wm_event_add_ghostevent(wmWindow *win, int type, void *customdata)
526 wmEvent event, *evt= win->eventstate;
528 /* initialize and copy state (only mouse x y and modifiers) */
533 case GHOST_kEventCursorMove: {
535 GHOST_TEventCursorData *cd= customdata;
538 GHOST_ScreenToClient(win->ghostwin, cd->x, cd->y, &cx, &cy);
540 event.type= MOUSEMOVE;
542 event.y= evt->y= (win->sizey-1) - cy;
544 ED_screen_set_subwinactive(win); /* state variables in screen */
546 update_tablet_data(win, &event);
547 wm_event_add(win, &event);
552 case GHOST_kEventButtonDown:
553 case GHOST_kEventButtonUp: {
554 GHOST_TEventButtonData *bd= customdata;
555 event.val= (type==GHOST_kEventButtonDown);
557 if (bd->button == GHOST_kButtonMaskLeft)
558 event.type= LEFTMOUSE;
559 else if (bd->button == GHOST_kButtonMaskRight)
560 event.type= RIGHTMOUSE;
562 event.type= MIDDLEMOUSE;
565 event.keymodifier= evt->keymodifier= event.type;
567 event.keymodifier= evt->keymodifier= 0;
569 update_tablet_data(win, &event);
570 wm_event_add(win, &event);
575 case GHOST_kEventKeyDown:
576 case GHOST_kEventKeyUp: {
577 GHOST_TEventKeyData *kd= customdata;
578 event.type= convert_key(kd->key);
579 event.ascii= kd->ascii;
580 event.val= (type==GHOST_kEventKeyDown);
583 if (event.type==LEFTSHIFTKEY || event.type==RIGHTSHIFTKEY) {
584 event.shift= evt->shift= event.val;
585 } else if (event.type==LEFTCTRLKEY || event.type==RIGHTCTRLKEY) {
586 event.ctrl= evt->ctrl= event.val;
587 } else if (event.type==LEFTALTKEY || event.type==RIGHTALTKEY) {
588 event.alt= evt->alt= event.val;
589 } else if (event.type==COMMANDKEY) {
590 event.oskey= evt->oskey= event.val;
593 wm_event_add(win, &event);
598 case GHOST_kEventWheel: {
599 GHOST_TEventWheelData* wheelData = customdata;
601 if (wheelData->z > 0)
602 event.type= WHEELUPMOUSE;
604 event.type= WHEELDOWNMOUSE;
606 event.val= wheelData->z; /* currently -1 or +1, see ghost for improvements here... */
607 wm_event_add(win, &event);
611 case GHOST_kEventUnknown:
612 case GHOST_kNumEventTypes: