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 void wm_event_free_handlers(ListBase *lb)
210 wmEventHandler *handler;
212 for(handler= lb->first; handler; handler= handler->next) {
214 MEM_freeN(handler->op);
219 static int wm_eventmatch(wmEvent *winevent, wmKeymapItem *km)
221 if(winevent->type!=km->type) return 0;
223 if(km->val) /* KM_PRESS, KM_RELEASE */
224 if(winevent->val!=km->val-1) return 0;
226 if(winevent->shift!=km->shift) return 0;
227 if(winevent->ctrl!=km->ctrl) return 0;
228 if(winevent->alt!=km->alt) return 0;
229 if(winevent->oskey!=km->oskey) return 0;
230 if(winevent->keymodifier!=km->keymodifier) return 0;
232 /* optional boundbox */
237 static int wm_handler_operator_call(bContext *C, wmEventHandler *handler, wmEvent *event)
241 /* derived, modal or blocking operator */
243 if( handler->op->type->poll(C)) {
244 if(handler->op->type->interactive)
245 retval= handler->op->type->interactive(C, handler->op, event);
247 printf("wm_handler_operator_call error\n");
251 wmOperatorType *ot= WM_operatortype_find(event->keymap_idname);
254 /* operator on stack, register or new modal handle malloc-copies */
257 memset(&op, 0, sizeof(wmOperator));
260 if(op.type->interactive)
261 retval= op.type->interactive(C, &op, event);
262 else if(&op.type->exec)
263 retval= op.type->exec(C, &op);
265 if( ot->flag & OPTYPE_REGISTER)
266 wm_operator_register(C->wm, &op);
271 return WM_HANDLER_BREAK;
273 return WM_HANDLER_CONTINUE;
276 static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
278 wmEventHandler *handler;
279 int action= WM_HANDLER_CONTINUE;
281 if(handlers==NULL) return action;
283 for(handler= handlers->first; handler; handler= handler->next) {
284 if(handler->keymap) {
287 for(km= handler->keymap->first; km; km= km->next) {
288 if(wm_eventmatch(event, km)) {
290 if(event->type!=MOUSEMOVE)
291 printf("handle evt %d win %d op %s\n", event->type, C->window->winid, km->idname);
293 event->keymap_idname= km->idname; /* weak, but allows interactive callback to not use rawkey */
295 action= wm_handler_operator_call(C, handler, event);
298 if(action==WM_HANDLER_BREAK)
301 /* modal+blocking handler */
302 if(handler->flag & WM_HANDLER_BLOCKING)
303 action= WM_HANDLER_BREAK;
308 static int wm_event_inside_i(wmEvent *event, rcti *rect)
310 return BLI_in_rcti(rect, event->x, event->y);
314 /* called in main loop */
315 /* goes over entire hierarchy: events -> window -> screen -> area -> region */
316 void wm_event_do_handlers(bContext *C)
320 for(win= C->wm->windows.first; win; win= win->next) {
323 if( win->screen==NULL )
324 wm_event_free_all(win);
326 while( (event=wm_event_next(win)) ) {
329 /* MVC demands to not draw in event handlers... for now we leave it */
330 /* it also updates context (win, screen) */
331 wm_window_make_drawable(C, win);
333 action= wm_handlers_do(C, event, &win->handlers);
335 if(action==WM_HANDLER_CONTINUE) {
336 ScrArea *sa= win->screen->areabase.first;
338 for(; sa; sa= sa->next) {
339 if(wm_event_inside_i(event, &sa->winrct)) {
342 action= wm_handlers_do(C, event, &sa->handlers);
343 if(action==WM_HANDLER_CONTINUE) {
344 ARegion *ar= sa->regionbase.first;
346 for(; ar; ar= ar->next) {
347 if(wm_event_inside_i(event, &ar->winrct)) {
349 action= wm_handlers_do(C, event, &ar->handlers);
350 if(action==WM_HANDLER_BREAK)
355 if(action==WM_HANDLER_BREAK)
360 wm_event_free(event);
365 /* lets not expose struct outside wm? */
366 void WM_event_set_handler_flag(wmEventHandler *handler, int flag)
371 wmEventHandler *WM_event_add_modal_keymap_handler(ListBase *keymap, ListBase *handlers, wmOperator *op)
373 /* debug test; operator not in registry */
374 if(op->type->flag & OPTYPE_REGISTER) {
375 printf("error: handler (%s) cannot be modal, was registered\n", op->type->idname);
378 wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event handler");
379 wmOperator *opc= MEM_mallocN(sizeof(wmOperator), "operator modal");
381 BLI_addtail(handlers, handler);
382 handler->keymap= keymap;
391 wmEventHandler *WM_event_add_keymap_handler(ListBase *keymap, ListBase *handlers)
393 wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event handler");
395 BLI_addtail(handlers, handler);
396 handler->keymap= keymap;
401 /* ********************* ghost stuff *************** */
403 static int convert_key(GHOST_TKey key)
405 if (key>=GHOST_kKeyA && key<=GHOST_kKeyZ) {
406 return (AKEY + ((int) key - GHOST_kKeyA));
407 } else if (key>=GHOST_kKey0 && key<=GHOST_kKey9) {
408 return (ZEROKEY + ((int) key - GHOST_kKey0));
409 } else if (key>=GHOST_kKeyNumpad0 && key<=GHOST_kKeyNumpad9) {
410 return (PAD0 + ((int) key - GHOST_kKeyNumpad0));
411 } else if (key>=GHOST_kKeyF1 && key<=GHOST_kKeyF12) {
412 return (F1KEY + ((int) key - GHOST_kKeyF1));
415 case GHOST_kKeyBackSpace: return BACKSPACEKEY;
416 case GHOST_kKeyTab: return TABKEY;
417 case GHOST_kKeyLinefeed: return LINEFEEDKEY;
418 case GHOST_kKeyClear: return 0;
419 case GHOST_kKeyEnter: return RETKEY;
421 case GHOST_kKeyEsc: return ESCKEY;
422 case GHOST_kKeySpace: return SPACEKEY;
423 case GHOST_kKeyQuote: return QUOTEKEY;
424 case GHOST_kKeyComma: return COMMAKEY;
425 case GHOST_kKeyMinus: return MINUSKEY;
426 case GHOST_kKeyPeriod: return PERIODKEY;
427 case GHOST_kKeySlash: return SLASHKEY;
429 case GHOST_kKeySemicolon: return SEMICOLONKEY;
430 case GHOST_kKeyEqual: return EQUALKEY;
432 case GHOST_kKeyLeftBracket: return LEFTBRACKETKEY;
433 case GHOST_kKeyRightBracket: return RIGHTBRACKETKEY;
434 case GHOST_kKeyBackslash: return BACKSLASHKEY;
435 case GHOST_kKeyAccentGrave: return ACCENTGRAVEKEY;
437 case GHOST_kKeyLeftShift: return LEFTSHIFTKEY;
438 case GHOST_kKeyRightShift: return RIGHTSHIFTKEY;
439 case GHOST_kKeyLeftControl: return LEFTCTRLKEY;
440 case GHOST_kKeyRightControl: return RIGHTCTRLKEY;
441 case GHOST_kKeyCommand: return COMMANDKEY;
442 case GHOST_kKeyLeftAlt: return LEFTALTKEY;
443 case GHOST_kKeyRightAlt: return RIGHTALTKEY;
445 case GHOST_kKeyCapsLock: return CAPSLOCKKEY;
446 case GHOST_kKeyNumLock: return 0;
447 case GHOST_kKeyScrollLock: return 0;
449 case GHOST_kKeyLeftArrow: return LEFTARROWKEY;
450 case GHOST_kKeyRightArrow: return RIGHTARROWKEY;
451 case GHOST_kKeyUpArrow: return UPARROWKEY;
452 case GHOST_kKeyDownArrow: return DOWNARROWKEY;
454 case GHOST_kKeyPrintScreen: return 0;
455 case GHOST_kKeyPause: return PAUSEKEY;
457 case GHOST_kKeyInsert: return INSERTKEY;
458 case GHOST_kKeyDelete: return DELKEY;
459 case GHOST_kKeyHome: return HOMEKEY;
460 case GHOST_kKeyEnd: return ENDKEY;
461 case GHOST_kKeyUpPage: return PAGEUPKEY;
462 case GHOST_kKeyDownPage: return PAGEDOWNKEY;
464 case GHOST_kKeyNumpadPeriod: return PADPERIOD;
465 case GHOST_kKeyNumpadEnter: return PADENTER;
466 case GHOST_kKeyNumpadPlus: return PADPLUSKEY;
467 case GHOST_kKeyNumpadMinus: return PADMINUS;
468 case GHOST_kKeyNumpadAsterisk: return PADASTERKEY;
469 case GHOST_kKeyNumpadSlash: return PADSLASHKEY;
471 case GHOST_kKeyGrLess: return GRLESSKEY;
474 return UNKNOWNKEY; /* GHOST_kKeyUnknown */
479 /* adds customdata to event */
480 static void update_tablet_data(wmWindow *win, wmEvent *event)
482 const GHOST_TabletData *td= GHOST_GetTabletData(win->ghostwin);
484 /* if there's tablet data from an active tablet device then add it */
485 if ((td != NULL) && td->Active) {
486 struct wmTabletData *wmtab= MEM_mallocN(sizeof(wmTabletData), "customdata tablet");
488 wmtab->Active = td->Active;
489 wmtab->Pressure = td->Pressure;
490 wmtab->Xtilt = td->Xtilt;
491 wmtab->Ytilt = td->Ytilt;
493 event->custom= EVT_TABLET;
494 event->customdata= wmtab;
499 /* windows store own event queues, no bContext here */
500 void wm_event_add_ghostevent(wmWindow *win, int type, void *customdata)
502 wmEvent event, *evt= win->eventstate;
504 /* initialize and copy state (only mouse x y and modifiers) */
509 case GHOST_kEventCursorMove: {
511 GHOST_TEventCursorData *cd= customdata;
514 GHOST_ScreenToClient(win->ghostwin, cd->x, cd->y, &cx, &cy);
516 event.type= MOUSEMOVE;
518 event.y= evt->y= (win->sizey-1) - cy;
520 update_tablet_data(win, &event);
521 wm_event_add(win, &event);
526 case GHOST_kEventButtonDown:
527 case GHOST_kEventButtonUp: {
528 GHOST_TEventButtonData *bd= customdata;
529 event.val= (type==GHOST_kEventButtonDown);
531 if (bd->button == GHOST_kButtonMaskLeft)
532 event.type= LEFTMOUSE;
533 else if (bd->button == GHOST_kButtonMaskRight)
534 event.type= RIGHTMOUSE;
536 event.type= MIDDLEMOUSE;
538 update_tablet_data(win, &event);
539 wm_event_add(win, &event);
544 case GHOST_kEventKeyDown:
545 case GHOST_kEventKeyUp: {
546 GHOST_TEventKeyData *kd= customdata;
547 event.type= convert_key(kd->key);
548 event.ascii= kd->ascii;
549 event.val= (type==GHOST_kEventKeyDown);
552 if (event.type==LEFTSHIFTKEY || event.type==RIGHTSHIFTKEY) {
553 event.shift= evt->shift= event.val;
554 } else if (event.type==LEFTCTRLKEY || event.type==RIGHTCTRLKEY) {
555 event.ctrl= evt->ctrl= event.val;
556 } else if (event.type==LEFTALTKEY || event.type==RIGHTALTKEY) {
557 event.alt= evt->alt= event.val;
558 } else if (event.type==COMMANDKEY) {
559 event.oskey= evt->oskey= event.val;
562 wm_event_add(win, &event);
567 case GHOST_kEventWheel: {
568 GHOST_TEventWheelData* wheelData = customdata;
570 if (wheelData->z > 0)
571 event.type= WHEELUPMOUSE;
573 event.type= WHEELDOWNMOUSE;
575 event.val= wheelData->z; /* currently -1 or +1, see ghost for improvements here... */
576 wm_event_add(win, &event);
580 case GHOST_kEventUnknown:
581 case GHOST_kNumEventTypes: