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