96a97e95bd7b2432f7e5dedcc9a77d62e55296d3
[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, IDProperty *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                 if(properties)
367                         op->properties= IDP_CopyProperty(properties);
368
369                 /* XXX adding new operator could be function, only happens here now */
370                 op->type= ot;
371                 BLI_strncpy(op->idname, ot->idname, OP_MAX_TYPENAME);
372                 
373                 op->ptr= MEM_callocN(sizeof(PointerRNA), "wmOperatorPtrRNA");
374                 RNA_pointer_create(&RNA_WindowManager, &wm->id, ot->srna, &op->properties, op->ptr);
375
376                 op->reports= MEM_callocN(sizeof(ReportList), "wmOperatorReportList");
377                 BKE_reports_init(op->reports, RPT_STORE);
378
379                 if(op->type->invoke && event)
380                         retval= (*op->type->invoke)(C, op, event);
381                 else if(op->type->exec)
382                         retval= op->type->exec(C, op);
383                 else
384                         printf("invalid operator call %s\n", ot->idname); /* debug, important to leave a while, should never happen */
385
386                 if(G.f & G_DEBUG)
387                         WM_operator_print(op);
388
389                 if(!(retval & OPERATOR_RUNNING_MODAL))
390                         if(op->reports->list.first)
391                                 uiPupmenuReports(C, op->reports);
392
393                 if((retval & OPERATOR_FINISHED) && (ot->flag & OPTYPE_REGISTER)) {
394                         wm_operator_register(wm, op);
395                 }
396                 else if(!(retval & OPERATOR_RUNNING_MODAL)) {
397                         WM_operator_free(op);
398                 }
399         }
400
401         return retval;
402 }
403
404 /* invokes operator in context */
405 int WM_operator_name_call(bContext *C, const char *opstring, int context, IDProperty *properties)
406 {
407         wmOperatorType *ot= WM_operatortype_find(opstring);
408         wmWindow *window= CTX_wm_window(C);
409         wmEvent *event;
410         
411         int retval;
412
413         /* dummie test */
414         if(ot && C && window) {
415                 event= window->eventstate;
416                 switch(context) {
417                         
418                         case WM_OP_EXEC_REGION_WIN:
419                                 event= NULL;    /* pass on without break */
420                         case WM_OP_INVOKE_REGION_WIN: 
421                         {
422                                 /* forces operator to go to the region window, for header menus */
423                                 ARegion *ar= CTX_wm_region(C);
424                                 ScrArea *area= CTX_wm_area(C);
425                                 
426                                 if(area) {
427                                         ARegion *ar1= area->regionbase.first;
428                                         for(; ar1; ar1= ar1->next)
429                                                 if(ar1->regiontype==RGN_TYPE_WINDOW)
430                                                         break;
431                                         if(ar1)
432                                                 CTX_wm_region_set(C, ar1);
433                                 }
434                                 
435                                 retval= wm_operator_invoke(C, ot, event, properties);
436                                 
437                                 /* set region back */
438                                 CTX_wm_region_set(C, ar);
439                                 
440                                 return retval;
441                         }
442                         case WM_OP_EXEC_AREA:
443                                 event= NULL;    /* pass on without break */
444                         case WM_OP_INVOKE_AREA:
445                         {
446                                         /* remove region from context */
447                                 ARegion *ar= CTX_wm_region(C);
448
449                                 CTX_wm_region_set(C, NULL);
450                                 retval= wm_operator_invoke(C, ot, event, properties);
451                                 CTX_wm_region_set(C, ar);
452
453                                 return retval;
454                         }
455                         case WM_OP_EXEC_SCREEN:
456                                 event= NULL;    /* pass on without break */
457                         case WM_OP_INVOKE_SCREEN:
458                         {
459                                 /* remove region + area from context */
460                                 ARegion *ar= CTX_wm_region(C);
461                                 ScrArea *area= CTX_wm_area(C);
462
463                                 CTX_wm_region_set(C, NULL);
464                                 CTX_wm_area_set(C, NULL);
465                                 retval= wm_operator_invoke(C, ot, window->eventstate, properties);
466                                 CTX_wm_region_set(C, ar);
467                                 CTX_wm_area_set(C, area);
468
469                                 return retval;
470                         }
471                         case WM_OP_EXEC_DEFAULT:
472                                 event= NULL;    /* pass on without break */
473                         case WM_OP_INVOKE_DEFAULT:
474                                 return wm_operator_invoke(C, ot, event, properties);
475                 }
476         }
477         
478         return 0;
479 }
480
481 /* ********************* handlers *************** */
482
483
484 /* not handler itself, is called by UI to move handlers to other queues, so don't close modal ones */
485 static void wm_event_free_handler(wmEventHandler *handler)
486 {
487         
488 }
489
490 /* called on exit or remove area, only here call cancel callback */
491 void WM_event_remove_handlers(bContext *C, ListBase *handlers)
492 {
493         wmEventHandler *handler;
494         
495         /* C is zero on freeing database, modal handlers then already were freed */
496         while((handler=handlers->first)) {
497                 BLI_remlink(handlers, handler);
498                 
499                 if(handler->op) {
500                         if(handler->op->type->cancel) {
501                                 ScrArea *area= CTX_wm_area(C);
502                                 ARegion *region= CTX_wm_region(C);
503                                 
504                                 CTX_wm_area_set(C, handler->op_area);
505                                 CTX_wm_region_set(C, handler->op_region);
506
507                                 handler->op->type->cancel(C, handler->op);
508
509                                 CTX_wm_area_set(C, area);
510                                 CTX_wm_region_set(C, region);
511                         }
512
513                         WM_operator_free(handler->op);
514                 }
515                 else if(handler->ui_remove) {
516                         ScrArea *area= CTX_wm_area(C);
517                         ARegion *region= CTX_wm_region(C);
518                         
519                         if(handler->ui_area) CTX_wm_area_set(C, handler->ui_area);
520                         if(handler->ui_region) CTX_wm_region_set(C, handler->ui_region);
521
522                         handler->ui_remove(C, handler->ui_userdata);
523
524                         CTX_wm_area_set(C, area);
525                         CTX_wm_region_set(C, region);
526                 }
527
528                 wm_event_free_handler(handler);
529                 MEM_freeN(handler);
530         }
531 }
532
533 /* do userdef mappings */
534 static int wm_userdef_event_map(int kmitype)
535 {
536         switch(kmitype) {
537                 case SELECTMOUSE:
538                         if(U.flag & USER_LMOUSESELECT)
539                                 return LEFTMOUSE;
540                         else
541                                 return RIGHTMOUSE;
542                         
543                 case ACTIONMOUSE:
544                         if(U.flag & USER_LMOUSESELECT)
545                                 return RIGHTMOUSE;
546                         else
547                                 return LEFTMOUSE;
548                         
549                 case WHEELOUTMOUSE:
550                         if(U.uiflag & USER_WHEELZOOMDIR)
551                                 return WHEELUPMOUSE;
552                         else
553                                 return WHEELDOWNMOUSE;
554                         
555                 case WHEELINMOUSE:
556                         if(U.uiflag & USER_WHEELZOOMDIR)
557                                 return WHEELDOWNMOUSE;
558                         else
559                                 return WHEELUPMOUSE;
560                         
561                 case EVT_TWEAK_A:
562                         if(U.flag & USER_LMOUSESELECT)
563                                 return EVT_TWEAK_R;
564                         else
565                                 return EVT_TWEAK_L;
566                         
567                 case EVT_TWEAK_S:
568                         if(U.flag & USER_LMOUSESELECT)
569                                 return EVT_TWEAK_L;
570                         else
571                                 return EVT_TWEAK_R;
572         }
573         
574         return kmitype;
575 }
576
577 static int wm_eventmatch(wmEvent *winevent, wmKeymapItem *kmi)
578 {
579         int kmitype= wm_userdef_event_map(kmi->type);
580         
581         /* the matching rules */
582         if(winevent->type!=kmitype) return 0;
583         
584         if(kmi->val!=KM_ANY)
585                 if(winevent->val!=kmi->val) return 0;
586         if(kmi->shift!=KM_ANY)
587                 if(winevent->shift!=kmi->shift) return 0;
588         if(kmi->ctrl!=KM_ANY)
589                 if(winevent->ctrl!=kmi->ctrl) return 0;
590         if(kmi->alt!=KM_ANY)
591                 if(winevent->alt!=kmi->alt) return 0;
592         if(kmi->oskey!=KM_ANY)
593                 if(winevent->oskey!=kmi->oskey) return 0;
594         if(kmi->keymodifier)
595                 if(winevent->keymodifier!=kmi->keymodifier) return 0;
596         
597         
598         return 1;
599 }
600
601 static int wm_event_always_pass(wmEvent *event)
602 {
603         /* some events we always pass on, to ensure proper communication */
604         return ELEM4(event->type, TIMER, TIMER0, TIMER1, TIMER2);
605 }
606
607 /* Warning: this function removes a modal handler, when finished */
608 static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHandler *handler, wmEvent *event, IDProperty *properties)
609 {
610         int retval= OPERATOR_PASS_THROUGH;
611         
612         /* derived, modal or blocking operator */
613         if(handler->op) {
614                 wmOperator *op= handler->op;
615                 wmOperatorType *ot= op->type;
616
617                 if(ot->modal) {
618                         /* we set context to where modal handler came from */
619                         ScrArea *area= CTX_wm_area(C);
620                         ARegion *region= CTX_wm_region(C);
621                         
622                         CTX_wm_area_set(C, handler->op_area);
623                         CTX_wm_region_set(C, handler->op_region);
624                         
625                         retval= ot->modal(C, op, event);
626
627                         /* putting back screen context */
628                         if((retval & OPERATOR_PASS_THROUGH) || wm_event_always_pass(event)) {
629                                 CTX_wm_area_set(C, area);
630                                 CTX_wm_region_set(C, region);
631                         }
632                         else {
633                                 /* this special cases is for areas and regions that get removed */
634                                 CTX_wm_area_set(C, NULL);
635                                 CTX_wm_region_set(C, NULL);
636                         }
637
638                         if(!(retval & OPERATOR_RUNNING_MODAL))
639                                 if(op->reports->list.first)
640                                         uiPupmenuReports(C, op->reports);
641                         
642                         if((retval & OPERATOR_FINISHED) && (ot->flag & OPTYPE_REGISTER)) {
643                                 wm_operator_register(CTX_wm_manager(C), op);
644                                 handler->op= NULL;
645                         }
646                         else if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) {
647                                 WM_operator_free(op);
648                                 handler->op= NULL;
649                         }
650                         
651                         /* remove modal handler, operator itself should have been cancelled and freed */
652                         if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) {
653                                 BLI_remlink(handlers, handler);
654                                 wm_event_free_handler(handler);
655                                 MEM_freeN(handler);
656                                 
657                                 /* prevent silly errors from operator users */
658                                 retval &= ~OPERATOR_PASS_THROUGH;
659                         }
660                         
661                 }
662                 else
663                         printf("wm_handler_operator_call error\n");
664         }
665         else {
666                 wmOperatorType *ot= WM_operatortype_find(event->keymap_idname);
667
668                 if(ot)
669                         retval= wm_operator_invoke(C, ot, event, properties);
670         }
671
672         if(retval & OPERATOR_PASS_THROUGH)
673                 return WM_HANDLER_CONTINUE;
674
675         return WM_HANDLER_BREAK;
676 }
677
678 static int wm_handler_ui_call(bContext *C, wmEventHandler *handler, wmEvent *event)
679 {
680         ScrArea *area= CTX_wm_area(C);
681         ARegion *region= CTX_wm_region(C);
682         int retval;
683                         
684         /* we set context to where ui handler came from */
685         if(handler->ui_area) CTX_wm_area_set(C, handler->ui_area);
686         if(handler->ui_region) CTX_wm_region_set(C, handler->ui_region);
687
688         retval= handler->ui_handle(C, event, handler->ui_userdata);
689
690         /* putting back screen context */
691         if((retval != WM_UI_HANDLER_BREAK) || wm_event_always_pass(event)) {
692                 CTX_wm_area_set(C, area);
693                 CTX_wm_region_set(C, region);
694         }
695         else {
696                 /* this special cases is for areas and regions that get removed */
697                 CTX_wm_area_set(C, NULL);
698                 CTX_wm_region_set(C, NULL);
699         }
700
701         if(retval == WM_UI_HANDLER_BREAK)
702                 return WM_HANDLER_BREAK;
703
704         return WM_HANDLER_CONTINUE;
705 }
706
707 static int handler_boundbox_test(wmEventHandler *handler, wmEvent *event)
708 {
709         if(handler->bbwin) {
710                 if(handler->bblocal) {
711                         rcti rect= *handler->bblocal;
712                         BLI_translate_rcti(&rect, handler->bbwin->xmin, handler->bbwin->ymin);
713                         return BLI_in_rcti(&rect, event->x, event->y);
714                 }
715                 else 
716                         return BLI_in_rcti(handler->bbwin, event->x, event->y);
717         }
718         return 1;
719 }
720
721 static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
722 {
723         wmEventHandler *handler, *nexthandler;
724         int action= WM_HANDLER_CONTINUE;
725
726         if(handlers==NULL) return action;
727         
728         /* modal handlers can get removed in this loop, we keep the loop this way */
729         for(handler= handlers->first; handler; handler= nexthandler) {
730                 nexthandler= handler->next;
731
732                 /* optional boundbox */
733                 if(handler_boundbox_test(handler, event)) {
734                 
735                         /* modal+blocking handler */
736                         if(handler->flag & WM_HANDLER_BLOCKING)
737                                 action= WM_HANDLER_BREAK;
738
739                         if(handler->keymap) {
740                                 wmKeymapItem *kmi;
741                                 
742                                 for(kmi= handler->keymap->first; kmi; kmi= kmi->next) {
743                                         if(wm_eventmatch(event, kmi)) {
744                                                 if((G.f & G_DEBUG) && event->type!=MOUSEMOVE)
745                                                         printf("handle evt %d win %d op %s\n", event->type, CTX_wm_screen(C)->subwinactive, kmi->idname); 
746                                                 
747                                                 event->keymap_idname= kmi->idname;      /* weak, but allows interactive callback to not use rawkey */
748                                                 
749                                                 action= wm_handler_operator_call(C, handlers, handler, event, kmi->properties);
750                                                 if(action==WM_HANDLER_BREAK)  /* not wm_event_always_pass(event) here, it denotes removed handler */
751                                                         break;
752                                         }
753                                 }
754                         }
755                         else if(handler->ui_handle) {
756                                 action= wm_handler_ui_call(C, handler, event);
757                         }
758                         else {
759                                 /* modal, swallows all */
760                                 action= wm_handler_operator_call(C, handlers, handler, event, NULL);
761                         }
762
763                         if(!wm_event_always_pass(event) && action==WM_HANDLER_BREAK)
764                                 break;
765                 }
766                 
767         }
768         return action;
769 }
770
771 static int wm_event_inside_i(wmEvent *event, rcti *rect)
772 {
773         return BLI_in_rcti(rect, event->x, event->y);
774 }
775
776 static int wm_event_prev_inside_i(wmEvent *event, rcti *rect)
777 {
778         if(BLI_in_rcti(rect, event->x, event->y))
779            return 1;
780         if(event->type==MOUSEMOVE) {
781                 if( BLI_in_rcti(rect, event->prevx, event->prevy)) {
782                         return 1;
783                 }
784                 return 0;
785         }
786         return 0;
787 }
788
789 static ScrArea *area_event_inside(bContext *C, wmEvent *event)
790 {
791         bScreen *screen= CTX_wm_screen(C);
792         ScrArea *sa;
793         
794         if(screen)
795                 for(sa= screen->areabase.first; sa; sa= sa->next)
796                         if(BLI_in_rcti(&sa->totrct, event->x, event->y))
797                                 return sa;
798         return NULL;
799 }
800
801 static ARegion *region_event_inside(bContext *C, wmEvent *event)
802 {
803         bScreen *screen= CTX_wm_screen(C);
804         ScrArea *area= CTX_wm_area(C);
805         ARegion *ar;
806         
807         if(screen && area)
808                 for(ar= area->regionbase.first; ar; ar= ar->next)
809                         if(BLI_in_rcti(&ar->winrct, event->x, event->y))
810                                 return ar;
811         return NULL;
812 }
813
814
815 /* called in main loop */
816 /* goes over entire hierarchy:  events -> window -> screen -> area -> region */
817 void wm_event_do_handlers(bContext *C)
818 {
819         wmWindow *win;
820
821         for(win= CTX_wm_manager(C)->windows.first; win; win= win->next) {
822                 wmEvent *event;
823                 
824                 if( win->screen==NULL )
825                         wm_event_free_all(win);
826                 
827                 while( (event=wm_event_next(win)) ) {
828                         int action;
829
830                         CTX_wm_window_set(C, win);
831                         CTX_wm_area_set(C, area_event_inside(C, event));
832                         CTX_wm_region_set(C, region_event_inside(C, event));
833                         
834                         /* MVC demands to not draw in event handlers... but we need to leave it for ogl selecting etc */
835                         wm_window_make_drawable(C, win);
836                         
837                         action= wm_handlers_do(C, event, &win->handlers);
838                         
839                         if(wm_event_always_pass(event) || action==WM_HANDLER_CONTINUE) {
840                                 ScrArea *sa;
841                                 ARegion *ar;
842                                 int doit= 0;
843                                 
844                                 /* XXX to solve, here screen handlers? */
845                                 if(!wm_event_always_pass(event))
846                                         ED_screen_set_subwinactive(win, event); /* state variables in screen */
847                                 
848                                 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
849                                         if(wm_event_always_pass(event) || wm_event_prev_inside_i(event, &sa->totrct)) {
850                                                 doit= 1;
851                                                 CTX_wm_area_set(C, sa);
852                                                 action= wm_handlers_do(C, event, &sa->handlers);
853
854                                                 if(wm_event_always_pass(event) || action==WM_HANDLER_CONTINUE) {
855                                                         for(ar=sa->regionbase.first; ar; ar= ar->next) {
856                                                                 if(wm_event_always_pass(event) || wm_event_inside_i(event, &ar->winrct) || wm_event_prev_inside_i(event, &ar->winrct)) {
857                                                                         CTX_wm_region_set(C, ar);
858                                                                         action= wm_handlers_do(C, event, &ar->handlers);
859                                                                         CTX_wm_region_set(C, NULL);
860
861                                                                         if(!wm_event_always_pass(event)) {
862                                                                                 if(action==WM_HANDLER_BREAK)
863                                                                                         break;
864                                                                         }
865                                                                 }
866                                                         }
867                                                 }
868
869                                                 CTX_wm_area_set(C, NULL);
870                                                 /* NOTE: do not escape on WM_HANDLER_BREAK, mousemove needs handled for previous area */
871                                         }
872                                 }
873                                 /* XXX hrmf, this gives reliable previous mouse coord for area change, feels bad? 
874                                    doing it on ghost queue gives errors when mousemoves go over area borders */
875                                 if(doit) {
876                                         CTX_wm_window(C)->eventstate->prevx= event->x;
877                                         CTX_wm_window(C)->eventstate->prevy= event->y;
878                                 }
879                         }
880                         wm_event_free(event);
881                         
882                         CTX_wm_window_set(C, NULL);
883                 }
884         }
885 }
886
887 /* lets not expose struct outside wm? */
888 void WM_event_set_handler_flag(wmEventHandler *handler, int flag)
889 {
890         handler->flag= flag;
891 }
892
893 wmEventHandler *WM_event_add_modal_handler(bContext *C, ListBase *handlers, wmOperator *op)
894 {
895         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event modal handler");
896         handler->op= op;
897         handler->op_area= CTX_wm_area(C);               /* means frozen screen context for modal handlers! */
898         handler->op_region= CTX_wm_region(C);
899         
900         BLI_addhead(handlers, handler);
901
902         return handler;
903 }
904
905 wmEventHandler *WM_event_add_keymap_handler(ListBase *handlers, ListBase *keymap)
906 {
907         wmEventHandler *handler;
908         
909         /* only allow same keymap once */
910         for(handler= handlers->first; handler; handler= handler->next)
911                 if(handler->keymap==keymap)
912                         return handler;
913
914         handler= MEM_callocN(sizeof(wmEventHandler), "event keymap handler");
915         BLI_addtail(handlers, handler);
916         handler->keymap= keymap;
917
918         return handler;
919 }
920
921 wmEventHandler *WM_event_add_keymap_handler_bb(ListBase *handlers, ListBase *keymap, rcti *bblocal, rcti *bbwin)
922 {
923         wmEventHandler *handler= WM_event_add_keymap_handler(handlers, keymap);
924         handler->bblocal= bblocal;
925         handler->bbwin= bbwin;
926         
927         return handler;
928 }
929
930 void WM_event_remove_keymap_handler(ListBase *handlers, ListBase *keymap)
931 {
932         wmEventHandler *handler;
933         
934         for(handler= handlers->first; handler; handler= handler->next) {
935                 if(handler->keymap==keymap) {
936                         BLI_remlink(handlers, handler);
937                         wm_event_free_handler(handler);
938                         MEM_freeN(handler);
939                         break;
940                 }
941         }
942 }
943
944 wmEventHandler *WM_event_add_ui_handler(bContext *C, ListBase *handlers, wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata)
945 {
946         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event ui handler");
947         handler->ui_handle= func;
948         handler->ui_remove= remove;
949         handler->ui_userdata= userdata;
950         handler->ui_area= (C)? CTX_wm_area(C): NULL;
951         handler->ui_region= (C)? CTX_wm_region(C): NULL;
952         
953         BLI_addhead(handlers, handler);
954         
955         return handler;
956 }
957
958 void WM_event_remove_ui_handler(ListBase *handlers, wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata)
959 {
960         wmEventHandler *handler;
961         
962         for(handler= handlers->first; handler; handler= handler->next) {
963                 if(handler->ui_handle == func && handler->ui_remove == remove && handler->ui_userdata == userdata) {
964                         BLI_remlink(handlers, handler);
965                         wm_event_free_handler(handler);
966                         MEM_freeN(handler);
967                         break;
968                 }
969         }
970 }
971
972 void WM_event_add_mousemove(bContext *C)
973 {
974         wmWindow *window= CTX_wm_window(C);
975         wmEvent event= *(window->eventstate);
976         event.type= MOUSEMOVE;
977         event.prevx= event.x;
978         event.prevy= event.y;
979         wm_event_add(window, &event);
980 }
981
982 /* for modal callbacks, check configuration for how to interpret exit with tweaks  */
983 int WM_modal_tweak_exit(wmEvent *evt, int tweak_event)
984 {
985         /* user preset?? dunno... */
986         int tweak_modal= 1;
987         
988         switch(tweak_event) {
989                 case EVT_TWEAK_L:
990                 case EVT_TWEAK_M:
991                 case EVT_TWEAK_R:
992                         if(evt->val==tweak_modal)
993                                 return 1;
994                 default:
995                         /* this case is when modal callcback didnt get started with a tweak */
996                         if(evt->val)
997                                 return 1;
998         }
999         return 0;
1000 }
1001
1002
1003 /* ********************* ghost stuff *************** */
1004
1005 static int convert_key(GHOST_TKey key) 
1006 {
1007         if (key>=GHOST_kKeyA && key<=GHOST_kKeyZ) {
1008                 return (AKEY + ((int) key - GHOST_kKeyA));
1009         } else if (key>=GHOST_kKey0 && key<=GHOST_kKey9) {
1010                 return (ZEROKEY + ((int) key - GHOST_kKey0));
1011         } else if (key>=GHOST_kKeyNumpad0 && key<=GHOST_kKeyNumpad9) {
1012                 return (PAD0 + ((int) key - GHOST_kKeyNumpad0));
1013         } else if (key>=GHOST_kKeyF1 && key<=GHOST_kKeyF12) {
1014                 return (F1KEY + ((int) key - GHOST_kKeyF1));
1015         } else {
1016                 switch (key) {
1017                         case GHOST_kKeyBackSpace:               return BACKSPACEKEY;
1018                         case GHOST_kKeyTab:                             return TABKEY;
1019                         case GHOST_kKeyLinefeed:                return LINEFEEDKEY;
1020                         case GHOST_kKeyClear:                   return 0;
1021                         case GHOST_kKeyEnter:                   return RETKEY;
1022                                 
1023                         case GHOST_kKeyEsc:                             return ESCKEY;
1024                         case GHOST_kKeySpace:                   return SPACEKEY;
1025                         case GHOST_kKeyQuote:                   return QUOTEKEY;
1026                         case GHOST_kKeyComma:                   return COMMAKEY;
1027                         case GHOST_kKeyMinus:                   return MINUSKEY;
1028                         case GHOST_kKeyPeriod:                  return PERIODKEY;
1029                         case GHOST_kKeySlash:                   return SLASHKEY;
1030                                 
1031                         case GHOST_kKeySemicolon:               return SEMICOLONKEY;
1032                         case GHOST_kKeyEqual:                   return EQUALKEY;
1033                                 
1034                         case GHOST_kKeyLeftBracket:             return LEFTBRACKETKEY;
1035                         case GHOST_kKeyRightBracket:    return RIGHTBRACKETKEY;
1036                         case GHOST_kKeyBackslash:               return BACKSLASHKEY;
1037                         case GHOST_kKeyAccentGrave:             return ACCENTGRAVEKEY;
1038                                 
1039                         case GHOST_kKeyLeftShift:               return LEFTSHIFTKEY;
1040                         case GHOST_kKeyRightShift:              return RIGHTSHIFTKEY;
1041                         case GHOST_kKeyLeftControl:             return LEFTCTRLKEY;
1042                         case GHOST_kKeyRightControl:    return RIGHTCTRLKEY;
1043                         case GHOST_kKeyCommand:                 return COMMANDKEY;
1044                         case GHOST_kKeyLeftAlt:                 return LEFTALTKEY;
1045                         case GHOST_kKeyRightAlt:                return RIGHTALTKEY;
1046                                 
1047                         case GHOST_kKeyCapsLock:                return CAPSLOCKKEY;
1048                         case GHOST_kKeyNumLock:                 return 0;
1049                         case GHOST_kKeyScrollLock:              return 0;
1050                                 
1051                         case GHOST_kKeyLeftArrow:               return LEFTARROWKEY;
1052                         case GHOST_kKeyRightArrow:              return RIGHTARROWKEY;
1053                         case GHOST_kKeyUpArrow:                 return UPARROWKEY;
1054                         case GHOST_kKeyDownArrow:               return DOWNARROWKEY;
1055                                 
1056                         case GHOST_kKeyPrintScreen:             return 0;
1057                         case GHOST_kKeyPause:                   return PAUSEKEY;
1058                                 
1059                         case GHOST_kKeyInsert:                  return INSERTKEY;
1060                         case GHOST_kKeyDelete:                  return DELKEY;
1061                         case GHOST_kKeyHome:                    return HOMEKEY;
1062                         case GHOST_kKeyEnd:                             return ENDKEY;
1063                         case GHOST_kKeyUpPage:                  return PAGEUPKEY;
1064                         case GHOST_kKeyDownPage:                return PAGEDOWNKEY;
1065                                 
1066                         case GHOST_kKeyNumpadPeriod:    return PADPERIOD;
1067                         case GHOST_kKeyNumpadEnter:             return PADENTER;
1068                         case GHOST_kKeyNumpadPlus:              return PADPLUSKEY;
1069                         case GHOST_kKeyNumpadMinus:             return PADMINUS;
1070                         case GHOST_kKeyNumpadAsterisk:  return PADASTERKEY;
1071                         case GHOST_kKeyNumpadSlash:             return PADSLASHKEY;
1072                                 
1073                         case GHOST_kKeyGrLess:              return GRLESSKEY; 
1074                                 
1075                         default:
1076                                 return UNKNOWNKEY;      /* GHOST_kKeyUnknown */
1077                 }
1078         }
1079 }
1080
1081 /* adds customdata to event */
1082 static void update_tablet_data(wmWindow *win, wmEvent *event)
1083 {
1084         const GHOST_TabletData *td= GHOST_GetTabletData(win->ghostwin);
1085         
1086         /* if there's tablet data from an active tablet device then add it */
1087         if ((td != NULL) && td->Active) {
1088                 struct wmTabletData *wmtab= MEM_mallocN(sizeof(wmTabletData), "customdata tablet");
1089                 
1090                 wmtab->Active = td->Active;
1091                 wmtab->Pressure = td->Pressure;
1092                 wmtab->Xtilt = td->Xtilt;
1093                 wmtab->Ytilt = td->Ytilt;
1094                 
1095                 event->custom= EVT_DATA_TABLET;
1096                 event->customdata= wmtab;
1097                 event->customdatafree= 1;
1098         } 
1099 }
1100
1101
1102 /* windows store own event queues, no bContext here */
1103 void wm_event_add_ghostevent(wmWindow *win, int type, void *customdata)
1104 {
1105         wmEvent event, *evt= win->eventstate;
1106         
1107         /* initialize and copy state (only mouse x y and modifiers) */
1108         event= *evt;
1109         
1110         switch (type) {
1111                 /* mouse move */
1112                 case GHOST_kEventCursorMove: {
1113                         if(win->active) {
1114                                 GHOST_TEventCursorData *cd= customdata;
1115                                 int cx, cy;
1116
1117                                 GHOST_ScreenToClient(win->ghostwin, cd->x, cd->y, &cx, &cy);
1118                                 
1119                                 event.type= MOUSEMOVE;
1120                                 event.x= evt->x= cx;
1121                                 event.y= evt->y= (win->sizey-1) - cy;
1122                                 
1123                                 update_tablet_data(win, &event);
1124                                 wm_event_add(win, &event);
1125                         }
1126                         break;
1127                 }
1128                 /* mouse button */
1129                 case GHOST_kEventButtonDown:
1130                 case GHOST_kEventButtonUp: {
1131                         GHOST_TEventButtonData *bd= customdata;
1132                         event.val= (type==GHOST_kEventButtonDown);
1133                         
1134                         if (bd->button == GHOST_kButtonMaskLeft)
1135                                 event.type= LEFTMOUSE;
1136                         else if (bd->button == GHOST_kButtonMaskRight)
1137                                 event.type= RIGHTMOUSE;
1138                         else
1139                                 event.type= MIDDLEMOUSE;
1140                         
1141                         if(event.val)
1142                                 event.keymodifier= evt->keymodifier= event.type;
1143                         else
1144                                 event.keymodifier= evt->keymodifier= 0;
1145                         
1146                         update_tablet_data(win, &event);
1147                         wm_event_add(win, &event);
1148                         
1149                         break;
1150                 }
1151                 /* keyboard */
1152                 case GHOST_kEventKeyDown:
1153                 case GHOST_kEventKeyUp: {
1154                         GHOST_TEventKeyData *kd= customdata;
1155                         event.type= convert_key(kd->key);
1156                         event.ascii= kd->ascii;
1157                         event.val= (type==GHOST_kEventKeyDown); /* XXX eventmatch uses defines, bad code... */
1158                         
1159                         /* modifiers */
1160                         if (event.type==LEFTSHIFTKEY || event.type==RIGHTSHIFTKEY) {
1161                                 event.shift= evt->shift= event.val;
1162                         } else if (event.type==LEFTCTRLKEY || event.type==RIGHTCTRLKEY) {
1163                                 event.ctrl= evt->ctrl= event.val;
1164                         } else if (event.type==LEFTALTKEY || event.type==RIGHTALTKEY) {
1165                                 event.alt= evt->alt= event.val;
1166                         } else if (event.type==COMMANDKEY) {
1167                                 event.oskey= evt->oskey= event.val;
1168                         }
1169                         
1170                         /* if test_break set, it catches this. Keep global for now? */
1171                         if(event.type==ESCKEY)
1172                                 G.afbreek= 1;
1173                         
1174                         wm_event_add(win, &event);
1175                         
1176                         break;
1177                 }
1178                         
1179                 case GHOST_kEventWheel: {
1180                         GHOST_TEventWheelData* wheelData = customdata;
1181                         
1182                         if (wheelData->z > 0)
1183                                 event.type= WHEELUPMOUSE;
1184                         else
1185                                 event.type= WHEELDOWNMOUSE;
1186                         
1187                         event.val= KM_PRESS;
1188                         wm_event_add(win, &event);
1189                         
1190                         break;
1191                 }
1192                 case GHOST_kEventTimer: {
1193                         event.type= TIMER;
1194                         event.custom= EVT_DATA_TIMER;
1195                         event.customdata= customdata;
1196                         wm_event_add(win, &event);
1197
1198                         break;
1199                 }
1200
1201                 case GHOST_kEventUnknown:
1202                 case GHOST_kNumEventTypes:
1203                         break;
1204         }
1205 }
1206