37efc1a1367c19accac6859e671ecf44d088c177
[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 static 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)
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 }
104
105 static wmNotifier *wm_notifier_next(wmWindowManager *wm)
106 {
107         wmNotifier *note= wm->queue.first;
108         
109         if(note) BLI_remlink(&wm->queue, note);
110         return note;
111 }
112
113 /* called in mainloop */
114 void wm_event_do_notifiers(bContext *C)
115 {
116         wmNotifier *note;
117         
118         while( (note=wm_notifier_next(C->wm)) ) {
119                 wmWindow *win;
120                 
121                 for(win= C->wm->windows.first; win; win= win->next) {
122                         ScrArea *sa;
123                         
124                         if(note->window && note->window!=win)
125                                 continue;
126                         if(win->screen==NULL)
127                                 continue;
128                         printf("notifier win %d screen %s\n", win->winid, win->screen->id.name+2);
129                         ED_screen_do_listen(win->screen, note);
130                         
131                         for(sa= win->screen->areabase.first; sa; sa= sa->next) {
132                                 ARegion *ar= sa->regionbase.first;
133                                 
134                                 for(; ar; ar= ar->next) {
135                                         if(note->swinid && note->swinid!=ar->swinid)
136                                                 continue;
137                                         ED_region_do_listen(ar, note);
138                                 }
139                         }
140                 }
141                 MEM_freeN(note);
142         }       
143 }
144
145 /* quick test to prevent changing window drawable */
146 static int wm_draw_update_test_window(wmWindow *win)
147 {
148         ScrArea *sa;
149         
150         if(win->screen->do_refresh)
151                 return 1;
152         if(win->screen->do_draw)
153                 return 1;
154         
155         for(sa= win->screen->areabase.first; sa; sa= sa->next) {
156                 ARegion *ar= sa->regionbase.first;
157                 
158                 for(; ar; ar= ar->next) {
159                         /* cached notifiers */
160                         if(ar->do_refresh)
161                                 return 1;
162                         if(ar->swinid && ar->do_draw)
163                                 return 1;
164                 }
165         }
166         return 0;
167 }
168
169 void wm_draw_update(bContext *C)
170 {
171         wmWindow *win;
172         
173         for(win= C->wm->windows.first; win; win= win->next) {
174                 if(wm_draw_update_test_window(win)) {
175                         ScrArea *sa;
176                         
177                         /* sets context window+screen */
178                         wm_window_make_drawable(C, win);
179                         
180                         /* notifiers for screen redraw */
181                         if(win->screen->do_refresh)
182                                 ED_screen_refresh(C->wm, win);
183                         if(win->screen->do_draw)
184                                 ED_screen_draw(win);
185                         
186                         for(sa= win->screen->areabase.first; sa; sa= sa->next) {
187                                 ARegion *ar= sa->regionbase.first;
188                                 int hasdrawn= 0;
189                                 
190                                 for(; ar; ar= ar->next) {
191                                         hasdrawn |= ar->do_draw;
192                                         
193                                         /* cached notifiers */
194                                         if(ar->do_refresh)
195                                                 ED_region_do_refresh(C, ar);
196                                         
197                                         if(ar->swinid && ar->do_draw)
198                                                 ED_region_do_draw(C, ar);
199                                 }
200                         }
201                         wm_window_swap_buffers(win);
202                 }
203         }
204 }
205
206 /* ********************* handlers *************** */
207
208 void wm_event_free_handlers(ListBase *lb)
209 {
210         wmEventHandler *handler;
211         
212         for(handler= lb->first; handler; handler= handler->next) {
213                 if(handler->op)
214                         MEM_freeN(handler->op);
215         }
216         BLI_freelistN(lb);
217 }
218
219 static int wm_eventmatch(wmEvent *winevent, wmKeymapItem *km)
220 {
221         if(winevent->type!=km->type) return 0;
222         
223         if(km->val) /* KM_PRESS, KM_RELEASE */
224                 if(winevent->val!=km->val-1) return 0;
225         
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;
231         
232         /* optional boundbox */
233         
234         return 1;
235 }
236
237 static int wm_handler_operator_call(bContext *C, wmEventHandler *handler, wmEvent *event)
238 {
239         int retval= 0;
240         
241         /* derived, modal or blocking operator */
242         if(handler->op) {
243                 if( handler->op->type->poll(C)) {
244                         if(handler->op->type->interactive)
245                                 retval= handler->op->type->interactive(C, handler->op, event);
246                         else
247                                 printf("wm_handler_operator_call error\n");
248                 }
249         }
250         else {
251                 wmOperatorType *ot= WM_operatortype_find(event->keymap_idname);
252                 if(ot) {
253                         if(ot->poll(C)) {
254                                 /* operator on stack, register or new modal handle malloc-copies */
255                                 wmOperator op;
256                                 
257                                 memset(&op, 0, sizeof(wmOperator));
258                                 op.type= ot;
259
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);
264                                 
265                                 if( ot->flag & OPTYPE_REGISTER)
266                                         wm_operator_register(C->wm, &op);
267                         }
268                 }
269         }
270         if(retval)
271                 return WM_HANDLER_BREAK;
272         
273         return WM_HANDLER_CONTINUE;
274 }
275
276 static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
277 {
278         wmEventHandler *handler;
279         int action= WM_HANDLER_CONTINUE;
280         
281         if(handlers==NULL) return action;
282         
283         for(handler= handlers->first; handler; handler= handler->next) {
284                 if(handler->keymap) {
285                         wmKeymapItem *km;
286                         
287                         for(km= handler->keymap->first; km; km= km->next) {
288                                 if(wm_eventmatch(event, km)) {
289                                         
290                                         if(event->type!=MOUSEMOVE)
291                                                 printf("handle evt %d win %d op %s\n", event->type, C->window->winid, km->idname);
292                                         
293                                         event->keymap_idname= km->idname;       /* weak, but allows interactive callback to not use rawkey */
294                                         
295                                         action= wm_handler_operator_call(C, handler, event);
296                                 }
297                         }
298                         if(action==WM_HANDLER_BREAK)
299                                 break;
300                 }
301                 /* modal+blocking handler */
302                 if(handler->flag & WM_HANDLER_BLOCKING)
303                         action= WM_HANDLER_BREAK;
304         }
305         return action;
306 }
307
308 static int wm_event_inside_i(wmEvent *event, rcti *rect)
309 {
310         return BLI_in_rcti(rect, event->x, event->y);
311 }
312
313
314 /* called in main loop */
315 /* goes over entire hierarchy:  events -> window -> screen -> area -> region */
316 void wm_event_do_handlers(bContext *C)
317 {
318         wmWindow *win;
319         
320         for(win= C->wm->windows.first; win; win= win->next) {
321                 wmEvent *event;
322                 
323                 if( win->screen==NULL )
324                         wm_event_free_all(win);
325                 
326                 while( (event=wm_event_next(win)) ) {
327                         int action;
328                         
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);
332                         
333                         action= wm_handlers_do(C, event, &win->handlers);
334                         
335                         if(action==WM_HANDLER_CONTINUE) {
336                                 ScrArea *sa= win->screen->areabase.first;
337                                 
338                                 for(; sa; sa= sa->next) {
339                                         if(wm_event_inside_i(event, &sa->winrct)) {
340                                                 
341                                                 C->curarea= sa;
342                                                 action= wm_handlers_do(C, event, &sa->handlers);
343                                                 if(action==WM_HANDLER_CONTINUE) {
344                                                         ARegion *ar= sa->regionbase.first;
345                                                         
346                                                         for(; ar; ar= ar->next) {
347                                                                 if(wm_event_inside_i(event, &ar->winrct)) {
348                                                                         C->region= ar;
349                                                                         action= wm_handlers_do(C, event, &ar->handlers);
350                                                                         if(action==WM_HANDLER_BREAK)
351                                                                                 break;
352                                                                 }
353                                                         }
354                                                 }
355                                                 if(action==WM_HANDLER_BREAK)
356                                                         break;
357                                         }
358                                 }
359                         }
360                         wm_event_free(event);
361                 }
362         }
363 }
364
365 /* lets not expose struct outside wm? */
366 void WM_event_set_handler_flag(wmEventHandler *handler, int flag)
367 {
368         handler->flag= flag;
369 }
370
371 wmEventHandler *WM_event_add_modal_keymap_handler(ListBase *keymap, ListBase *handlers, wmOperator *op)
372 {
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);
376         }
377         else {
378                 wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event handler");
379                 wmOperator *opc= MEM_mallocN(sizeof(wmOperator), "operator modal");
380                 
381                 BLI_addtail(handlers, handler);
382                 handler->keymap= keymap;
383                 *opc= *op;
384                 handler->op= opc;
385                 
386                 return handler;
387         }
388         return NULL;
389 }
390
391 wmEventHandler *WM_event_add_keymap_handler(ListBase *keymap, ListBase *handlers)
392 {
393         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event handler");
394         
395         BLI_addtail(handlers, handler);
396         handler->keymap= keymap;
397         
398         return handler;
399 }
400
401 /* ********************* ghost stuff *************** */
402
403 static int convert_key(GHOST_TKey key) 
404 {
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));
413         } else {
414                 switch (key) {
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;
420                                 
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;
428                                 
429                         case GHOST_kKeySemicolon:               return SEMICOLONKEY;
430                         case GHOST_kKeyEqual:                   return EQUALKEY;
431                                 
432                         case GHOST_kKeyLeftBracket:             return LEFTBRACKETKEY;
433                         case GHOST_kKeyRightBracket:    return RIGHTBRACKETKEY;
434                         case GHOST_kKeyBackslash:               return BACKSLASHKEY;
435                         case GHOST_kKeyAccentGrave:             return ACCENTGRAVEKEY;
436                                 
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;
444                                 
445                         case GHOST_kKeyCapsLock:                return CAPSLOCKKEY;
446                         case GHOST_kKeyNumLock:                 return 0;
447                         case GHOST_kKeyScrollLock:              return 0;
448                                 
449                         case GHOST_kKeyLeftArrow:               return LEFTARROWKEY;
450                         case GHOST_kKeyRightArrow:              return RIGHTARROWKEY;
451                         case GHOST_kKeyUpArrow:                 return UPARROWKEY;
452                         case GHOST_kKeyDownArrow:               return DOWNARROWKEY;
453                                 
454                         case GHOST_kKeyPrintScreen:             return 0;
455                         case GHOST_kKeyPause:                   return PAUSEKEY;
456                                 
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;
463                                 
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;
470                                 
471                         case GHOST_kKeyGrLess:              return GRLESSKEY; 
472                                 
473                         default:
474                                 return UNKNOWNKEY;      /* GHOST_kKeyUnknown */
475                 }
476         }
477 }
478
479 /* adds customdata to event */
480 static void update_tablet_data(wmWindow *win, wmEvent *event)
481 {
482         const GHOST_TabletData *td= GHOST_GetTabletData(win->ghostwin);
483         
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");
487                 
488                 wmtab->Active = td->Active;
489                 wmtab->Pressure = td->Pressure;
490                 wmtab->Xtilt = td->Xtilt;
491                 wmtab->Ytilt = td->Ytilt;
492                 
493                 event->custom= EVT_TABLET;
494                 event->customdata= wmtab;
495         } 
496 }
497
498
499 /* windows store own event queues, no bContext here */
500 void wm_event_add_ghostevent(wmWindow *win, int type, void *customdata)
501 {
502         wmEvent event, *evt= win->eventstate;
503         
504         /* initialize and copy state (only mouse x y and modifiers) */
505         event= *evt;
506         
507         switch (type) {
508                 /* mouse move */
509                 case GHOST_kEventCursorMove: {
510                         if(win->active) {
511                                 GHOST_TEventCursorData *cd= customdata;
512                                 int cx, cy;
513
514                                 GHOST_ScreenToClient(win->ghostwin, cd->x, cd->y, &cx, &cy);
515                                 
516                                 event.type= MOUSEMOVE;
517                                 event.x= evt->x= cx;
518                                 event.y= evt->y= (win->sizey-1) - cy;
519                                 
520                                 update_tablet_data(win, &event);
521                                 wm_event_add(win, &event);
522                         }
523                         break;
524                 }
525                 /* mouse button */
526                 case GHOST_kEventButtonDown:
527                 case GHOST_kEventButtonUp: {
528                         GHOST_TEventButtonData *bd= customdata;
529                         event.val= (type==GHOST_kEventButtonDown);
530                         
531                         if (bd->button == GHOST_kButtonMaskLeft)
532                                 event.type= LEFTMOUSE;
533                         else if (bd->button == GHOST_kButtonMaskRight)
534                                 event.type= RIGHTMOUSE;
535                         else
536                                 event.type= MIDDLEMOUSE;
537                         
538                         update_tablet_data(win, &event);
539                         wm_event_add(win, &event);
540                         
541                         break;
542                 }
543                 /* keyboard */
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);
550                         
551                         /* modifiers */
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;
560                         }
561                         
562                         wm_event_add(win, &event);
563                         
564                         break;
565                 }
566                         
567                 case GHOST_kEventWheel: {
568                         GHOST_TEventWheelData* wheelData = customdata;
569                         
570                         if (wheelData->z > 0)
571                                 event.type= WHEELUPMOUSE;
572                         else
573                                 event.type= WHEELDOWNMOUSE;
574                         
575                         event.val= wheelData->z;        /* currently -1 or +1, see ghost for improvements here... */
576                         wm_event_add(win, &event);
577                         
578                         break;
579                 }
580                 case GHOST_kEventUnknown:
581                 case GHOST_kNumEventTypes:
582                         break;
583         }
584 }
585