8cfd45662ac2e75e7928bce15f299e4d222654bf
[blender-staging.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 #include <math.h>
32
33 #include "DNA_listBase.h"
34 #include "DNA_screen_types.h"
35 #include "DNA_scene_types.h"
36 #include "DNA_windowmanager_types.h"
37 #include "DNA_userdef_types.h"
38
39 #include "MEM_guardedalloc.h"
40
41 #include "GHOST_C-api.h"
42
43 #include "BLI_blenlib.h"
44
45 #include "BKE_blender.h"
46 #include "BKE_context.h"
47 #include "BKE_idprop.h"
48 #include "BKE_global.h"
49 #include "BKE_main.h"
50 #include "BKE_report.h"
51 #include "BKE_scene.h"
52 #include "BKE_screen.h"
53 #include "BKE_utildefines.h"
54 #include "BKE_sound.h"
55
56 #include "ED_fileselect.h"
57 #include "ED_info.h"
58 #include "ED_screen.h"
59 #include "ED_space_api.h"
60 #include "ED_util.h"
61
62 #include "RNA_access.h"
63
64 #include "UI_interface.h"
65
66 #include "PIL_time.h"
67
68 #include "WM_api.h"
69 #include "WM_types.h"
70 #include "wm.h"
71 #include "wm_window.h"
72 #include "wm_event_system.h"
73 #include "wm_event_types.h"
74
75 /* ************ event management ************** */
76
77 void wm_event_add(wmWindow *win, wmEvent *event_to_add)
78 {
79         wmEvent *event= MEM_callocN(sizeof(wmEvent), "event");
80         
81         *event= *event_to_add;
82         BLI_addtail(&win->queue, event);
83 }
84
85 void wm_event_free(wmEvent *event)
86 {
87         if(event->customdata) {
88                 if(event->customdatafree) {
89                         /* note: pointer to listbase struct elsewhere */
90                         if(event->custom==EVT_DATA_LISTBASE)
91                                 BLI_freelistN(event->customdata);
92                         else
93                                 MEM_freeN(event->customdata);
94                 }
95         }
96         MEM_freeN(event);
97 }
98
99 void wm_event_free_all(wmWindow *win)
100 {
101         wmEvent *event;
102         
103         while((event= win->queue.first)) {
104                 BLI_remlink(&win->queue, event);
105                 wm_event_free(event);
106         }
107 }
108
109 /* ********************* notifiers, listeners *************** */
110
111 static int wm_test_duplicate_notifier(wmWindowManager *wm, unsigned int type, void *reference)
112 {
113         wmNotifier *note;
114
115         for(note=wm->queue.first; note; note=note->next)
116                 if((note->category|note->data|note->subtype|note->action) == type && note->reference == reference)
117                         return 1;
118         
119         return 0;
120 }
121
122 /* XXX: in future, which notifiers to send to other windows? */
123 void WM_event_add_notifier(const bContext *C, unsigned int type, void *reference)
124 {
125         wmNotifier *note= MEM_callocN(sizeof(wmNotifier), "notifier");
126         
127         note->wm= CTX_wm_manager(C);
128         BLI_addtail(&note->wm->queue, note);
129         
130         note->window= CTX_wm_window(C);
131         
132         if(CTX_wm_region(C))
133                 note->swinid= CTX_wm_region(C)->swinid;
134         
135         note->category= type & NOTE_CATEGORY;
136         note->data= type & NOTE_DATA;
137         note->subtype= type & NOTE_SUBTYPE;
138         note->action= type & NOTE_ACTION;
139         
140         note->reference= reference;
141 }
142
143 void WM_main_add_notifier(unsigned int type, void *reference)
144 {
145         Main *bmain= G.main;
146         wmWindowManager *wm= bmain->wm.first;
147
148         if(wm && !wm_test_duplicate_notifier(wm, type, reference)) {
149                 wmNotifier *note= MEM_callocN(sizeof(wmNotifier), "notifier");
150                 
151                 note->wm= wm;
152                 BLI_addtail(&note->wm->queue, note);
153                 
154                 note->category= type & NOTE_CATEGORY;
155                 note->data= type & NOTE_DATA;
156                 note->subtype= type & NOTE_SUBTYPE;
157                 note->action= type & NOTE_ACTION;
158                 
159                 note->reference= reference;
160         }
161 }
162
163 static wmNotifier *wm_notifier_next(wmWindowManager *wm)
164 {
165         wmNotifier *note= wm->queue.first;
166         
167         if(note) BLI_remlink(&wm->queue, note);
168         return note;
169 }
170
171 /* called in mainloop */
172 void wm_event_do_notifiers(bContext *C)
173 {
174         wmWindowManager *wm= CTX_wm_manager(C);
175         wmNotifier *note, *next;
176         wmWindow *win;
177         
178         if(wm==NULL)
179                 return;
180         
181         /* cache & catch WM level notifiers, such as frame change, scene/screen set */
182         for(win= wm->windows.first; win; win= win->next) {
183                 int do_anim= 0;
184                 
185                 CTX_wm_window_set(C, win);
186                 
187                 for(note= wm->queue.first; note; note= next) {
188                         next= note->next;
189
190                         if(note->category==NC_WM) {
191                                 if( ELEM(note->data, ND_FILEREAD, ND_FILESAVE)) {
192                                         wm->file_saved= 1;
193                                         wm_window_title(wm, win);
194                                 }
195                                 else if(note->data==ND_DATACHANGED)
196                                         wm_window_title(wm, win);
197                         }
198                         if(note->window==win) {
199                                 if(note->category==NC_SCREEN) {
200                                         if(note->data==ND_SCREENBROWSE) {
201                                                 ED_screen_set(C, note->reference);      // XXX hrms, think this over!
202                                                 if(G.f & G_DEBUG)
203                                                         printf("screen set %p\n", note->reference);
204                                         }
205                                         else if(note->data==ND_SCREENDELETE) {
206                                                 ED_screen_delete(C, note->reference);   // XXX hrms, think this over!
207                                                 if(G.f & G_DEBUG)
208                                                         printf("screen delete %p\n", note->reference);
209                                         }
210                                 }
211                         }
212
213                         if(note->window==win || (note->window == NULL && (note->reference == NULL || note->reference == CTX_data_scene(C)))) {
214                                 if(note->category==NC_SCENE) {
215                                         if(note->data==ND_SCENEBROWSE) {
216                                                 ED_screen_set_scene(C, note->reference);        // XXX hrms, think this over!
217                                                 if(G.f & G_DEBUG)
218                                                         printf("scene set %p\n", note->reference);
219                                         }
220                                         else if(note->data==ND_FRAME)
221                                                 do_anim= 1;
222                                         
223                                         if(note->action == NA_REMOVED) {
224                                                 ED_screen_delete_scene(C, note->reference);     // XXX hrms, think this over!
225                                                 if(G.f & G_DEBUG)
226                                                         printf("scene delete %p\n", note->reference);
227                                         }
228                                                 
229                                 }
230                         }
231                         if(ELEM5(note->category, NC_SCENE, NC_OBJECT, NC_GEOM, NC_SCENE, NC_WM)) {
232                                 ED_info_stats_clear(CTX_data_scene(C));
233                                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_INFO, NULL);
234                         }
235                 }
236                 if(do_anim) {
237                         /* depsgraph gets called, might send more notifiers */
238                         ED_update_for_newframe(C, 1);
239                 }
240         }
241         
242         /* the notifiers are sent without context, to keep it clean */
243         while( (note=wm_notifier_next(wm)) ) {
244                 wmWindow *win;
245                 
246                 for(win= wm->windows.first; win; win= win->next) {
247                         
248                         /* filter out notifiers */
249                         if(note->category==NC_SCREEN && note->reference && note->reference!=win->screen);
250                         else if(note->category==NC_SCENE && note->reference && note->reference!=win->screen->scene);
251                         else {
252                                 ScrArea *sa;
253                                 ARegion *ar;
254
255                                 /* XXX context in notifiers? */
256                                 CTX_wm_window_set(C, win);
257
258                                 /* printf("notifier win %d screen %s cat %x\n", win->winid, win->screen->id.name+2, note->category); */
259                                 ED_screen_do_listen(win, note);
260
261                                 for(ar=win->screen->regionbase.first; ar; ar= ar->next) {
262                                         ED_region_do_listen(ar, note);
263                                 }
264                                 
265                                 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
266                                         ED_area_do_listen(sa, note);
267                                         for(ar=sa->regionbase.first; ar; ar= ar->next) {
268                                                 ED_region_do_listen(ar, note);
269                                         }
270                                 }
271                         }
272                 }
273                 
274                 MEM_freeN(note);
275         }
276         
277         /* cached: editor refresh callbacks now, they get context */
278         for(win= wm->windows.first; win; win= win->next) {
279                 ScrArea *sa;
280                 
281                 CTX_wm_window_set(C, win);
282                 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
283                         if(sa->do_refresh) {
284                                 CTX_wm_area_set(C, sa);
285                                 ED_area_do_refresh(C, sa);
286                         }
287                 }
288                 
289                 /* XXX make lock in future, or separated derivedmesh users in scene */
290                 if(!G.rendering)
291                         /* depsgraph & animation: update tagged datablocks */
292                         scene_update_tagged(win->screen->scene);
293         }
294
295         CTX_wm_window_set(C, NULL);
296 }
297
298 /* ********************* ui handler ******************* */
299
300 static int wm_handler_ui_call(bContext *C, wmEventHandler *handler, wmEvent *event, int always_pass)
301 {
302         ScrArea *area= CTX_wm_area(C);
303         ARegion *region= CTX_wm_region(C);
304         ARegion *menu= CTX_wm_menu(C);
305         int retval;
306                         
307         /* we set context to where ui handler came from */
308         if(handler->ui_area) CTX_wm_area_set(C, handler->ui_area);
309         if(handler->ui_region) CTX_wm_region_set(C, handler->ui_region);
310         if(handler->ui_menu) CTX_wm_menu_set(C, handler->ui_menu);
311
312         retval= handler->ui_handle(C, event, handler->ui_userdata);
313
314         /* putting back screen context */
315         if((retval != WM_UI_HANDLER_BREAK) || always_pass) {
316                 CTX_wm_area_set(C, area);
317                 CTX_wm_region_set(C, region);
318                 CTX_wm_menu_set(C, menu);
319         }
320         else {
321                 /* this special cases is for areas and regions that get removed */
322                 CTX_wm_area_set(C, NULL);
323                 CTX_wm_region_set(C, NULL);
324                 CTX_wm_menu_set(C, NULL);
325         }
326
327         if(retval == WM_UI_HANDLER_BREAK)
328                 return WM_HANDLER_BREAK;
329
330         return WM_HANDLER_CONTINUE;
331 }
332
333 static void wm_handler_ui_cancel(bContext *C)
334 {
335         wmWindow *win= CTX_wm_window(C);
336         ARegion *ar= CTX_wm_region(C);
337         wmEventHandler *handler, *nexthandler;
338
339         if(!ar)
340                 return;
341
342         for(handler= ar->handlers.first; handler; handler= nexthandler) {
343                 nexthandler= handler->next;
344
345                 if(handler->ui_handle) {
346                         wmEvent event= *(win->eventstate);
347                         event.type= EVT_BUT_CANCEL;
348                         handler->ui_handle(C, &event, handler->ui_userdata);
349                 }
350         }
351 }
352
353 /* ********************* operators ******************* */
354
355 int WM_operator_poll(bContext *C, wmOperatorType *ot)
356 {
357         wmOperatorTypeMacro *otmacro;
358         
359         for(otmacro= ot->macro.first; otmacro; otmacro= otmacro->next) {
360                 wmOperatorType *ot= WM_operatortype_find(otmacro->idname, 0);
361                 
362                 if(0==WM_operator_poll(C, ot))
363                         return 0;
364         }
365         
366         /* python needs operator type, so we added exception for it */
367         if(ot->pyop_poll)
368                 return ot->pyop_poll(C, ot);
369         else if(ot->poll)
370                 return ot->poll(C);
371
372         return 1;
373 }
374
375 static void wm_operator_finished(bContext *C, wmOperator *op, int repeat)
376 {
377         wmWindowManager *wm= CTX_wm_manager(C);
378
379         op->customdata= NULL;
380
381         /* we don't want to do undo pushes for operators that are being
382            called from operators that already do an undo push. usually
383            this will happen for python operators that call C operators */
384         if(wm->op_undo_depth == 0)
385                 if(op->type->flag & OPTYPE_UNDO)
386                         ED_undo_push_op(C, op);
387         
388         if(repeat==0) {
389                 if(G.f & G_DEBUG) {
390                         char *buf = WM_operator_pystring(C, op->type, op->ptr, 1);
391                         BKE_report(CTX_wm_reports(C), RPT_OPERATOR, buf);
392                         MEM_freeN(buf);
393                 }
394
395                 if((wm->op_undo_depth == 0) && (op->type->flag & OPTYPE_REGISTER))
396                         wm_operator_register(C, op);
397                 else
398                         WM_operator_free(op);
399         }
400 }
401
402 /* if repeat is true, it doesn't register again, nor does it free */
403 static int wm_operator_exec(bContext *C, wmOperator *op, int repeat)
404 {
405         wmWindowManager *wm= CTX_wm_manager(C);
406         int retval= OPERATOR_CANCELLED;
407         
408         if(op==NULL || op->type==NULL)
409                 return retval;
410         
411         if(0==WM_operator_poll(C, op->type))
412                 return retval;
413         
414         if(op->type->exec) {
415                 if(op->type->flag & OPTYPE_UNDO)
416                         wm->op_undo_depth++;
417
418                 retval= op->type->exec(C, op);
419
420                 if(op->type->flag & OPTYPE_UNDO)
421                         wm->op_undo_depth--;
422         }
423         
424         if(retval & (OPERATOR_FINISHED|OPERATOR_CANCELLED))
425                 if(op->reports->list.first)
426                         uiPupMenuReports(C, op->reports);
427         
428         if(retval & OPERATOR_FINISHED)
429                 wm_operator_finished(C, op, repeat);
430         else if(repeat==0)
431                 WM_operator_free(op);
432         
433         return retval | OPERATOR_HANDLED;
434         
435 }
436
437 /* for running operators with frozen context (modal handlers, menus) */
438 int WM_operator_call(bContext *C, wmOperator *op)
439 {
440         return wm_operator_exec(C, op, 0);
441 }
442
443 /* do this operator again, put here so it can share above code */
444 int WM_operator_repeat(bContext *C, wmOperator *op)
445 {
446         return wm_operator_exec(C, op, 1);
447 }
448
449 static wmOperator *wm_operator_create(wmWindowManager *wm, wmOperatorType *ot, PointerRNA *properties, ReportList *reports)
450 {
451         wmOperator *op= MEM_callocN(sizeof(wmOperator), ot->idname);    /* XXX operatortype names are static still. for debug */
452         
453         /* XXX adding new operator could be function, only happens here now */
454         op->type= ot;
455         BLI_strncpy(op->idname, ot->idname, OP_MAX_TYPENAME);
456         
457         /* initialize properties, either copy or create */
458         op->ptr= MEM_callocN(sizeof(PointerRNA), "wmOperatorPtrRNA");
459         if(properties && properties->data) {
460                 op->properties= IDP_CopyProperty(properties->data);
461         }
462         else {
463                 IDPropertyTemplate val = {0};
464                 op->properties= IDP_New(IDP_GROUP, val, "wmOperatorProperties");
465         }
466         RNA_pointer_create(&wm->id, ot->srna, op->properties, op->ptr);
467
468         /* initialize error reports */
469         if (reports) {
470                 op->reports= reports; /* must be initialized already */
471         }
472         else {
473                 op->reports= MEM_mallocN(sizeof(ReportList), "wmOperatorReportList");
474                 BKE_reports_init(op->reports, RPT_STORE|RPT_FREE);
475         }
476         
477         /* recursive filling of operator macro list */
478         if(ot->macro.first) {
479                 static wmOperator *motherop= NULL;
480                 wmOperatorTypeMacro *otmacro;
481                 int root = 0;
482                 
483                 /* ensure all ops are in execution order in 1 list */
484                 if(motherop==NULL) {
485                         motherop = op;
486                         root = 1;
487                 }
488
489                 
490                 /* if properties exist, it will contain everything needed */
491                 if (properties) {
492                         otmacro= ot->macro.first;
493
494                         RNA_STRUCT_BEGIN(properties, prop) {
495
496                                 if (otmacro == NULL)
497                                         break;
498
499                                 /* skip invalid properties */
500                                 if (strcmp(RNA_property_identifier(prop), otmacro->idname) == 0)
501                                 {
502                                         wmOperatorType *otm= WM_operatortype_find(otmacro->idname, 0);
503                                         PointerRNA someptr = RNA_property_pointer_get(properties, prop);
504                                         wmOperator *opm= wm_operator_create(wm, otm, &someptr, NULL);
505
506                                         IDP_ReplaceGroupInGroup(opm->properties, otmacro->properties);
507
508                                         BLI_addtail(&motherop->macro, opm);
509                                         opm->opm= motherop; /* pointer to mom, for modal() */
510
511                                         otmacro= otmacro->next;
512                                 }
513                         }
514                         RNA_STRUCT_END;
515                 } else {
516                         for (otmacro = ot->macro.first; otmacro; otmacro = otmacro->next) {
517                                 wmOperatorType *otm= WM_operatortype_find(otmacro->idname, 0);
518                                 wmOperator *opm= wm_operator_create(wm, otm, otmacro->ptr, NULL);
519
520                                 BLI_addtail(&motherop->macro, opm);
521                                 opm->opm= motherop; /* pointer to mom, for modal() */
522                         }
523                 }
524                 
525                 if (root)
526                         motherop= NULL;
527         }
528         
529         WM_operator_properties_sanitize(op->ptr, 0);
530
531         return op;
532 }
533
534 static void wm_operator_print(wmOperator *op)
535 {
536         char *buf = WM_operator_pystring(NULL, op->type, op->ptr, 1);
537         printf("%s\n", buf);
538         MEM_freeN(buf);
539 }
540
541 static void wm_region_mouse_co(bContext *C, wmEvent *event)
542 {
543         ARegion *ar= CTX_wm_region(C);
544         if(ar) {
545                 /* compatibility convention */
546                 event->mval[0]= event->x - ar->winrct.xmin;
547                 event->mval[1]= event->y - ar->winrct.ymin;
548         }
549 }
550
551 static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, PointerRNA *properties, ReportList *reports)
552 {
553         wmWindowManager *wm= CTX_wm_manager(C);
554         int retval= OPERATOR_PASS_THROUGH;
555
556         if(WM_operator_poll(C, ot)) {
557                 wmOperator *op= wm_operator_create(wm, ot, properties, reports); /* if reports==NULL, theyll be initialized */
558                 
559                 if((G.f & G_DEBUG) && event && event->type!=MOUSEMOVE)
560                         printf("handle evt %d win %d op %s\n", event?event->type:0, CTX_wm_screen(C)->subwinactive, ot->idname); 
561                 
562                 if(op->type->invoke && event) {
563                         wm_region_mouse_co(C, event);
564
565                         if(op->type->flag & OPTYPE_UNDO)
566                                 wm->op_undo_depth++;
567
568                         retval= op->type->invoke(C, op, event);
569
570                         if(op->type->flag & OPTYPE_UNDO)
571                                 wm->op_undo_depth--;
572                 }
573                 else if(op->type->exec) {
574                         if(op->type->flag & OPTYPE_UNDO)
575                                 wm->op_undo_depth++;
576
577                         retval= op->type->exec(C, op);
578
579                         if(op->type->flag & OPTYPE_UNDO)
580                                 wm->op_undo_depth--;
581                 }
582                 else
583                         printf("invalid operator call %s\n", ot->idname); /* debug, important to leave a while, should never happen */
584
585                 /* Note, if the report is given as an argument then assume the caller will deal with displaying them
586                  * currently python only uses this */
587                 if((retval & (OPERATOR_FINISHED|OPERATOR_CANCELLED)) && reports==NULL)
588                         if(op->reports->list.first) /* only show the report if the report list was not given in the function */
589                                 uiPupMenuReports(C, op->reports);
590                 
591                 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 */
592                         if(G.f & G_DEBUG)
593                                 wm_operator_print(op);
594                 }
595
596                 if(retval & OPERATOR_HANDLED)
597                         ; /* do nothing, wm_operator_exec() has been called somewhere */
598                 else if(retval & OPERATOR_FINISHED) {
599                         wm_operator_finished(C, op, 0);
600                 }
601                 else if(retval & OPERATOR_RUNNING_MODAL) {
602                         /* grab cursor during blocking modal ops (X11)
603                          * Also check for macro
604                          * */
605                         if(ot->flag & OPTYPE_BLOCKING || (op->opm && op->opm->type->flag & OPTYPE_BLOCKING)) {
606                                 int bounds[4] = {-1,-1,-1,-1};
607                                 int wrap;
608
609                                 if (op->opm) {
610                                         wrap = (U.uiflag & USER_CONTINUOUS_MOUSE) && ((op->opm->flag & OP_GRAB_POINTER) || (op->opm->type->flag & OPTYPE_GRAB_POINTER));
611                                 } else {
612                                         wrap = (U.uiflag & USER_CONTINUOUS_MOUSE) && ((op->flag & OP_GRAB_POINTER) || (ot->flag & OPTYPE_GRAB_POINTER));
613                                 }
614
615                                 if(wrap) {
616                                         ARegion *ar= CTX_wm_region(C);
617                                         if(ar) {
618                                                 bounds[0]= ar->winrct.xmin;
619                                                 bounds[1]= ar->winrct.ymax;
620                                                 bounds[2]= ar->winrct.xmax;
621                                                 bounds[3]= ar->winrct.ymin;
622                                         }
623                                 }
624
625                                 WM_cursor_grab(CTX_wm_window(C), wrap, FALSE, bounds);
626                         }
627
628                         /* cancel UI handlers, typically tooltips that can hang around
629                            while dragging the view or worse, that stay there permanently
630                            after the modal operator has swallowed all events and passed
631                            none to the UI handler */
632                         wm_handler_ui_cancel(C);
633                 }
634                 else
635                         WM_operator_free(op);
636         }
637
638         return retval;
639 }
640
641 /* WM_operator_name_call is the main accessor function
642  * this is for python to access since its done the operator lookup
643  * 
644  * invokes operator in context */
645 static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, int context, PointerRNA *properties, ReportList *reports)
646 {
647         wmWindow *window= CTX_wm_window(C);
648         wmEvent *event;
649         
650         int retval;
651
652         /* dummie test */
653         if(ot && C) {
654                 switch(context) {
655                         case WM_OP_INVOKE_DEFAULT:
656                         case WM_OP_INVOKE_REGION_WIN:
657                         case WM_OP_INVOKE_AREA:
658                         case WM_OP_INVOKE_SCREEN:
659                                 /* window is needed for invoke, cancel operator */
660                                 if (window == NULL)
661                                         return 0;
662                                 else
663                                         event= window->eventstate;
664                                 break;
665                         default:
666                                 event = NULL;
667                 }
668
669                 switch(context) {
670                         
671                         case WM_OP_EXEC_REGION_WIN:
672                         case WM_OP_INVOKE_REGION_WIN: 
673                         case WM_OP_EXEC_REGION_CHANNELS:
674                         case WM_OP_INVOKE_REGION_CHANNELS:
675                         case WM_OP_EXEC_REGION_PREVIEW:
676                         case WM_OP_INVOKE_REGION_PREVIEW:
677                         {
678                                 /* forces operator to go to the region window/channels/preview, for header menus
679                                  * but we stay in the same region if we are already in one 
680                                  */
681                                 ARegion *ar= CTX_wm_region(C);
682                                 ScrArea *area= CTX_wm_area(C);
683                                 int type = RGN_TYPE_WINDOW;
684                                 
685                                 switch (context) {
686                                         case WM_OP_EXEC_REGION_CHANNELS:
687                                         case WM_OP_INVOKE_REGION_CHANNELS:
688                                                 type = RGN_TYPE_CHANNELS;
689                                         
690                                         case WM_OP_EXEC_REGION_PREVIEW:
691                                         case WM_OP_INVOKE_REGION_PREVIEW:
692                                                 type = RGN_TYPE_PREVIEW;
693                                                 break;
694                                         
695                                         case WM_OP_EXEC_REGION_WIN:
696                                         case WM_OP_INVOKE_REGION_WIN: 
697                                         default:
698                                                 type = RGN_TYPE_WINDOW;
699                                                 break;
700                                 }
701                                 
702                                 if(!(ar && ar->regiontype == type) && area) {
703                                         ARegion *ar1= BKE_area_find_region_type(area, type);
704                                         if(ar1)
705                                                 CTX_wm_region_set(C, ar1);
706                                 }
707                                 
708                                 retval= wm_operator_invoke(C, ot, event, properties, reports);
709                                 
710                                 /* set region back */
711                                 CTX_wm_region_set(C, ar);
712                                 
713                                 return retval;
714                         }
715                         case WM_OP_EXEC_AREA:
716                         case WM_OP_INVOKE_AREA:
717                         {
718                                         /* remove region from context */
719                                 ARegion *ar= CTX_wm_region(C);
720
721                                 CTX_wm_region_set(C, NULL);
722                                 retval= wm_operator_invoke(C, ot, event, properties, reports);
723                                 CTX_wm_region_set(C, ar);
724
725                                 return retval;
726                         }
727                         case WM_OP_EXEC_SCREEN:
728                         case WM_OP_INVOKE_SCREEN:
729                         {
730                                 /* remove region + area from context */
731                                 ARegion *ar= CTX_wm_region(C);
732                                 ScrArea *area= CTX_wm_area(C);
733
734                                 CTX_wm_region_set(C, NULL);
735                                 CTX_wm_area_set(C, NULL);
736                                 retval= wm_operator_invoke(C, ot, event, properties, reports);
737                                 CTX_wm_region_set(C, ar);
738                                 CTX_wm_area_set(C, area);
739
740                                 return retval;
741                         }
742                         case WM_OP_EXEC_DEFAULT:
743                         case WM_OP_INVOKE_DEFAULT:
744                                 return wm_operator_invoke(C, ot, event, properties, reports);
745                 }
746         }
747         
748         return 0;
749 }
750
751
752 /* invokes operator in context */
753 int WM_operator_name_call(bContext *C, const char *opstring, int context, PointerRNA *properties)
754 {
755         wmOperatorType *ot= WM_operatortype_find(opstring, 0);
756         if(ot)
757                 return wm_operator_call_internal(C, ot, context, properties, NULL);
758
759         return 0;
760 }
761
762 /* Similar to WM_operator_name_call called with WM_OP_EXEC_DEFAULT context.
763    - wmOperatorType is used instead of operator name since python alredy has the operator type
764    - poll() must be called by python before this runs.
765    - reports can be passed to this function (so python can report them as exceptions)
766 */
767 int WM_operator_call_py(bContext *C, wmOperatorType *ot, int context, PointerRNA *properties, ReportList *reports)
768 {
769         int retval= OPERATOR_CANCELLED;
770
771 #if 0
772         wmOperator *op;
773         wmWindowManager *wm=    CTX_wm_manager(C);
774         op= wm_operator_create(wm, ot, properties, reports);
775
776         if (op->type->exec) {
777                 if(op->type->flag & OPTYPE_UNDO)
778                         wm->op_undo_depth++;
779
780                 retval= op->type->exec(C, op);
781
782                 if(op->type->flag & OPTYPE_UNDO)
783                         wm->op_undo_depth--;
784         }
785         else
786                 printf("error \"%s\" operator has no exec function, python cannot call it\n", op->type->name);
787 #endif
788
789         retval= wm_operator_call_internal(C, ot, context, properties, reports);
790         
791         /* keep the reports around if needed later */
792         if (retval & OPERATOR_RUNNING_MODAL || ot->flag & OPTYPE_REGISTER)
793         {
794                 reports->flag |= RPT_FREE;
795         }
796         
797         return retval;
798 }
799
800
801 /* ********************* handlers *************** */
802
803 /* future extra customadata free? */
804 void wm_event_free_handler(wmEventHandler *handler)
805 {
806         MEM_freeN(handler);
807 }
808
809 /* only set context when area/region is part of screen */
810 static void wm_handler_op_context(bContext *C, wmEventHandler *handler)
811 {
812         bScreen *screen= CTX_wm_screen(C);
813         
814         if(screen && handler->op) {
815                 if(handler->op_area==NULL)
816                         CTX_wm_area_set(C, NULL);
817                 else {
818                         ScrArea *sa;
819                         
820                         for(sa= screen->areabase.first; sa; sa= sa->next)
821                                 if(sa==handler->op_area)
822                                         break;
823                         if(sa==NULL) {
824                                 /* when changing screen layouts with running modal handlers (like render display), this
825                                    is not an error to print */
826                                 if(handler->op==NULL)
827                                         printf("internal error: handler (%s) has invalid area\n", handler->op->type->idname);
828                         }
829                         else {
830                                 ARegion *ar;
831                                 CTX_wm_area_set(C, sa);
832                                 for(ar= sa->regionbase.first; ar; ar= ar->next)
833                                         if(ar==handler->op_region)
834                                                 break;
835                                 /* XXX no warning print here, after full-area and back regions are remade */
836                                 if(ar)
837                                         CTX_wm_region_set(C, ar);
838                         }
839                 }
840         }
841 }
842
843 /* called on exit or remove area, only here call cancel callback */
844 void WM_event_remove_handlers(bContext *C, ListBase *handlers)
845 {
846         wmEventHandler *handler;
847         wmWindowManager *wm= CTX_wm_manager(C);
848         
849         /* C is zero on freeing database, modal handlers then already were freed */
850         while((handler=handlers->first)) {
851                 BLI_remlink(handlers, handler);
852                 
853                 if(handler->op) {
854                         if(handler->op->type->cancel) {
855                                 ScrArea *area= CTX_wm_area(C);
856                                 ARegion *region= CTX_wm_region(C);
857                                 
858                                 wm_handler_op_context(C, handler);
859
860                                 if(handler->op->type->flag & OPTYPE_UNDO)
861                                         wm->op_undo_depth++;
862
863                                 handler->op->type->cancel(C, handler->op);
864
865                                 if(handler->op->type->flag & OPTYPE_UNDO)
866                                         wm->op_undo_depth--;
867
868                                 CTX_wm_area_set(C, area);
869                                 CTX_wm_region_set(C, region);
870                         }
871
872                         WM_cursor_ungrab(CTX_wm_window(C));
873                         WM_operator_free(handler->op);
874                 }
875                 else if(handler->ui_remove) {
876                         ScrArea *area= CTX_wm_area(C);
877                         ARegion *region= CTX_wm_region(C);
878                         ARegion *menu= CTX_wm_menu(C);
879                         
880                         if(handler->ui_area) CTX_wm_area_set(C, handler->ui_area);
881                         if(handler->ui_region) CTX_wm_region_set(C, handler->ui_region);
882                         if(handler->ui_menu) CTX_wm_menu_set(C, handler->ui_menu);
883
884                         handler->ui_remove(C, handler->ui_userdata);
885
886                         CTX_wm_area_set(C, area);
887                         CTX_wm_region_set(C, region);
888                         CTX_wm_menu_set(C, menu);
889                 }
890
891                 wm_event_free_handler(handler);
892         }
893 }
894
895 /* do userdef mappings */
896 int WM_userdef_event_map(int kmitype)
897 {
898         switch(kmitype) {
899                 case SELECTMOUSE:
900                         if(U.flag & USER_LMOUSESELECT)
901                                 return LEFTMOUSE;
902                         else
903                                 return RIGHTMOUSE;
904                         
905                 case ACTIONMOUSE:
906                         if(U.flag & USER_LMOUSESELECT)
907                                 return RIGHTMOUSE;
908                         else
909                                 return LEFTMOUSE;
910                         
911                 case WHEELOUTMOUSE:
912                         if(U.uiflag & USER_WHEELZOOMDIR)
913                                 return WHEELUPMOUSE;
914                         else
915                                 return WHEELDOWNMOUSE;
916                         
917                 case WHEELINMOUSE:
918                         if(U.uiflag & USER_WHEELZOOMDIR)
919                                 return WHEELDOWNMOUSE;
920                         else
921                                 return WHEELUPMOUSE;
922                         
923                 case EVT_TWEAK_A:
924                         if(U.flag & USER_LMOUSESELECT)
925                                 return EVT_TWEAK_R;
926                         else
927                                 return EVT_TWEAK_L;
928                         
929                 case EVT_TWEAK_S:
930                         if(U.flag & USER_LMOUSESELECT)
931                                 return EVT_TWEAK_L;
932                         else
933                                 return EVT_TWEAK_R;
934         }
935         
936         return kmitype;
937 }
938
939 static void wm_eventemulation(wmEvent *event)
940 {
941         static int mmb_emulated = 0; /* this should be in a data structure somwhere */
942         
943         /* middlemouse emulation */
944         if(U.flag & USER_TWOBUTTONMOUSE) {
945                 if(event->type == LEFTMOUSE && (event->alt || mmb_emulated == KM_PRESS)) {
946                         event->type = MIDDLEMOUSE;
947                         event->alt = 0;
948                         mmb_emulated = event->val;
949                 }
950         }
951
952 #ifdef __APPLE__
953         /* rightmouse emulation */
954         if(U.flag & USER_TWOBUTTONMOUSE) {
955                 if(event->type == LEFTMOUSE && (event->oskey || mmb_emulated == KM_PRESS)) {
956                         event->type = RIGHTMOUSE;
957                         event->oskey = 0;
958                         mmb_emulated = event->val;
959                 }
960         }
961 #endif
962
963         /* numpad emulation */
964         if(U.flag & USER_NONUMPAD) {
965                 switch(event->type) {
966                         case ZEROKEY: event->type = PAD0; break;
967                         case ONEKEY: event->type = PAD1; break;
968                         case TWOKEY: event->type = PAD2; break;
969                         case THREEKEY: event->type = PAD3; break;
970                         case FOURKEY: event->type = PAD4; break;
971                         case FIVEKEY: event->type = PAD5; break;
972                         case SIXKEY: event->type = PAD6; break;
973                         case SEVENKEY: event->type = PAD7; break;
974                         case EIGHTKEY: event->type = PAD8; break;
975                         case NINEKEY: event->type = PAD9; break;
976                         case MINUSKEY: event->type = PADMINUS; break;
977                         case EQUALKEY: event->type = PADPLUSKEY; break;
978                         case BACKSLASHKEY: event->type = PADSLASHKEY; break;
979                 }
980         }
981 }
982
983 static int wm_eventmatch(wmEvent *winevent, wmKeyMapItem *kmi)
984 {
985         int kmitype= WM_userdef_event_map(kmi->type);
986
987         if(kmi->flag & KMI_INACTIVE) return 0;
988
989         /* the matching rules */
990         if(kmitype==KM_TEXTINPUT)
991                 if(ISTEXTINPUT(winevent->type) && winevent->ascii) return 1;
992         if(kmitype!=KM_ANY)
993                 if(winevent->type!=kmitype) return 0;
994         
995         if(kmi->val!=KM_ANY)
996                 if(winevent->val!=kmi->val) return 0;
997         
998         /* modifiers also check bits, so it allows modifier order */
999         if(kmi->shift!=KM_ANY)
1000                 if(winevent->shift != kmi->shift && !(winevent->shift & kmi->shift)) return 0;
1001         if(kmi->ctrl!=KM_ANY)
1002                 if(winevent->ctrl != kmi->ctrl && !(winevent->ctrl & kmi->ctrl)) return 0;
1003         if(kmi->alt!=KM_ANY)
1004                 if(winevent->alt != kmi->alt && !(winevent->alt & kmi->alt)) return 0;
1005         if(kmi->oskey!=KM_ANY)
1006                 if(winevent->oskey != kmi->oskey && !(winevent->oskey & kmi->oskey)) return 0;
1007         
1008         if(kmi->keymodifier)
1009                 if(winevent->keymodifier!=kmi->keymodifier) return 0;
1010                 
1011         /* key modifiers always check when event has it */
1012         /* otherwise regular keypresses with keymodifier still work */
1013         if(winevent->keymodifier)
1014                 if(ISTEXTINPUT(winevent->type)) 
1015                         if(winevent->keymodifier!=kmi->keymodifier) return 0;
1016         
1017         return 1;
1018 }
1019
1020 static int wm_event_always_pass(wmEvent *event)
1021 {
1022         /* some events we always pass on, to ensure proper communication */
1023         return ISTIMER(event->type) || (event->type == WINDEACTIVATE);
1024 }
1025
1026 /* operator exists */
1027 static void wm_event_modalkeymap(const bContext *C, wmOperator *op, wmEvent *event)
1028 {
1029         /* support for modal keymap in macros */
1030         if (op->opm)
1031                 op = op->opm;
1032
1033         if(op->type->modalkeymap) {
1034                 wmKeyMap *keymap= WM_keymap_active(CTX_wm_manager(C), op->type->modalkeymap);
1035                 wmKeyMapItem *kmi;
1036
1037                 for(kmi= keymap->items.first; kmi; kmi= kmi->next) {
1038                         if(wm_eventmatch(event, kmi)) {
1039                                         
1040                                 event->type= EVT_MODAL_MAP;
1041                                 event->val= kmi->propvalue;
1042                         }
1043                 }
1044         }
1045 }
1046
1047 /* Warning: this function removes a modal handler, when finished */
1048 static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHandler *handler, wmEvent *event, PointerRNA *properties)
1049 {
1050         int retval= OPERATOR_PASS_THROUGH;
1051         
1052         /* derived, modal or blocking operator */
1053         if(handler->op) {
1054                 wmOperator *op= handler->op;
1055                 wmOperatorType *ot= op->type;
1056
1057                 if(ot->modal) {
1058                         /* we set context to where modal handler came from */
1059                         wmWindowManager *wm= CTX_wm_manager(C);
1060                         ScrArea *area= CTX_wm_area(C);
1061                         ARegion *region= CTX_wm_region(C);
1062                         
1063                         wm_handler_op_context(C, handler);
1064                         wm_region_mouse_co(C, event);
1065                         wm_event_modalkeymap(C, op, event);
1066                         
1067                         if(ot->flag & OPTYPE_UNDO)
1068                                 wm->op_undo_depth++;
1069
1070                         retval= ot->modal(C, op, event);
1071
1072                         if(ot->flag & OPTYPE_UNDO)
1073                                 wm->op_undo_depth--;
1074
1075                         /* putting back screen context, reval can pass trough after modal failures! */
1076                         if((retval & OPERATOR_PASS_THROUGH) || wm_event_always_pass(event)) {
1077                                 CTX_wm_area_set(C, area);
1078                                 CTX_wm_region_set(C, region);
1079                         }
1080                         else {
1081                                 /* this special cases is for areas and regions that get removed */
1082                                 CTX_wm_area_set(C, NULL);
1083                                 CTX_wm_region_set(C, NULL);
1084                         }
1085
1086                         if(retval & (OPERATOR_FINISHED|OPERATOR_CANCELLED))
1087                                 if(op->reports->list.first)
1088                                         uiPupMenuReports(C, op->reports);
1089
1090                         if (retval & OPERATOR_FINISHED) {
1091                                 if(G.f & G_DEBUG)
1092                                         wm_operator_print(op); /* todo - this print may double up, might want to check more flags then the FINISHED */
1093                         }                       
1094
1095                         if(retval & OPERATOR_FINISHED) {
1096                                 wm_operator_finished(C, op, 0);
1097                                 handler->op= NULL;
1098                         }
1099                         else if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) {
1100                                 WM_operator_free(op);
1101                                 handler->op= NULL;
1102                         }
1103                         
1104                         /* remove modal handler, operator itself should have been cancelled and freed */
1105                         if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) {
1106                                 WM_cursor_ungrab(CTX_wm_window(C));
1107
1108                                 BLI_remlink(handlers, handler);
1109                                 wm_event_free_handler(handler);
1110                                 
1111                                 /* prevent silly errors from operator users */
1112                                 //retval &= ~OPERATOR_PASS_THROUGH;
1113                         }
1114                         
1115                 }
1116                 else
1117                         printf("wm_handler_operator_call error\n");
1118         }
1119         else {
1120                 wmOperatorType *ot= WM_operatortype_find(event->keymap_idname, 0);
1121
1122                 if(ot)
1123                         retval= wm_operator_invoke(C, ot, event, properties, NULL);
1124         }
1125
1126         /* Finished and pass through flag as handled */
1127         if(retval == (OPERATOR_FINISHED|OPERATOR_PASS_THROUGH))
1128                 return WM_HANDLER_HANDLED;
1129
1130         /* Modal unhandled, break */
1131         if(retval == (OPERATOR_PASS_THROUGH|OPERATOR_RUNNING_MODAL))
1132                 return (WM_HANDLER_BREAK|WM_HANDLER_MODAL);
1133
1134         if(retval & OPERATOR_PASS_THROUGH)
1135                 return WM_HANDLER_CONTINUE;
1136
1137         return WM_HANDLER_BREAK;
1138 }
1139
1140 /* fileselect handlers are only in the window queue, so it's save to switch screens or area types */
1141 static int wm_handler_fileselect_call(bContext *C, ListBase *handlers, wmEventHandler *handler, wmEvent *event)
1142 {
1143         wmWindowManager *wm= CTX_wm_manager(C);
1144         SpaceFile *sfile;
1145         int action= WM_HANDLER_CONTINUE;
1146         
1147         if(event->type != EVT_FILESELECT)
1148                 return action;
1149         if(handler->op != (wmOperator *)event->customdata)
1150                 return action;
1151         
1152         switch(event->val) {
1153                 case EVT_FILESELECT_OPEN: 
1154                 case EVT_FILESELECT_FULL_OPEN: 
1155                         {       
1156                                 ScrArea *sa;
1157                                 
1158                                 /* sa can be null when window A is active, but mouse is over window B */
1159                                 /* in this case, open file select in original window A */
1160                                 if (handler->op_area == NULL) {
1161                                         bScreen *screen = CTX_wm_screen(C);
1162                                         sa = (ScrArea *)screen->areabase.first;
1163                                 } else
1164                                         sa = handler->op_area;
1165                                         
1166                                 if(event->val==EVT_FILESELECT_OPEN)
1167                                         ED_area_newspace(C, sa, SPACE_FILE);
1168                                 else
1169                                         ED_screen_full_newspace(C, sa, SPACE_FILE);     /* sets context */
1170                                 
1171                                 /* settings for filebrowser, sfile is not operator owner but sends events */
1172                                 sa = CTX_wm_area(C);
1173                                 sfile= (SpaceFile*)sa->spacedata.first;
1174                                 sfile->op= handler->op;
1175
1176                                 ED_fileselect_set_params(sfile);
1177                                 
1178                                 action= WM_HANDLER_BREAK;
1179                         }
1180                         break;
1181                         
1182                 case EVT_FILESELECT_EXEC:
1183                 case EVT_FILESELECT_CANCEL:
1184                         {
1185                                 /* XXX validate area and region? */
1186                                 bScreen *screen= CTX_wm_screen(C);
1187                                 char *path= RNA_string_get_alloc(handler->op->ptr, "path", NULL, 0);
1188                                 
1189                                 if(screen != handler->filescreen)
1190                                         ED_screen_full_prevspace(C, CTX_wm_area(C));
1191                                 else
1192                                         ED_area_prevspace(C, CTX_wm_area(C));
1193                                 
1194                                 /* remlink now, for load file case */
1195                                 BLI_remlink(handlers, handler);
1196                                 
1197                                 wm_handler_op_context(C, handler);
1198
1199                                 /* needed for uiPupMenuReports */
1200
1201                                 if(event->val==EVT_FILESELECT_EXEC) {
1202                                         /* a bit weak, might become arg for WM_event_fileselect? */
1203                                         /* XXX also extension code in image-save doesnt work for this yet */
1204                                         if (RNA_struct_find_property(handler->op->ptr, "check_existing") && 
1205                                                         RNA_boolean_get(handler->op->ptr, "check_existing")) {
1206                                                 /* this gives ownership to pupmenu */
1207                                                 uiPupMenuSaveOver(C, handler->op, (path)? path: "");
1208                                         }
1209                                         else {
1210                                                 int retval;
1211                                                 
1212                                                 if(handler->op->type->flag & OPTYPE_UNDO)
1213                                                         wm->op_undo_depth++;
1214
1215                                                 retval= handler->op->type->exec(C, handler->op);
1216
1217                                                 if(handler->op->type->flag & OPTYPE_UNDO)
1218                                                         wm->op_undo_depth--;
1219                                                 
1220                                                 if (retval & OPERATOR_FINISHED)
1221                                                         if(G.f & G_DEBUG)
1222                                                                 wm_operator_print(handler->op);
1223                                                 
1224                                                 if(wm->op_undo_depth == 0)
1225                                                         if(handler->op->type->flag & OPTYPE_UNDO)
1226                                                                 ED_undo_push_op(C, handler->op);
1227
1228                                                 if(handler->op->reports->list.first) {
1229
1230                                                         /* FIXME, temp setting window, this is really bad!
1231                                                          * only have because lib linking errors need to be seen by users :(
1232                                                          * it can be removed without breaking anything but then no linking errors - campbell */
1233                                                         wmWindow *win_prev= CTX_wm_window(C);
1234                                                         if(win_prev==NULL)
1235                                                                 CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first);
1236
1237                                                         handler->op->reports->printlevel = RPT_WARNING;
1238                                                         uiPupMenuReports(C, handler->op->reports);
1239
1240                                                         CTX_wm_window_set(C, win_prev);
1241                                                 }
1242
1243                                                 WM_operator_free(handler->op);
1244                                         }
1245                                 }
1246                                 else {
1247                                         if(handler->op->type->cancel) {
1248                                                 if(handler->op->type->flag & OPTYPE_UNDO)
1249                                                         wm->op_undo_depth++;
1250
1251                                                 handler->op->type->cancel(C, handler->op);
1252
1253                                                 if(handler->op->type->flag & OPTYPE_UNDO)
1254                                                         wm->op_undo_depth--;
1255                                         }
1256
1257                                         WM_operator_free(handler->op);
1258                                 }
1259
1260                                 CTX_wm_area_set(C, NULL);
1261                                 
1262                                 wm_event_free_handler(handler);
1263                                 if(path)
1264                                         MEM_freeN(path);
1265                                 
1266                                 action= WM_HANDLER_BREAK;
1267                         }
1268                         break;
1269         }
1270         
1271         return action;
1272 }
1273
1274 static int handler_boundbox_test(wmEventHandler *handler, wmEvent *event)
1275 {
1276         if(handler->bbwin) {
1277                 if(handler->bblocal) {
1278                         rcti rect= *handler->bblocal;
1279                         BLI_translate_rcti(&rect, handler->bbwin->xmin, handler->bbwin->ymin);
1280
1281                         if(BLI_in_rcti(&rect, event->x, event->y))
1282                                 return 1;
1283                         else if(event->type==MOUSEMOVE && BLI_in_rcti(&rect, event->prevx, event->prevy))
1284                                 return 1;
1285                         else
1286                                 return 0;
1287                 }
1288                 else {
1289                         if(BLI_in_rcti(handler->bbwin, event->x, event->y))
1290                                 return 1;
1291                         else if(event->type==MOUSEMOVE && BLI_in_rcti(handler->bbwin, event->prevx, event->prevy))
1292                                 return 1;
1293                         else
1294                                 return 0;
1295                 }
1296         }
1297         return 1;
1298 }
1299
1300 static int wm_action_not_handled(int action)
1301 {
1302         return action == WM_HANDLER_CONTINUE || action == (WM_HANDLER_BREAK|WM_HANDLER_MODAL);
1303 }
1304
1305 static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
1306 {
1307         wmWindowManager *wm= CTX_wm_manager(C);
1308         wmEventHandler *handler, *nexthandler;
1309         int action= WM_HANDLER_CONTINUE;
1310         int always_pass;
1311
1312         if(handlers==NULL) return action;
1313
1314         /* modal handlers can get removed in this loop, we keep the loop this way */
1315         for(handler= handlers->first; handler; handler= nexthandler) {
1316                 nexthandler= handler->next;
1317
1318                 /* optional boundbox */
1319                 if(handler_boundbox_test(handler, event)) {
1320                         /* in advance to avoid access to freed event on window close */
1321                         always_pass= wm_event_always_pass(event);
1322                 
1323                         /* modal+blocking handler */
1324                         if(handler->flag & WM_HANDLER_BLOCKING)
1325                                 action |= WM_HANDLER_BREAK;
1326
1327                         if(handler->keymap) {
1328                                 wmKeyMap *keymap= WM_keymap_active(wm, handler->keymap);
1329                                 wmKeyMapItem *kmi;
1330                                 
1331                                 if(!keymap->poll || keymap->poll(C)) {
1332                                         for(kmi= keymap->items.first; kmi; kmi= kmi->next) {
1333                                                 if(wm_eventmatch(event, kmi)) {
1334                                                         
1335                                                         event->keymap_idname= kmi->idname;      /* weak, but allows interactive callback to not use rawkey */
1336                                                         
1337                                                         action |= wm_handler_operator_call(C, handlers, handler, event, kmi->ptr);
1338                                                         if(action & WM_HANDLER_BREAK)  /* not always_pass here, it denotes removed handler */
1339                                                                 break;
1340                                                 }
1341                                         }
1342                                 }
1343                         }
1344                         else if(handler->ui_handle) {
1345                                 action |= wm_handler_ui_call(C, handler, event, always_pass);
1346                         }
1347                         else if(handler->type==WM_HANDLER_FILESELECT) {
1348                                 /* screen context changes here */
1349                                 action |= wm_handler_fileselect_call(C, handlers, handler, event);
1350                         }
1351                         else if(handler->dropboxes) {
1352                                 if(event->type==EVT_DROP) {
1353                                         wmDropBox *drop= handler->dropboxes->first;
1354                                         for(; drop; drop= drop->next) {
1355                                                 /* other drop custom types allowed */
1356                                                 if(event->custom==EVT_DATA_LISTBASE) {
1357                                                         ListBase *lb= (ListBase *)event->customdata;
1358                                                         wmDrag *drag;
1359                                                         for(drag= lb->first; drag; drag= drag->next) {
1360                                                                 if(drop->poll(C, drag, event)) {
1361                                                                         drop->copy(drag, drop);
1362                                                                         
1363                                                                         wm_operator_invoke(C, drop->ot, event, drop->ptr, NULL);
1364                                                                         action |= WM_HANDLER_BREAK;
1365                                                                 }
1366                                                         }
1367                                                 }
1368                                         }
1369                                 }
1370                         }
1371                         else {
1372                                 /* modal, swallows all */
1373                                 action |= wm_handler_operator_call(C, handlers, handler, event, NULL);
1374                         }
1375
1376                         if(action & WM_HANDLER_BREAK) {
1377                                 if(always_pass)
1378                                         action &= ~WM_HANDLER_BREAK;
1379                                 else
1380                                         break;
1381                         }
1382                 }
1383                 
1384                 /* fileread case */
1385                 if(CTX_wm_window(C)==NULL)
1386                         return action;
1387         }
1388
1389         /* test for CLICK event */
1390         if (wm_action_not_handled(action) && event->val == KM_RELEASE) {
1391                 wmWindow *win = CTX_wm_window(C);
1392
1393                 if (win && win->eventstate->prevtype == event->type && win->eventstate->prevval == KM_PRESS) {
1394                         /* test for double click first */
1395                         if ((PIL_check_seconds_timer() - win->eventstate->prevclicktime) * 1000 < U.dbl_click_time) {
1396                                 event->val = KM_DBL_CLICK;
1397                                 action |= wm_handlers_do(C, event, handlers);
1398                         }
1399
1400                         if (wm_action_not_handled(action)) {
1401                                 event->val = KM_CLICK;
1402                                 action |= wm_handlers_do(C, event, handlers);
1403                         }
1404
1405
1406                         /* revert value if not handled */
1407                         if (wm_action_not_handled(action)) {
1408                                 event->val = KM_RELEASE;
1409                         }
1410                 }
1411         }
1412
1413         return action;
1414 }
1415
1416 static int wm_event_inside_i(wmEvent *event, rcti *rect)
1417 {
1418         if(wm_event_always_pass(event))
1419                 return 1;
1420         if(BLI_in_rcti(rect, event->x, event->y))
1421            return 1;
1422         if(event->type==MOUSEMOVE) {
1423                 if( BLI_in_rcti(rect, event->prevx, event->prevy)) {
1424                         return 1;
1425                 }
1426                 return 0;
1427         }
1428         return 0;
1429 }
1430
1431 static ScrArea *area_event_inside(bContext *C, int x, int y)
1432 {
1433         bScreen *screen= CTX_wm_screen(C);
1434         ScrArea *sa;
1435         
1436         if(screen)
1437                 for(sa= screen->areabase.first; sa; sa= sa->next)
1438                         if(BLI_in_rcti(&sa->totrct, x, y))
1439                                 return sa;
1440         return NULL;
1441 }
1442
1443 static ARegion *region_event_inside(bContext *C, int x, int y)
1444 {
1445         bScreen *screen= CTX_wm_screen(C);
1446         ScrArea *area= CTX_wm_area(C);
1447         ARegion *ar;
1448         
1449         if(screen && area)
1450                 for(ar= area->regionbase.first; ar; ar= ar->next)
1451                         if(BLI_in_rcti(&ar->winrct, x, y))
1452                                 return ar;
1453         return NULL;
1454 }
1455
1456 static void wm_paintcursor_tag(bContext *C, wmPaintCursor *pc, ARegion *ar)
1457 {
1458         if(ar) {
1459                 for(; pc; pc= pc->next) {
1460                         if(pc->poll == NULL || pc->poll(C)) {
1461                                 wmWindow *win= CTX_wm_window(C);
1462                                 win->screen->do_draw_paintcursor= 1;
1463
1464                                 if(win->drawmethod != USER_DRAW_TRIPLE)
1465                                         ED_region_tag_redraw(ar);
1466                         }
1467                 }
1468         }
1469 }
1470
1471 /* called on mousemove, check updates for paintcursors */
1472 /* context was set on active area and region */
1473 static void wm_paintcursor_test(bContext *C, wmEvent *event)
1474 {
1475         wmWindowManager *wm= CTX_wm_manager(C);
1476         
1477         if(wm->paintcursors.first) {
1478                 ARegion *ar= CTX_wm_region(C);
1479                 if(ar)
1480                         wm_paintcursor_tag(C, wm->paintcursors.first, ar);
1481                 
1482                 /* if previous position was not in current region, we have to set a temp new context */
1483                 if(ar==NULL || !BLI_in_rcti(&ar->winrct, event->prevx, event->prevy)) {
1484                         ScrArea *sa= CTX_wm_area(C);
1485                         
1486                         CTX_wm_area_set(C, area_event_inside(C, event->prevx, event->prevy));
1487                         CTX_wm_region_set(C, region_event_inside(C, event->prevx, event->prevy));
1488
1489                         wm_paintcursor_tag(C, wm->paintcursors.first, CTX_wm_region(C));
1490                         
1491                         CTX_wm_area_set(C, sa);
1492                         CTX_wm_region_set(C, ar);
1493                 }
1494         }
1495 }
1496
1497 static void wm_event_drag_test(wmWindowManager *wm, wmWindow *win, wmEvent *event)
1498 {
1499         if(wm->drags.first==NULL) return;
1500         
1501         if(event->type==MOUSEMOVE)
1502                 win->screen->do_draw_drag= 1;
1503         else if(event->type==ESCKEY) {
1504                 BLI_freelistN(&wm->drags);
1505                 win->screen->do_draw_drag= 1;
1506         }
1507         else if(event->type==LEFTMOUSE && event->val==KM_RELEASE) {
1508                 event->type= EVT_DROP;
1509                 
1510                 /* create customdata, first free existing */
1511                 if(event->customdata) {
1512                         if(event->customdatafree)
1513                                 MEM_freeN(event->customdata);
1514                 }
1515                 
1516                 event->custom= EVT_DATA_LISTBASE;
1517                 event->customdata= &wm->drags;
1518                 event->customdatafree= 1;
1519                 
1520                 /* clear drop icon */
1521                 win->screen->do_draw_drag= 1;
1522                 
1523                 /* restore cursor (disabled, see wm_dragdrop.c) */
1524                 // WM_cursor_restore(win);
1525         }
1526         
1527         /* overlap fails otherwise */
1528         if(win->screen->do_draw_drag)
1529                 if(win->drawmethod == USER_DRAW_OVERLAP)
1530                         win->screen->do_draw= 1;
1531         
1532 }
1533
1534 /* called in main loop */
1535 /* goes over entire hierarchy:  events -> window -> screen -> area -> region */
1536 void wm_event_do_handlers(bContext *C)
1537 {
1538         wmWindowManager *wm= CTX_wm_manager(C);
1539         wmWindow *win;
1540
1541         for(win= wm->windows.first; win; win= win->next) {
1542                 wmEvent *event;
1543                 
1544                 if( win->screen==NULL )
1545                         wm_event_free_all(win);
1546                 else
1547                 {
1548                         Scene* scene = win->screen->scene;
1549                         if(scene)
1550                         {
1551                                 int playing = sound_scene_playing(win->screen->scene);
1552                                 if(playing != -1)
1553                                 {
1554                                         CTX_wm_window_set(C, win);
1555                                         CTX_wm_screen_set(C, win->screen);
1556                                         CTX_data_scene_set(C, scene);
1557                                         if(((playing == 1) && (!win->screen->animtimer)) || ((playing == 0) && (win->screen->animtimer)))
1558                                         {
1559                                                 ED_screen_animation_play(C, -1, 1);
1560                                         }
1561                                         if(playing == 0)
1562                                         {
1563                                                 int ncfra = floor(sound_sync_scene(scene) * FPS);
1564                                                 if(ncfra != scene->r.cfra)
1565                                                 {
1566                                                         scene->r.cfra = ncfra;
1567                                                         ED_update_for_newframe(C, 1);
1568                                                         WM_event_add_notifier(C, NC_WINDOW, NULL);
1569                                                 }
1570                                         }
1571                                         CTX_data_scene_set(C, NULL);
1572                                         CTX_wm_screen_set(C, NULL);
1573                                         CTX_wm_window_set(C, NULL);
1574                                 }
1575                         }
1576                 }
1577                 
1578                 while( (event= win->queue.first) ) {
1579                         int action = WM_HANDLER_CONTINUE;
1580
1581                         wm_eventemulation(event);
1582
1583                         CTX_wm_window_set(C, win);
1584                         
1585                         /* we let modal handlers get active area/region, also wm_paintcursor_test needs it */
1586                         CTX_wm_area_set(C, area_event_inside(C, event->x, event->y));
1587                         CTX_wm_region_set(C, region_event_inside(C, event->x, event->y));
1588                         
1589                         /* MVC demands to not draw in event handlers... but we need to leave it for ogl selecting etc */
1590                         wm_window_make_drawable(C, win);
1591                         
1592                         /* first we do priority handlers, modal + some limited keymaps */
1593                         action |= wm_handlers_do(C, event, &win->modalhandlers);
1594                         
1595                         /* fileread case */
1596                         if(CTX_wm_window(C)==NULL)
1597                                 return;
1598                         
1599                         /* check dragging, creates new event or frees, adds draw tag */
1600                         wm_event_drag_test(wm, win, event);
1601                         
1602                         /* builtin tweak, if action is break it removes tweak */
1603                         wm_tweakevent_test(C, event, action);
1604
1605                         if((action & WM_HANDLER_BREAK) == 0) {
1606                                 ScrArea *sa;
1607                                 ARegion *ar;
1608                                 int doit= 0;
1609                                 
1610                                 /* XXX to solve, here screen handlers? */
1611                                 if(event->type==MOUSEMOVE) {
1612                                         /* state variables in screen, cursors */
1613                                         ED_screen_set_subwinactive(win, event); 
1614                                         /* for regions having custom cursors */
1615                                         wm_paintcursor_test(C, event);
1616                                 }
1617
1618                                 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
1619                                         if(wm_event_inside_i(event, &sa->totrct)) {
1620                                                 CTX_wm_area_set(C, sa);
1621
1622                                                 if((action & WM_HANDLER_BREAK) == 0) {
1623                                                         for(ar=sa->regionbase.first; ar; ar= ar->next) {
1624                                                                 if(wm_event_inside_i(event, &ar->winrct)) {
1625                                                                         CTX_wm_region_set(C, ar);
1626                                                                         
1627                                                                         /* does polls for drop regions and checks uibuts */
1628                                                                         /* need to be here to make sure region context is true */
1629                                                                         if(event->type==MOUSEMOVE) {
1630                                                                                 wm_region_mouse_co(C, event);
1631                                                                                 wm_drags_check_ops(C, event);
1632                                                                         }
1633                                                                         
1634                                                                         action |= wm_handlers_do(C, event, &ar->handlers);
1635                                                                         
1636                                                                         doit |= (BLI_in_rcti(&ar->winrct, event->x, event->y));
1637                                                                         
1638                                                                         if(action & WM_HANDLER_BREAK)
1639                                                                                 break;
1640                                                                 }
1641                                                         }
1642                                                 }
1643
1644                                                 CTX_wm_region_set(C, NULL);
1645
1646                                                 if((action & WM_HANDLER_BREAK) == 0)
1647                                                         action |= wm_handlers_do(C, event, &sa->handlers);
1648
1649                                                 CTX_wm_area_set(C, NULL);
1650
1651                                                 /* NOTE: do not escape on WM_HANDLER_BREAK, mousemove needs handled for previous area */
1652                                         }
1653                                 }
1654                                 
1655                                 if((action & WM_HANDLER_BREAK) == 0) {
1656                                         /* also some non-modal handlers need active area/region */
1657                                         CTX_wm_area_set(C, area_event_inside(C, event->x, event->y));
1658                                         CTX_wm_region_set(C, region_event_inside(C, event->x, event->y));
1659
1660                                         action |= wm_handlers_do(C, event, &win->handlers);
1661
1662                                         /* fileread case */
1663                                         if(CTX_wm_window(C)==NULL)
1664                                                 return;
1665                                 }
1666
1667                                 /* XXX hrmf, this gives reliable previous mouse coord for area change, feels bad? 
1668                                    doing it on ghost queue gives errors when mousemoves go over area borders */
1669                                 if(doit && win->screen && win->screen->subwinactive != win->screen->mainwin) {
1670                                         win->eventstate->prevx= event->x;
1671                                         win->eventstate->prevy= event->y;
1672                                 }
1673                         }
1674                         
1675                         /* store last event for this window */
1676                         /* mousemove and timer events don't overwrite last type */
1677                         if (event->type != MOUSEMOVE && !ISTIMER(event->type)) {
1678                                 if (wm_action_not_handled(action)) {
1679                                         if (win->eventstate->prevtype == event->type) {
1680                                                 /* set click time on first click (press -> release) */
1681                                                 if (win->eventstate->prevval == KM_PRESS && event->val == KM_RELEASE) {
1682                                                         win->eventstate->prevclicktime = PIL_check_seconds_timer();
1683                                                 }
1684                                         } else {
1685                                                 /* reset click time if event type not the same */
1686                                                 win->eventstate->prevclicktime = 0;
1687                                         }
1688
1689                                         win->eventstate->prevval = event->val;
1690                                         win->eventstate->prevtype = event->type;
1691                                 } else if (event->val == KM_CLICK) { /* keep click for double click later */
1692                                         win->eventstate->prevtype = event->type;
1693                                         win->eventstate->prevval = event->val;
1694                                         win->eventstate->prevclicktime = PIL_check_seconds_timer();
1695                                 } else { /* reset if not */
1696                                         win->eventstate->prevtype = -1;
1697                                         win->eventstate->prevval = 0;
1698                                         win->eventstate->prevclicktime = 0;
1699                                 }
1700                         }
1701
1702                         /* unlink and free here, blender-quit then frees all */
1703                         BLI_remlink(&win->queue, event);
1704                         wm_event_free(event);
1705                         
1706                 }
1707                 
1708                 /* only add mousemove when queue was read entirely */
1709                 if(win->addmousemove && win->eventstate) {
1710                         wmEvent event= *(win->eventstate);
1711                         event.type= MOUSEMOVE;
1712                         event.prevx= event.x;
1713                         event.prevy= event.y;
1714                         wm_event_add(win, &event);
1715                         win->addmousemove= 0;
1716                 }
1717                 
1718                 CTX_wm_window_set(C, NULL);
1719         }
1720 }
1721
1722 /* ********** filesector handling ************ */
1723
1724 void WM_event_fileselect_event(bContext *C, void *ophandle, int eventval)
1725 {
1726         /* add to all windows! */
1727         wmWindow *win;
1728         
1729         for(win= CTX_wm_manager(C)->windows.first; win; win= win->next) {
1730                 wmEvent event= *win->eventstate;
1731                 
1732                 event.type= EVT_FILESELECT;
1733                 event.val= eventval;
1734                 event.customdata= ophandle;             // only as void pointer type check
1735
1736                 wm_event_add(win, &event);
1737         }
1738 }
1739
1740 /* operator is supposed to have a filled "path" property */
1741 /* optional property: filetype (XXX enum?) */
1742
1743 /* Idea is to keep a handler alive on window queue, owning the operator.
1744    The filewindow can send event to make it execute, thus ensuring
1745    executing happens outside of lower level queues, with UI refreshed. 
1746    Should also allow multiwin solutions */
1747
1748 void WM_event_add_fileselect(bContext *C, wmOperator *op)
1749 {
1750         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "fileselect handler");
1751         wmWindow *win= CTX_wm_window(C);
1752         int full= 1;    // XXX preset?
1753         
1754         handler->type= WM_HANDLER_FILESELECT;
1755         handler->op= op;
1756         handler->op_area= CTX_wm_area(C);
1757         handler->op_region= CTX_wm_region(C);
1758         handler->filescreen= CTX_wm_screen(C);
1759         
1760         BLI_addhead(&win->modalhandlers, handler);
1761         
1762         WM_event_fileselect_event(C, op, full?EVT_FILESELECT_FULL_OPEN:EVT_FILESELECT_OPEN);
1763 }
1764
1765 /* lets not expose struct outside wm? */
1766 void WM_event_set_handler_flag(wmEventHandler *handler, int flag)
1767 {
1768         handler->flag= flag;
1769 }
1770
1771 wmEventHandler *WM_event_add_modal_handler(bContext *C, wmOperator *op)
1772 {
1773         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event modal handler");
1774         wmWindow *win= CTX_wm_window(C);
1775         
1776         /* operator was part of macro */
1777         if(op->opm) {
1778                 /* give the mother macro to the handler */
1779                 handler->op= op->opm;
1780                 /* mother macro opm becomes the macro element */
1781                 handler->op->opm= op;
1782         }
1783         else
1784                 handler->op= op;
1785         
1786         handler->op_area= CTX_wm_area(C);               /* means frozen screen context for modal handlers! */
1787         handler->op_region= CTX_wm_region(C);
1788         
1789         BLI_addhead(&win->modalhandlers, handler);
1790
1791         return handler;
1792 }
1793
1794 wmEventHandler *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
1795 {
1796         wmEventHandler *handler;
1797
1798         if(!keymap) {
1799                 printf("WM_event_add_keymap_handler called with NULL keymap\n");
1800                 return NULL;
1801         }
1802
1803         /* only allow same keymap once */
1804         for(handler= handlers->first; handler; handler= handler->next)
1805                 if(handler->keymap==keymap)
1806                         return handler;
1807         
1808         handler= MEM_callocN(sizeof(wmEventHandler), "event keymap handler");
1809         BLI_addtail(handlers, handler);
1810         handler->keymap= keymap;
1811
1812         return handler;
1813 }
1814
1815 /* priorities not implemented yet, for time being just insert in begin of list */
1816 wmEventHandler *WM_event_add_keymap_handler_priority(ListBase *handlers, wmKeyMap *keymap, int priority)
1817 {
1818         wmEventHandler *handler;
1819         
1820         WM_event_remove_keymap_handler(handlers, keymap);
1821         
1822         handler= MEM_callocN(sizeof(wmEventHandler), "event keymap handler");
1823         BLI_addhead(handlers, handler);
1824         handler->keymap= keymap;
1825         
1826         return handler;
1827 }
1828
1829 wmEventHandler *WM_event_add_keymap_handler_bb(ListBase *handlers, wmKeyMap *keymap, rcti *bblocal, rcti *bbwin)
1830 {
1831         wmEventHandler *handler= WM_event_add_keymap_handler(handlers, keymap);
1832         
1833         if(handler) {
1834                 handler->bblocal= bblocal;
1835                 handler->bbwin= bbwin;
1836         }
1837         return handler;
1838 }
1839
1840 void WM_event_remove_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
1841 {
1842         wmEventHandler *handler;
1843         
1844         for(handler= handlers->first; handler; handler= handler->next) {
1845                 if(handler->keymap==keymap) {
1846                         BLI_remlink(handlers, handler);
1847                         wm_event_free_handler(handler);
1848                         break;
1849                 }
1850         }
1851 }
1852
1853 wmEventHandler *WM_event_add_ui_handler(const bContext *C, ListBase *handlers, wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata)
1854 {
1855         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event ui handler");
1856         handler->ui_handle= func;
1857         handler->ui_remove= remove;
1858         handler->ui_userdata= userdata;
1859         handler->ui_area= (C)? CTX_wm_area(C): NULL;
1860         handler->ui_region= (C)? CTX_wm_region(C): NULL;
1861         handler->ui_menu= (C)? CTX_wm_menu(C): NULL;
1862         
1863         BLI_addhead(handlers, handler);
1864         
1865         return handler;
1866 }
1867
1868 void WM_event_remove_ui_handler(ListBase *handlers, wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata)
1869 {
1870         wmEventHandler *handler;
1871         
1872         for(handler= handlers->first; handler; handler= handler->next) {
1873                 if(handler->ui_handle == func && handler->ui_remove == remove && handler->ui_userdata == userdata) {
1874                         BLI_remlink(handlers, handler);
1875                         wm_event_free_handler(handler);
1876                         break;
1877                 }
1878         }
1879 }
1880
1881 wmEventHandler *WM_event_add_dropbox_handler(ListBase *handlers, ListBase *dropboxes)
1882 {
1883         wmEventHandler *handler;
1884
1885         /* only allow same dropbox once */
1886         for(handler= handlers->first; handler; handler= handler->next)
1887                 if(handler->dropboxes==dropboxes)
1888                         return handler;
1889         
1890         handler= MEM_callocN(sizeof(wmEventHandler), "dropbox handler");
1891         
1892         /* dropbox stored static, no free or copy */
1893         handler->dropboxes= dropboxes;
1894         BLI_addhead(handlers, handler);
1895         
1896         return handler;
1897 }
1898
1899 /* XXX solution works, still better check the real cause (ton) */
1900 void WM_event_remove_area_handler(ListBase *handlers, void *area)
1901 {
1902         wmEventHandler *handler, *nexthandler;
1903
1904         for(handler = handlers->first; handler; handler= nexthandler) {
1905                 nexthandler = handler->next;
1906                 if (handler->type != WM_HANDLER_FILESELECT) {
1907                         if (handler->ui_area == area) {
1908                                 BLI_remlink(handlers, handler);
1909                                 wm_event_free_handler(handler);
1910                         }
1911                 }
1912         }
1913 }
1914
1915 void WM_event_remove_handler(ListBase *handlers, wmEventHandler *handler)
1916 {
1917         BLI_remlink(handlers, handler);
1918         wm_event_free_handler(handler);
1919 }
1920
1921 void WM_event_add_mousemove(bContext *C)
1922 {
1923         wmWindow *window= CTX_wm_window(C);
1924         
1925         window->addmousemove= 1;
1926 }
1927
1928 /* for modal callbacks, check configuration for how to interpret exit with tweaks  */
1929 int WM_modal_tweak_exit(wmEvent *evt, int tweak_event)
1930 {
1931         /* user preset or keymap? dunno... */
1932         int tweak_modal= (U.flag & USER_DRAGIMMEDIATE)==0;
1933         
1934         switch(tweak_event) {
1935                 case EVT_TWEAK_L:
1936                 case EVT_TWEAK_M:
1937                 case EVT_TWEAK_R:
1938                         if(evt->val==tweak_modal)
1939                                 return 1;
1940                 default:
1941                         /* this case is when modal callcback didnt get started with a tweak */
1942                         if(evt->val)
1943                                 return 1;
1944         }
1945         return 0;
1946 }
1947
1948 /* ********************* ghost stuff *************** */
1949
1950 static int convert_key(GHOST_TKey key) 
1951 {
1952         if (key>=GHOST_kKeyA && key<=GHOST_kKeyZ) {
1953                 return (AKEY + ((int) key - GHOST_kKeyA));
1954         } else if (key>=GHOST_kKey0 && key<=GHOST_kKey9) {
1955                 return (ZEROKEY + ((int) key - GHOST_kKey0));
1956         } else if (key>=GHOST_kKeyNumpad0 && key<=GHOST_kKeyNumpad9) {
1957                 return (PAD0 + ((int) key - GHOST_kKeyNumpad0));
1958         } else if (key>=GHOST_kKeyF1 && key<=GHOST_kKeyF12) {
1959                 return (F1KEY + ((int) key - GHOST_kKeyF1));
1960         } else {
1961                 switch (key) {
1962                         case GHOST_kKeyBackSpace:               return BACKSPACEKEY;
1963                         case GHOST_kKeyTab:                             return TABKEY;
1964                         case GHOST_kKeyLinefeed:                return LINEFEEDKEY;
1965                         case GHOST_kKeyClear:                   return 0;
1966                         case GHOST_kKeyEnter:                   return RETKEY;
1967                                 
1968                         case GHOST_kKeyEsc:                             return ESCKEY;
1969                         case GHOST_kKeySpace:                   return SPACEKEY;
1970                         case GHOST_kKeyQuote:                   return QUOTEKEY;
1971                         case GHOST_kKeyComma:                   return COMMAKEY;
1972                         case GHOST_kKeyMinus:                   return MINUSKEY;
1973                         case GHOST_kKeyPeriod:                  return PERIODKEY;
1974                         case GHOST_kKeySlash:                   return SLASHKEY;
1975                                 
1976                         case GHOST_kKeySemicolon:               return SEMICOLONKEY;
1977                         case GHOST_kKeyEqual:                   return EQUALKEY;
1978                                 
1979                         case GHOST_kKeyLeftBracket:             return LEFTBRACKETKEY;
1980                         case GHOST_kKeyRightBracket:    return RIGHTBRACKETKEY;
1981                         case GHOST_kKeyBackslash:               return BACKSLASHKEY;
1982                         case GHOST_kKeyAccentGrave:             return ACCENTGRAVEKEY;
1983                                 
1984                         case GHOST_kKeyLeftShift:               return LEFTSHIFTKEY;
1985                         case GHOST_kKeyRightShift:              return RIGHTSHIFTKEY;
1986                         case GHOST_kKeyLeftControl:             return LEFTCTRLKEY;
1987                         case GHOST_kKeyRightControl:    return RIGHTCTRLKEY;
1988                         case GHOST_kKeyCommand:                 return COMMANDKEY;
1989                         case GHOST_kKeyLeftAlt:                 return LEFTALTKEY;
1990                         case GHOST_kKeyRightAlt:                return RIGHTALTKEY;
1991                                 
1992                         case GHOST_kKeyCapsLock:                return CAPSLOCKKEY;
1993                         case GHOST_kKeyNumLock:                 return 0;
1994                         case GHOST_kKeyScrollLock:              return 0;
1995                                 
1996                         case GHOST_kKeyLeftArrow:               return LEFTARROWKEY;
1997                         case GHOST_kKeyRightArrow:              return RIGHTARROWKEY;
1998                         case GHOST_kKeyUpArrow:                 return UPARROWKEY;
1999                         case GHOST_kKeyDownArrow:               return DOWNARROWKEY;
2000                                 
2001                         case GHOST_kKeyPrintScreen:             return 0;
2002                         case GHOST_kKeyPause:                   return PAUSEKEY;
2003                                 
2004                         case GHOST_kKeyInsert:                  return INSERTKEY;
2005                         case GHOST_kKeyDelete:                  return DELKEY;
2006                         case GHOST_kKeyHome:                    return HOMEKEY;
2007                         case GHOST_kKeyEnd:                             return ENDKEY;
2008                         case GHOST_kKeyUpPage:                  return PAGEUPKEY;
2009                         case GHOST_kKeyDownPage:                return PAGEDOWNKEY;
2010                                 
2011                         case GHOST_kKeyNumpadPeriod:    return PADPERIOD;
2012                         case GHOST_kKeyNumpadEnter:             return PADENTER;
2013                         case GHOST_kKeyNumpadPlus:              return PADPLUSKEY;
2014                         case GHOST_kKeyNumpadMinus:             return PADMINUS;
2015                         case GHOST_kKeyNumpadAsterisk:  return PADASTERKEY;
2016                         case GHOST_kKeyNumpadSlash:             return PADSLASHKEY;
2017                                 
2018                         case GHOST_kKeyGrLess:              return GRLESSKEY; 
2019                                 
2020                         default:
2021                                 return UNKNOWNKEY;      /* GHOST_kKeyUnknown */
2022                 }
2023         }
2024 }
2025
2026 /* adds customdata to event */
2027 static void update_tablet_data(wmWindow *win, wmEvent *event)
2028 {
2029         const GHOST_TabletData *td= GHOST_GetTabletData(win->ghostwin);
2030         
2031         /* if there's tablet data from an active tablet device then add it */
2032         if ((td != NULL) && td->Active != GHOST_kTabletModeNone) {
2033                 struct wmTabletData *wmtab= MEM_mallocN(sizeof(wmTabletData), "customdata tablet");
2034                 
2035                 wmtab->Active = (int)td->Active;
2036                 wmtab->Pressure = td->Pressure;
2037                 wmtab->Xtilt = td->Xtilt;
2038                 wmtab->Ytilt = td->Ytilt;
2039                 
2040                 event->custom= EVT_DATA_TABLET;
2041                 event->customdata= wmtab;
2042                 event->customdatafree= 1;
2043         } 
2044 }
2045
2046 /* imperfect but probably usable... draw/enable drags to other windows */
2047 static wmWindow *wm_event_cursor_other_windows(wmWindowManager *wm, wmWindow *win, wmEvent *evt)
2048 {
2049         short mx= evt->x, my= evt->y;
2050         
2051         if(wm->windows.first== wm->windows.last)
2052                 return NULL;
2053         
2054         /* top window bar... */
2055         if(mx<0 || my<0 || mx>win->sizex || my>win->sizey+30) { 
2056                 wmWindow *owin;
2057                 wmEventHandler *handler;
2058                 
2059                 /* let's skip windows having modal handlers now */
2060                 /* potential XXX ugly... I wouldn't have added a modalhandlers list (introduced in rev 23331, ton) */
2061                 for(handler= win->modalhandlers.first; handler; handler= handler->next)
2062                         if(handler->ui_handle || handler->op)
2063                                 return NULL;
2064                 
2065                 /* to desktop space */
2066                 mx+= win->posx;
2067                 my+= win->posy;
2068                 
2069                 /* check other windows to see if it has mouse inside */
2070                 for(owin= wm->windows.first; owin; owin= owin->next) {
2071                         
2072                         if(owin!=win) {
2073                                 if(mx-owin->posx >= 0 && my-owin->posy >= 0 &&
2074                                    mx-owin->posx <= owin->sizex && my-owin->posy <= owin->sizey) {
2075                                         evt->x= mx-owin->posx;
2076                                         evt->y= my-owin->posy;
2077                                         
2078                                         return owin;
2079                                 }
2080                         }
2081                 }
2082         }
2083         return NULL;
2084 }
2085
2086 /* windows store own event queues, no bContext here */
2087 /* time is in 1000s of seconds, from ghost */
2088 void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int time, void *customdata)
2089 {
2090         wmWindow *owin;
2091         wmEvent event, *evt= win->eventstate;
2092         
2093         /* initialize and copy state (only mouse x y and modifiers) */
2094         event= *evt;
2095         
2096         switch (type) {
2097                 /* mouse move */
2098                 case GHOST_kEventCursorMove: {
2099                         if(win->active) {
2100                                 GHOST_TEventCursorData *cd= customdata;
2101                                 
2102 #if defined(__APPLE__) && defined(GHOST_COCOA)
2103                                 //Cocoa already uses coordinates with y=0 at bottom, and returns inwindow coordinates on mouse moved event
2104                                 evt->x= cd->x;
2105                                 evt->y= cd->y;
2106 #else
2107                                 int cx, cy;
2108                                 
2109                                 GHOST_ScreenToClient(win->ghostwin, cd->x, cd->y, &cx, &cy);
2110                                 evt->x= cx;
2111                                 evt->y= (win->sizey-1) - cy;
2112 #endif
2113                                 
2114                                 event.x= evt->x;
2115                                 event.y= evt->y;
2116
2117                                 event.type= MOUSEMOVE;
2118
2119                                 update_tablet_data(win, &event);
2120                                 wm_event_add(win, &event);
2121                                 
2122                                 /* also add to other window if event is there, this makes overdraws disappear nicely */
2123                                 /* it remaps mousecoord to other window in event */
2124                                 owin= wm_event_cursor_other_windows(wm, win, &event);
2125                                 if(owin) {
2126                                         wmEvent oevent= *(owin->eventstate);
2127                                         
2128                                         oevent.x= event.x;
2129                                         oevent.y= event.y;
2130                                         oevent.type= MOUSEMOVE;
2131                                         
2132                                         *(owin->eventstate)= oevent;
2133                                         update_tablet_data(owin, &oevent);
2134                                         wm_event_add(owin, &oevent);
2135                                 }
2136                                 
2137                         }
2138                         break;
2139                 }
2140                 case GHOST_kEventTrackpad: {
2141                         GHOST_TEventTrackpadData * pd = customdata;
2142                         switch (pd->subtype) {
2143                                 case GHOST_kTrackpadEventMagnify:
2144                                         event.type = MOUSEZOOM;
2145                                         break;
2146                                 case GHOST_kTrackpadEventRotate:
2147                                         event.type = MOUSEROTATE;
2148                                         break;
2149                                 case GHOST_kTrackpadEventScroll:
2150                                 default:
2151                                         event.type= MOUSEPAN;
2152                                         break;
2153                         }
2154 #if defined(__APPLE__) && defined(GHOST_COCOA)
2155                         //Cocoa already uses coordinates with y=0 at bottom, and returns inwindow coordinates on mouse moved event
2156                         event.x= evt->x = pd->x;
2157                         event.y = evt->y = pd->y;
2158 #else
2159                         {
2160                         int cx, cy;
2161                         GHOST_ScreenToClient(win->ghostwin, pd->x, pd->y, &cx, &cy);
2162                         event.x= evt->x= cx;
2163                         event.y= evt->y= (win->sizey-1) - cy;
2164                         }
2165 #endif
2166                         // Use prevx/prevy so we can calculate the delta later
2167                         event.prevx= event.x - pd->deltaX;
2168                         event.prevy= event.y - pd->deltaY;
2169                         
2170                         update_tablet_data(win, &event);
2171                         wm_event_add(win, &event);
2172                         break;
2173                 }
2174                 /* mouse button */
2175                 case GHOST_kEventButtonDown:
2176                 case GHOST_kEventButtonUp: {
2177                         GHOST_TEventButtonData *bd= customdata;
2178                         event.val= (type==GHOST_kEventButtonDown) ? KM_PRESS:KM_RELEASE; /* Note!, this starts as 0/1 but later is converted to KM_PRESS/KM_RELEASE by tweak */
2179                         
2180                         if (bd->button == GHOST_kButtonMaskLeft)
2181                                 event.type= LEFTMOUSE;
2182                         else if (bd->button == GHOST_kButtonMaskRight)
2183                                 event.type= RIGHTMOUSE;
2184                         else if (bd->button == GHOST_kButtonMaskButton4)
2185                                 event.type= BUTTON4MOUSE;
2186                         else if (bd->button == GHOST_kButtonMaskButton5)
2187                                 event.type= BUTTON5MOUSE;
2188                         else
2189                                 event.type= MIDDLEMOUSE;
2190                         
2191                         /* add to other window if event is there (not to both!) */
2192                         owin= wm_event_cursor_other_windows(wm, win, &event);
2193                         if(owin) {
2194                                 wmEvent oevent= *(owin->eventstate);
2195                                 
2196                                 oevent.x= event.x;
2197                                 oevent.y= event.y;
2198                                 oevent.type= event.type;
2199                                 oevent.val= event.val;
2200                                 
2201                                 update_tablet_data(owin, &oevent);
2202                                 wm_event_add(owin, &oevent);
2203                         }
2204                         else {
2205                                 update_tablet_data(win, &event);
2206                                 wm_event_add(win, &event);
2207                         }
2208                         
2209                         break;
2210                 }
2211                 /* keyboard */
2212                 case GHOST_kEventKeyDown:
2213                 case GHOST_kEventKeyUp: {
2214                         GHOST_TEventKeyData *kd= customdata;
2215                         event.type= convert_key(kd->key);
2216                         event.ascii= kd->ascii;
2217                         event.val= (type==GHOST_kEventKeyDown)?KM_PRESS:KM_RELEASE;
2218                         
2219                         /* exclude arrow keys, esc, etc from text input */
2220                         if(type==GHOST_kEventKeyUp || (event.ascii<32 && event.ascii>0))
2221                                 event.ascii= '\0';
2222                         
2223                         /* modifiers */
2224                         if (event.type==LEFTSHIFTKEY || event.type==RIGHTSHIFTKEY) {
2225                                 event.shift= evt->shift= (event.val==KM_PRESS);
2226                                 if(event.val==KM_PRESS && (evt->ctrl || evt->alt || evt->oskey))
2227                                    event.shift= evt->shift = 3;         // define?
2228                         } 
2229                         else if (event.type==LEFTCTRLKEY || event.type==RIGHTCTRLKEY) {
2230                                 event.ctrl= evt->ctrl= (event.val==KM_PRESS);
2231                                 if(event.val==KM_PRESS && (evt->shift || evt->alt || evt->oskey))
2232                                    event.ctrl= evt->ctrl = 3;           // define?
2233                         } 
2234                         else if (event.type==LEFTALTKEY || event.type==RIGHTALTKEY) {
2235                                 event.alt= evt->alt= (event.val==KM_PRESS);
2236                                 if(event.val==KM_PRESS && (evt->ctrl || evt->shift || evt->oskey))
2237                                    event.alt= evt->alt = 3;             // define?
2238                         } 
2239                         else if (event.type==COMMANDKEY) {
2240                                 event.oskey= evt->oskey= (event.val==KM_PRESS);
2241                                 if(event.val==KM_PRESS && (evt->ctrl || evt->alt || evt->shift))
2242                                    event.oskey= evt->oskey = 3;         // define?
2243                         }
2244                         else {
2245                                 if(event.val==KM_PRESS && event.keymodifier==0)
2246                                         evt->keymodifier= event.type; /* only set in eventstate, for next event */
2247                                 else if(event.val==KM_RELEASE && event.keymodifier==event.type)
2248                                         event.keymodifier= evt->keymodifier= 0;
2249                         }
2250
2251                         /* this case happens on some systems that on holding a key pressed,
2252                            generate press events without release, we still want to keep the
2253                            modifier in win->eventstate, but for the press event of the same
2254                            key we don't want the key modifier */
2255                         if(event.keymodifier == event.type)
2256                                 event.keymodifier= 0;
2257                         
2258                         /* if test_break set, it catches this. XXX Keep global for now? */
2259                         if(event.type==ESCKEY)
2260                                 G.afbreek= 1;
2261                         
2262                         wm_event_add(win, &event);
2263                         
2264                         break;
2265                 }
2266                         
2267                 case GHOST_kEventWheel: {
2268                         GHOST_TEventWheelData* wheelData = customdata;
2269                         
2270                         if (wheelData->z > 0)
2271                                 event.type= WHEELUPMOUSE;
2272                         else
2273                                 event.type= WHEELDOWNMOUSE;
2274                         
2275                         event.val= KM_PRESS;
2276                         wm_event_add(win, &event);
2277                         
2278                         break;
2279                 }
2280                 case GHOST_kEventTimer: {
2281                         event.type= TIMER;
2282                         event.custom= EVT_DATA_TIMER;
2283                         event.customdata= customdata;
2284                         wm_event_add(win, &event);
2285
2286                         break;
2287                 }
2288
2289                 case GHOST_kEventUnknown:
2290                 case GHOST_kNumEventTypes:
2291                         break;
2292
2293                 case GHOST_kEventWindowDeactivate: {
2294                         event.type= WINDEACTIVATE;
2295                         wm_event_add(win, &event);
2296
2297                         break;
2298                         
2299                 }
2300
2301         }
2302 }