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