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