c33ac0cd3422f39d4ab4579e92ec0585b9f122bb
[blender.git] / source / blender / windowmanager / intern / wm_event_system.c
1 /**
2  * $Id:
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2007 Blender Foundation.
21  * All rights reserved.
22  *
23  * 
24  * Contributor(s): Blender Foundation
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include <stdlib.h>
30 #include <string.h>
31
32 #include "DNA_listBase.h"
33 #include "DNA_screen_types.h"
34 #include "DNA_windowmanager_types.h"
35 #include "DNA_userdef_types.h"  /* U.flag & TWOBUTTONMOUSE */
36
37 #include "MEM_guardedalloc.h"
38
39 #include "GHOST_C-api.h"
40
41 #include "BLI_blenlib.h"
42
43 #include "BKE_blender.h"
44 #include "BKE_global.h"
45
46 #include "ED_screen.h"
47 #include "ED_area.h"
48
49 #include "WM_api.h"
50 #include "WM_types.h"
51 #include "wm.h"
52 #include "wm_window.h"
53 #include "wm_event_system.h"
54 #include "wm_event_types.h"
55
56 /* ************ event management ************** */
57
58 void wm_event_add(wmWindow *win, wmEvent *event_to_add)
59 {
60         wmEvent *event= MEM_callocN(sizeof(wmEvent), "event");
61         
62         *event= *event_to_add;
63         BLI_addtail(&win->queue, event);
64 }
65
66 wmEvent *wm_event_next(wmWindow *win)
67 {
68         wmEvent *event= win->queue.first;
69
70         if(event) BLI_remlink(&win->queue, event);
71         return event;
72 }
73
74 static void wm_event_free(wmEvent *event)
75 {
76         if(event->customdata) MEM_freeN(event->customdata);
77         MEM_freeN(event);
78 }
79
80 void wm_event_free_all(wmWindow *win)
81 {
82         wmEvent *event;
83         
84         while((event= win->queue.first)) {
85                 BLI_remlink(&win->queue, event);
86                 wm_event_free(event);
87         }
88 }
89
90 /* ********************* notifiers, listeners *************** */
91
92 /* win and swinid are optional context limitors */
93 void WM_event_add_notifier(wmWindowManager *wm, wmWindow *window, int swinid, int type, int value, void *data)
94 {
95         wmNotifier *note= MEM_callocN(sizeof(wmNotifier), "notifier");
96         
97         BLI_addtail(&wm->queue, note);
98         
99         note->window= window;
100         note->swinid= swinid;
101         note->type= type;
102         note->value= value;
103         note->data= data;
104 }
105
106 static wmNotifier *wm_notifier_next(wmWindowManager *wm)
107 {
108         wmNotifier *note= wm->queue.first;
109         
110         if(note) BLI_remlink(&wm->queue, note);
111         return note;
112 }
113
114 /* called in mainloop */
115 void wm_event_do_notifiers(bContext *C)
116 {
117         wmNotifier *note;
118         
119         while( (note=wm_notifier_next(C->wm)) ) {
120                 wmWindow *win;
121                 
122                 for(win= C->wm->windows.first; win; win= win->next) {
123                         ScrArea *sa;
124
125                         C->window= win;
126                         C->screen= win->screen;
127                         
128                         if(note->window && note->window!=win)
129                                 continue;
130                         if(win->screen==NULL)
131                                 continue;
132
133                         printf("notifier win %d screen %s\n", win->winid, win->screen->id.name+2);
134                         ED_screen_do_listen(win, note);
135                         
136                         for(sa= win->screen->areabase.first; sa; sa= sa->next) {
137                                 ARegion *ar= sa->regionbase.first;
138                                 
139                                 C->area= sa;
140
141                                 for(; ar; ar= ar->next) {
142                                         if(note->swinid && note->swinid!=ar->swinid)
143                                                 continue;
144
145                                         C->region= ar;
146                                         ED_region_do_listen(ar, note);
147                                         C->region= NULL;
148                                 }
149
150                                 C->area= NULL;
151                         }
152
153                         C->window= NULL;
154                         C->screen= NULL;
155                 }
156                 if(note->data)
157                         MEM_freeN(note->data);
158                 MEM_freeN(note);
159         }       
160 }
161
162 /* quick test to prevent changing window drawable */
163 static int wm_draw_update_test_window(wmWindow *win)
164 {
165         ScrArea *sa;
166         
167         if(win->screen->do_refresh)
168                 return 1;
169         if(win->screen->do_draw)
170                 return 1;
171         if(win->screen->do_gesture)
172                 return 1;
173
174         for(sa= win->screen->areabase.first; sa; sa= sa->next) {
175                 ARegion *ar= sa->regionbase.first;
176                 
177                 for(; ar; ar= ar->next) {
178                         /* cached notifiers */
179                         if(ar->do_refresh)
180                                 return 1;
181                         if(ar->swinid && ar->do_draw)
182                                 return 1;
183                 }
184         }
185         return 0;
186 }
187
188 void wm_draw_update(bContext *C)
189 {
190         wmWindow *win;
191         
192         for(win= C->wm->windows.first; win; win= win->next) {
193                 if(wm_draw_update_test_window(win)) {
194                         ScrArea *sa;
195
196                         C->window= win;
197                         C->screen= win->screen;
198                         
199                         /* sets context window+screen */
200                         wm_window_make_drawable(C, win);
201                         
202                         /* notifiers for screen redraw */
203                         if(win->screen->do_refresh)
204                                 ED_screen_refresh(C->wm, win);
205                         
206                         for(sa= win->screen->areabase.first; sa; sa= sa->next) {
207                                 ARegion *ar= sa->regionbase.first;
208                                 int hasdrawn= 0;
209
210                                 C->area= sa;
211                                 
212                                 for(; ar; ar= ar->next) {
213                                         hasdrawn |= ar->do_draw;
214
215                                         C->region= ar;
216                                         
217                                         /* cached notifiers */
218                                         if(ar->do_refresh)
219                                                 ED_region_do_refresh(C, ar);
220                                         
221                                         if(ar->swinid && ar->do_draw)
222                                                 ED_region_do_draw(C, ar);
223
224                                         C->region= NULL;
225                                 }
226
227                                 C->area = NULL;
228                         }
229                         
230                         /* move this here so we can do area 'overlay' drawing */
231                         if(win->screen->do_draw)
232                                 ED_screen_draw(win);
233                         
234                         if(win->screen->do_gesture)
235                                 ED_screen_gesture(win);
236
237                         wm_window_swap_buffers(win);
238
239                         C->window= NULL;
240                         C->screen= NULL;
241                 }
242         }
243 }
244
245 /* ********************* handlers *************** */
246
247 /* not handler itself */
248 static void wm_event_free_handler(wmEventHandler *handler)
249 {
250 }
251
252 void wm_event_free_handlers(ListBase *lb)
253 {
254         wmEventHandler *handler;
255         
256         for(handler= lb->first; handler; handler= handler->next)
257                 wm_event_free_handler(handler);
258         
259         BLI_freelistN(lb);
260 }
261
262 static int wm_eventmatch(wmEvent *winevent, wmKeymapItem *km)
263 {
264         if(winevent->type!=km->type) return 0;
265         
266         if(km->val) /* KM_PRESS, KM_RELEASE */
267                 if(winevent->val!=km->val-1) return 0;
268         
269         if(winevent->shift!=km->shift) return 0;
270         if(winevent->ctrl!=km->ctrl) return 0;
271         if(winevent->alt!=km->alt) return 0;
272         if(winevent->oskey!=km->oskey) return 0;
273         if(km->keymodifier)
274                 if(winevent->keymodifier!=km->keymodifier) return 0;
275         
276         /* optional boundbox */
277         
278         return 1;
279 }
280
281 /* note: this might free the handler from the operator */
282 static int wm_handler_operator_call(bContext *C, wmEventHandler *handler, wmEvent *event)
283 {
284         int retval= OPERATOR_PASS_THROUGH;
285         
286         /* derived, modal or blocking operator */
287         if(handler->op) {
288                 wmOperator *op= handler->op;
289                 wmOperatorType *ot= op->type;
290
291                 if(ot->modal) {
292
293                         retval= ot->modal(C, op, event);
294
295                         if(retval == OPERATOR_FINISHED && (ot->flag & OPTYPE_REGISTER))
296                                 wm_operator_register(C->wm, op);
297                         else if(retval == OPERATOR_CANCELLED || retval == OPERATOR_FINISHED)
298                                 wm_operator_free(op);
299                 }
300                 else
301                         printf("wm_handler_operator_call error\n");
302         }
303         else {
304                 wmOperatorType *ot= WM_operatortype_find(event->keymap_idname);
305
306                 if(ot) {
307                         if(ot->poll==NULL || ot->poll(C)) {
308                                 wmOperator *op= MEM_callocN(sizeof(wmOperator), "wmOperator");
309
310                                 op->type= ot;
311
312                                 if(op->type->invoke)
313                                         retval= (*op->type->invoke)(C, op, event);
314                                 else if(op->type->exec)
315                                         retval= op->type->exec(C, op);
316
317                                 if(retval == OPERATOR_FINISHED && (ot->flag & OPTYPE_REGISTER))
318                                         wm_operator_register(C->wm, op);
319                                 else if(retval != OPERATOR_RUNNING_MODAL)
320                                         wm_operator_free(op);
321                         }
322                 }
323         }
324
325         if(retval == OPERATOR_PASS_THROUGH)
326                 return WM_HANDLER_CONTINUE;
327
328         return WM_HANDLER_BREAK;
329 }
330
331 static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
332 {
333         wmEventHandler *handler, *nexthandler;
334         int action= WM_HANDLER_CONTINUE;
335         
336         if(handlers==NULL) return action;
337         
338         /* in this loop, the handler might be freed in wm_handler_operator_call,
339          * and new handler might be added to the head of the list */
340         for(handler= handlers->first; handler; handler= nexthandler) {
341                 nexthandler= handler->next;
342
343                 /* modal+blocking handler */
344                 if(handler->flag & WM_HANDLER_BLOCKING)
345                         action= WM_HANDLER_BREAK;
346
347                 if(handler->keymap) {
348                         wmKeymapItem *km;
349                         
350                         for(km= handler->keymap->first; km; km= km->next) {
351                                 if(wm_eventmatch(event, km)) {
352                                         if(event->type!=MOUSEMOVE)
353                                                 printf("handle evt %d win %d op %s\n", event->type, C->window->winid, km->idname);
354                                         
355                                         event->keymap_idname= km->idname;       /* weak, but allows interactive callback to not use rawkey */
356                                         
357                                         action= wm_handler_operator_call(C, handler, event);
358                                         if(action==WM_HANDLER_BREAK)
359                                                 break;
360                                 }
361                         }
362                 }
363                 else {
364                         /* modal, swallows all */
365                         action= wm_handler_operator_call(C, handler, event);
366                 }
367
368                 if(action==WM_HANDLER_BREAK)
369                         break;
370                 
371         }
372         return action;
373 }
374
375 static int wm_event_inside_i(wmEvent *event, rcti *rect)
376 {
377         return BLI_in_rcti(rect, event->x, event->y);
378 }
379
380
381 /* called in main loop */
382 /* goes over entire hierarchy:  events -> window -> screen -> area -> region */
383 void wm_event_do_handlers(bContext *C)
384 {
385         wmWindow *win;
386
387         for(win= C->wm->windows.first; win; win= win->next) {
388                 wmEvent *event;
389                 
390                 if( win->screen==NULL )
391                         wm_event_free_all(win);
392                 
393                 while( (event=wm_event_next(win)) ) {
394                         int action;
395
396                         C->window= win;
397                         C->screen= win->screen;
398
399                         /* MVC demands to not draw in event handlers... for now we leave it */
400                         wm_window_make_drawable(C, win);
401                         
402                         action= wm_handlers_do(C, event, &win->handlers);
403                         
404                         if(action==WM_HANDLER_CONTINUE) {
405                                 ScrArea *sa= win->screen->areabase.first;
406                                 
407                                 for(; sa; sa= sa->next) {
408                                         if(wm_event_inside_i(event, &sa->totrct)) {
409                                                 
410                                                 C->area= sa;
411                                                 action= wm_handlers_do(C, event, &sa->handlers);
412                                                 if(action==WM_HANDLER_CONTINUE) {
413                                                         ARegion *ar= sa->regionbase.first;
414                                                         
415                                                         for(; ar; ar= ar->next) {
416                                                                 if(wm_event_inside_i(event, &ar->winrct)) {
417                                                                         C->region= ar;
418                                                                         action= wm_handlers_do(C, event, &ar->handlers);
419                                                                         C->region= NULL;
420                                                                         if(action==WM_HANDLER_BREAK)
421                                                                                 break;
422                                                                 }
423                                                         }
424                                                 }
425                                                 C->area= NULL;
426                                                 if(action==WM_HANDLER_BREAK)
427                                                         break;
428                                         }
429                                 }
430                         }
431                         wm_event_free(event);
432
433                         C->window= NULL;
434                         C->screen= NULL;
435                 }
436         }
437 }
438
439 /* lets not expose struct outside wm? */
440 void WM_event_set_handler_flag(wmEventHandler *handler, int flag)
441 {
442         handler->flag= flag;
443 }
444
445 wmEventHandler *WM_event_add_modal_handler(ListBase *handlers, wmOperator *op)
446 {
447         /* debug test; operator not in registry */
448         if(op->type->flag & OPTYPE_REGISTER) {
449                 printf("error: handler (%s) cannot be modal, was registered\n", op->type->idname);
450         }
451         else {
452                 wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event handler");
453                 handler->op= op;
454                 BLI_addhead(handlers, handler);
455                 
456                 return handler;
457         }
458         return NULL;
459 }
460
461 void WM_event_remove_modal_handler(ListBase *handlers, wmOperator *op)
462 {
463         wmEventHandler *handler;
464         
465         for(handler= handlers->first; handler; handler= handler->next) {
466                 if(handler->op==op) {
467                         BLI_remlink(handlers, handler);
468                         wm_event_free_handler(handler);
469                         MEM_freeN(handler);
470                         break;
471                 }
472         }
473 }
474
475 wmEventHandler *WM_event_add_keymap_handler(ListBase *keymap, ListBase *handlers)
476 {
477         wmEventHandler *handler;
478         
479         /* only allow same keymap once */
480         for(handler= handlers->first; handler; handler= handler->next)
481                 if(handler->keymap==keymap)
482                         return handler;
483
484         handler= MEM_callocN(sizeof(wmEventHandler), "event handler");
485         BLI_addtail(handlers, handler);
486         handler->keymap= keymap;
487         
488         return handler;
489 }
490
491 void WM_event_remove_keymap_handler(ListBase *keymap, ListBase *handlers)
492 {
493         wmEventHandler *handler;
494         
495         for(handler= handlers->first; handler; handler= handler->next) {
496                 if(handler->keymap==keymap) {
497                         BLI_remlink(handlers, handler);
498                         wm_event_free_handler(handler);
499                         MEM_freeN(handler);
500                         break;
501                 }
502         }
503 }
504
505 /* ********************* ghost stuff *************** */
506
507 static int convert_key(GHOST_TKey key) 
508 {
509         if (key>=GHOST_kKeyA && key<=GHOST_kKeyZ) {
510                 return (AKEY + ((int) key - GHOST_kKeyA));
511         } else if (key>=GHOST_kKey0 && key<=GHOST_kKey9) {
512                 return (ZEROKEY + ((int) key - GHOST_kKey0));
513         } else if (key>=GHOST_kKeyNumpad0 && key<=GHOST_kKeyNumpad9) {
514                 return (PAD0 + ((int) key - GHOST_kKeyNumpad0));
515         } else if (key>=GHOST_kKeyF1 && key<=GHOST_kKeyF12) {
516                 return (F1KEY + ((int) key - GHOST_kKeyF1));
517         } else {
518                 switch (key) {
519                         case GHOST_kKeyBackSpace:               return BACKSPACEKEY;
520                         case GHOST_kKeyTab:                             return TABKEY;
521                         case GHOST_kKeyLinefeed:                return LINEFEEDKEY;
522                         case GHOST_kKeyClear:                   return 0;
523                         case GHOST_kKeyEnter:                   return RETKEY;
524                                 
525                         case GHOST_kKeyEsc:                             return ESCKEY;
526                         case GHOST_kKeySpace:                   return SPACEKEY;
527                         case GHOST_kKeyQuote:                   return QUOTEKEY;
528                         case GHOST_kKeyComma:                   return COMMAKEY;
529                         case GHOST_kKeyMinus:                   return MINUSKEY;
530                         case GHOST_kKeyPeriod:                  return PERIODKEY;
531                         case GHOST_kKeySlash:                   return SLASHKEY;
532                                 
533                         case GHOST_kKeySemicolon:               return SEMICOLONKEY;
534                         case GHOST_kKeyEqual:                   return EQUALKEY;
535                                 
536                         case GHOST_kKeyLeftBracket:             return LEFTBRACKETKEY;
537                         case GHOST_kKeyRightBracket:    return RIGHTBRACKETKEY;
538                         case GHOST_kKeyBackslash:               return BACKSLASHKEY;
539                         case GHOST_kKeyAccentGrave:             return ACCENTGRAVEKEY;
540                                 
541                         case GHOST_kKeyLeftShift:               return LEFTSHIFTKEY;
542                         case GHOST_kKeyRightShift:              return RIGHTSHIFTKEY;
543                         case GHOST_kKeyLeftControl:             return LEFTCTRLKEY;
544                         case GHOST_kKeyRightControl:    return RIGHTCTRLKEY;
545                         case GHOST_kKeyCommand:                 return COMMANDKEY;
546                         case GHOST_kKeyLeftAlt:                 return LEFTALTKEY;
547                         case GHOST_kKeyRightAlt:                return RIGHTALTKEY;
548                                 
549                         case GHOST_kKeyCapsLock:                return CAPSLOCKKEY;
550                         case GHOST_kKeyNumLock:                 return 0;
551                         case GHOST_kKeyScrollLock:              return 0;
552                                 
553                         case GHOST_kKeyLeftArrow:               return LEFTARROWKEY;
554                         case GHOST_kKeyRightArrow:              return RIGHTARROWKEY;
555                         case GHOST_kKeyUpArrow:                 return UPARROWKEY;
556                         case GHOST_kKeyDownArrow:               return DOWNARROWKEY;
557                                 
558                         case GHOST_kKeyPrintScreen:             return 0;
559                         case GHOST_kKeyPause:                   return PAUSEKEY;
560                                 
561                         case GHOST_kKeyInsert:                  return INSERTKEY;
562                         case GHOST_kKeyDelete:                  return DELKEY;
563                         case GHOST_kKeyHome:                    return HOMEKEY;
564                         case GHOST_kKeyEnd:                             return ENDKEY;
565                         case GHOST_kKeyUpPage:                  return PAGEUPKEY;
566                         case GHOST_kKeyDownPage:                return PAGEDOWNKEY;
567                                 
568                         case GHOST_kKeyNumpadPeriod:    return PADPERIOD;
569                         case GHOST_kKeyNumpadEnter:             return PADENTER;
570                         case GHOST_kKeyNumpadPlus:              return PADPLUSKEY;
571                         case GHOST_kKeyNumpadMinus:             return PADMINUS;
572                         case GHOST_kKeyNumpadAsterisk:  return PADASTERKEY;
573                         case GHOST_kKeyNumpadSlash:             return PADSLASHKEY;
574                                 
575                         case GHOST_kKeyGrLess:              return GRLESSKEY; 
576                                 
577                         default:
578                                 return UNKNOWNKEY;      /* GHOST_kKeyUnknown */
579                 }
580         }
581 }
582
583 /* adds customdata to event */
584 static void update_tablet_data(wmWindow *win, wmEvent *event)
585 {
586         const GHOST_TabletData *td= GHOST_GetTabletData(win->ghostwin);
587         
588         /* if there's tablet data from an active tablet device then add it */
589         if ((td != NULL) && td->Active) {
590                 struct wmTabletData *wmtab= MEM_mallocN(sizeof(wmTabletData), "customdata tablet");
591                 
592                 wmtab->Active = td->Active;
593                 wmtab->Pressure = td->Pressure;
594                 wmtab->Xtilt = td->Xtilt;
595                 wmtab->Ytilt = td->Ytilt;
596                 
597                 event->custom= EVT_TABLET;
598                 event->customdata= wmtab;
599         } 
600 }
601
602
603 /* windows store own event queues, no bContext here */
604 void wm_event_add_ghostevent(wmWindow *win, int type, void *customdata)
605 {
606         wmEvent event, *evt= win->eventstate;
607         
608         /* initialize and copy state (only mouse x y and modifiers) */
609         event= *evt;
610         
611         switch (type) {
612                 /* mouse move */
613                 case GHOST_kEventCursorMove: {
614                         if(win->active) {
615                                 GHOST_TEventCursorData *cd= customdata;
616                                 int cx, cy;
617
618                                 GHOST_ScreenToClient(win->ghostwin, cd->x, cd->y, &cx, &cy);
619                                 
620                                 event.type= MOUSEMOVE;
621                                 event.x= evt->x= cx;
622                                 event.y= evt->y= (win->sizey-1) - cy;
623                                 
624                                 ED_screen_set_subwinactive(win);        /* state variables in screen */
625                                 
626                                 update_tablet_data(win, &event);
627                                 wm_event_add(win, &event);
628                         }
629                         break;
630                 }
631                 /* mouse button */
632                 case GHOST_kEventButtonDown:
633                 case GHOST_kEventButtonUp: {
634                         GHOST_TEventButtonData *bd= customdata;
635                         event.val= (type==GHOST_kEventButtonDown);
636                         
637                         if (bd->button == GHOST_kButtonMaskLeft)
638                                 event.type= LEFTMOUSE;
639                         else if (bd->button == GHOST_kButtonMaskRight)
640                                 event.type= RIGHTMOUSE;
641                         else
642                                 event.type= MIDDLEMOUSE;
643                         
644                         if(event.val)
645                                 event.keymodifier= evt->keymodifier= event.type;
646                         else
647                                 event.keymodifier= evt->keymodifier= 0;
648                         
649                         update_tablet_data(win, &event);
650                         wm_event_add(win, &event);
651                         
652                         break;
653                 }
654                 /* keyboard */
655                 case GHOST_kEventKeyDown:
656                 case GHOST_kEventKeyUp: {
657                         GHOST_TEventKeyData *kd= customdata;
658                         event.type= convert_key(kd->key);
659                         event.ascii= kd->ascii;
660                         event.val= (type==GHOST_kEventKeyDown);
661                         
662                         /* modifiers */
663                         if (event.type==LEFTSHIFTKEY || event.type==RIGHTSHIFTKEY) {
664                                 event.shift= evt->shift= event.val;
665                         } else if (event.type==LEFTCTRLKEY || event.type==RIGHTCTRLKEY) {
666                                 event.ctrl= evt->ctrl= event.val;
667                         } else if (event.type==LEFTALTKEY || event.type==RIGHTALTKEY) {
668                                 event.alt= evt->alt= event.val;
669                         } else if (event.type==COMMANDKEY) {
670                                 event.oskey= evt->oskey= event.val;
671                         }
672                         
673                         wm_event_add(win, &event);
674                         
675                         break;
676                 }
677                         
678                 case GHOST_kEventWheel: {
679                         GHOST_TEventWheelData* wheelData = customdata;
680                         
681                         if (wheelData->z > 0)
682                                 event.type= WHEELUPMOUSE;
683                         else
684                                 event.type= WHEELDOWNMOUSE;
685                         
686                         event.val= wheelData->z;        /* currently -1 or +1, see ghost for improvements here... */
687                         wm_event_add(win, &event);
688                         
689                         break;
690                 }
691                 case GHOST_kEventUnknown:
692                 case GHOST_kNumEventTypes:
693                         break;
694         }
695 }
696