Undo revision 23130 which was a merge with 2.5, a messy one because I did something...
[blender.git] / source / blender / windowmanager / intern / wm_event_system.c
1 /**
2  * $Id:
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2007 Blender Foundation.
21  * All rights reserved.
22  *
23  * 
24  * Contributor(s): Blender Foundation
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include <stdlib.h>
30 #include <string.h>
31
32 #include "DNA_listBase.h"
33 #include "DNA_screen_types.h"
34 #include "DNA_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 #include "BKE_pointcache.h"
53
54 #include "ED_fileselect.h"
55 #include "ED_screen.h"
56 #include "ED_space_api.h"
57 #include "ED_util.h"
58
59 #include "RNA_access.h"
60
61 #include "UI_interface.h"
62
63 #include "WM_api.h"
64 #include "WM_types.h"
65 #include "wm.h"
66 #include "wm_window.h"
67 #include "wm_event_system.h"
68 #include "wm_event_types.h"
69
70 /* ************ event management ************** */
71
72 void wm_event_add(wmWindow *win, wmEvent *event_to_add)
73 {
74         wmEvent *event= MEM_callocN(sizeof(wmEvent), "event");
75         
76         *event= *event_to_add;
77         BLI_addtail(&win->queue, event);
78 }
79
80 void wm_event_free(wmEvent *event)
81 {
82         if(event->customdata && event->customdatafree)
83                 MEM_freeN(event->customdata);
84         MEM_freeN(event);
85 }
86
87 void wm_event_free_all(wmWindow *win)
88 {
89         wmEvent *event;
90         
91         while((event= win->queue.first)) {
92                 BLI_remlink(&win->queue, event);
93                 wm_event_free(event);
94         }
95 }
96
97 /* ********************* notifiers, listeners *************** */
98
99 /* XXX: in future, which notifiers to send to other windows? */
100 void WM_event_add_notifier(const bContext *C, unsigned int type, void *reference)
101 {
102         wmNotifier *note= MEM_callocN(sizeof(wmNotifier), "notifier");
103         
104         note->wm= CTX_wm_manager(C);
105         BLI_addtail(&note->wm->queue, note);
106         
107         note->window= CTX_wm_window(C);
108         
109         if(CTX_wm_region(C))
110                 note->swinid= CTX_wm_region(C)->swinid;
111         
112         note->category= type & NOTE_CATEGORY;
113         note->data= type & NOTE_DATA;
114         note->subtype= type & NOTE_SUBTYPE;
115         note->action= type & NOTE_ACTION;
116         
117         note->reference= reference;
118 }
119
120 static wmNotifier *wm_notifier_next(wmWindowManager *wm)
121 {
122         wmNotifier *note= wm->queue.first;
123         
124         if(note) BLI_remlink(&wm->queue, note);
125         return note;
126 }
127
128 /* called in mainloop */
129 void wm_event_do_notifiers(bContext *C)
130 {
131         wmWindowManager *wm= CTX_wm_manager(C);
132         wmNotifier *note;
133         wmWindow *win;
134         
135         if(wm==NULL)
136                 return;
137         
138         /* cache & catch WM level notifiers, such as frame change, scene/screen set */
139         for(win= wm->windows.first; win; win= win->next) {
140                 int do_anim= 0;
141                 
142                 CTX_wm_window_set(C, win);
143                 
144                 for(note= wm->queue.first; note; note= note->next) {
145                         if(note->category==NC_WM) {
146                                 if( ELEM(note->data, ND_FILEREAD, ND_FILESAVE)) {
147                                         wm->file_saved= 1;
148                                         wm_window_title(wm, win);
149                                 }
150                                 else if(note->data==ND_DATACHANGED)
151                                         wm_window_title(wm, win);
152                         }
153                         if(note->window==win) {
154                                 if(note->category==NC_SCREEN) {
155                                         if(note->data==ND_SCREENBROWSE) {
156                                                 ED_screen_set(C, note->reference);      // XXX hrms, think this over!
157                                                 printf("screen set %p\n", note->reference);
158                                         }
159                                         else if(note->data==ND_SCREENDELETE) {
160                                                 ED_screen_delete(C, note->reference);   // XXX hrms, think this over!
161                                                 printf("screen delete %p\n", note->reference);
162                                         }
163                                 }
164                                 else if(note->category==NC_SCENE) {
165                                         if(note->data==ND_SCENEBROWSE) {
166                                                 ED_screen_set_scene(C, note->reference);        // XXX hrms, think this over!
167                                                 printf("scene set %p\n", note->reference);
168                                         }
169                                         if(note->data==ND_SCENEDELETE) {
170                                                 ED_screen_delete_scene(C, note->reference);     // XXX hrms, think this over!
171                                                 printf("scene delete %p\n", note->reference);
172                                         }
173                                         else if(note->data==ND_FRAME)
174                                                 do_anim= 1;
175                                 }
176                         }
177                 }
178                 if(do_anim) {
179                         /* depsgraph gets called, might send more notifiers */
180                         ED_update_for_newframe(C, 1);
181                 }
182         }
183         
184         /* the notifiers are sent without context, to keep it clean */
185         while( (note=wm_notifier_next(wm)) ) {
186                 wmWindow *win;
187                 
188                 for(win= wm->windows.first; win; win= win->next) {
189                         
190                         /* filter out notifiers */
191                         if(note->category==NC_SCREEN && note->reference && note->reference!=win->screen);
192                         else if(note->category==NC_SCENE && note->reference && note->reference!=win->screen->scene);
193                         else {
194                                 ScrArea *sa;
195                                 ARegion *ar;
196
197                                 /* XXX context in notifiers? */
198                                 CTX_wm_window_set(C, win);
199
200                                 /* printf("notifier win %d screen %s cat %x\n", win->winid, win->screen->id.name+2, note->category); */
201                                 ED_screen_do_listen(win, note);
202
203                                 for(ar=win->screen->regionbase.first; ar; ar= ar->next) {
204                                         ED_region_do_listen(ar, note);
205                                 }
206                                 
207                                 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
208                                         ED_area_do_listen(sa, note);
209                                         for(ar=sa->regionbase.first; ar; ar= ar->next) {
210                                                 ED_region_do_listen(ar, note);
211                                         }
212                                 }
213                         }
214                 }
215                 
216                 MEM_freeN(note);
217         }
218         
219         /* cached: editor refresh callbacks now, they get context */
220         for(win= wm->windows.first; win; win= win->next) {
221                 Scene *sce, *scene= win->screen->scene;
222                 ScrArea *sa;
223                 Base *base;
224                 
225                 CTX_wm_window_set(C, win);
226                 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
227                         if(sa->do_refresh) {
228                                 CTX_wm_area_set(C, sa);
229                                 ED_area_do_refresh(C, sa);
230                         }
231                 }
232                 
233                 if(G.rendering==0) { // XXX make lock in future, or separated derivedmesh users in scene
234                         
235                         /* update all objects, ipos, matrices, displists, etc. Flags set by depgraph or manual, 
236                                 no layer check here, gets correct flushed */
237                         /* sets first, we allow per definition current scene to have dependencies on sets */
238                         if(scene->set) {
239                                 for(SETLOOPER(scene->set, base))
240                                         object_handle_update(scene, base->object);
241                         }
242                         
243                         for(base= scene->base.first; base; base= base->next) {
244                                 object_handle_update(scene, base->object);
245                         }
246
247                         BKE_ptcache_quick_cache_all(scene);
248                 }               
249         }
250         CTX_wm_window_set(C, NULL);
251 }
252
253 /* ********************* operators ******************* */
254
255 static int wm_operator_poll(bContext *C, wmOperatorType *ot)
256 {
257         wmOperatorTypeMacro *otmacro;
258         
259         for(otmacro= ot->macro.first; otmacro; otmacro= otmacro->next) {
260                 wmOperatorType *ot= WM_operatortype_find(otmacro->idname, 0);
261                 
262                 if(0==wm_operator_poll(C, ot))
263                         return 0;
264         }
265         
266         if(ot->poll)
267                 return ot->poll(C);
268         
269         return 1;
270 }
271
272 /* if repeat is true, it doesn't register again, nor does it free */
273 static int wm_operator_exec(bContext *C, wmOperator *op, int repeat)
274 {
275         int retval= OPERATOR_CANCELLED;
276         
277         if(op==NULL || op->type==NULL)
278                 return retval;
279         
280         if(0==wm_operator_poll(C, op->type))
281                 return retval;
282         
283         if(op->type->exec)
284                 retval= op->type->exec(C, op);
285         
286         if(!(retval & OPERATOR_RUNNING_MODAL))
287                 if(op->reports->list.first)
288                         uiPupMenuReports(C, op->reports);
289         
290         if(retval & OPERATOR_FINISHED) {
291                 if(op->type->flag & OPTYPE_UNDO)
292                         ED_undo_push_op(C, op);
293                 
294                 if(repeat==0) {
295                         if((op->type->flag & OPTYPE_REGISTER) || (G.f & G_DEBUG))
296                                 wm_operator_register(C, op);
297                         else
298                                 WM_operator_free(op);
299                 }
300         }
301         else if(repeat==0)
302                 WM_operator_free(op);
303         
304         return retval;
305         
306 }
307
308 /* for running operators with frozen context (modal handlers, menus) */
309 int WM_operator_call(bContext *C, wmOperator *op)
310 {
311         return wm_operator_exec(C, op, 0);
312 }
313
314 /* do this operator again, put here so it can share above code */
315 int WM_operator_repeat(bContext *C, wmOperator *op)
316 {
317         return wm_operator_exec(C, op, 1);
318 }
319
320 static wmOperator *wm_operator_create(wmWindowManager *wm, wmOperatorType *ot, PointerRNA *properties, ReportList *reports)
321 {
322         wmOperator *op= MEM_callocN(sizeof(wmOperator), ot->idname);    /* XXX operatortype names are static still. for debug */
323         
324         /* XXX adding new operator could be function, only happens here now */
325         op->type= ot;
326         BLI_strncpy(op->idname, ot->idname, OP_MAX_TYPENAME);
327         
328         /* initialize properties, either copy or create */
329         op->ptr= MEM_callocN(sizeof(PointerRNA), "wmOperatorPtrRNA");
330         if(properties && properties->data) {
331                 op->properties= IDP_CopyProperty(properties->data);
332         }
333         else {
334                 IDPropertyTemplate val = {0};
335                 op->properties= IDP_New(IDP_GROUP, val, "wmOperatorProperties");
336         }
337         RNA_pointer_create(&wm->id, ot->srna, op->properties, op->ptr);
338
339         /* initialize error reports */
340         if (reports) {
341                 op->reports= reports; /* must be initialized alredy */
342         }
343         else {
344                 op->reports= MEM_mallocN(sizeof(ReportList), "wmOperatorReportList");
345                 BKE_reports_init(op->reports, RPT_STORE);
346         }
347         
348         /* recursive filling of operator macro list */
349         if(ot->macro.first) {
350                 static wmOperator *motherop= NULL;
351                 wmOperatorTypeMacro *otmacro;
352                 
353                 /* ensure all ops are in execution order in 1 list */
354                 if(motherop==NULL) 
355                         motherop= op;
356                 
357                 for(otmacro= ot->macro.first; otmacro; otmacro= otmacro->next) {
358                         wmOperatorType *otm= WM_operatortype_find(otmacro->idname, 0);
359                         wmOperator *opm= wm_operator_create(wm, otm, otmacro->ptr, NULL);
360                         
361                         BLI_addtail(&motherop->macro, opm);
362                         opm->opm= motherop; /* pointer to mom, for modal() */
363                 }
364                 
365                 motherop= NULL;
366         }
367         
368         return op;
369 }
370
371 static void wm_operator_print(wmOperator *op)
372 {
373         char *buf = WM_operator_pystring(NULL, op->type, op->ptr, 1);
374         printf("%s\n", buf);
375         MEM_freeN(buf);
376 }
377
378 static void wm_region_mouse_co(bContext *C, wmEvent *event)
379 {
380         ARegion *ar= CTX_wm_region(C);
381         if(ar) {
382                 /* compatibility convention */
383                 event->mval[0]= event->x - ar->winrct.xmin;
384                 event->mval[1]= event->y - ar->winrct.ymin;
385         }
386 }
387
388 static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, PointerRNA *properties)
389 {
390         wmWindowManager *wm= CTX_wm_manager(C);
391         int retval= OPERATOR_PASS_THROUGH;
392
393         if(wm_operator_poll(C, ot)) {
394                 wmOperator *op= wm_operator_create(wm, ot, properties, NULL);
395                 
396                 if((G.f & G_DEBUG) && event && event->type!=MOUSEMOVE)
397                         printf("handle evt %d win %d op %s\n", event?event->type:0, CTX_wm_screen(C)->subwinactive, ot->idname); 
398                 
399                 if(op->type->invoke && event) {
400                         wm_region_mouse_co(C, event);
401                         retval= op->type->invoke(C, op, event);
402                 }
403                 else if(op->type->exec)
404                         retval= op->type->exec(C, op);
405                 else
406                         printf("invalid operator call %s\n", ot->idname); /* debug, important to leave a while, should never happen */
407
408                 if(!(retval & OPERATOR_RUNNING_MODAL)) {
409                         if(op->reports->list.first) /* only show the report if the report list was not given in the function */
410                                 uiPupMenuReports(C, op->reports);
411                 
412                 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 */
413                         if(G.f & G_DEBUG)
414                                 wm_operator_print(op);
415                 }
416
417                 if(retval & OPERATOR_FINISHED) {
418                         if(ot->flag & OPTYPE_UNDO)
419                                 ED_undo_push_op(C, op);
420                         
421                         if((ot->flag & OPTYPE_REGISTER) || (G.f & G_DEBUG))
422                                 wm_operator_register(C, op);
423                         else
424                                 WM_operator_free(op);
425                 }
426                 else if(retval & OPERATOR_RUNNING_MODAL) {
427                         /* grab cursor during blocking modal ops (X11) */
428                         if(ot->flag & OPTYPE_BLOCKING)
429                                 WM_cursor_grab(CTX_wm_window(C), 1);
430                 }
431                 else
432                         WM_operator_free(op);
433         }
434
435         return retval;
436 }
437
438 /* invokes operator in context */
439 int WM_operator_name_call(bContext *C, const char *opstring, int context, PointerRNA *properties)
440 {
441         wmOperatorType *ot= WM_operatortype_find(opstring, 0);
442         wmWindow *window= CTX_wm_window(C);
443         wmEvent *event;
444         
445         int retval;
446
447         /* dummie test */
448         if(ot && C && window) {
449                 event= window->eventstate;
450                 switch(context) {
451                         
452                         case WM_OP_EXEC_REGION_WIN:
453                                 event= NULL;    /* pass on without break */
454                         case WM_OP_INVOKE_REGION_WIN: 
455                         {
456                                 /* forces operator to go to the region window, for header menus */
457                                 ARegion *ar= CTX_wm_region(C);
458                                 ScrArea *area= CTX_wm_area(C);
459                                 
460                                 if(area) {
461                                         ARegion *ar1= area->regionbase.first;
462                                         for(; ar1; ar1= ar1->next)
463                                                 if(ar1->regiontype==RGN_TYPE_WINDOW)
464                                                         break;
465                                         if(ar1)
466                                                 CTX_wm_region_set(C, ar1);
467                                 }
468                                 
469                                 retval= wm_operator_invoke(C, ot, event, properties);
470                                 
471                                 /* set region back */
472                                 CTX_wm_region_set(C, ar);
473                                 
474                                 return retval;
475                         }
476                         case WM_OP_EXEC_AREA:
477                                 event= NULL;    /* pass on without break */
478                         case WM_OP_INVOKE_AREA:
479                         {
480                                         /* remove region from context */
481                                 ARegion *ar= CTX_wm_region(C);
482
483                                 CTX_wm_region_set(C, NULL);
484                                 retval= wm_operator_invoke(C, ot, event, properties);
485                                 CTX_wm_region_set(C, ar);
486
487                                 return retval;
488                         }
489                         case WM_OP_EXEC_SCREEN:
490                                 event= NULL;    /* pass on without break */
491                         case WM_OP_INVOKE_SCREEN:
492                         {
493                                 /* remove region + area from context */
494                                 ARegion *ar= CTX_wm_region(C);
495                                 ScrArea *area= CTX_wm_area(C);
496
497                                 CTX_wm_region_set(C, NULL);
498                                 CTX_wm_area_set(C, NULL);
499                                 retval= wm_operator_invoke(C, ot, event, properties);
500                                 CTX_wm_region_set(C, ar);
501                                 CTX_wm_area_set(C, area);
502
503                                 return retval;
504                         }
505                         case WM_OP_EXEC_DEFAULT:
506                                 event= NULL;    /* pass on without break */
507                         case WM_OP_INVOKE_DEFAULT:
508                                 return wm_operator_invoke(C, ot, event, properties);
509                 }
510         }
511         
512         return 0;
513 }
514
515 /* Similar to WM_operator_name_call called with WM_OP_EXEC_DEFAULT context.
516    - wmOperatorType is used instead of operator name since python alredy has the operator type
517    - poll() must be called by python before this runs.
518    - reports can be passed to this function (so python can report them as exceptions)
519 */
520 int WM_operator_call_py(bContext *C, wmOperatorType *ot, PointerRNA *properties, ReportList *reports)
521 {
522         wmWindowManager *wm=    CTX_wm_manager(C);
523         wmOperator *op=                 wm_operator_create(wm, ot, properties, reports);
524         int retval= OPERATOR_CANCELLED;
525         
526         if (op->type->exec)
527                 retval= op->type->exec(C, op);
528         else
529                 printf("error \"%s\" operator has no exec function, python cannot call it\n", op->type->name);
530         
531         if (reports)
532                 op->reports= NULL; /* dont let the operator free reports passed to this function */
533         WM_operator_free(op);
534         
535         return retval;
536 }
537
538
539 /* ********************* handlers *************** */
540
541 /* future extra customadata free? */
542 static void wm_event_free_handler(wmEventHandler *handler)
543 {
544         MEM_freeN(handler);
545 }
546
547 /* only set context when area/region is part of screen */
548 static void wm_handler_op_context(bContext *C, wmEventHandler *handler)
549 {
550         bScreen *screen= CTX_wm_screen(C);
551         
552         if(screen && handler->op) {
553                 if(handler->op_area==NULL)
554                         CTX_wm_area_set(C, NULL);
555                 else {
556                         ScrArea *sa;
557                         
558                         for(sa= screen->areabase.first; sa; sa= sa->next)
559                                 if(sa==handler->op_area)
560                                         break;
561                         if(sa==NULL) {
562                                 /* when changing screen layouts with running modal handlers (like render display), this
563                                    is not an error to print */
564                                 if(handler->op==NULL)
565                                         printf("internal error: handler (%s) has invalid area\n", handler->op->type->idname);
566                         }
567                         else {
568                                 ARegion *ar;
569                                 CTX_wm_area_set(C, sa);
570                                 for(ar= sa->regionbase.first; ar; ar= ar->next)
571                                         if(ar==handler->op_region)
572                                                 break;
573                                 /* XXX no warning print here, after full-area and back regions are remade */
574                                 if(ar)
575                                         CTX_wm_region_set(C, ar);
576                         }
577                 }
578         }
579 }
580
581 /* called on exit or remove area, only here call cancel callback */
582 void WM_event_remove_handlers(bContext *C, ListBase *handlers)
583 {
584         wmEventHandler *handler;
585         
586         /* C is zero on freeing database, modal handlers then already were freed */
587         while((handler=handlers->first)) {
588                 BLI_remlink(handlers, handler);
589                 
590                 if(handler->op) {
591                         if(handler->op->type->cancel) {
592                                 ScrArea *area= CTX_wm_area(C);
593                                 ARegion *region= CTX_wm_region(C);
594                                 
595                                 wm_handler_op_context(C, handler);
596
597                                 handler->op->type->cancel(C, handler->op);
598
599                                 CTX_wm_area_set(C, area);
600                                 CTX_wm_region_set(C, region);
601                         }
602
603                         WM_operator_free(handler->op);
604                         WM_cursor_grab(CTX_wm_window(C), 0);
605                 }
606                 else if(handler->ui_remove) {
607                         ScrArea *area= CTX_wm_area(C);
608                         ARegion *region= CTX_wm_region(C);
609                         ARegion *menu= CTX_wm_menu(C);
610                         
611                         if(handler->ui_area) CTX_wm_area_set(C, handler->ui_area);
612                         if(handler->ui_region) CTX_wm_region_set(C, handler->ui_region);
613                         if(handler->ui_menu) CTX_wm_menu_set(C, handler->ui_menu);
614
615                         handler->ui_remove(C, handler->ui_userdata);
616
617                         CTX_wm_area_set(C, area);
618                         CTX_wm_region_set(C, region);
619                         CTX_wm_menu_set(C, menu);
620                 }
621
622                 wm_event_free_handler(handler);
623         }
624 }
625
626 /* do userdef mappings */
627 static int wm_userdef_event_map(int kmitype)
628 {
629         switch(kmitype) {
630                 case SELECTMOUSE:
631                         if(U.flag & USER_LMOUSESELECT)
632                                 return LEFTMOUSE;
633                         else
634                                 return RIGHTMOUSE;
635                         
636                 case ACTIONMOUSE:
637                         if(U.flag & USER_LMOUSESELECT)
638                                 return RIGHTMOUSE;
639                         else
640                                 return LEFTMOUSE;
641                         
642                 case WHEELOUTMOUSE:
643                         if(U.uiflag & USER_WHEELZOOMDIR)
644                                 return WHEELUPMOUSE;
645                         else
646                                 return WHEELDOWNMOUSE;
647                         
648                 case WHEELINMOUSE:
649                         if(U.uiflag & USER_WHEELZOOMDIR)
650                                 return WHEELDOWNMOUSE;
651                         else
652                                 return WHEELUPMOUSE;
653                         
654                 case EVT_TWEAK_A:
655                         if(U.flag & USER_LMOUSESELECT)
656                                 return EVT_TWEAK_R;
657                         else
658                                 return EVT_TWEAK_L;
659                         
660                 case EVT_TWEAK_S:
661                         if(U.flag & USER_LMOUSESELECT)
662                                 return EVT_TWEAK_L;
663                         else
664                                 return EVT_TWEAK_R;
665         }
666         
667         return kmitype;
668 }
669
670 static int wm_eventmatch(wmEvent *winevent, wmKeymapItem *kmi)
671 {
672         int kmitype= wm_userdef_event_map(kmi->type);
673
674         if(kmi->inactive) return 0;
675
676         /* exception for middlemouse emulation */
677         if((U.flag & USER_TWOBUTTONMOUSE) && (kmi->type == MIDDLEMOUSE)) {
678                 if(winevent->type == LEFTMOUSE && winevent->alt) {
679                         wmKeymapItem tmp= *kmi;
680
681                         tmp.type= winevent->type;
682                         tmp.alt= winevent->alt;
683                         if(wm_eventmatch(winevent, &tmp))
684                                 return 1;
685                 }
686         }
687
688         /* the matching rules */
689         if(kmitype==KM_TEXTINPUT)
690                 if(ISKEYBOARD(winevent->type)) return 1;
691         if(kmitype!=KM_ANY)
692                 if(winevent->type!=kmitype) return 0;
693         
694         if(kmi->val!=KM_ANY)
695                 if(winevent->val!=kmi->val) return 0;
696         
697         /* modifiers also check bits, so it allows modifier order */
698         if(kmi->shift!=KM_ANY)
699                 if(winevent->shift != kmi->shift && !(winevent->shift & kmi->shift)) return 0;
700         if(kmi->ctrl!=KM_ANY)
701                 if(winevent->ctrl != kmi->ctrl && !(winevent->ctrl & kmi->ctrl)) return 0;
702         if(kmi->alt!=KM_ANY)
703                 if(winevent->alt != kmi->alt && !(winevent->alt & kmi->alt)) return 0;
704         if(kmi->oskey!=KM_ANY)
705                 if(winevent->oskey != kmi->oskey && !(winevent->oskey & kmi->oskey)) return 0;
706         
707         if(kmi->keymodifier)
708                 if(winevent->keymodifier!=kmi->keymodifier) return 0;
709                 
710         /* key modifiers always check when event has it */
711         /* otherwise regular keypresses with keymodifier still work */
712         if(winevent->keymodifier)
713                 if(ISKEYBOARD(winevent->type)) 
714                         if(winevent->keymodifier!=kmi->keymodifier) return 0;
715         
716         return 1;
717 }
718
719 static int wm_event_always_pass(wmEvent *event)
720 {
721         /* some events we always pass on, to ensure proper communication */
722         return ELEM5(event->type, TIMER, TIMER0, TIMER1, TIMER2, TIMERJOBS);
723 }
724
725 /* operator exists */
726 static void wm_event_modalkeymap(wmOperator *op, wmEvent *event)
727 {
728         if(op->type->modalkeymap) {
729                 wmKeymapItem *kmi;
730                 
731                 for(kmi= op->type->modalkeymap->keymap.first; kmi; kmi= kmi->next) {
732                         if(wm_eventmatch(event, kmi)) {
733                                         
734                                 event->type= EVT_MODAL_MAP;
735                                 event->val= kmi->propvalue;
736                         }
737                 }
738         }
739 }
740
741 /* Warning: this function removes a modal handler, when finished */
742 static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHandler *handler, wmEvent *event, PointerRNA *properties)
743 {
744         int retval= OPERATOR_PASS_THROUGH;
745         
746         /* derived, modal or blocking operator */
747         if(handler->op) {
748                 wmOperator *op= handler->op;
749                 wmOperatorType *ot= op->type;
750
751                 if(ot->modal) {
752                         /* we set context to where modal handler came from */
753                         ScrArea *area= CTX_wm_area(C);
754                         ARegion *region= CTX_wm_region(C);
755                         
756                         wm_handler_op_context(C, handler);
757                         wm_region_mouse_co(C, event);
758                         wm_event_modalkeymap(op, event);
759                         
760                         retval= ot->modal(C, op, event);
761
762                         /* putting back screen context, reval can pass trough after modal failures! */
763                         if((retval & OPERATOR_PASS_THROUGH) || wm_event_always_pass(event)) {
764                                 CTX_wm_area_set(C, area);
765                                 CTX_wm_region_set(C, region);
766                         }
767                         else {
768                                 /* this special cases is for areas and regions that get removed */
769                                 CTX_wm_area_set(C, NULL);
770                                 CTX_wm_region_set(C, NULL);
771                         }
772
773                         if(!(retval & OPERATOR_RUNNING_MODAL))
774                                 if(op->reports->list.first)
775                                         uiPupMenuReports(C, op->reports);
776
777                         if (retval & OPERATOR_FINISHED) {
778                                 if(G.f & G_DEBUG)
779                                         wm_operator_print(op); /* todo - this print may double up, might want to check more flags then the FINISHED */
780                         }                       
781
782                         if(retval & OPERATOR_FINISHED) {
783                                 if(ot->flag & OPTYPE_UNDO)
784                                         ED_undo_push_op(C, op);
785                                 
786                                 if((ot->flag & OPTYPE_REGISTER) || (G.f & G_DEBUG))
787                                         wm_operator_register(C, op);
788                                 else
789                                         WM_operator_free(op);
790                                 handler->op= NULL;
791                         }
792                         else if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) {
793                                 WM_operator_free(op);
794                                 handler->op= NULL;
795                         }
796                         
797                         /* remove modal handler, operator itself should have been cancelled and freed */
798                         if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) {
799                                 WM_cursor_grab(CTX_wm_window(C), 0);
800
801                                 BLI_remlink(handlers, handler);
802                                 wm_event_free_handler(handler);
803                                 
804                                 /* prevent silly errors from operator users */
805                                 //retval &= ~OPERATOR_PASS_THROUGH;
806                         }
807                         
808                 }
809                 else
810                         printf("wm_handler_operator_call error\n");
811         }
812         else {
813                 wmOperatorType *ot= WM_operatortype_find(event->keymap_idname, 0);
814
815                 if(ot)
816                         retval= wm_operator_invoke(C, ot, event, properties);
817         }
818
819         if(retval & OPERATOR_PASS_THROUGH)
820                 return WM_HANDLER_CONTINUE;
821
822         return WM_HANDLER_BREAK;
823 }
824
825 static int wm_handler_ui_call(bContext *C, wmEventHandler *handler, wmEvent *event)
826 {
827         ScrArea *area= CTX_wm_area(C);
828         ARegion *region= CTX_wm_region(C);
829         ARegion *menu= CTX_wm_menu(C);
830         int retval, always_pass;
831                         
832         /* we set context to where ui handler came from */
833         if(handler->ui_area) CTX_wm_area_set(C, handler->ui_area);
834         if(handler->ui_region) CTX_wm_region_set(C, handler->ui_region);
835         if(handler->ui_menu) CTX_wm_menu_set(C, handler->ui_menu);
836
837         /* in advance to avoid access to freed event on window close */
838         always_pass= wm_event_always_pass(event);
839
840         retval= handler->ui_handle(C, event, handler->ui_userdata);
841
842         /* putting back screen context */
843         if((retval != WM_UI_HANDLER_BREAK) || always_pass) {
844                 CTX_wm_area_set(C, area);
845                 CTX_wm_region_set(C, region);
846                 CTX_wm_menu_set(C, menu);
847         }
848         else {
849                 /* this special cases is for areas and regions that get removed */
850                 CTX_wm_area_set(C, NULL);
851                 CTX_wm_region_set(C, NULL);
852                 CTX_wm_menu_set(C, NULL);
853         }
854
855         if(retval == WM_UI_HANDLER_BREAK)
856                 return WM_HANDLER_BREAK;
857
858         return WM_HANDLER_CONTINUE;
859 }
860
861 /* fileselect handlers are only in the window queue, so it's save to switch screens or area types */
862 static int wm_handler_fileselect_call(bContext *C, ListBase *handlers, wmEventHandler *handler, wmEvent *event)
863 {
864         SpaceFile *sfile;
865         int action= WM_HANDLER_CONTINUE;
866         
867         if(event->type != EVT_FILESELECT)
868                 return action;
869         if(handler->op != (wmOperator *)event->customdata)
870                 return action;
871         
872         switch(event->val) {
873                 case EVT_FILESELECT_OPEN: 
874                 case EVT_FILESELECT_FULL_OPEN: 
875                         {
876                                 char *dir= NULL; char *path= RNA_string_get_alloc(handler->op->ptr, "filename", NULL, 0);
877                                         
878                                 if(event->val==EVT_FILESELECT_OPEN)
879                                         ED_area_newspace(C, handler->op_area, SPACE_FILE);
880                                 else
881                                         ED_screen_full_newspace(C, handler->op_area, SPACE_FILE);
882                                 
883                                 /* settings for filebrowser, sfile is not operator owner but sends events */
884                                 sfile= (SpaceFile*)CTX_wm_space_data(C);
885                                 sfile->op= handler->op;
886
887                                 ED_fileselect_set_params(sfile);
888                                 dir = NULL;
889                                 MEM_freeN(path);
890                                 
891                                 action= WM_HANDLER_BREAK;
892                         }
893                         break;
894                         
895                 case EVT_FILESELECT_EXEC:
896                 case EVT_FILESELECT_CANCEL:
897                         {
898                                 /* XXX validate area and region? */
899                                 bScreen *screen= CTX_wm_screen(C);
900                                 char *path= RNA_string_get_alloc(handler->op->ptr, "filename", NULL, 0);
901                                 
902                                 if(screen != handler->filescreen)
903                                         ED_screen_full_prevspace(C);
904                                 else
905                                         ED_area_prevspace(C);
906                                 
907                                 /* remlink now, for load file case */
908                                 BLI_remlink(handlers, handler);
909                                 
910                                 if(event->val==EVT_FILESELECT_EXEC) {
911                                         wm_handler_op_context(C, handler);
912                                 
913                                         /* a bit weak, might become arg for WM_event_fileselect? */
914                                         /* XXX also extension code in image-save doesnt work for this yet */
915                                         if(strncmp(handler->op->type->name, "Save", 4)==0) {
916                                                 /* this gives ownership to pupmenu */
917                                                 uiPupMenuSaveOver(C, handler->op, path);
918                                         }
919                                         else {
920                                                 int retval= handler->op->type->exec(C, handler->op);
921                                                 
922                                                 if (retval & OPERATOR_FINISHED)
923                                                         if(G.f & G_DEBUG)
924                                                                 wm_operator_print(handler->op);
925                                                 
926                                                 WM_operator_free(handler->op);
927                                         }
928                                         
929                                         CTX_wm_area_set(C, NULL);
930                                 }
931                                 else 
932                                         WM_operator_free(handler->op);
933                                 
934                                 wm_event_free_handler(handler);
935                                 MEM_freeN(path);
936                                 
937                                 action= WM_HANDLER_BREAK;
938                         }
939                         break;
940         }
941         
942         return action;
943 }
944
945 static int handler_boundbox_test(wmEventHandler *handler, wmEvent *event)
946 {
947         if(handler->bbwin) {
948                 if(handler->bblocal) {
949                         rcti rect= *handler->bblocal;
950                         BLI_translate_rcti(&rect, handler->bbwin->xmin, handler->bbwin->ymin);
951
952                         if(BLI_in_rcti(&rect, event->x, event->y))
953                                 return 1;
954                         else if(event->type==MOUSEMOVE && BLI_in_rcti(&rect, event->prevx, event->prevy))
955                                 return 1;
956                         else
957                                 return 0;
958                 }
959                 else {
960                         if(BLI_in_rcti(handler->bbwin, event->x, event->y))
961                                 return 1;
962                         else if(event->type==MOUSEMOVE && BLI_in_rcti(handler->bbwin, event->prevx, event->prevy))
963                                 return 1;
964                         else
965                                 return 0;
966                 }
967         }
968         return 1;
969 }
970
971 static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
972 {
973         wmEventHandler *handler, *nexthandler;
974         int action= WM_HANDLER_CONTINUE;
975         int always_pass;
976
977         if(handlers==NULL) return action;
978         
979         /* modal handlers can get removed in this loop, we keep the loop this way */
980         for(handler= handlers->first; handler; handler= nexthandler) {
981                 nexthandler= handler->next;
982
983                 /* optional boundbox */
984                 if(handler_boundbox_test(handler, event)) {
985                         /* in advance to avoid access to freed event on window close */
986                         always_pass= wm_event_always_pass(event);
987                 
988                         /* modal+blocking handler */
989                         if(handler->flag & WM_HANDLER_BLOCKING)
990                                 action= WM_HANDLER_BREAK;
991
992                         if(handler->keymap) {
993                                 wmKeymapItem *kmi;
994                                 
995                                 for(kmi= handler->keymap->first; kmi; kmi= kmi->next) {
996                                         if(wm_eventmatch(event, kmi)) {
997                                                 
998                                                 event->keymap_idname= kmi->idname;      /* weak, but allows interactive callback to not use rawkey */
999                                                 
1000                                                 action= wm_handler_operator_call(C, handlers, handler, event, kmi->ptr);
1001                                                 if(action==WM_HANDLER_BREAK)  /* not wm_event_always_pass(event) here, it denotes removed handler */
1002                                                         break;
1003                                         }
1004                                 }
1005                         }
1006                         else if(handler->ui_handle) {
1007                                 action= wm_handler_ui_call(C, handler, event);
1008                         }
1009                         else if(handler->type==WM_HANDLER_FILESELECT) {
1010                                 /* screen context changes here */
1011                                 action= wm_handler_fileselect_call(C, handlers, handler, event);
1012                         }
1013                         else {
1014                                 /* modal, swallows all */
1015                                 action= wm_handler_operator_call(C, handlers, handler, event, NULL);
1016                         }
1017
1018                         if(!always_pass && action==WM_HANDLER_BREAK)
1019                                 break;
1020                 }
1021                 
1022                 /* fileread case */
1023                 if(CTX_wm_window(C)==NULL)
1024                         break;
1025         }
1026         return action;
1027 }
1028
1029 static int wm_event_inside_i(wmEvent *event, rcti *rect)
1030 {
1031         if(BLI_in_rcti(rect, event->x, event->y))
1032            return 1;
1033         if(event->type==MOUSEMOVE) {
1034                 if( BLI_in_rcti(rect, event->prevx, event->prevy)) {
1035                         return 1;
1036                 }
1037                 return 0;
1038         }
1039         return 0;
1040 }
1041
1042 static ScrArea *area_event_inside(bContext *C, int x, int y)
1043 {
1044         bScreen *screen= CTX_wm_screen(C);
1045         ScrArea *sa;
1046         
1047         if(screen)
1048                 for(sa= screen->areabase.first; sa; sa= sa->next)
1049                         if(BLI_in_rcti(&sa->totrct, x, y))
1050                                 return sa;
1051         return NULL;
1052 }
1053
1054 static ARegion *region_event_inside(bContext *C, int x, int y)
1055 {
1056         bScreen *screen= CTX_wm_screen(C);
1057         ScrArea *area= CTX_wm_area(C);
1058         ARegion *ar;
1059         
1060         if(screen && area)
1061                 for(ar= area->regionbase.first; ar; ar= ar->next)
1062                         if(BLI_in_rcti(&ar->winrct, x, y))
1063                                 return ar;
1064         return NULL;
1065 }
1066
1067 static void wm_paintcursor_tag(bContext *C, wmPaintCursor *pc, ARegion *ar)
1068 {
1069         if(ar) {
1070                 for(; pc; pc= pc->next) {
1071                         if(pc->poll(C)) {
1072                                 wmWindow *win= CTX_wm_window(C);
1073                                 win->screen->do_draw_paintcursor= 1;
1074
1075                                 if(win->drawmethod != USER_DRAW_TRIPLE)
1076                                         ED_region_tag_redraw(ar);
1077                         }
1078                 }
1079         }
1080 }
1081
1082 /* called on mousemove, check updates for paintcursors */
1083 /* context was set on active area and region */
1084 static void wm_paintcursor_test(bContext *C, wmEvent *event)
1085 {
1086         wmWindowManager *wm= CTX_wm_manager(C);
1087         
1088         if(wm->paintcursors.first) {
1089                 ARegion *ar= CTX_wm_region(C);
1090                 if(ar)
1091                         wm_paintcursor_tag(C, wm->paintcursors.first, ar);
1092                 
1093                 /* if previous position was not in current region, we have to set a temp new context */
1094                 if(ar==NULL || !BLI_in_rcti(&ar->winrct, event->prevx, event->prevy)) {
1095                         ScrArea *sa= CTX_wm_area(C);
1096                         
1097                         CTX_wm_area_set(C, area_event_inside(C, event->prevx, event->prevy));
1098                         CTX_wm_region_set(C, region_event_inside(C, event->prevx, event->prevy));
1099
1100                         wm_paintcursor_tag(C, wm->paintcursors.first, CTX_wm_region(C));
1101                         
1102                         CTX_wm_area_set(C, sa);
1103                         CTX_wm_region_set(C, ar);
1104                 }
1105         }
1106 }
1107
1108 /* called in main loop */
1109 /* goes over entire hierarchy:  events -> window -> screen -> area -> region */
1110 void wm_event_do_handlers(bContext *C)
1111 {
1112         wmWindow *win;
1113
1114         for(win= CTX_wm_manager(C)->windows.first; win; win= win->next) {
1115                 wmEvent *event;
1116                 
1117                 if( win->screen==NULL )
1118                         wm_event_free_all(win);
1119                 
1120                 while( (event= win->queue.first) ) {
1121                         int action;
1122                         
1123                         CTX_wm_window_set(C, win);
1124                         
1125                         /* we let modal handlers get active area/region, also wm_paintcursor_test needs it */
1126                         CTX_wm_area_set(C, area_event_inside(C, event->x, event->y));
1127                         CTX_wm_region_set(C, region_event_inside(C, event->x, event->y));
1128                         
1129                         /* MVC demands to not draw in event handlers... but we need to leave it for ogl selecting etc */
1130                         wm_window_make_drawable(C, win);
1131                         
1132                         action= wm_handlers_do(C, event, &win->handlers);
1133                         
1134                         /* fileread case */
1135                         if(CTX_wm_window(C)==NULL) {
1136                                 return;
1137                         }
1138                         
1139                         /* builtin tweak, if action is break it removes tweak */
1140                         if(!wm_event_always_pass(event))
1141                                 wm_tweakevent_test(C, event, action);
1142                         
1143                         if(wm_event_always_pass(event) || action==WM_HANDLER_CONTINUE) {
1144                                 ScrArea *sa;
1145                                 ARegion *ar;
1146                                 int doit= 0;
1147                                 
1148                                 /* XXX to solve, here screen handlers? */
1149                                 if(!wm_event_always_pass(event)) {
1150                                         if(event->type==MOUSEMOVE) {
1151                                                 /* state variables in screen, cursors */
1152                                                 ED_screen_set_subwinactive(win, event); 
1153                                                 /* for regions having custom cursors */
1154                                                 wm_paintcursor_test(C, event);
1155                                         }
1156                                 }
1157                                 
1158                                 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
1159                                         if(wm_event_always_pass(event) || wm_event_inside_i(event, &sa->totrct)) {
1160                                                 
1161                                                 CTX_wm_area_set(C, sa);
1162                                                 CTX_wm_region_set(C, NULL);
1163                                                 action= wm_handlers_do(C, event, &sa->handlers);
1164
1165                                                 if(wm_event_always_pass(event) || action==WM_HANDLER_CONTINUE) {
1166                                                         for(ar=sa->regionbase.first; ar; ar= ar->next) {
1167                                                                 if(wm_event_always_pass(event) || wm_event_inside_i(event, &ar->winrct)) {
1168                                                                         CTX_wm_region_set(C, ar);
1169                                                                         action= wm_handlers_do(C, event, &ar->handlers);
1170
1171                                                                         doit |= (BLI_in_rcti(&ar->winrct, event->x, event->y));
1172                                                                         
1173                                                                         if(!wm_event_always_pass(event)) {
1174                                                                                 if(action==WM_HANDLER_BREAK)
1175                                                                                         break;
1176                                                                         }
1177                                                                 }
1178                                                         }
1179                                                 }
1180                                                 /* NOTE: do not escape on WM_HANDLER_BREAK, mousemove needs handled for previous area */
1181                                         }
1182                                 }
1183                                 
1184                                 /* XXX hrmf, this gives reliable previous mouse coord for area change, feels bad? 
1185                                    doing it on ghost queue gives errors when mousemoves go over area borders */
1186                                 if(doit && win->screen->subwinactive != win->screen->mainwin) {
1187                                         win->eventstate->prevx= event->x;
1188                                         win->eventstate->prevy= event->y;
1189                                 }
1190                         }
1191                         
1192                         /* unlink and free here, blender-quit then frees all */
1193                         BLI_remlink(&win->queue, event);
1194                         wm_event_free(event);
1195                         
1196                 }
1197                 
1198                 /* only add mousemove when queue was read entirely */
1199                 if(win->addmousemove) {
1200                         wmEvent event= *(win->eventstate);
1201                         event.type= MOUSEMOVE;
1202                         event.prevx= event.x;
1203                         event.prevy= event.y;
1204                         wm_event_add(win, &event);
1205                         win->addmousemove= 0;
1206                 }
1207                 
1208                 CTX_wm_window_set(C, NULL);
1209         }
1210 }
1211
1212 /* ********** filesector handling ************ */
1213
1214 void WM_event_fileselect_event(bContext *C, void *ophandle, int eventval)
1215 {
1216         /* add to all windows! */
1217         wmWindow *win;
1218         
1219         for(win= CTX_wm_manager(C)->windows.first; win; win= win->next) {
1220                 wmEvent event= *win->eventstate;
1221                 
1222                 event.type= EVT_FILESELECT;
1223                 event.val= eventval;
1224                 event.customdata= ophandle;             // only as void pointer type check
1225
1226                 wm_event_add(win, &event);
1227         }
1228 }
1229
1230 /* operator is supposed to have a filled "filename" property */
1231 /* optional property: filetype (XXX enum?) */
1232
1233 /* Idea is to keep a handler alive on window queue, owning the operator.
1234    The filewindow can send event to make it execute, thus ensuring
1235    executing happens outside of lower level queues, with UI refreshed. 
1236    Should also allow multiwin solutions */
1237
1238 void WM_event_add_fileselect(bContext *C, wmOperator *op)
1239 {
1240         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "fileselect handler");
1241         wmWindow *win= CTX_wm_window(C);
1242         int full= 1;    // XXX preset?
1243         
1244         handler->type= WM_HANDLER_FILESELECT;
1245         handler->op= op;
1246         handler->op_area= CTX_wm_area(C);
1247         handler->op_region= CTX_wm_region(C);
1248         handler->filescreen= CTX_wm_screen(C);
1249         
1250         BLI_addhead(&win->handlers, handler);
1251         
1252         WM_event_fileselect_event(C, op, full?EVT_FILESELECT_FULL_OPEN:EVT_FILESELECT_OPEN);
1253 }
1254
1255 /* lets not expose struct outside wm? */
1256 void WM_event_set_handler_flag(wmEventHandler *handler, int flag)
1257 {
1258         handler->flag= flag;
1259 }
1260
1261 wmEventHandler *WM_event_add_modal_handler(bContext *C, ListBase *handlers, wmOperator *op)
1262 {
1263         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event modal handler");
1264         
1265         /* operator was part of macro */
1266         if(op->opm) {
1267                 /* give the mother macro to the handler */
1268                 handler->op= op->opm;
1269                 /* mother macro opm becomes the macro element */
1270                 handler->op->opm= op;
1271         }
1272         else
1273                 handler->op= op;
1274         
1275         handler->op_area= CTX_wm_area(C);               /* means frozen screen context for modal handlers! */
1276         handler->op_region= CTX_wm_region(C);
1277         
1278         BLI_addhead(handlers, handler);
1279
1280         return handler;
1281 }
1282
1283 wmEventHandler *WM_event_add_keymap_handler(ListBase *handlers, ListBase *keymap)
1284 {
1285         wmEventHandler *handler;
1286
1287         /* only allow same keymap once */
1288         for(handler= handlers->first; handler; handler= handler->next)
1289                 if(handler->keymap==keymap)
1290                         return handler;
1291         
1292         handler= MEM_callocN(sizeof(wmEventHandler), "event keymap handler");
1293         BLI_addtail(handlers, handler);
1294         handler->keymap= keymap;
1295
1296         return handler;
1297 }
1298
1299 /* priorities not implemented yet, for time being just insert in begin of list */
1300 wmEventHandler *WM_event_add_keymap_handler_priority(ListBase *handlers, ListBase *keymap, int priority)
1301 {
1302         wmEventHandler *handler;
1303         
1304         WM_event_remove_keymap_handler(handlers, keymap);
1305         
1306         handler= MEM_callocN(sizeof(wmEventHandler), "event keymap handler");
1307         BLI_addhead(handlers, handler);
1308         handler->keymap= keymap;
1309         
1310         return handler;
1311 }
1312
1313 wmEventHandler *WM_event_add_keymap_handler_bb(ListBase *handlers, ListBase *keymap, rcti *bblocal, rcti *bbwin)
1314 {
1315         wmEventHandler *handler= WM_event_add_keymap_handler(handlers, keymap);
1316         
1317         if(handler) {
1318                 handler->bblocal= bblocal;
1319                 handler->bbwin= bbwin;
1320         }
1321         return handler;
1322 }
1323
1324 void WM_event_remove_keymap_handler(ListBase *handlers, ListBase *keymap)
1325 {
1326         wmEventHandler *handler;
1327         
1328         for(handler= handlers->first; handler; handler= handler->next) {
1329                 if(handler->keymap==keymap) {
1330                         BLI_remlink(handlers, handler);
1331                         wm_event_free_handler(handler);
1332                         break;
1333                 }
1334         }
1335 }
1336
1337 wmEventHandler *WM_event_add_ui_handler(const bContext *C, ListBase *handlers, wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata)
1338 {
1339         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event ui handler");
1340         handler->ui_handle= func;
1341         handler->ui_remove= remove;
1342         handler->ui_userdata= userdata;
1343         handler->ui_area= (C)? CTX_wm_area(C): NULL;
1344         handler->ui_region= (C)? CTX_wm_region(C): NULL;
1345         handler->ui_menu= (C)? CTX_wm_menu(C): NULL;
1346         
1347         BLI_addhead(handlers, handler);
1348         
1349         return handler;
1350 }
1351
1352 void WM_event_remove_ui_handler(ListBase *handlers, wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata)
1353 {
1354         wmEventHandler *handler;
1355         
1356         for(handler= handlers->first; handler; handler= handler->next) {
1357                 if(handler->ui_handle == func && handler->ui_remove == remove && handler->ui_userdata == userdata) {
1358                         BLI_remlink(handlers, handler);
1359                         wm_event_free_handler(handler);
1360                         break;
1361                 }
1362         }
1363 }
1364
1365 void WM_event_add_mousemove(bContext *C)
1366 {
1367         wmWindow *window= CTX_wm_window(C);
1368         
1369         window->addmousemove= 1;
1370 }
1371
1372 /* for modal callbacks, check configuration for how to interpret exit with tweaks  */
1373 int WM_modal_tweak_exit(wmEvent *evt, int tweak_event)
1374 {
1375         /* user preset or keymap? dunno... */
1376         int tweak_modal= (U.flag & USER_DRAGIMMEDIATE)==0;
1377         
1378         switch(tweak_event) {
1379                 case EVT_TWEAK_L:
1380                 case EVT_TWEAK_M:
1381                 case EVT_TWEAK_R:
1382                         if(evt->val==tweak_modal)
1383                                 return 1;
1384                 default:
1385                         /* this case is when modal callcback didnt get started with a tweak */
1386                         if(evt->val)
1387                                 return 1;
1388         }
1389         return 0;
1390 }
1391
1392
1393 /* ********************* ghost stuff *************** */
1394
1395 static int convert_key(GHOST_TKey key) 
1396 {
1397         if (key>=GHOST_kKeyA && key<=GHOST_kKeyZ) {
1398                 return (AKEY + ((int) key - GHOST_kKeyA));
1399         } else if (key>=GHOST_kKey0 && key<=GHOST_kKey9) {
1400                 return (ZEROKEY + ((int) key - GHOST_kKey0));
1401         } else if (key>=GHOST_kKeyNumpad0 && key<=GHOST_kKeyNumpad9) {
1402                 return (PAD0 + ((int) key - GHOST_kKeyNumpad0));
1403         } else if (key>=GHOST_kKeyF1 && key<=GHOST_kKeyF12) {
1404                 return (F1KEY + ((int) key - GHOST_kKeyF1));
1405         } else {
1406                 switch (key) {
1407                         case GHOST_kKeyBackSpace:               return BACKSPACEKEY;
1408                         case GHOST_kKeyTab:                             return TABKEY;
1409                         case GHOST_kKeyLinefeed:                return LINEFEEDKEY;
1410                         case GHOST_kKeyClear:                   return 0;
1411                         case GHOST_kKeyEnter:                   return RETKEY;
1412                                 
1413                         case GHOST_kKeyEsc:                             return ESCKEY;
1414                         case GHOST_kKeySpace:                   return SPACEKEY;
1415                         case GHOST_kKeyQuote:                   return QUOTEKEY;
1416                         case GHOST_kKeyComma:                   return COMMAKEY;
1417                         case GHOST_kKeyMinus:                   return MINUSKEY;
1418                         case GHOST_kKeyPeriod:                  return PERIODKEY;
1419                         case GHOST_kKeySlash:                   return SLASHKEY;
1420                                 
1421                         case GHOST_kKeySemicolon:               return SEMICOLONKEY;
1422                         case GHOST_kKeyEqual:                   return EQUALKEY;
1423                                 
1424                         case GHOST_kKeyLeftBracket:             return LEFTBRACKETKEY;
1425                         case GHOST_kKeyRightBracket:    return RIGHTBRACKETKEY;
1426                         case GHOST_kKeyBackslash:               return BACKSLASHKEY;
1427                         case GHOST_kKeyAccentGrave:             return ACCENTGRAVEKEY;
1428                                 
1429                         case GHOST_kKeyLeftShift:               return LEFTSHIFTKEY;
1430                         case GHOST_kKeyRightShift:              return RIGHTSHIFTKEY;
1431                         case GHOST_kKeyLeftControl:             return LEFTCTRLKEY;
1432                         case GHOST_kKeyRightControl:    return RIGHTCTRLKEY;
1433                         case GHOST_kKeyCommand:                 return COMMANDKEY;
1434                         case GHOST_kKeyLeftAlt:                 return LEFTALTKEY;
1435                         case GHOST_kKeyRightAlt:                return RIGHTALTKEY;
1436                                 
1437                         case GHOST_kKeyCapsLock:                return CAPSLOCKKEY;
1438                         case GHOST_kKeyNumLock:                 return 0;
1439                         case GHOST_kKeyScrollLock:              return 0;
1440                                 
1441                         case GHOST_kKeyLeftArrow:               return LEFTARROWKEY;
1442                         case GHOST_kKeyRightArrow:              return RIGHTARROWKEY;
1443                         case GHOST_kKeyUpArrow:                 return UPARROWKEY;
1444                         case GHOST_kKeyDownArrow:               return DOWNARROWKEY;
1445                                 
1446                         case GHOST_kKeyPrintScreen:             return 0;
1447                         case GHOST_kKeyPause:                   return PAUSEKEY;
1448                                 
1449                         case GHOST_kKeyInsert:                  return INSERTKEY;
1450                         case GHOST_kKeyDelete:                  return DELKEY;
1451                         case GHOST_kKeyHome:                    return HOMEKEY;
1452                         case GHOST_kKeyEnd:                             return ENDKEY;
1453                         case GHOST_kKeyUpPage:                  return PAGEUPKEY;
1454                         case GHOST_kKeyDownPage:                return PAGEDOWNKEY;
1455                                 
1456                         case GHOST_kKeyNumpadPeriod:    return PADPERIOD;
1457                         case GHOST_kKeyNumpadEnter:             return PADENTER;
1458                         case GHOST_kKeyNumpadPlus:              return PADPLUSKEY;
1459                         case GHOST_kKeyNumpadMinus:             return PADMINUS;
1460                         case GHOST_kKeyNumpadAsterisk:  return PADASTERKEY;
1461                         case GHOST_kKeyNumpadSlash:             return PADSLASHKEY;
1462                                 
1463                         case GHOST_kKeyGrLess:              return GRLESSKEY; 
1464                                 
1465                         default:
1466                                 return UNKNOWNKEY;      /* GHOST_kKeyUnknown */
1467                 }
1468         }
1469 }
1470
1471 /* adds customdata to event */
1472 static void update_tablet_data(wmWindow *win, wmEvent *event)
1473 {
1474         const GHOST_TabletData *td= GHOST_GetTabletData(win->ghostwin);
1475         
1476         /* if there's tablet data from an active tablet device then add it */
1477         if ((td != NULL) && td->Active) {
1478                 struct wmTabletData *wmtab= MEM_mallocN(sizeof(wmTabletData), "customdata tablet");
1479                 
1480                 wmtab->Active = td->Active;
1481                 wmtab->Pressure = td->Pressure;
1482                 wmtab->Xtilt = td->Xtilt;
1483                 wmtab->Ytilt = td->Ytilt;
1484                 
1485                 event->custom= EVT_DATA_TABLET;
1486                 event->customdata= wmtab;
1487                 event->customdatafree= 1;
1488         } 
1489 }
1490
1491
1492 /* windows store own event queues, no bContext here */
1493 void wm_event_add_ghostevent(wmWindow *win, int type, void *customdata)
1494 {
1495         wmEvent event, *evt= win->eventstate;
1496         
1497         /* initialize and copy state (only mouse x y and modifiers) */
1498         event= *evt;
1499         
1500         switch (type) {
1501                 /* mouse move */
1502                 case GHOST_kEventCursorMove: {
1503                         if(win->active) {
1504                                 GHOST_TEventCursorData *cd= customdata;
1505                                 int cx, cy;
1506
1507                                 GHOST_ScreenToClient(win->ghostwin, cd->x, cd->y, &cx, &cy);
1508                                 
1509                                 event.type= MOUSEMOVE;
1510                                 event.x= evt->x= cx;
1511                                 event.y= evt->y= (win->sizey-1) - cy;
1512                                 
1513                                 update_tablet_data(win, &event);
1514                                 wm_event_add(win, &event);
1515                         }
1516                         break;
1517                 }
1518                 /* mouse button */
1519                 case GHOST_kEventButtonDown:
1520                 case GHOST_kEventButtonUp: {
1521                         GHOST_TEventButtonData *bd= customdata;
1522                         event.val= (type==GHOST_kEventButtonDown);
1523                         
1524                         if (bd->button == GHOST_kButtonMaskLeft)
1525                                 event.type= LEFTMOUSE;
1526                         else if (bd->button == GHOST_kButtonMaskRight)
1527                                 event.type= RIGHTMOUSE;
1528                         else
1529                                 event.type= MIDDLEMOUSE;
1530                         
1531                         update_tablet_data(win, &event);
1532                         wm_event_add(win, &event);
1533                         
1534                         break;
1535                 }
1536                 /* keyboard */
1537                 case GHOST_kEventKeyDown:
1538                 case GHOST_kEventKeyUp: {
1539                         GHOST_TEventKeyData *kd= customdata;
1540                         event.type= convert_key(kd->key);
1541                         event.ascii= kd->ascii;
1542                         event.val= (type==GHOST_kEventKeyDown)?KM_PRESS:KM_RELEASE;
1543                         
1544                         /* exclude arrow keys, esc, etc from text input */
1545                         if(type==GHOST_kEventKeyUp || (event.ascii<32 && event.ascii>14))
1546                                 event.ascii= '\0';
1547                         
1548                         /* modifiers */
1549                         if (event.type==LEFTSHIFTKEY || event.type==RIGHTSHIFTKEY) {
1550                                 event.shift= evt->shift= (event.val==KM_PRESS);
1551                                 if(event.val==KM_PRESS && (evt->ctrl || evt->alt || evt->oskey))
1552                                    event.shift= evt->shift = 3;         // define?
1553                         } 
1554                         else if (event.type==LEFTCTRLKEY || event.type==RIGHTCTRLKEY) {
1555                                 event.ctrl= evt->ctrl= (event.val==KM_PRESS);
1556                                 if(event.val==KM_PRESS && (evt->shift || evt->alt || evt->oskey))
1557                                    event.ctrl= evt->ctrl = 3;           // define?
1558                         } 
1559                         else if (event.type==LEFTALTKEY || event.type==RIGHTALTKEY) {
1560                                 event.alt= evt->alt= (event.val==KM_PRESS);
1561                                 if(event.val==KM_PRESS && (evt->ctrl || evt->shift || evt->oskey))
1562                                    event.alt= evt->alt = 3;             // define?
1563                         } 
1564                         else if (event.type==COMMANDKEY) {
1565                                 event.oskey= evt->oskey= (event.val==KM_PRESS);
1566                                 if(event.val==KM_PRESS && (evt->ctrl || evt->alt || evt->shift))
1567                                    event.oskey= evt->oskey = 3;         // define?
1568                         }
1569                         else {
1570                                 if(event.val==KM_PRESS && event.keymodifier==0)
1571                                         evt->keymodifier= event.type; /* only set in eventstate, for next event */
1572                                 else if(event.val==KM_RELEASE && event.keymodifier==event.type)
1573                                         event.keymodifier= evt->keymodifier= 0;
1574                         }
1575                         
1576                         /* if test_break set, it catches this. XXX Keep global for now? */
1577                         if(event.type==ESCKEY)
1578                                 G.afbreek= 1;
1579
1580                         wm_event_add(win, &event);
1581                         
1582                         break;
1583                 }
1584                         
1585                 case GHOST_kEventWheel: {
1586                         GHOST_TEventWheelData* wheelData = customdata;
1587                         
1588                         if (wheelData->z > 0)
1589                                 event.type= WHEELUPMOUSE;
1590                         else
1591                                 event.type= WHEELDOWNMOUSE;
1592                         
1593                         event.val= KM_PRESS;
1594                         wm_event_add(win, &event);
1595                         
1596                         break;
1597                 }
1598                 case GHOST_kEventTimer: {
1599                         event.type= TIMER;
1600                         event.custom= EVT_DATA_TIMER;
1601                         event.customdata= customdata;
1602                         wm_event_add(win, &event);
1603
1604                         break;
1605                 }
1606
1607                 case GHOST_kEventUnknown:
1608                 case GHOST_kNumEventTypes:
1609                         break;
1610         }
1611 }