782c1325e2fff7638c54f4e0edd8e63dd316d8e8
[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 "WM_api.h"
47 #include "WM_types.h"
48 #include "wm.h"
49 #include "wm_window.h"
50 #include "wm_event_system.h"
51 #include "wm_event_types.h"
52
53 /* ************ event management ************** */
54
55 static void wm_event_add(wmWindow *win, wmEvent *event_to_add)
56 {
57         wmEvent *event= MEM_callocN(sizeof(wmEvent), "event");
58         
59         *event= *event_to_add;
60         BLI_addtail(&win->queue, event);
61 }
62
63 wmEvent *wm_event_next(wmWindow *win)
64 {
65         wmEvent *event= win->queue.first;
66
67         if(event) BLI_remlink(&win->queue, event);
68         return event;
69 }
70
71 static void wm_event_free(wmEvent *event)
72 {
73         if(event->customdata) MEM_freeN(event->customdata);
74         MEM_freeN(event);
75 }
76
77 void wm_event_free_all(wmWindow *win)
78 {
79         wmEvent *event;
80         
81         while((event= win->queue.first)) {
82                 BLI_remlink(&win->queue, event);
83                 wm_event_free(event);
84         }
85 }
86
87 /* ********************* handlers *************** */
88
89 void wm_event_free_handlers(ListBase *lb)
90 {
91         wmEventHandler *handler;
92         
93         for(handler= lb->first; handler; handler= handler->next) {
94                 if(handler->op)
95                         MEM_freeN(handler->op);
96         }
97         BLI_freelistN(lb);
98 }
99
100 static int wm_eventmatch(wmEvent *winevent, wmKeymapItem *km)
101 {
102         if(winevent->type!=km->type) return 0;
103         
104         if(km->val) /* KM_PRESS, KM_RELEASE */
105                 if(winevent->val!=km->val-1) return 0;
106         
107         if(winevent->shift!=km->shift) return 0;
108         if(winevent->ctrl!=km->ctrl) return 0;
109         if(winevent->alt!=km->alt) return 0;
110         if(winevent->oskey!=km->oskey) return 0;
111         if(winevent->keymodifier!=km->keymodifier) return 0;
112         
113         /* optional boundbox */
114         
115         return 1;
116 }
117
118 static int wm_handler_operator_call(bContext *C, wmEventHandler *handler, wmEvent *event)
119 {
120         int retval= 0;
121         
122         /* derived, modal or blocking operator */
123         if(handler->op) {
124                 if( handler->op->type->poll(C)) {
125                         if(handler->op->type->interactive)
126                                 retval= handler->op->type->interactive(C, handler->op, event);
127                         else
128                                 printf("wm_handler_operator_call error\n");
129                 }
130         }
131         else {
132                 wmOperatorType *ot= WM_operatortype_find(event->keymap_idname);
133                 if(ot) {
134                         if(ot->poll(C)) {
135                                 /* operator on stack, register or new modal handle malloc-copies */
136                                 wmOperator op;
137                                 
138                                 memset(&op, 0, sizeof(wmOperator));
139                                 op.type= ot;
140
141                                 if(op.type->interactive)
142                                         retval= op.type->interactive(C, &op, event);
143                                 else if(&op.type->exec)
144                                         retval= op.type->exec(C, &op);
145                                 
146                                 if( ot->flag & OPTYPE_REGISTER)
147                                         WM_operator_register(C->wm, &op);
148                         }
149                 }
150         }
151         if(retval)
152                 return WM_HANDLER_BREAK;
153         
154         return WM_HANDLER_CONTINUE;
155 }
156
157 static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
158 {
159         wmEventHandler *handler;
160         int action= WM_HANDLER_CONTINUE;
161         
162         if(handlers==NULL) return action;
163         
164         for(handler= handlers->first; handler; handler= handler->next) {
165                 if(handler->keymap) {
166                         wmKeymapItem *km;
167                         
168                         for(km= handler->keymap->first; km; km= km->next) {
169                                 if(wm_eventmatch(event, km)) {
170                                         
171                                         if(event->type!=MOUSEMOVE)
172                                                 printf("handle evt %d win %d op %s\n", event->type, C->window->winid, km->idname);
173                                         
174                                         event->keymap_idname= km->idname;       /* weak, but allows interactive callback to not use rawkey */
175                                         
176                                         action= wm_handler_operator_call(C, handler, event);
177                                 }
178                         }
179                         if(action==WM_HANDLER_BREAK)
180                                 break;
181                 }
182                 /* modal+blocking handler */
183                 if(handler->flag & WM_HANDLER_BLOCKING)
184                         action= WM_HANDLER_BREAK;
185         }
186         return action;
187 }
188
189 static int wm_event_inside_i(wmEvent *event, rcti *rect)
190 {
191         return BLI_in_rcti(rect, event->x, event->y);
192 }
193 //static int wm_event_inside_f(wmEvent *event, rctf *rect)
194 //{
195 //      return BLI_in_rctf(rect, (float)event->x, (float)event->y);
196 //}
197
198 /* called in main loop */
199 /* goes over entire hierarchy:  events -> window -> screen -> area -> region */
200 void wm_event_do_handlers(bContext *C)
201 {
202         wmWindow *win;
203         
204         for(win= C->wm->windows.first; win; win= win->next) {
205                 wmEvent *event;
206                 
207                 /* MVC demands to not draw in event handlers... for now we leave it */
208                 /* it also updates context (win, screen) */
209                 wm_window_make_drawable(C, win);
210                 
211                 if( C->screen==NULL )
212                         wm_event_free_all(C->window);
213                 
214                 while( (event=wm_event_next(C->window)) ) {
215                         int action= wm_handlers_do(C, event, &C->window->handlers);
216                         
217                         if(action==WM_HANDLER_CONTINUE)
218                                 action= wm_handlers_do(C, event, &C->screen->handlers);
219                         
220                         if(action==WM_HANDLER_CONTINUE) {
221                                 ScrArea *sa= C->screen->areabase.first;
222                                 
223                                 for(; sa; sa= sa->next) {
224                                         if(wm_event_inside_i(event, &sa->winrct)) {
225                                                 
226                                                 C->curarea= sa;
227                                                 action= wm_handlers_do(C, event, &sa->handlers);
228                                                 if(action==WM_HANDLER_CONTINUE) {
229                                                         ARegion *ar= sa->regionbase.first;
230                                                         
231                                                         for(; ar; ar= ar->next) {
232                                                                 if(wm_event_inside_i(event, &ar->winrct)) {
233                                                                         C->region= ar;
234                                                                         action= wm_handlers_do(C, event, &ar->handlers);
235                                                                         if(action==WM_HANDLER_BREAK)
236                                                                                 break;
237                                                                 }
238                                                         }
239                                                 }
240                                                 if(action==WM_HANDLER_BREAK)
241                                                         break;
242                                         }
243                                 }
244                         }
245                         wm_event_free(event);
246                 }
247         }
248 }
249
250 /* lets not expose struct outside wm? */
251 void WM_event_set_handler_flag(wmEventHandler *handler, int flag)
252 {
253         handler->flag= flag;
254 }
255
256 wmEventHandler *WM_event_add_modal_keymap_handler(ListBase *keymap, ListBase *handlers, wmOperator *op)
257 {
258         /* debug test; operator not in registry */
259         if(op->type->flag & OPTYPE_REGISTER) {
260                 printf("error: handler (%s) cannot be modal, was registered\n", op->type->idname);
261         }
262         else {
263                 wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event handler");
264                 wmOperator *opc= MEM_mallocN(sizeof(wmOperator), "operator modal");
265                 
266                 BLI_addtail(handlers, handler);
267                 handler->keymap= keymap;
268                 *opc= *op;
269                 handler->op= opc;
270                 
271                 return handler;
272         }
273         return NULL;
274 }
275
276 wmEventHandler *WM_event_add_keymap_handler(ListBase *keymap, ListBase *handlers)
277 {
278         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event handler");
279         
280         BLI_addtail(handlers, handler);
281         handler->keymap= keymap;
282         
283         return handler;
284 }
285
286 /* ********************* ghost stuff *************** */
287
288 static int convert_key(GHOST_TKey key) 
289 {
290         if (key>=GHOST_kKeyA && key<=GHOST_kKeyZ) {
291                 return (AKEY + ((int) key - GHOST_kKeyA));
292         } else if (key>=GHOST_kKey0 && key<=GHOST_kKey9) {
293                 return (ZEROKEY + ((int) key - GHOST_kKey0));
294         } else if (key>=GHOST_kKeyNumpad0 && key<=GHOST_kKeyNumpad9) {
295                 return (PAD0 + ((int) key - GHOST_kKeyNumpad0));
296         } else if (key>=GHOST_kKeyF1 && key<=GHOST_kKeyF12) {
297                 return (F1KEY + ((int) key - GHOST_kKeyF1));
298         } else {
299                 switch (key) {
300                         case GHOST_kKeyBackSpace:               return BACKSPACEKEY;
301                         case GHOST_kKeyTab:                             return TABKEY;
302                         case GHOST_kKeyLinefeed:                return LINEFEEDKEY;
303                         case GHOST_kKeyClear:                   return 0;
304                         case GHOST_kKeyEnter:                   return RETKEY;
305                                 
306                         case GHOST_kKeyEsc:                             return ESCKEY;
307                         case GHOST_kKeySpace:                   return SPACEKEY;
308                         case GHOST_kKeyQuote:                   return QUOTEKEY;
309                         case GHOST_kKeyComma:                   return COMMAKEY;
310                         case GHOST_kKeyMinus:                   return MINUSKEY;
311                         case GHOST_kKeyPeriod:                  return PERIODKEY;
312                         case GHOST_kKeySlash:                   return SLASHKEY;
313                                 
314                         case GHOST_kKeySemicolon:               return SEMICOLONKEY;
315                         case GHOST_kKeyEqual:                   return EQUALKEY;
316                                 
317                         case GHOST_kKeyLeftBracket:             return LEFTBRACKETKEY;
318                         case GHOST_kKeyRightBracket:    return RIGHTBRACKETKEY;
319                         case GHOST_kKeyBackslash:               return BACKSLASHKEY;
320                         case GHOST_kKeyAccentGrave:             return ACCENTGRAVEKEY;
321                                 
322                         case GHOST_kKeyLeftShift:               return LEFTSHIFTKEY;
323                         case GHOST_kKeyRightShift:              return RIGHTSHIFTKEY;
324                         case GHOST_kKeyLeftControl:             return LEFTCTRLKEY;
325                         case GHOST_kKeyRightControl:    return RIGHTCTRLKEY;
326                         case GHOST_kKeyCommand:                 return COMMANDKEY;
327                         case GHOST_kKeyLeftAlt:                 return LEFTALTKEY;
328                         case GHOST_kKeyRightAlt:                return RIGHTALTKEY;
329                                 
330                         case GHOST_kKeyCapsLock:                return CAPSLOCKKEY;
331                         case GHOST_kKeyNumLock:                 return 0;
332                         case GHOST_kKeyScrollLock:              return 0;
333                                 
334                         case GHOST_kKeyLeftArrow:               return LEFTARROWKEY;
335                         case GHOST_kKeyRightArrow:              return RIGHTARROWKEY;
336                         case GHOST_kKeyUpArrow:                 return UPARROWKEY;
337                         case GHOST_kKeyDownArrow:               return DOWNARROWKEY;
338                                 
339                         case GHOST_kKeyPrintScreen:             return 0;
340                         case GHOST_kKeyPause:                   return PAUSEKEY;
341                                 
342                         case GHOST_kKeyInsert:                  return INSERTKEY;
343                         case GHOST_kKeyDelete:                  return DELKEY;
344                         case GHOST_kKeyHome:                    return HOMEKEY;
345                         case GHOST_kKeyEnd:                             return ENDKEY;
346                         case GHOST_kKeyUpPage:                  return PAGEUPKEY;
347                         case GHOST_kKeyDownPage:                return PAGEDOWNKEY;
348                                 
349                         case GHOST_kKeyNumpadPeriod:    return PADPERIOD;
350                         case GHOST_kKeyNumpadEnter:             return PADENTER;
351                         case GHOST_kKeyNumpadPlus:              return PADPLUSKEY;
352                         case GHOST_kKeyNumpadMinus:             return PADMINUS;
353                         case GHOST_kKeyNumpadAsterisk:  return PADASTERKEY;
354                         case GHOST_kKeyNumpadSlash:             return PADSLASHKEY;
355                                 
356                         case GHOST_kKeyGrLess:              return GRLESSKEY; 
357                                 
358                         default:
359                                 return UNKNOWNKEY;      /* GHOST_kKeyUnknown */
360                 }
361         }
362 }
363
364 /* adds customdata to event */
365 static void update_tablet_data(wmWindow *win, wmEvent *event)
366 {
367         const GHOST_TabletData *td= GHOST_GetTabletData(win->ghostwin);
368         
369         /* if there's tablet data from an active tablet device then add it */
370         if ((td != NULL) && td->Active) {
371                 struct wmTabletData *wmtab= MEM_mallocN(sizeof(wmTabletData), "customdata tablet");
372                 
373                 wmtab->Active = td->Active;
374                 wmtab->Pressure = td->Pressure;
375                 wmtab->Xtilt = td->Xtilt;
376                 wmtab->Ytilt = td->Ytilt;
377                 
378                 event->custom= EVT_TABLET;
379                 event->customdata= wmtab;
380         } 
381 }
382
383
384 /* windows store own event queues, no bContext here */
385 void wm_event_add_ghostevent(wmWindow *win, int type, void *customdata)
386 {
387         wmEvent event, *evt= win->eventstate;
388         
389         /* initialize and copy state (only mouse x y and modifiers) */
390         event= *evt;
391         
392         switch (type) {
393                 /* mouse move */
394                 case GHOST_kEventCursorMove: {
395                         if(win->active) {
396                                 GHOST_TEventCursorData *cd= customdata;
397                                 int cx, cy;
398                                 
399                                 GHOST_ScreenToClient(win->ghostwin, cd->x, cd->y, &cx, &cy);
400                                 
401                                 event.type= MOUSEMOVE;
402                                 event.x= evt->x= cx;
403                                 event.y= evt->y= (win->sizey-1) - cy;
404                                 
405                                 update_tablet_data(win, &event);
406                                 wm_event_add(win, &event);
407                         }
408                         break;
409                 }
410                 /* mouse button */
411                 case GHOST_kEventButtonDown:
412                 case GHOST_kEventButtonUp: {
413                         GHOST_TEventButtonData *bd= customdata;
414                         event.val= (type==GHOST_kEventButtonDown);
415                         
416                         if (bd->button == GHOST_kButtonMaskLeft)
417                                 event.type= LEFTMOUSE;
418                         else if (bd->button == GHOST_kButtonMaskRight)
419                                 event.type= RIGHTMOUSE;
420                         else
421                                 event.type= MIDDLEMOUSE;
422                         
423                         update_tablet_data(win, &event);
424                         wm_event_add(win, &event);
425                         
426                         break;
427                 }
428                 /* keyboard */
429                 case GHOST_kEventKeyDown:
430                 case GHOST_kEventKeyUp: {
431                         GHOST_TEventKeyData *kd= customdata;
432                         event.type= convert_key(kd->key);
433                         event.ascii= kd->ascii;
434                         event.val= (type==GHOST_kEventKeyDown);
435                         
436                         /* modifiers */
437                         if (event.type==LEFTSHIFTKEY || event.type==RIGHTSHIFTKEY) {
438                                 event.shift= evt->shift= event.val;
439                         } else if (event.type==LEFTCTRLKEY || event.type==RIGHTCTRLKEY) {
440                                 event.ctrl= evt->ctrl= event.val;
441                         } else if (event.type==LEFTALTKEY || event.type==RIGHTALTKEY) {
442                                 event.alt= evt->alt= event.val;
443                         } else if (event.type==COMMANDKEY) {
444                                 event.oskey= evt->oskey= event.val;
445                         }
446                         
447                         wm_event_add(win, &event);
448                         
449                         break;
450                 }
451                         
452                 case GHOST_kEventWheel: {
453                         GHOST_TEventWheelData* wheelData = customdata;
454                         
455                         if (wheelData->z > 0)
456                                 event.type= WHEELUPMOUSE;
457                         else
458                                 event.type= WHEELDOWNMOUSE;
459                         
460                         event.val= wheelData->z;        /* currently -1 or +1, see ghost for improvements here... */
461                         wm_event_add(win, &event);
462                         
463                         break;
464                 }
465                 case GHOST_kEventUnknown:
466                 case GHOST_kNumEventTypes:
467                         break;
468         }
469 }
470