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