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