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