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