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