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