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