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