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