9d5bd13ea259ed307a8ff55f54ae79959ccead1b
[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                                 wmKeymapItem *kmi;
1018                                 
1019                                 for(kmi= handler->keymap->first; kmi; kmi= kmi->next) {
1020                                         if(wm_eventmatch(event, kmi)) {
1021                                                 
1022                                                 event->keymap_idname= kmi->idname;      /* weak, but allows interactive callback to not use rawkey */
1023                                                 
1024                                                 action= wm_handler_operator_call(C, handlers, handler, event, kmi->ptr);
1025                                                 if(action==WM_HANDLER_BREAK)  /* not wm_event_always_pass(event) here, it denotes removed handler */
1026                                                         break;
1027                                         }
1028                                 }
1029                         }
1030                         else if(handler->ui_handle) {
1031                                 action= wm_handler_ui_call(C, handler, event);
1032                         }
1033                         else if(handler->type==WM_HANDLER_FILESELECT) {
1034                                 /* screen context changes here */
1035                                 action= wm_handler_fileselect_call(C, handlers, handler, event);
1036                         }
1037                         else {
1038                                 /* modal, swallows all */
1039                                 action= wm_handler_operator_call(C, handlers, handler, event, NULL);
1040                         }
1041
1042                         if(!always_pass && action==WM_HANDLER_BREAK)
1043                                 break;
1044                 }
1045                 
1046                 /* fileread case */
1047                 if(CTX_wm_window(C)==NULL)
1048                         break;
1049         }
1050         return action;
1051 }
1052
1053 static int wm_event_inside_i(wmEvent *event, rcti *rect)
1054 {
1055         if(BLI_in_rcti(rect, event->x, event->y))
1056            return 1;
1057         if(event->type==MOUSEMOVE) {
1058                 if( BLI_in_rcti(rect, event->prevx, event->prevy)) {
1059                         return 1;
1060                 }
1061                 return 0;
1062         }
1063         return 0;
1064 }
1065
1066 static ScrArea *area_event_inside(bContext *C, int x, int y)
1067 {
1068         bScreen *screen= CTX_wm_screen(C);
1069         ScrArea *sa;
1070         
1071         if(screen)
1072                 for(sa= screen->areabase.first; sa; sa= sa->next)
1073                         if(BLI_in_rcti(&sa->totrct, x, y))
1074                                 return sa;
1075         return NULL;
1076 }
1077
1078 static ARegion *region_event_inside(bContext *C, int x, int y)
1079 {
1080         bScreen *screen= CTX_wm_screen(C);
1081         ScrArea *area= CTX_wm_area(C);
1082         ARegion *ar;
1083         
1084         if(screen && area)
1085                 for(ar= area->regionbase.first; ar; ar= ar->next)
1086                         if(BLI_in_rcti(&ar->winrct, x, y))
1087                                 return ar;
1088         return NULL;
1089 }
1090
1091 static void wm_paintcursor_tag(bContext *C, wmPaintCursor *pc, ARegion *ar)
1092 {
1093         if(ar) {
1094                 for(; pc; pc= pc->next) {
1095                         if(pc->poll(C)) {
1096                                 wmWindow *win= CTX_wm_window(C);
1097                                 win->screen->do_draw_paintcursor= 1;
1098
1099                                 if(win->drawmethod != USER_DRAW_TRIPLE)
1100                                         ED_region_tag_redraw(ar);
1101                         }
1102                 }
1103         }
1104 }
1105
1106 /* called on mousemove, check updates for paintcursors */
1107 /* context was set on active area and region */
1108 static void wm_paintcursor_test(bContext *C, wmEvent *event)
1109 {
1110         wmWindowManager *wm= CTX_wm_manager(C);
1111         
1112         if(wm->paintcursors.first) {
1113                 ARegion *ar= CTX_wm_region(C);
1114                 if(ar)
1115                         wm_paintcursor_tag(C, wm->paintcursors.first, ar);
1116                 
1117                 /* if previous position was not in current region, we have to set a temp new context */
1118                 if(ar==NULL || !BLI_in_rcti(&ar->winrct, event->prevx, event->prevy)) {
1119                         ScrArea *sa= CTX_wm_area(C);
1120                         
1121                         CTX_wm_area_set(C, area_event_inside(C, event->prevx, event->prevy));
1122                         CTX_wm_region_set(C, region_event_inside(C, event->prevx, event->prevy));
1123
1124                         wm_paintcursor_tag(C, wm->paintcursors.first, CTX_wm_region(C));
1125                         
1126                         CTX_wm_area_set(C, sa);
1127                         CTX_wm_region_set(C, ar);
1128                 }
1129         }
1130 }
1131
1132 /* called in main loop */
1133 /* goes over entire hierarchy:  events -> window -> screen -> area -> region */
1134 void wm_event_do_handlers(bContext *C)
1135 {
1136         wmWindow *win;
1137
1138         for(win= CTX_wm_manager(C)->windows.first; win; win= win->next) {
1139                 wmEvent *event;
1140                 
1141                 if( win->screen==NULL )
1142                         wm_event_free_all(win);
1143                 
1144                 while( (event= win->queue.first) ) {
1145                         int action;
1146                         
1147                         CTX_wm_window_set(C, win);
1148                         
1149                         /* we let modal handlers get active area/region, also wm_paintcursor_test needs it */
1150                         CTX_wm_area_set(C, area_event_inside(C, event->x, event->y));
1151                         CTX_wm_region_set(C, region_event_inside(C, event->x, event->y));
1152                         
1153                         /* MVC demands to not draw in event handlers... but we need to leave it for ogl selecting etc */
1154                         wm_window_make_drawable(C, win);
1155                         
1156                         action= wm_handlers_do(C, event, &win->handlers);
1157                         
1158                         /* fileread case */
1159                         if(CTX_wm_window(C)==NULL) {
1160                                 return;
1161                         }
1162                         
1163                         /* builtin tweak, if action is break it removes tweak */
1164                         if(!wm_event_always_pass(event))
1165                                 wm_tweakevent_test(C, event, action);
1166                         
1167                         if(wm_event_always_pass(event) || action==WM_HANDLER_CONTINUE) {
1168                                 ScrArea *sa;
1169                                 ARegion *ar;
1170                                 int doit= 0;
1171                                 
1172                                 /* XXX to solve, here screen handlers? */
1173                                 if(!wm_event_always_pass(event)) {
1174                                         if(event->type==MOUSEMOVE) {
1175                                                 /* state variables in screen, cursors */
1176                                                 ED_screen_set_subwinactive(win, event); 
1177                                                 /* for regions having custom cursors */
1178                                                 wm_paintcursor_test(C, event);
1179                                         }
1180                                 }
1181                                 
1182                                 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
1183                                         if(wm_event_always_pass(event) || wm_event_inside_i(event, &sa->totrct)) {
1184                                                 
1185                                                 CTX_wm_area_set(C, sa);
1186                                                 CTX_wm_region_set(C, NULL);
1187                                                 action= wm_handlers_do(C, event, &sa->handlers);
1188
1189                                                 if(wm_event_always_pass(event) || action==WM_HANDLER_CONTINUE) {
1190                                                         for(ar=sa->regionbase.first; ar; ar= ar->next) {
1191                                                                 if(wm_event_always_pass(event) || wm_event_inside_i(event, &ar->winrct)) {
1192                                                                         CTX_wm_region_set(C, ar);
1193                                                                         action= wm_handlers_do(C, event, &ar->handlers);
1194
1195                                                                         doit |= (BLI_in_rcti(&ar->winrct, event->x, event->y));
1196                                                                         
1197                                                                         if(!wm_event_always_pass(event)) {
1198                                                                                 if(action==WM_HANDLER_BREAK)
1199                                                                                         break;
1200                                                                         }
1201                                                                 }
1202                                                         }
1203                                                 }
1204                                                 /* NOTE: do not escape on WM_HANDLER_BREAK, mousemove needs handled for previous area */
1205                                         }
1206                                 }
1207                                 
1208                                 /* XXX hrmf, this gives reliable previous mouse coord for area change, feels bad? 
1209                                    doing it on ghost queue gives errors when mousemoves go over area borders */
1210                                 if(doit && win->screen->subwinactive != win->screen->mainwin) {
1211                                         win->eventstate->prevx= event->x;
1212                                         win->eventstate->prevy= event->y;
1213                                 }
1214                         }
1215                         
1216                         /* unlink and free here, blender-quit then frees all */
1217                         BLI_remlink(&win->queue, event);
1218                         wm_event_free(event);
1219                         
1220                 }
1221                 
1222                 /* only add mousemove when queue was read entirely */
1223                 if(win->addmousemove) {
1224                         wmEvent event= *(win->eventstate);
1225                         event.type= MOUSEMOVE;
1226                         event.prevx= event.x;
1227                         event.prevy= event.y;
1228                         wm_event_add(win, &event);
1229                         win->addmousemove= 0;
1230                 }
1231                 
1232                 CTX_wm_window_set(C, NULL);
1233         }
1234 }
1235
1236 /* ********** filesector handling ************ */
1237
1238 void WM_event_fileselect_event(bContext *C, void *ophandle, int eventval)
1239 {
1240         /* add to all windows! */
1241         wmWindow *win;
1242         
1243         for(win= CTX_wm_manager(C)->windows.first; win; win= win->next) {
1244                 wmEvent event= *win->eventstate;
1245                 
1246                 event.type= EVT_FILESELECT;
1247                 event.val= eventval;
1248                 event.customdata= ophandle;             // only as void pointer type check
1249
1250                 wm_event_add(win, &event);
1251         }
1252 }
1253
1254 /* operator is supposed to have a filled "path" property */
1255 /* optional property: filetype (XXX enum?) */
1256
1257 /* Idea is to keep a handler alive on window queue, owning the operator.
1258    The filewindow can send event to make it execute, thus ensuring
1259    executing happens outside of lower level queues, with UI refreshed. 
1260    Should also allow multiwin solutions */
1261
1262 void WM_event_add_fileselect(bContext *C, wmOperator *op)
1263 {
1264         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "fileselect handler");
1265         wmWindow *win= CTX_wm_window(C);
1266         int full= 1;    // XXX preset?
1267         
1268         handler->type= WM_HANDLER_FILESELECT;
1269         handler->op= op;
1270         handler->op_area= CTX_wm_area(C);
1271         handler->op_region= CTX_wm_region(C);
1272         handler->filescreen= CTX_wm_screen(C);
1273         
1274         BLI_addhead(&win->handlers, handler);
1275         
1276         WM_event_fileselect_event(C, op, full?EVT_FILESELECT_FULL_OPEN:EVT_FILESELECT_OPEN);
1277 }
1278
1279 /* lets not expose struct outside wm? */
1280 void WM_event_set_handler_flag(wmEventHandler *handler, int flag)
1281 {
1282         handler->flag= flag;
1283 }
1284
1285 wmEventHandler *WM_event_add_modal_handler(bContext *C, ListBase *handlers, wmOperator *op)
1286 {
1287         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event modal handler");
1288         
1289         /* operator was part of macro */
1290         if(op->opm) {
1291                 /* give the mother macro to the handler */
1292                 handler->op= op->opm;
1293                 /* mother macro opm becomes the macro element */
1294                 handler->op->opm= op;
1295         }
1296         else
1297                 handler->op= op;
1298         
1299         handler->op_area= CTX_wm_area(C);               /* means frozen screen context for modal handlers! */
1300         handler->op_region= CTX_wm_region(C);
1301         
1302         BLI_addhead(handlers, handler);
1303
1304         return handler;
1305 }
1306
1307 wmEventHandler *WM_event_add_keymap_handler(ListBase *handlers, ListBase *keymap)
1308 {
1309         wmEventHandler *handler;
1310
1311         /* only allow same keymap once */
1312         for(handler= handlers->first; handler; handler= handler->next)
1313                 if(handler->keymap==keymap)
1314                         return handler;
1315         
1316         handler= MEM_callocN(sizeof(wmEventHandler), "event keymap handler");
1317         BLI_addtail(handlers, handler);
1318         handler->keymap= keymap;
1319
1320         return handler;
1321 }
1322
1323 /* priorities not implemented yet, for time being just insert in begin of list */
1324 wmEventHandler *WM_event_add_keymap_handler_priority(ListBase *handlers, ListBase *keymap, int priority)
1325 {
1326         wmEventHandler *handler;
1327         
1328         WM_event_remove_keymap_handler(handlers, keymap);
1329         
1330         handler= MEM_callocN(sizeof(wmEventHandler), "event keymap handler");
1331         BLI_addhead(handlers, handler);
1332         handler->keymap= keymap;
1333         
1334         return handler;
1335 }
1336
1337 wmEventHandler *WM_event_add_keymap_handler_bb(ListBase *handlers, ListBase *keymap, rcti *bblocal, rcti *bbwin)
1338 {
1339         wmEventHandler *handler= WM_event_add_keymap_handler(handlers, keymap);
1340         
1341         if(handler) {
1342                 handler->bblocal= bblocal;
1343                 handler->bbwin= bbwin;
1344         }
1345         return handler;
1346 }
1347
1348 void WM_event_remove_keymap_handler(ListBase *handlers, ListBase *keymap)
1349 {
1350         wmEventHandler *handler;
1351         
1352         for(handler= handlers->first; handler; handler= handler->next) {
1353                 if(handler->keymap==keymap) {
1354                         BLI_remlink(handlers, handler);
1355                         wm_event_free_handler(handler);
1356                         break;
1357                 }
1358         }
1359 }
1360
1361 wmEventHandler *WM_event_add_ui_handler(const bContext *C, ListBase *handlers, wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata)
1362 {
1363         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event ui handler");
1364         handler->ui_handle= func;
1365         handler->ui_remove= remove;
1366         handler->ui_userdata= userdata;
1367         handler->ui_area= (C)? CTX_wm_area(C): NULL;
1368         handler->ui_region= (C)? CTX_wm_region(C): NULL;
1369         handler->ui_menu= (C)? CTX_wm_menu(C): NULL;
1370         
1371         BLI_addhead(handlers, handler);
1372         
1373         return handler;
1374 }
1375
1376 void WM_event_remove_ui_handler(ListBase *handlers, wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata)
1377 {
1378         wmEventHandler *handler;
1379         
1380         for(handler= handlers->first; handler; handler= handler->next) {
1381                 if(handler->ui_handle == func && handler->ui_remove == remove && handler->ui_userdata == userdata) {
1382                         BLI_remlink(handlers, handler);
1383                         wm_event_free_handler(handler);
1384                         break;
1385                 }
1386         }
1387 }
1388
1389 void WM_event_add_mousemove(bContext *C)
1390 {
1391         wmWindow *window= CTX_wm_window(C);
1392         
1393         window->addmousemove= 1;
1394 }
1395
1396 /* for modal callbacks, check configuration for how to interpret exit with tweaks  */
1397 int WM_modal_tweak_exit(wmEvent *evt, int tweak_event)
1398 {
1399         /* user preset or keymap? dunno... */
1400         int tweak_modal= (U.flag & USER_DRAGIMMEDIATE)==0;
1401         
1402         switch(tweak_event) {
1403                 case EVT_TWEAK_L:
1404                 case EVT_TWEAK_M:
1405                 case EVT_TWEAK_R:
1406                         if(evt->val==tweak_modal)
1407                                 return 1;
1408                 default:
1409                         /* this case is when modal callcback didnt get started with a tweak */
1410                         if(evt->val)
1411                                 return 1;
1412         }
1413         return 0;
1414 }
1415
1416
1417 /* ********************* ghost stuff *************** */
1418
1419 static int convert_key(GHOST_TKey key) 
1420 {
1421         if (key>=GHOST_kKeyA && key<=GHOST_kKeyZ) {
1422                 return (AKEY + ((int) key - GHOST_kKeyA));
1423         } else if (key>=GHOST_kKey0 && key<=GHOST_kKey9) {
1424                 return (ZEROKEY + ((int) key - GHOST_kKey0));
1425         } else if (key>=GHOST_kKeyNumpad0 && key<=GHOST_kKeyNumpad9) {
1426                 return (PAD0 + ((int) key - GHOST_kKeyNumpad0));
1427         } else if (key>=GHOST_kKeyF1 && key<=GHOST_kKeyF12) {
1428                 return (F1KEY + ((int) key - GHOST_kKeyF1));
1429         } else {
1430                 switch (key) {
1431                         case GHOST_kKeyBackSpace:               return BACKSPACEKEY;
1432                         case GHOST_kKeyTab:                             return TABKEY;
1433                         case GHOST_kKeyLinefeed:                return LINEFEEDKEY;
1434                         case GHOST_kKeyClear:                   return 0;
1435                         case GHOST_kKeyEnter:                   return RETKEY;
1436                                 
1437                         case GHOST_kKeyEsc:                             return ESCKEY;
1438                         case GHOST_kKeySpace:                   return SPACEKEY;
1439                         case GHOST_kKeyQuote:                   return QUOTEKEY;
1440                         case GHOST_kKeyComma:                   return COMMAKEY;
1441                         case GHOST_kKeyMinus:                   return MINUSKEY;
1442                         case GHOST_kKeyPeriod:                  return PERIODKEY;
1443                         case GHOST_kKeySlash:                   return SLASHKEY;
1444                                 
1445                         case GHOST_kKeySemicolon:               return SEMICOLONKEY;
1446                         case GHOST_kKeyEqual:                   return EQUALKEY;
1447                                 
1448                         case GHOST_kKeyLeftBracket:             return LEFTBRACKETKEY;
1449                         case GHOST_kKeyRightBracket:    return RIGHTBRACKETKEY;
1450                         case GHOST_kKeyBackslash:               return BACKSLASHKEY;
1451                         case GHOST_kKeyAccentGrave:             return ACCENTGRAVEKEY;
1452                                 
1453                         case GHOST_kKeyLeftShift:               return LEFTSHIFTKEY;
1454                         case GHOST_kKeyRightShift:              return RIGHTSHIFTKEY;
1455                         case GHOST_kKeyLeftControl:             return LEFTCTRLKEY;
1456                         case GHOST_kKeyRightControl:    return RIGHTCTRLKEY;
1457                         case GHOST_kKeyCommand:                 return COMMANDKEY;
1458                         case GHOST_kKeyLeftAlt:                 return LEFTALTKEY;
1459                         case GHOST_kKeyRightAlt:                return RIGHTALTKEY;
1460                                 
1461                         case GHOST_kKeyCapsLock:                return CAPSLOCKKEY;
1462                         case GHOST_kKeyNumLock:                 return 0;
1463                         case GHOST_kKeyScrollLock:              return 0;
1464                                 
1465                         case GHOST_kKeyLeftArrow:               return LEFTARROWKEY;
1466                         case GHOST_kKeyRightArrow:              return RIGHTARROWKEY;
1467                         case GHOST_kKeyUpArrow:                 return UPARROWKEY;
1468                         case GHOST_kKeyDownArrow:               return DOWNARROWKEY;
1469                                 
1470                         case GHOST_kKeyPrintScreen:             return 0;
1471                         case GHOST_kKeyPause:                   return PAUSEKEY;
1472                                 
1473                         case GHOST_kKeyInsert:                  return INSERTKEY;
1474                         case GHOST_kKeyDelete:                  return DELKEY;
1475                         case GHOST_kKeyHome:                    return HOMEKEY;
1476                         case GHOST_kKeyEnd:                             return ENDKEY;
1477                         case GHOST_kKeyUpPage:                  return PAGEUPKEY;
1478                         case GHOST_kKeyDownPage:                return PAGEDOWNKEY;
1479                                 
1480                         case GHOST_kKeyNumpadPeriod:    return PADPERIOD;
1481                         case GHOST_kKeyNumpadEnter:             return PADENTER;
1482                         case GHOST_kKeyNumpadPlus:              return PADPLUSKEY;
1483                         case GHOST_kKeyNumpadMinus:             return PADMINUS;
1484                         case GHOST_kKeyNumpadAsterisk:  return PADASTERKEY;
1485                         case GHOST_kKeyNumpadSlash:             return PADSLASHKEY;
1486                                 
1487                         case GHOST_kKeyGrLess:              return GRLESSKEY; 
1488                                 
1489                         default:
1490                                 return UNKNOWNKEY;      /* GHOST_kKeyUnknown */
1491                 }
1492         }
1493 }
1494
1495 /* adds customdata to event */
1496 static void update_tablet_data(wmWindow *win, wmEvent *event)
1497 {
1498         const GHOST_TabletData *td= GHOST_GetTabletData(win->ghostwin);
1499         
1500         /* if there's tablet data from an active tablet device then add it */
1501         if ((td != NULL) && td->Active != GHOST_kTabletModeNone) {
1502                 struct wmTabletData *wmtab= MEM_mallocN(sizeof(wmTabletData), "customdata tablet");
1503                 
1504                 wmtab->Active = (int)td->Active;
1505                 wmtab->Pressure = td->Pressure;
1506                 wmtab->Xtilt = td->Xtilt;
1507                 wmtab->Ytilt = td->Ytilt;
1508                 
1509                 event->custom= EVT_DATA_TABLET;
1510                 event->customdata= wmtab;
1511                 event->customdatafree= 1;
1512         } 
1513 }
1514
1515
1516 /* windows store own event queues, no bContext here */
1517 void wm_event_add_ghostevent(wmWindow *win, int type, void *customdata)
1518 {
1519         wmEvent event, *evt= win->eventstate;
1520         
1521         /* initialize and copy state (only mouse x y and modifiers) */
1522         event= *evt;
1523         
1524         switch (type) {
1525                 /* mouse move */
1526                 case GHOST_kEventCursorMove: {
1527                         if(win->active) {
1528                                 GHOST_TEventCursorData *cd= customdata;
1529                                 int cx, cy;
1530
1531                                 GHOST_ScreenToClient(win->ghostwin, cd->x, cd->y, &cx, &cy);
1532                                 
1533                                 event.type= MOUSEMOVE;
1534                                 event.x= evt->x= cx;
1535                                 event.y= evt->y= (win->sizey-1) - cy;
1536                                 
1537                                 update_tablet_data(win, &event);
1538                                 wm_event_add(win, &event);
1539                         }
1540                         break;
1541                 }
1542                 /* mouse button */
1543                 case GHOST_kEventButtonDown:
1544                 case GHOST_kEventButtonUp: {
1545                         GHOST_TEventButtonData *bd= customdata;
1546                         event.val= (type==GHOST_kEventButtonDown);
1547                         
1548                         if (bd->button == GHOST_kButtonMaskLeft)
1549                                 event.type= LEFTMOUSE;
1550                         else if (bd->button == GHOST_kButtonMaskRight)
1551                                 event.type= RIGHTMOUSE;
1552                         else
1553                                 event.type= MIDDLEMOUSE;
1554                         
1555                         update_tablet_data(win, &event);
1556                         wm_event_add(win, &event);
1557                         
1558                         break;
1559                 }
1560                 /* keyboard */
1561                 case GHOST_kEventKeyDown:
1562                 case GHOST_kEventKeyUp: {
1563                         GHOST_TEventKeyData *kd= customdata;
1564                         event.type= convert_key(kd->key);
1565                         event.ascii= kd->ascii;
1566                         event.val= (type==GHOST_kEventKeyDown)?KM_PRESS:KM_RELEASE;
1567                         
1568                         /* exclude arrow keys, esc, etc from text input */
1569                         if(type==GHOST_kEventKeyUp || (event.ascii<32 && event.ascii>14))
1570                                 event.ascii= '\0';
1571                         
1572                         /* modifiers */
1573                         if (event.type==LEFTSHIFTKEY || event.type==RIGHTSHIFTKEY) {
1574                                 event.shift= evt->shift= (event.val==KM_PRESS);
1575                                 if(event.val==KM_PRESS && (evt->ctrl || evt->alt || evt->oskey))
1576                                    event.shift= evt->shift = 3;         // define?
1577                         } 
1578                         else if (event.type==LEFTCTRLKEY || event.type==RIGHTCTRLKEY) {
1579                                 event.ctrl= evt->ctrl= (event.val==KM_PRESS);
1580                                 if(event.val==KM_PRESS && (evt->shift || evt->alt || evt->oskey))
1581                                    event.ctrl= evt->ctrl = 3;           // define?
1582                         } 
1583                         else if (event.type==LEFTALTKEY || event.type==RIGHTALTKEY) {
1584                                 event.alt= evt->alt= (event.val==KM_PRESS);
1585                                 if(event.val==KM_PRESS && (evt->ctrl || evt->shift || evt->oskey))
1586                                    event.alt= evt->alt = 3;             // define?
1587                         } 
1588                         else if (event.type==COMMANDKEY) {
1589                                 event.oskey= evt->oskey= (event.val==KM_PRESS);
1590                                 if(event.val==KM_PRESS && (evt->ctrl || evt->alt || evt->shift))
1591                                    event.oskey= evt->oskey = 3;         // define?
1592                         }
1593                         else {
1594                                 if(event.val==KM_PRESS && event.keymodifier==0)
1595                                         evt->keymodifier= event.type; /* only set in eventstate, for next event */
1596                                 else if(event.val==KM_RELEASE && event.keymodifier==event.type)
1597                                         event.keymodifier= evt->keymodifier= 0;
1598                         }
1599                         
1600                         /* if test_break set, it catches this. XXX Keep global for now? */
1601                         if(event.type==ESCKEY)
1602                                 G.afbreek= 1;
1603
1604                         wm_event_add(win, &event);
1605                         
1606                         break;
1607                 }
1608                         
1609                 case GHOST_kEventWheel: {
1610                         GHOST_TEventWheelData* wheelData = customdata;
1611                         
1612                         if (wheelData->z > 0)
1613                                 event.type= WHEELUPMOUSE;
1614                         else
1615                                 event.type= WHEELDOWNMOUSE;
1616                         
1617                         event.val= KM_PRESS;
1618                         wm_event_add(win, &event);
1619                         
1620                         break;
1621                 }
1622                 case GHOST_kEventTimer: {
1623                         event.type= TIMER;
1624                         event.custom= EVT_DATA_TIMER;
1625                         event.customdata= customdata;
1626                         wm_event_add(win, &event);
1627
1628                         break;
1629                 }
1630
1631                 case GHOST_kEventUnknown:
1632                 case GHOST_kNumEventTypes:
1633                         break;
1634         }
1635 }