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