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