2.5
[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 "RNA_access.h"
50
51 #include "WM_api.h"
52 #include "WM_types.h"
53 #include "wm.h"
54 #include "wm_window.h"
55 #include "wm_event_system.h"
56 #include "wm_event_types.h"
57
58 /* ************ event management ************** */
59
60 void wm_event_add(wmWindow *win, wmEvent *event_to_add)
61 {
62         wmEvent *event= MEM_callocN(sizeof(wmEvent), "event");
63         
64         *event= *event_to_add;
65         BLI_addtail(&win->queue, event);
66 }
67
68 wmEvent *wm_event_next(wmWindow *win)
69 {
70         wmEvent *event= win->queue.first;
71
72         if(event) BLI_remlink(&win->queue, event);
73         return event;
74 }
75
76 static void wm_event_free(wmEvent *event)
77 {
78         if(event->customdata && event->customdatafree)
79                 MEM_freeN(event->customdata);
80         MEM_freeN(event);
81 }
82
83 void wm_event_free_all(wmWindow *win)
84 {
85         wmEvent *event;
86         
87         while((event= win->queue.first)) {
88                 BLI_remlink(&win->queue, event);
89                 wm_event_free(event);
90         }
91 }
92
93 /* ********************* notifiers, listeners *************** */
94
95 /* XXX: in future, which notifiers to send to other windows? */
96 void WM_event_add_notifier(bContext *C, int type, int value, void *data)
97 {
98         wmNotifier *note= MEM_callocN(sizeof(wmNotifier), "notifier");
99         
100         BLI_addtail(&C->wm->queue, note);
101         
102         note->window= C->window;
103
104         /* catch global notifications here */
105         switch (type) {
106                 case WM_NOTE_WINDOW_REDRAW:
107                 case WM_NOTE_SCREEN_CHANGED:
108                         break;
109                 default:
110                         if(C->region) note->swinid= C->region->swinid;
111         }
112         
113         note->type= type;
114         note->value= value;
115         note->data= data;
116 }
117
118 static wmNotifier *wm_notifier_next(wmWindowManager *wm)
119 {
120         wmNotifier *note= wm->queue.first;
121         
122         if(note) BLI_remlink(&wm->queue, note);
123         return note;
124 }
125
126 /* called in mainloop */
127 void wm_event_do_notifiers(bContext *C)
128 {
129         wmNotifier *note;
130         
131         while( (note=wm_notifier_next(C->wm)) ) {
132                 wmWindow *win;
133                 
134                 for(win= C->wm->windows.first; win; win= win->next) {
135                         ScrArea *sa;
136                         ARegion *ar;
137
138                         C->window= win;
139                         C->screen= win->screen;
140                         
141                         if(note->window && note->window!=win)
142                                 continue;
143                         if(win->screen==NULL)
144                                 continue;
145
146                         /* printf("notifier win %d screen %s\n", win->winid, win->screen->id.name+2); */
147                         ED_screen_do_listen(win, note);
148
149                         for(ar=win->screen->regionbase.first; ar; ar= ar->next) {
150                                 if(note->swinid && note->swinid!=ar->swinid)
151                                         continue;
152
153                                 C->region= ar;
154                                 ED_region_do_listen(ar, note);
155                                 C->region= NULL;
156                         }
157                         
158                         for(sa= win->screen->areabase.first; sa; sa= sa->next) {
159                                 C->area= sa;
160
161                                 for(ar=sa->regionbase.first; ar; ar= ar->next) {
162                                         if(note->swinid && note->swinid!=ar->swinid)
163                                                 continue;
164
165                                         C->region= ar;
166                                         ED_region_do_listen(ar, note);
167                                         C->region= NULL;
168                                 }
169
170                                 C->area= NULL;
171                         }
172
173                         C->window= NULL;
174                         C->screen= NULL;
175                 }
176                 if(note->data)
177                         MEM_freeN(note->data);
178                 MEM_freeN(note);
179         }       
180 }
181
182 /* quick test to prevent changing window drawable */
183 static int wm_draw_update_test_window(wmWindow *win)
184 {
185         ScrArea *sa;
186         ARegion *ar;
187         
188         if(win->screen->do_refresh)
189                 return 1;
190         if(win->screen->do_draw)
191                 return 1;
192         if(win->screen->do_gesture)
193                 return 1;
194
195         for(ar=win->screen->regionbase.first; ar; ar= ar->next) {
196                 /* cached notifiers */
197                 if(ar->do_refresh)
198                         return 1;
199                 if(ar->swinid && ar->do_draw)
200                         return 1;
201         }
202
203         for(sa= win->screen->areabase.first; sa; sa= sa->next) {
204                 for(ar=sa->regionbase.first; ar; ar= ar->next) {
205                         /* cached notifiers */
206                         if(ar->do_refresh)
207                                 return 1;
208                         if(ar->swinid && ar->do_draw)
209                                 return 1;
210                 }
211         }
212         return 0;
213 }
214
215 void wm_draw_update(bContext *C)
216 {
217         wmWindow *win;
218         
219         for(win= C->wm->windows.first; win; win= win->next) {
220                 if(wm_draw_update_test_window(win)) {
221                         ScrArea *sa;
222                         ARegion *ar;
223
224                         C->window= win;
225                         C->screen= win->screen;
226                         
227                         /* sets context window+screen */
228                         wm_window_make_drawable(C, win);
229                         
230                         /* notifiers for screen redraw */
231                         if(win->screen->do_refresh)
232                                 ED_screen_refresh(C->wm, win);
233
234                         for(sa= win->screen->areabase.first; sa; sa= sa->next) {
235                                 int area_do_draw= 0;
236                                 
237                                 C->area= sa;
238                                 
239                                 for(ar=sa->regionbase.first; ar; ar= ar->next) {
240                                         C->region= ar;
241                                         
242                                         /* cached notifiers */
243                                         if(ar->do_refresh)
244                                                 ED_region_do_refresh(C, ar);
245                                         
246                                         if(ar->swinid && ar->do_draw) {
247                                                 ED_region_do_draw(C, ar);
248                                                 area_do_draw= 1;
249                                         }
250                                         
251                                         C->region= NULL;
252                                 }
253                                 /* only internal decoration, like AZone */
254                                 if(area_do_draw)
255                                         ED_area_do_draw(C, sa);
256                                 
257                                 C->area = NULL;
258                         }
259                         
260                         /* move this here so we can do area 'overlay' drawing */
261                         if(win->screen->do_draw)
262                                 ED_screen_draw(win);
263
264                         /* regions are menus here */
265                         for(ar=win->screen->regionbase.first; ar; ar= ar->next) {
266                                 C->region= ar;
267                                 
268                                 /* cached notifiers */
269                                 if(ar->do_refresh)
270                                         ED_region_do_refresh(C, ar);
271                                 
272                                 if(ar->swinid && ar->do_draw)
273                                         ED_region_do_draw(C, ar);
274
275                                 C->region= NULL;
276                         }
277                         
278                         if(win->screen->do_gesture)
279                                 wm_gesture_draw(win);
280
281                         wm_window_swap_buffers(win);
282
283                         C->window= NULL;
284                         C->screen= NULL;
285                 }
286         }
287 }
288
289 /* ********************* operators ******************* */
290
291
292 int WM_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event)
293 {
294         int retval= OPERATOR_PASS_THROUGH;
295
296         if(ot->poll==NULL || ot->poll(C)) {
297                 wmOperator *op= MEM_callocN(sizeof(wmOperator), "wmOperator");
298
299                 /* XXX adding new operator could be function, only happens here now */
300                 op->type= ot;
301                 BLI_strncpy(op->idname, ot->idname, OP_MAX_TYPENAME);
302                 
303                 op->ptr= MEM_callocN(sizeof(PointerRNA), "wmOperatorPtrRNA");
304                 RNA_pointer_create(&RNA_WindowManager, &C->wm->id, ot->srna, op, op->ptr);
305
306                 if(op->type->invoke)
307                         retval= (*op->type->invoke)(C, op, event);
308                 else if(op->type->exec)
309                         retval= op->type->exec(C, op);
310
311                 if((retval & OPERATOR_FINISHED) && (ot->flag & OPTYPE_REGISTER)) {
312                         wm_operator_register(C->wm, op);
313                         handler->op= NULL;
314                 }
315                 else if(!(retval & OPERATOR_RUNNING_MODAL)) {
316                         wm_operator_free(op);
317                         handler->op= NULL;
318                 }
319         }
320
321         return retval;
322 }
323
324 /* ********************* handlers *************** */
325
326
327 /* not handler itself, is called by UI to move handlers to other queues, so don't close modal ones */
328 static void wm_event_free_handler(wmEventHandler *handler)
329 {
330         
331 }
332
333 /* called on exit or remove area, only here call cancel callback */
334 void WM_event_remove_handlers(bContext *C, ListBase *handlers)
335 {
336         wmEventHandler *handler;
337         
338         /* C is zero on freeing database, modal handlers then already were freed */
339         while((handler=handlers->first)) {
340                 BLI_remlink(handlers, handler);
341                 
342                 if(C && handler->op) {
343                         if(handler->op->type->cancel)
344                                 handler->op->type->cancel(C, handler->op);
345                         wm_operator_free(handler->op);
346                 }
347                 wm_event_free_handler(handler);
348                 MEM_freeN(handler);
349         }
350 }
351
352 static int wm_eventmatch(wmEvent *winevent, wmKeymapItem *kmi)
353 {
354         
355         if(winevent->type!=kmi->type) return 0;
356         
357         if(kmi->val!=KM_ANY)
358                 if(winevent->val!=kmi->val) return 0;
359         
360         if(winevent->shift!=kmi->shift) return 0;
361         if(winevent->ctrl!=kmi->ctrl) return 0;
362         if(winevent->alt!=kmi->alt) return 0;
363         if(winevent->oskey!=kmi->oskey) return 0;
364         if(kmi->keymodifier)
365                 if(winevent->keymodifier!=kmi->keymodifier) return 0;
366         
367         /* optional boundbox */
368         
369         return 1;
370 }
371
372 /* Warning: this function removes a modal handler, when finished */
373 static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHandler *handler, wmEvent *event)
374 {
375         int retval= OPERATOR_PASS_THROUGH;
376         
377         /* derived, modal or blocking operator */
378         if(handler->op) {
379                 wmOperator *op= handler->op;
380                 wmOperatorType *ot= op->type;
381
382                 if(ot->modal) {
383                         /* we set context to where modal handler came from */
384                         ScrArea *area= C->area;
385                         ARegion *region= C->region;
386                         
387                         C->area= handler->op_area;
388                         C->region= handler->op_region;
389                         
390                         retval= ot->modal(C, op, event);
391
392                         /* putting back screen context */
393                         C->area= area;
394                         C->region= region;
395                         
396                         if((retval & OPERATOR_FINISHED) && (ot->flag & OPTYPE_REGISTER)) {
397                                 wm_operator_register(C->wm, op);
398                                 handler->op= NULL;
399                         }
400                         else if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) {
401                                 wm_operator_free(op);
402                                 handler->op= NULL;
403                         }
404                         
405                         
406                         /* remove modal handler, operator itself should have been cancelled and freed */
407                         if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) {
408                                 BLI_remlink(handlers, handler);
409                                 wm_event_free_handler(handler);
410                                 MEM_freeN(handler);
411                                 
412                                 /* prevent silly errors from operator users */
413                                 retval &= ~OPERATOR_PASS_THROUGH;
414                         }
415                         
416                 }
417                 else
418                         printf("wm_handler_operator_call error\n");
419         }
420         else {
421                 wmOperatorType *ot= WM_operatortype_find(event->keymap_idname);
422
423                 if(ot)
424                         retval= WM_operator_invoke(C, ot, event);
425         }
426
427         if(retval & OPERATOR_PASS_THROUGH)
428                 return WM_HANDLER_CONTINUE;
429
430         return WM_HANDLER_BREAK;
431 }
432
433 static int wm_event_always_pass(wmEvent *event)
434 {
435         /* some events we always pass on, to ensure proper communication */
436         return (event->type == TIMER || event->type == MESSAGE);
437 }
438
439 static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
440 {
441         wmEventHandler *handler, *nexthandler;
442         int action= WM_HANDLER_CONTINUE;
443
444         if(handlers==NULL) return action;
445         
446         /* modal handlers can get removed in this loop, we keep the loop this way */
447         for(handler= handlers->first; handler; handler= nexthandler) {
448                 nexthandler= handler->next;
449
450                 /* modal+blocking handler */
451                 if(handler->flag & WM_HANDLER_BLOCKING)
452                         action= WM_HANDLER_BREAK;
453
454                 if(handler->keymap) {
455                         wmKeymapItem *kmi;
456                         
457                         for(kmi= handler->keymap->first; kmi; kmi= kmi->next) {
458                                 if(wm_eventmatch(event, kmi)) {
459                                         /* if(event->type!=MOUSEMOVE)
460                                                 printf("handle evt %d win %d op %s\n", event->type, C->window->winid, kmi->idname); */
461                                         
462                                         event->keymap_idname= kmi->idname;      /* weak, but allows interactive callback to not use rawkey */
463                                         
464                                         action= wm_handler_operator_call(C, handlers, handler, event);
465                                         if(action==WM_HANDLER_BREAK)  /* not wm_event_always_pass(event) here, it denotes removed handler */
466                                                 break;
467                                 }
468                         }
469                 }
470                 else {
471                         /* modal, swallows all */
472                         action= wm_handler_operator_call(C, handlers, handler, event);
473                 }
474
475                 if(!wm_event_always_pass(event) && action==WM_HANDLER_BREAK)
476                         break;
477                 
478         }
479         return action;
480 }
481
482 static int wm_event_inside_i(wmEvent *event, rcti *rect)
483 {
484         return BLI_in_rcti(rect, event->x, event->y);
485 }
486
487 static int wm_event_prev_inside_i(wmEvent *event, rcti *rect)
488 {
489         if(BLI_in_rcti(rect, event->x, event->y))
490            return 1;
491         if(event->type==MOUSEMOVE) {
492                 if( BLI_in_rcti(rect, event->prevx, event->prevy)) {
493                         return 1;
494                 }
495                 return 0;
496         }
497         return 0;
498 }
499
500 static ScrArea *area_event_inside(bContext *C, wmEvent *event)
501 {
502         ScrArea *sa;
503         
504         if(C->screen)
505                 for(sa= C->screen->areabase.first; sa; sa= sa->next)
506                         if(BLI_in_rcti(&sa->totrct, event->x, event->y))
507                                 return sa;
508         return NULL;
509 }
510
511 static ARegion *region_event_inside(bContext *C, wmEvent *event)
512 {
513         ARegion *ar;
514         
515         if(C->screen && C->area)
516                 for(ar= C->area->regionbase.first; ar; ar= ar->next)
517                         if(BLI_in_rcti(&ar->winrct, event->x, event->y))
518                                 return ar;
519         return NULL;
520 }
521
522
523 /* called in main loop */
524 /* goes over entire hierarchy:  events -> window -> screen -> area -> region */
525 void wm_event_do_handlers(bContext *C)
526 {
527         wmWindow *win;
528
529         for(win= C->wm->windows.first; win; win= win->next) {
530                 wmEvent *event;
531                 
532                 if( win->screen==NULL )
533                         wm_event_free_all(win);
534                 
535                 while( (event=wm_event_next(win)) ) {
536                         int action;
537
538                         C->window= win;
539                         C->screen= win->screen;
540                         C->area= area_event_inside(C, event);
541                         C->region= region_event_inside(C, event);
542                         
543                         /* MVC demands to not draw in event handlers... for now we leave it */
544                         wm_window_make_drawable(C, win);
545                                 
546                         action= wm_handlers_do(C, event, &win->handlers);
547                         
548                         /* modal menus in Blender use (own) regions linked to screen */
549                         if(wm_event_always_pass(event) || action==WM_HANDLER_CONTINUE) {
550                                 ARegion *ar;
551
552                                 /* region are in drawing order, i.e. frontmost region last so
553                                  * we handle events in the opposite order last to first */
554                                 for(ar=win->screen->regionbase.last; ar; ar= ar->prev) {
555                                         if(wm_event_always_pass(event) || wm_event_inside_i(event, &ar->winrct)) {
556                                                 C->region= ar;
557                                                 wm_handlers_do(C, event, &ar->handlers);
558                                                 C->region= NULL;
559
560                                                 if(!wm_event_always_pass(event)) {
561                                                         action= WM_HANDLER_BREAK;
562                                                         break;
563                                                 }
564                                         }
565                                 }
566                         }
567         
568                         if(wm_event_always_pass(event) || action==WM_HANDLER_CONTINUE) {
569                                 ScrArea *sa;
570                                 ARegion *ar;
571                                 int doit= 0;
572
573                                 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
574                                         if(wm_event_always_pass(event) || wm_event_prev_inside_i(event, &sa->totrct)) {
575                                                 doit= 1;
576                                                 C->area= sa;
577                                                 action= wm_handlers_do(C, event, &sa->handlers);
578
579                                                 if(wm_event_always_pass(event) || action==WM_HANDLER_CONTINUE) {
580                                                         for(ar=sa->regionbase.first; ar; ar= ar->next) {
581                                                                 if(wm_event_always_pass(event) || wm_event_inside_i(event, &ar->winrct)) {
582                                                                         C->region= ar;
583                                                                         action= wm_handlers_do(C, event, &ar->handlers);
584                                                                         C->region= NULL;
585
586                                                                         if(!wm_event_always_pass(event)) {
587                                                                                 if(action==WM_HANDLER_BREAK)
588                                                                                         break;
589                                                                         }
590                                                                 }
591                                                         }
592                                                 }
593
594                                                 C->area= NULL;
595                                                 /* NOTE: do not escape on WM_HANDLER_BREAK, mousemove needs handled for previous area */
596                                         }
597                                 }
598                                 /* XXX hrmf, this gives reliable previous mouse coord for area change, feels bad? 
599                                    doing it on ghost queue gives errors when mousemoves go over area borders */
600                                 if(doit) {
601                                         C->window->eventstate->prevx= event->x;
602                                         C->window->eventstate->prevy= event->y;
603                                 }
604                         }
605                         wm_event_free(event);
606                         
607                         C->window= NULL;
608                         C->screen= NULL;
609                 }
610         }
611 }
612
613 /* lets not expose struct outside wm? */
614 void WM_event_set_handler_flag(wmEventHandler *handler, int flag)
615 {
616         handler->flag= flag;
617 }
618
619 wmEventHandler *WM_event_add_modal_handler(bContext *C, ListBase *handlers, wmOperator *op)
620 {
621         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event handler");
622         handler->op= op;
623         handler->op_area= C->area;              /* means frozen screen context for modal handlers! */
624         handler->op_region= C->region;
625         
626         BLI_addhead(handlers, handler);
627         
628         return handler;
629 }
630
631 wmEventHandler *WM_event_add_keymap_handler(ListBase *handlers, ListBase *keymap)
632 {
633         wmEventHandler *handler;
634         
635         /* only allow same keymap once */
636         for(handler= handlers->first; handler; handler= handler->next)
637                 if(handler->keymap==keymap)
638                         return handler;
639
640         handler= MEM_callocN(sizeof(wmEventHandler), "event handler");
641         BLI_addtail(handlers, handler);
642         handler->keymap= keymap;
643
644         return handler;
645 }
646
647 void WM_event_remove_keymap_handler(ListBase *handlers, ListBase *keymap)
648 {
649         wmEventHandler *handler;
650         
651         for(handler= handlers->first; handler; handler= handler->next) {
652                 if(handler->keymap==keymap) {
653                         BLI_remlink(handlers, handler);
654                         wm_event_free_handler(handler);
655                         MEM_freeN(handler);
656                         break;
657                 }
658         }
659 }
660
661 void WM_event_add_message(wmWindowManager *wm, void *customdata, short customdatafree)
662 {
663         wmEvent event;
664         wmWindow *win;
665
666         for(win=wm->windows.first; win; win=win->next) {
667                 event= *(win->eventstate);
668
669                 event.type= MESSAGE;
670                 if(customdata) {
671                         event.custom= EVT_DATA_MESSAGE;
672                         event.customdata= customdata;
673                         event.customdatafree= customdatafree;
674                 }
675                 wm_event_add(win, &event);
676         }
677 }
678
679 void WM_event_add_mousemove(bContext *C)
680 {
681         wmEvent event= *(C->window->eventstate);
682         event.type= MOUSEMOVE;
683         wm_event_add(C->window, &event);
684         
685 }
686
687 /* ********************* ghost stuff *************** */
688
689 static int convert_key(GHOST_TKey key) 
690 {
691         if (key>=GHOST_kKeyA && key<=GHOST_kKeyZ) {
692                 return (AKEY + ((int) key - GHOST_kKeyA));
693         } else if (key>=GHOST_kKey0 && key<=GHOST_kKey9) {
694                 return (ZEROKEY + ((int) key - GHOST_kKey0));
695         } else if (key>=GHOST_kKeyNumpad0 && key<=GHOST_kKeyNumpad9) {
696                 return (PAD0 + ((int) key - GHOST_kKeyNumpad0));
697         } else if (key>=GHOST_kKeyF1 && key<=GHOST_kKeyF12) {
698                 return (F1KEY + ((int) key - GHOST_kKeyF1));
699         } else {
700                 switch (key) {
701                         case GHOST_kKeyBackSpace:               return BACKSPACEKEY;
702                         case GHOST_kKeyTab:                             return TABKEY;
703                         case GHOST_kKeyLinefeed:                return LINEFEEDKEY;
704                         case GHOST_kKeyClear:                   return 0;
705                         case GHOST_kKeyEnter:                   return RETKEY;
706                                 
707                         case GHOST_kKeyEsc:                             return ESCKEY;
708                         case GHOST_kKeySpace:                   return SPACEKEY;
709                         case GHOST_kKeyQuote:                   return QUOTEKEY;
710                         case GHOST_kKeyComma:                   return COMMAKEY;
711                         case GHOST_kKeyMinus:                   return MINUSKEY;
712                         case GHOST_kKeyPeriod:                  return PERIODKEY;
713                         case GHOST_kKeySlash:                   return SLASHKEY;
714                                 
715                         case GHOST_kKeySemicolon:               return SEMICOLONKEY;
716                         case GHOST_kKeyEqual:                   return EQUALKEY;
717                                 
718                         case GHOST_kKeyLeftBracket:             return LEFTBRACKETKEY;
719                         case GHOST_kKeyRightBracket:    return RIGHTBRACKETKEY;
720                         case GHOST_kKeyBackslash:               return BACKSLASHKEY;
721                         case GHOST_kKeyAccentGrave:             return ACCENTGRAVEKEY;
722                                 
723                         case GHOST_kKeyLeftShift:               return LEFTSHIFTKEY;
724                         case GHOST_kKeyRightShift:              return RIGHTSHIFTKEY;
725                         case GHOST_kKeyLeftControl:             return LEFTCTRLKEY;
726                         case GHOST_kKeyRightControl:    return RIGHTCTRLKEY;
727                         case GHOST_kKeyCommand:                 return COMMANDKEY;
728                         case GHOST_kKeyLeftAlt:                 return LEFTALTKEY;
729                         case GHOST_kKeyRightAlt:                return RIGHTALTKEY;
730                                 
731                         case GHOST_kKeyCapsLock:                return CAPSLOCKKEY;
732                         case GHOST_kKeyNumLock:                 return 0;
733                         case GHOST_kKeyScrollLock:              return 0;
734                                 
735                         case GHOST_kKeyLeftArrow:               return LEFTARROWKEY;
736                         case GHOST_kKeyRightArrow:              return RIGHTARROWKEY;
737                         case GHOST_kKeyUpArrow:                 return UPARROWKEY;
738                         case GHOST_kKeyDownArrow:               return DOWNARROWKEY;
739                                 
740                         case GHOST_kKeyPrintScreen:             return 0;
741                         case GHOST_kKeyPause:                   return PAUSEKEY;
742                                 
743                         case GHOST_kKeyInsert:                  return INSERTKEY;
744                         case GHOST_kKeyDelete:                  return DELKEY;
745                         case GHOST_kKeyHome:                    return HOMEKEY;
746                         case GHOST_kKeyEnd:                             return ENDKEY;
747                         case GHOST_kKeyUpPage:                  return PAGEUPKEY;
748                         case GHOST_kKeyDownPage:                return PAGEDOWNKEY;
749                                 
750                         case GHOST_kKeyNumpadPeriod:    return PADPERIOD;
751                         case GHOST_kKeyNumpadEnter:             return PADENTER;
752                         case GHOST_kKeyNumpadPlus:              return PADPLUSKEY;
753                         case GHOST_kKeyNumpadMinus:             return PADMINUS;
754                         case GHOST_kKeyNumpadAsterisk:  return PADASTERKEY;
755                         case GHOST_kKeyNumpadSlash:             return PADSLASHKEY;
756                                 
757                         case GHOST_kKeyGrLess:              return GRLESSKEY; 
758                                 
759                         default:
760                                 return UNKNOWNKEY;      /* GHOST_kKeyUnknown */
761                 }
762         }
763 }
764
765 /* adds customdata to event */
766 static void update_tablet_data(wmWindow *win, wmEvent *event)
767 {
768         const GHOST_TabletData *td= GHOST_GetTabletData(win->ghostwin);
769         
770         /* if there's tablet data from an active tablet device then add it */
771         if ((td != NULL) && td->Active) {
772                 struct wmTabletData *wmtab= MEM_mallocN(sizeof(wmTabletData), "customdata tablet");
773                 
774                 wmtab->Active = td->Active;
775                 wmtab->Pressure = td->Pressure;
776                 wmtab->Xtilt = td->Xtilt;
777                 wmtab->Ytilt = td->Ytilt;
778                 
779                 event->custom= EVT_DATA_TABLET;
780                 event->customdata= wmtab;
781                 event->customdatafree= 1;
782         } 
783 }
784
785
786 /* windows store own event queues, no bContext here */
787 void wm_event_add_ghostevent(wmWindow *win, int type, void *customdata)
788 {
789         wmEvent event, *evt= win->eventstate;
790         
791         /* initialize and copy state (only mouse x y and modifiers) */
792         event= *evt;
793         
794         switch (type) {
795                 /* mouse move */
796                 case GHOST_kEventCursorMove: {
797                         if(win->active) {
798                                 GHOST_TEventCursorData *cd= customdata;
799                                 int cx, cy;
800
801                                 GHOST_ScreenToClient(win->ghostwin, cd->x, cd->y, &cx, &cy);
802                                 
803                                 event.type= MOUSEMOVE;
804                                 event.x= evt->x= cx;
805                                 event.y= evt->y= (win->sizey-1) - cy;
806                                 
807                                 ED_screen_set_subwinactive(win);        /* state variables in screen */
808                                 
809                                 update_tablet_data(win, &event);
810                                 wm_event_add(win, &event);
811                         }
812                         break;
813                 }
814                 /* mouse button */
815                 case GHOST_kEventButtonDown:
816                 case GHOST_kEventButtonUp: {
817                         GHOST_TEventButtonData *bd= customdata;
818                         event.val= (type==GHOST_kEventButtonDown);
819                         
820                         if (bd->button == GHOST_kButtonMaskLeft)
821                                 event.type= LEFTMOUSE;
822                         else if (bd->button == GHOST_kButtonMaskRight)
823                                 event.type= RIGHTMOUSE;
824                         else
825                                 event.type= MIDDLEMOUSE;
826                         
827                         if(event.val)
828                                 event.keymodifier= evt->keymodifier= event.type;
829                         else
830                                 event.keymodifier= evt->keymodifier= 0;
831                         
832                         update_tablet_data(win, &event);
833                         wm_event_add(win, &event);
834                         
835                         break;
836                 }
837                 /* keyboard */
838                 case GHOST_kEventKeyDown:
839                 case GHOST_kEventKeyUp: {
840                         GHOST_TEventKeyData *kd= customdata;
841                         event.type= convert_key(kd->key);
842                         event.ascii= kd->ascii;
843                         event.val= (type==GHOST_kEventKeyDown); /* XXX eventmatch uses defines, bad code... */
844                         
845                         /* modifiers */
846                         if (event.type==LEFTSHIFTKEY || event.type==RIGHTSHIFTKEY) {
847                                 event.shift= evt->shift= event.val;
848                         } else if (event.type==LEFTCTRLKEY || event.type==RIGHTCTRLKEY) {
849                                 event.ctrl= evt->ctrl= event.val;
850                         } else if (event.type==LEFTALTKEY || event.type==RIGHTALTKEY) {
851                                 event.alt= evt->alt= event.val;
852                         } else if (event.type==COMMANDKEY) {
853                                 event.oskey= evt->oskey= event.val;
854                         }
855                         
856                         wm_event_add(win, &event);
857                         
858                         break;
859                 }
860                         
861                 case GHOST_kEventWheel: {
862                         GHOST_TEventWheelData* wheelData = customdata;
863                         
864                         if (wheelData->z > 0)
865                                 event.type= WHEELUPMOUSE;
866                         else
867                                 event.type= WHEELDOWNMOUSE;
868                         
869                         event.val= wheelData->z;        /* currently -1 or +1, see ghost for improvements here... */
870                         wm_event_add(win, &event);
871                         
872                         break;
873                 }
874                 case GHOST_kEventTimer: {
875                         event.type= TIMER;
876                         event.custom= EVT_DATA_TIMER;
877                         event.customdata= customdata;
878                         wm_event_add(win, &event);
879
880                         break;
881                 }
882
883                 case GHOST_kEventUnknown:
884                 case GHOST_kNumEventTypes:
885                         break;
886         }
887 }
888