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