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