warning fixes and minor cmake changes.
[blender-staging.git] / source / blender / windowmanager / intern / wm_event_system.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2007 Blender Foundation.
21  * All rights reserved.
22  *
23  * 
24  * Contributor(s): Blender Foundation
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include <stdlib.h>
30 #include <string.h>
31 #include <math.h>
32
33 #include "DNA_listBase.h"
34 #include "DNA_screen_types.h"
35 #include "DNA_scene_types.h"
36 #include "DNA_windowmanager_types.h"
37 #include "DNA_userdef_types.h"
38
39 #include "MEM_guardedalloc.h"
40
41 #include "GHOST_C-api.h"
42
43 #include "BLI_blenlib.h"
44
45 #include "BKE_blender.h"
46 #include "BKE_context.h"
47 #include "BKE_idprop.h"
48 #include "BKE_global.h"
49 #include "BKE_main.h"
50 #include "BKE_report.h"
51 #include "BKE_scene.h"
52 #include "BKE_screen.h"
53 #include "BKE_utildefines.h"
54 #include "BKE_sound.h"
55
56 #include "ED_fileselect.h"
57 #include "ED_info.h"
58 #include "ED_screen.h"
59 #include "ED_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                 case EVT_FILESELECT_EXTERNAL_CANCEL:
1228                         {
1229                                 /* XXX validate area and region? */
1230                                 bScreen *screen= CTX_wm_screen(C);
1231
1232                                 /* remlink now, for load file case before removing*/
1233                                 BLI_remlink(handlers, handler);
1234                                 
1235                                 if(event->val!=EVT_FILESELECT_EXTERNAL_CANCEL) {
1236                                         if(screen != handler->filescreen) {
1237                                                 ED_screen_full_prevspace(C, CTX_wm_area(C));
1238                                         }
1239                                         else {
1240                                                 ED_area_prevspace(C, CTX_wm_area(C));
1241                                         }
1242                                 }
1243                                 
1244                                 wm_handler_op_context(C, handler);
1245
1246                                 /* needed for uiPupMenuReports */
1247
1248                                 if(event->val==EVT_FILESELECT_EXEC) {
1249 #if 0                           // use REDALERT now
1250
1251                                         /* a bit weak, might become arg for WM_event_fileselect? */
1252                                         /* XXX also extension code in image-save doesnt work for this yet */
1253                                         if (RNA_struct_find_property(handler->op->ptr, "check_existing") && 
1254                                                         RNA_boolean_get(handler->op->ptr, "check_existing")) {
1255                                                 char *path= RNA_string_get_alloc(handler->op->ptr, "filepath", NULL, 0);
1256                                                 /* this gives ownership to pupmenu */
1257                                                 uiPupMenuSaveOver(C, handler->op, (path)? path: "");
1258                                                 if(path)
1259                                                         MEM_freeN(path);
1260                                         }
1261                                         else
1262 #endif
1263                                         {
1264                                                 int retval;
1265                                                 
1266                                                 if(handler->op->type->flag & OPTYPE_UNDO)
1267                                                         wm->op_undo_depth++;
1268
1269                                                 retval= handler->op->type->exec(C, handler->op);
1270
1271                                                 if(handler->op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm)
1272                                                         wm->op_undo_depth--;
1273                                                 
1274                                                 if (retval & OPERATOR_FINISHED)
1275                                                         if(G.f & G_DEBUG)
1276                                                                 wm_operator_print(handler->op);
1277                                                 
1278                                                 if(wm->op_undo_depth == 0)
1279                                                         if(handler->op->type->flag & OPTYPE_UNDO)
1280                                                                 ED_undo_push_op(C, handler->op);
1281
1282                                                 if(handler->op->reports->list.first) {
1283
1284                                                         /* FIXME, temp setting window, this is really bad!
1285                                                          * only have because lib linking errors need to be seen by users :(
1286                                                          * it can be removed without breaking anything but then no linking errors - campbell */
1287                                                         wmWindow *win_prev= CTX_wm_window(C);
1288                                                         if(win_prev==NULL)
1289                                                                 CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first);
1290
1291                                                         handler->op->reports->printlevel = RPT_WARNING;
1292                                                         uiPupMenuReports(C, handler->op->reports);
1293
1294                                                         /* XXX - copied from 'wm_operator_finished()' */
1295                                                         /* add reports to the global list, otherwise they are not seen */
1296                                                         addlisttolist(&CTX_wm_reports(C)->list, &handler->op->reports->list);
1297
1298                                                         CTX_wm_window_set(C, win_prev);
1299                                                 }
1300
1301                                                 WM_operator_free(handler->op);
1302                                         }
1303                                 }
1304                                 else {
1305                                         if(handler->op->type->cancel) {
1306                                                 if(handler->op->type->flag & OPTYPE_UNDO)
1307                                                         wm->op_undo_depth++;
1308
1309                                                 handler->op->type->cancel(C, handler->op);
1310
1311                                                 if(handler->op->type->flag & OPTYPE_UNDO)
1312                                                         wm->op_undo_depth--;
1313                                         }
1314
1315                                         WM_operator_free(handler->op);
1316                                 }
1317
1318                                 CTX_wm_area_set(C, NULL);
1319                                 
1320                                 wm_event_free_handler(handler);
1321                                 
1322                                 action= WM_HANDLER_BREAK;
1323                         }
1324                         break;
1325         }
1326         
1327         return action;
1328 }
1329
1330 static int handler_boundbox_test(wmEventHandler *handler, wmEvent *event)
1331 {
1332         if(handler->bbwin) {
1333                 if(handler->bblocal) {
1334                         rcti rect= *handler->bblocal;
1335                         BLI_translate_rcti(&rect, handler->bbwin->xmin, handler->bbwin->ymin);
1336
1337                         if(BLI_in_rcti(&rect, event->x, event->y))
1338                                 return 1;
1339                         else if(event->type==MOUSEMOVE && BLI_in_rcti(&rect, event->prevx, event->prevy))
1340                                 return 1;
1341                         else
1342                                 return 0;
1343                 }
1344                 else {
1345                         if(BLI_in_rcti(handler->bbwin, event->x, event->y))
1346                                 return 1;
1347                         else if(event->type==MOUSEMOVE && BLI_in_rcti(handler->bbwin, event->prevx, event->prevy))
1348                                 return 1;
1349                         else
1350                                 return 0;
1351                 }
1352         }
1353         return 1;
1354 }
1355
1356 static int wm_action_not_handled(int action)
1357 {
1358         return action == WM_HANDLER_CONTINUE || action == (WM_HANDLER_BREAK|WM_HANDLER_MODAL);
1359 }
1360
1361 static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
1362 {
1363         wmWindowManager *wm= CTX_wm_manager(C);
1364         wmEventHandler *handler, *nexthandler;
1365         int action= WM_HANDLER_CONTINUE;
1366         int always_pass;
1367
1368         if(handlers==NULL) return action;
1369
1370         /* modal handlers can get removed in this loop, we keep the loop this way */
1371         for(handler= handlers->first; handler; handler= nexthandler) {
1372                 nexthandler= handler->next;
1373
1374                 /* optional boundbox */
1375                 if(handler_boundbox_test(handler, event)) {
1376                         /* in advance to avoid access to freed event on window close */
1377                         always_pass= wm_event_always_pass(event);
1378                 
1379                         /* modal+blocking handler */
1380                         if(handler->flag & WM_HANDLER_BLOCKING)
1381                                 action |= WM_HANDLER_BREAK;
1382
1383                         if(handler->keymap) {
1384                                 wmKeyMap *keymap= WM_keymap_active(wm, handler->keymap);
1385                                 wmKeyMapItem *kmi;
1386                                 
1387                                 if(!keymap->poll || keymap->poll(C)) {
1388                                         for(kmi= keymap->items.first; kmi; kmi= kmi->next) {
1389                                                 if(wm_eventmatch(event, kmi)) {
1390                                                         
1391                                                         event->keymap_idname= kmi->idname;      /* weak, but allows interactive callback to not use rawkey */
1392                                                         
1393                                                         action |= wm_handler_operator_call(C, handlers, handler, event, kmi->ptr);
1394                                                         if(action & WM_HANDLER_BREAK)  /* not always_pass here, it denotes removed handler */
1395                                                                 break;
1396                                                 }
1397                                         }
1398                                 }
1399                         }
1400                         else if(handler->ui_handle) {
1401                                 action |= wm_handler_ui_call(C, handler, event, always_pass);
1402                         }
1403                         else if(handler->type==WM_HANDLER_FILESELECT) {
1404                                 /* screen context changes here */
1405                                 action |= wm_handler_fileselect_call(C, handlers, handler, event);
1406                         }
1407                         else if(handler->dropboxes) {
1408                                 if(event->type==EVT_DROP) {
1409                                         wmDropBox *drop= handler->dropboxes->first;
1410                                         for(; drop; drop= drop->next) {
1411                                                 /* other drop custom types allowed */
1412                                                 if(event->custom==EVT_DATA_LISTBASE) {
1413                                                         ListBase *lb= (ListBase *)event->customdata;
1414                                                         wmDrag *drag;
1415                                                         for(drag= lb->first; drag; drag= drag->next) {
1416                                                                 if(drop->poll(C, drag, event)) {
1417                                                                         drop->copy(drag, drop);
1418                                                                         
1419                                                                         wm_operator_invoke(C, drop->ot, event, drop->ptr, NULL);
1420                                                                         action |= WM_HANDLER_BREAK;
1421                                                                 }
1422                                                         }
1423                                                 }
1424                                         }
1425                                 }
1426                         }
1427                         else {
1428                                 /* modal, swallows all */
1429                                 action |= wm_handler_operator_call(C, handlers, handler, event, NULL);
1430                         }
1431
1432                         if(action & WM_HANDLER_BREAK) {
1433                                 if(always_pass)
1434                                         action &= ~WM_HANDLER_BREAK;
1435                                 else
1436                                         break;
1437                         }
1438                 }
1439                 
1440                 /* fileread case */
1441                 if(CTX_wm_window(C)==NULL)
1442                         return action;
1443         }
1444
1445         /* test for CLICK event */
1446         if (wm_action_not_handled(action) && event->val == KM_RELEASE) {
1447                 wmWindow *win = CTX_wm_window(C);
1448
1449                 if (win && win->eventstate->prevtype == event->type && win->eventstate->prevval == KM_PRESS) {
1450                         /* test for double click first */
1451                         if ((PIL_check_seconds_timer() - win->eventstate->prevclicktime) * 1000 < U.dbl_click_time) {
1452                                 event->val = KM_DBL_CLICK;
1453                                 event->x = win->eventstate->prevclickx;
1454                                 event->y = win->eventstate->prevclicky;
1455                                 action |= wm_handlers_do(C, event, handlers);
1456                         }
1457
1458                         if (wm_action_not_handled(action)) {
1459                                 event->val = KM_CLICK;
1460                                 action |= wm_handlers_do(C, event, handlers);
1461                         }
1462
1463
1464                         /* revert value if not handled */
1465                         if (wm_action_not_handled(action)) {
1466                                 event->val = KM_RELEASE;
1467                         }
1468                 }
1469         }
1470
1471         return action;
1472 }
1473
1474 static int wm_event_inside_i(wmEvent *event, rcti *rect)
1475 {
1476         if(wm_event_always_pass(event))
1477                 return 1;
1478         if(BLI_in_rcti(rect, event->x, event->y))
1479            return 1;
1480         if(event->type==MOUSEMOVE) {
1481                 if( BLI_in_rcti(rect, event->prevx, event->prevy)) {
1482                         return 1;
1483                 }
1484                 return 0;
1485         }
1486         return 0;
1487 }
1488
1489 static ScrArea *area_event_inside(bContext *C, int x, int y)
1490 {
1491         bScreen *screen= CTX_wm_screen(C);
1492         ScrArea *sa;
1493         
1494         if(screen)
1495                 for(sa= screen->areabase.first; sa; sa= sa->next)
1496                         if(BLI_in_rcti(&sa->totrct, x, y))
1497                                 return sa;
1498         return NULL;
1499 }
1500
1501 static ARegion *region_event_inside(bContext *C, int x, int y)
1502 {
1503         bScreen *screen= CTX_wm_screen(C);
1504         ScrArea *area= CTX_wm_area(C);
1505         ARegion *ar;
1506         
1507         if(screen && area)
1508                 for(ar= area->regionbase.first; ar; ar= ar->next)
1509                         if(BLI_in_rcti(&ar->winrct, x, y))
1510                                 return ar;
1511         return NULL;
1512 }
1513
1514 static void wm_paintcursor_tag(bContext *C, wmPaintCursor *pc, ARegion *ar)
1515 {
1516         if(ar) {
1517                 for(; pc; pc= pc->next) {
1518                         if(pc->poll == NULL || pc->poll(C)) {
1519                                 wmWindow *win= CTX_wm_window(C);
1520                                 win->screen->do_draw_paintcursor= 1;
1521                                 wm_tag_redraw_overlay(win, ar);
1522                         }
1523                 }
1524         }
1525 }
1526
1527 /* called on mousemove, check updates for paintcursors */
1528 /* context was set on active area and region */
1529 static void wm_paintcursor_test(bContext *C, wmEvent *event)
1530 {
1531         wmWindowManager *wm= CTX_wm_manager(C);
1532         
1533         if(wm->paintcursors.first) {
1534                 ARegion *ar= CTX_wm_region(C);
1535                 if(ar)
1536                         wm_paintcursor_tag(C, wm->paintcursors.first, ar);
1537                 
1538                 /* if previous position was not in current region, we have to set a temp new context */
1539                 if(ar==NULL || !BLI_in_rcti(&ar->winrct, event->prevx, event->prevy)) {
1540                         ScrArea *sa= CTX_wm_area(C);
1541                         
1542                         CTX_wm_area_set(C, area_event_inside(C, event->prevx, event->prevy));
1543                         CTX_wm_region_set(C, region_event_inside(C, event->prevx, event->prevy));
1544
1545                         wm_paintcursor_tag(C, wm->paintcursors.first, CTX_wm_region(C));
1546                         
1547                         CTX_wm_area_set(C, sa);
1548                         CTX_wm_region_set(C, ar);
1549                 }
1550         }
1551 }
1552
1553 static void wm_event_drag_test(wmWindowManager *wm, wmWindow *win, wmEvent *event)
1554 {
1555         if(wm->drags.first==NULL) return;
1556         
1557         if(event->type==MOUSEMOVE)
1558                 win->screen->do_draw_drag= 1;
1559         else if(event->type==ESCKEY) {
1560                 BLI_freelistN(&wm->drags);
1561                 win->screen->do_draw_drag= 1;
1562         }
1563         else if(event->type==LEFTMOUSE && event->val==KM_RELEASE) {
1564                 event->type= EVT_DROP;
1565                 
1566                 /* create customdata, first free existing */
1567                 if(event->customdata) {
1568                         if(event->customdatafree)
1569                                 MEM_freeN(event->customdata);
1570                 }
1571                 
1572                 event->custom= EVT_DATA_LISTBASE;
1573                 event->customdata= &wm->drags;
1574                 event->customdatafree= 1;
1575                 
1576                 /* clear drop icon */
1577                 win->screen->do_draw_drag= 1;
1578                 
1579                 /* restore cursor (disabled, see wm_dragdrop.c) */
1580                 // WM_cursor_restore(win);
1581         }
1582         
1583         /* overlap fails otherwise */
1584         if(win->screen->do_draw_drag)
1585                 if(win->drawmethod == USER_DRAW_OVERLAP)
1586                         win->screen->do_draw= 1;
1587         
1588 }
1589
1590 /* called in main loop */
1591 /* goes over entire hierarchy:  events -> window -> screen -> area -> region */
1592 void wm_event_do_handlers(bContext *C)
1593 {
1594         wmWindowManager *wm= CTX_wm_manager(C);
1595         wmWindow *win;
1596
1597         for(win= wm->windows.first; win; win= win->next) {
1598                 wmEvent *event;
1599                 
1600                 if( win->screen==NULL )
1601                         wm_event_free_all(win);
1602                 else {
1603                         Scene* scene = win->screen->scene;
1604                         
1605                         if(scene) {
1606                                 int playing = sound_scene_playing(win->screen->scene);
1607                                 
1608                                 if(playing != -1) {
1609                                         CTX_wm_window_set(C, win);
1610                                         CTX_wm_screen_set(C, win->screen);
1611                                         CTX_data_scene_set(C, scene);
1612                                         
1613                                         if(((playing == 1) && (!win->screen->animtimer)) || ((playing == 0) && (win->screen->animtimer))){
1614                                                 ED_screen_animation_play(C, -1, 1);
1615                                         }
1616                                         
1617                                         if(playing == 0) {
1618                                                 int ncfra = sound_sync_scene(scene) * FPS + 0.5;
1619                                                 if(ncfra != scene->r.cfra)      {
1620                                                         scene->r.cfra = ncfra;
1621                                                         ED_update_for_newframe(C, 1);
1622                                                         WM_event_add_notifier(C, NC_WINDOW, NULL);
1623                                                 }
1624                                         }
1625                                         
1626                                         CTX_data_scene_set(C, NULL);
1627                                         CTX_wm_screen_set(C, NULL);
1628                                         CTX_wm_window_set(C, NULL);
1629                                 }
1630                         }
1631                 }
1632                 
1633                 while( (event= win->queue.first) ) {
1634                         int action = WM_HANDLER_CONTINUE;
1635
1636                         if((G.f & G_DEBUG) && event && !ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE))
1637                                 printf("pass on evt %d val %d\n", event->type, event->val); 
1638                         
1639                         wm_eventemulation(event);
1640
1641                         CTX_wm_window_set(C, win);
1642                         
1643                         /* we let modal handlers get active area/region, also wm_paintcursor_test needs it */
1644                         CTX_wm_area_set(C, area_event_inside(C, event->x, event->y));
1645                         CTX_wm_region_set(C, region_event_inside(C, event->x, event->y));
1646                         
1647                         /* MVC demands to not draw in event handlers... but we need to leave it for ogl selecting etc */
1648                         wm_window_make_drawable(C, win);
1649                         
1650                         /* first we do priority handlers, modal + some limited keymaps */
1651                         action |= wm_handlers_do(C, event, &win->modalhandlers);
1652                         
1653                         /* fileread case */
1654                         if(CTX_wm_window(C)==NULL)
1655                                 return;
1656                         
1657                         /* check dragging, creates new event or frees, adds draw tag */
1658                         wm_event_drag_test(wm, win, event);
1659                         
1660                         /* builtin tweak, if action is break it removes tweak */
1661                         wm_tweakevent_test(C, event, action);
1662
1663                         if((action & WM_HANDLER_BREAK) == 0) {
1664                                 ScrArea *sa;
1665                                 ARegion *ar;
1666                                 int doit= 0;
1667                                 
1668                                 /* XXX to solve, here screen handlers? */
1669                                 if(event->type==MOUSEMOVE) {
1670                                         /* state variables in screen, cursors */
1671                                         ED_screen_set_subwinactive(win, event); 
1672                                         /* for regions having custom cursors */
1673                                         wm_paintcursor_test(C, event);
1674                                 }
1675
1676                                 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
1677                                         if(wm_event_inside_i(event, &sa->totrct)) {
1678                                                 CTX_wm_area_set(C, sa);
1679
1680                                                 if((action & WM_HANDLER_BREAK) == 0) {
1681                                                         for(ar=sa->regionbase.first; ar; ar= ar->next) {
1682                                                                 if(wm_event_inside_i(event, &ar->winrct)) {
1683                                                                         CTX_wm_region_set(C, ar);
1684                                                                         
1685                                                                         /* does polls for drop regions and checks uibuts */
1686                                                                         /* need to be here to make sure region context is true */
1687                                                                         if(ELEM(event->type, MOUSEMOVE, EVT_DROP)) {
1688                                                                                 wm_region_mouse_co(C, event);
1689                                                                                 wm_drags_check_ops(C, event);
1690                                                                         }
1691                                                                         
1692                                                                         action |= wm_handlers_do(C, event, &ar->handlers);
1693                                                                         
1694                                                                         doit |= (BLI_in_rcti(&ar->winrct, event->x, event->y));
1695                                                                         
1696                                                                         if(action & WM_HANDLER_BREAK)
1697                                                                                 break;
1698                                                                 }
1699                                                         }
1700                                                 }
1701
1702                                                 CTX_wm_region_set(C, NULL);
1703
1704                                                 if((action & WM_HANDLER_BREAK) == 0)
1705                                                         action |= wm_handlers_do(C, event, &sa->handlers);
1706
1707                                                 CTX_wm_area_set(C, NULL);
1708
1709                                                 /* NOTE: do not escape on WM_HANDLER_BREAK, mousemove needs handled for previous area */
1710                                         }
1711                                 }
1712                                 
1713                                 if((action & WM_HANDLER_BREAK) == 0) {
1714                                         /* also some non-modal handlers need active area/region */
1715                                         CTX_wm_area_set(C, area_event_inside(C, event->x, event->y));
1716                                         CTX_wm_region_set(C, region_event_inside(C, event->x, event->y));
1717
1718                                         action |= wm_handlers_do(C, event, &win->handlers);
1719
1720                                         /* fileread case */
1721                                         if(CTX_wm_window(C)==NULL)
1722                                                 return;
1723                                 }
1724
1725                                 /* XXX hrmf, this gives reliable previous mouse coord for area change, feels bad? 
1726                                    doing it on ghost queue gives errors when mousemoves go over area borders */
1727                                 if(doit && win->screen && win->screen->subwinactive != win->screen->mainwin) {
1728                                         win->eventstate->prevx= event->x;
1729                                         win->eventstate->prevy= event->y;
1730                                 }
1731                         }
1732                         
1733                         /* store last event for this window */
1734                         /* mousemove and timer events don't overwrite last type */
1735                         if (event->type != MOUSEMOVE && !ISTIMER(event->type)) {
1736                                 if (wm_action_not_handled(action)) {
1737                                         if (win->eventstate->prevtype == event->type) {
1738                                                 /* set click time on first click (press -> release) */
1739                                                 if (win->eventstate->prevval == KM_PRESS && event->val == KM_RELEASE) {
1740                                                         win->eventstate->prevclicktime = PIL_check_seconds_timer();
1741                                                         win->eventstate->prevclickx = event->x;
1742                                                         win->eventstate->prevclicky = event->y;
1743                                                 }
1744                                         } else {
1745                                                 /* reset click time if event type not the same */
1746                                                 win->eventstate->prevclicktime = 0;
1747                                         }
1748
1749                                         win->eventstate->prevval = event->val;
1750                                         win->eventstate->prevtype = event->type;
1751                                 } else if (event->val == KM_CLICK) { /* keep click for double click later */
1752                                         win->eventstate->prevtype = event->type;
1753                                         win->eventstate->prevval = event->val;
1754                                         win->eventstate->prevclicktime = PIL_check_seconds_timer();
1755                                         win->eventstate->prevclickx = event->x;
1756                                         win->eventstate->prevclicky = event->y;
1757                                 } else { /* reset if not */
1758                                         win->eventstate->prevtype = -1;
1759                                         win->eventstate->prevval = 0;
1760                                         win->eventstate->prevclicktime = 0;
1761                                 }
1762                         }
1763
1764                         /* unlink and free here, blender-quit then frees all */
1765                         BLI_remlink(&win->queue, event);
1766                         wm_event_free(event);
1767                         
1768                 }
1769                 
1770                 /* only add mousemove when queue was read entirely */
1771                 if(win->addmousemove && win->eventstate) {
1772                         wmEvent event= *(win->eventstate);
1773                         event.type= MOUSEMOVE;
1774                         event.prevx= event.x;
1775                         event.prevy= event.y;
1776                         wm_event_add(win, &event);
1777                         win->addmousemove= 0;
1778                 }
1779                 
1780                 CTX_wm_window_set(C, NULL);
1781         }
1782 }
1783
1784 /* ********** filesector handling ************ */
1785
1786 void WM_event_fileselect_event(bContext *C, void *ophandle, int eventval)
1787 {
1788         /* add to all windows! */
1789         wmWindow *win;
1790         
1791         for(win= CTX_wm_manager(C)->windows.first; win; win= win->next) {
1792                 wmEvent event= *win->eventstate;
1793                 
1794                 event.type= EVT_FILESELECT;
1795                 event.val= eventval;
1796                 event.customdata= ophandle;             // only as void pointer type check
1797
1798                 wm_event_add(win, &event);
1799         }
1800 }
1801
1802 /* operator is supposed to have a filled "path" property */
1803 /* optional property: filetype (XXX enum?) */
1804
1805 /* Idea is to keep a handler alive on window queue, owning the operator.
1806    The filewindow can send event to make it execute, thus ensuring
1807    executing happens outside of lower level queues, with UI refreshed. 
1808    Should also allow multiwin solutions */
1809
1810 void WM_event_add_fileselect(bContext *C, wmOperator *op)
1811 {
1812         wmEventHandler *handler;
1813         wmWindow *win= CTX_wm_window(C);
1814         int full= 1;    // XXX preset?
1815
1816         /* only allow file selector open per window bug [#23553] */
1817         for(handler= win->modalhandlers.first; handler; handler=handler->next) {
1818                 if(handler->type == WM_HANDLER_FILESELECT)
1819                         return;
1820         }
1821         
1822         handler = MEM_callocN(sizeof(wmEventHandler), "fileselect handler");
1823         
1824         handler->type= WM_HANDLER_FILESELECT;
1825         handler->op= op;
1826         handler->op_area= CTX_wm_area(C);
1827         handler->op_region= CTX_wm_region(C);
1828         handler->filescreen= CTX_wm_screen(C);
1829         
1830         BLI_addhead(&win->modalhandlers, handler);
1831         
1832         /* check props once before invoking if check is available
1833          * ensures initial properties are valid */
1834         if(op->type->check) {
1835                 op->type->check(C, op); /* ignore return value */
1836         }
1837
1838         WM_event_fileselect_event(C, op, full?EVT_FILESELECT_FULL_OPEN:EVT_FILESELECT_OPEN);
1839 }
1840
1841 /* lets not expose struct outside wm? */
1842 void WM_event_set_handler_flag(wmEventHandler *handler, int flag)
1843 {
1844         handler->flag= flag;
1845 }
1846
1847 wmEventHandler *WM_event_add_modal_handler(bContext *C, wmOperator *op)
1848 {
1849         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event modal handler");
1850         wmWindow *win= CTX_wm_window(C);
1851         
1852         /* operator was part of macro */
1853         if(op->opm) {
1854                 /* give the mother macro to the handler */
1855                 handler->op= op->opm;
1856                 /* mother macro opm becomes the macro element */
1857                 handler->op->opm= op;
1858         }
1859         else
1860                 handler->op= op;
1861         
1862         handler->op_area= CTX_wm_area(C);               /* means frozen screen context for modal handlers! */
1863         handler->op_region= CTX_wm_region(C);
1864         
1865         BLI_addhead(&win->modalhandlers, handler);
1866
1867         return handler;
1868 }
1869
1870 wmEventHandler *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
1871 {
1872         wmEventHandler *handler;
1873
1874         if(!keymap) {
1875                 printf("WM_event_add_keymap_handler called with NULL keymap\n");
1876                 return NULL;
1877         }
1878
1879         /* only allow same keymap once */
1880         for(handler= handlers->first; handler; handler= handler->next)
1881                 if(handler->keymap==keymap)
1882                         return handler;
1883         
1884         handler= MEM_callocN(sizeof(wmEventHandler), "event keymap handler");
1885         BLI_addtail(handlers, handler);
1886         handler->keymap= keymap;
1887
1888         return handler;
1889 }
1890
1891 /* priorities not implemented yet, for time being just insert in begin of list */
1892 wmEventHandler *WM_event_add_keymap_handler_priority(ListBase *handlers, wmKeyMap *keymap, int priority)
1893 {
1894         wmEventHandler *handler;
1895         
1896         WM_event_remove_keymap_handler(handlers, keymap);
1897         
1898         handler= MEM_callocN(sizeof(wmEventHandler), "event keymap handler");
1899         BLI_addhead(handlers, handler);
1900         handler->keymap= keymap;
1901         
1902         return handler;
1903 }
1904
1905 wmEventHandler *WM_event_add_keymap_handler_bb(ListBase *handlers, wmKeyMap *keymap, rcti *bblocal, rcti *bbwin)
1906 {
1907         wmEventHandler *handler= WM_event_add_keymap_handler(handlers, keymap);
1908         
1909         if(handler) {
1910                 handler->bblocal= bblocal;
1911                 handler->bbwin= bbwin;
1912         }
1913         return handler;
1914 }
1915
1916 void WM_event_remove_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
1917 {
1918         wmEventHandler *handler;
1919         
1920         for(handler= handlers->first; handler; handler= handler->next) {
1921                 if(handler->keymap==keymap) {
1922                         BLI_remlink(handlers, handler);
1923                         wm_event_free_handler(handler);
1924                         break;
1925                 }
1926         }
1927 }
1928
1929 wmEventHandler *WM_event_add_ui_handler(const bContext *C, ListBase *handlers, wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata)
1930 {
1931         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event ui handler");
1932         handler->ui_handle= func;
1933         handler->ui_remove= remove;
1934         handler->ui_userdata= userdata;
1935         handler->ui_area= (C)? CTX_wm_area(C): NULL;
1936         handler->ui_region= (C)? CTX_wm_region(C): NULL;
1937         handler->ui_menu= (C)? CTX_wm_menu(C): NULL;
1938         
1939         BLI_addhead(handlers, handler);
1940         
1941         return handler;
1942 }
1943
1944 void WM_event_remove_ui_handler(ListBase *handlers, wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata)
1945 {
1946         wmEventHandler *handler;
1947         
1948         for(handler= handlers->first; handler; handler= handler->next) {
1949                 if(handler->ui_handle == func && handler->ui_remove == remove && handler->ui_userdata == userdata) {
1950                         BLI_remlink(handlers, handler);
1951                         wm_event_free_handler(handler);
1952                         break;
1953                 }
1954         }
1955 }
1956
1957 wmEventHandler *WM_event_add_dropbox_handler(ListBase *handlers, ListBase *dropboxes)
1958 {
1959         wmEventHandler *handler;
1960
1961         /* only allow same dropbox once */
1962         for(handler= handlers->first; handler; handler= handler->next)
1963                 if(handler->dropboxes==dropboxes)
1964                         return handler;
1965         
1966         handler= MEM_callocN(sizeof(wmEventHandler), "dropbox handler");
1967         
1968         /* dropbox stored static, no free or copy */
1969         handler->dropboxes= dropboxes;
1970         BLI_addhead(handlers, handler);
1971         
1972         return handler;
1973 }
1974
1975 /* XXX solution works, still better check the real cause (ton) */
1976 void WM_event_remove_area_handler(ListBase *handlers, void *area)
1977 {
1978         wmEventHandler *handler, *nexthandler;
1979
1980         for(handler = handlers->first; handler; handler= nexthandler) {
1981                 nexthandler = handler->next;
1982                 if (handler->type != WM_HANDLER_FILESELECT) {
1983                         if (handler->ui_area == area) {
1984                                 BLI_remlink(handlers, handler);
1985                                 wm_event_free_handler(handler);
1986                         }
1987                 }
1988         }
1989 }
1990
1991 void WM_event_remove_handler(ListBase *handlers, wmEventHandler *handler)
1992 {
1993         BLI_remlink(handlers, handler);
1994         wm_event_free_handler(handler);
1995 }
1996
1997 void WM_event_add_mousemove(bContext *C)
1998 {
1999         wmWindow *window= CTX_wm_window(C);
2000         
2001         window->addmousemove= 1;
2002 }
2003
2004 /* for modal callbacks, check configuration for how to interpret exit with tweaks  */
2005 int WM_modal_tweak_exit(wmEvent *evt, int tweak_event)
2006 {
2007         /* user preset or keymap? dunno... */
2008         // XXX WTH is this?
2009         int tweak_modal= (U.flag & USER_RELEASECONFIRM)==0;
2010         
2011         switch(tweak_event) {
2012                 case EVT_TWEAK_L:
2013                 case EVT_TWEAK_M:
2014                 case EVT_TWEAK_R:
2015                         if(evt->val==tweak_modal)
2016                                 return 1;
2017                 default:
2018                         /* this case is when modal callcback didnt get started with a tweak */
2019                         if(evt->val)
2020                                 return 1;
2021         }
2022         return 0;
2023 }
2024
2025 /* ********************* ghost stuff *************** */
2026
2027 static int convert_key(GHOST_TKey key) 
2028 {
2029         if (key>=GHOST_kKeyA && key<=GHOST_kKeyZ) {
2030                 return (AKEY + ((int) key - GHOST_kKeyA));
2031         } else if (key>=GHOST_kKey0 && key<=GHOST_kKey9) {
2032                 return (ZEROKEY + ((int) key - GHOST_kKey0));
2033         } else if (key>=GHOST_kKeyNumpad0 && key<=GHOST_kKeyNumpad9) {
2034                 return (PAD0 + ((int) key - GHOST_kKeyNumpad0));
2035         } else if (key>=GHOST_kKeyF1 && key<=GHOST_kKeyF19) {
2036                 return (F1KEY + ((int) key - GHOST_kKeyF1));
2037         } else {
2038                 switch (key) {
2039                         case GHOST_kKeyBackSpace:               return BACKSPACEKEY;
2040                         case GHOST_kKeyTab:                             return TABKEY;
2041                         case GHOST_kKeyLinefeed:                return LINEFEEDKEY;
2042                         case GHOST_kKeyClear:                   return 0;
2043                         case GHOST_kKeyEnter:                   return RETKEY;
2044                                 
2045                         case GHOST_kKeyEsc:                             return ESCKEY;
2046                         case GHOST_kKeySpace:                   return SPACEKEY;
2047                         case GHOST_kKeyQuote:                   return QUOTEKEY;
2048                         case GHOST_kKeyComma:                   return COMMAKEY;
2049                         case GHOST_kKeyMinus:                   return MINUSKEY;
2050                         case GHOST_kKeyPeriod:                  return PERIODKEY;
2051                         case GHOST_kKeySlash:                   return SLASHKEY;
2052                                 
2053                         case GHOST_kKeySemicolon:               return SEMICOLONKEY;
2054                         case GHOST_kKeyEqual:                   return EQUALKEY;
2055                                 
2056                         case GHOST_kKeyLeftBracket:             return LEFTBRACKETKEY;
2057                         case GHOST_kKeyRightBracket:    return RIGHTBRACKETKEY;
2058                         case GHOST_kKeyBackslash:               return BACKSLASHKEY;
2059                         case GHOST_kKeyAccentGrave:             return ACCENTGRAVEKEY;
2060                                 
2061                         case GHOST_kKeyLeftShift:               return LEFTSHIFTKEY;
2062                         case GHOST_kKeyRightShift:              return RIGHTSHIFTKEY;
2063                         case GHOST_kKeyLeftControl:             return LEFTCTRLKEY;
2064                         case GHOST_kKeyRightControl:    return RIGHTCTRLKEY;
2065                         case GHOST_kKeyCommand:                 return COMMANDKEY;
2066                         case GHOST_kKeyLeftAlt:                 return LEFTALTKEY;
2067                         case GHOST_kKeyRightAlt:                return RIGHTALTKEY;
2068                                 
2069                         case GHOST_kKeyCapsLock:                return CAPSLOCKKEY;
2070                         case GHOST_kKeyNumLock:                 return 0;
2071                         case GHOST_kKeyScrollLock:              return 0;
2072                                 
2073                         case GHOST_kKeyLeftArrow:               return LEFTARROWKEY;
2074                         case GHOST_kKeyRightArrow:              return RIGHTARROWKEY;
2075                         case GHOST_kKeyUpArrow:                 return UPARROWKEY;
2076                         case GHOST_kKeyDownArrow:               return DOWNARROWKEY;
2077                                 
2078                         case GHOST_kKeyPrintScreen:             return 0;
2079                         case GHOST_kKeyPause:                   return PAUSEKEY;
2080                                 
2081                         case GHOST_kKeyInsert:                  return INSERTKEY;
2082                         case GHOST_kKeyDelete:                  return DELKEY;
2083                         case GHOST_kKeyHome:                    return HOMEKEY;
2084                         case GHOST_kKeyEnd:                             return ENDKEY;
2085                         case GHOST_kKeyUpPage:                  return PAGEUPKEY;
2086                         case GHOST_kKeyDownPage:                return PAGEDOWNKEY;
2087                                 
2088                         case GHOST_kKeyNumpadPeriod:    return PADPERIOD;
2089                         case GHOST_kKeyNumpadEnter:             return PADENTER;
2090                         case GHOST_kKeyNumpadPlus:              return PADPLUSKEY;
2091                         case GHOST_kKeyNumpadMinus:             return PADMINUS;
2092                         case GHOST_kKeyNumpadAsterisk:  return PADASTERKEY;
2093                         case GHOST_kKeyNumpadSlash:             return PADSLASHKEY;
2094                                 
2095                         case GHOST_kKeyGrLess:              return GRLESSKEY; 
2096                                 
2097                         default:
2098                                 return UNKNOWNKEY;      /* GHOST_kKeyUnknown */
2099                 }
2100         }
2101 }
2102
2103 /* adds customdata to event */
2104 static void update_tablet_data(wmWindow *win, wmEvent *event)
2105 {
2106         const GHOST_TabletData *td= GHOST_GetTabletData(win->ghostwin);
2107         
2108         /* if there's tablet data from an active tablet device then add it */
2109         if ((td != NULL) && td->Active != GHOST_kTabletModeNone) {
2110                 struct wmTabletData *wmtab= MEM_mallocN(sizeof(wmTabletData), "customdata tablet");
2111                 
2112                 wmtab->Active = (int)td->Active;
2113                 wmtab->Pressure = td->Pressure;
2114                 wmtab->Xtilt = td->Xtilt;
2115                 wmtab->Ytilt = td->Ytilt;
2116                 
2117                 event->custom= EVT_DATA_TABLET;
2118                 event->customdata= wmtab;
2119                 event->customdatafree= 1;
2120         } 
2121 }
2122
2123 /* imperfect but probably usable... draw/enable drags to other windows */
2124 static wmWindow *wm_event_cursor_other_windows(wmWindowManager *wm, wmWindow *win, wmEvent *evt)
2125 {
2126         short mx= evt->x, my= evt->y;
2127         
2128         if(wm->windows.first== wm->windows.last)
2129                 return NULL;
2130         
2131         /* top window bar... */
2132         if(mx<0 || my<0 || mx>win->sizex || my>win->sizey+30) { 
2133                 wmWindow *owin;
2134                 wmEventHandler *handler;
2135                 
2136                 /* let's skip windows having modal handlers now */
2137                 /* potential XXX ugly... I wouldn't have added a modalhandlers list (introduced in rev 23331, ton) */
2138                 for(handler= win->modalhandlers.first; handler; handler= handler->next)
2139                         if(handler->ui_handle || handler->op)
2140                                 return NULL;
2141                 
2142                 /* to desktop space */
2143                 mx+= win->posx;
2144                 my+= win->posy;
2145                 
2146                 /* check other windows to see if it has mouse inside */
2147                 for(owin= wm->windows.first; owin; owin= owin->next) {
2148                         
2149                         if(owin!=win) {
2150                                 if(mx-owin->posx >= 0 && my-owin->posy >= 0 &&
2151                                    mx-owin->posx <= owin->sizex && my-owin->posy <= owin->sizey) {
2152                                         evt->x= mx-owin->posx;
2153                                         evt->y= my-owin->posy;
2154                                         
2155                                         return owin;
2156                                 }
2157                         }
2158                 }
2159         }
2160         return NULL;
2161 }
2162
2163 /* windows store own event queues, no bContext here */
2164 /* time is in 1000s of seconds, from ghost */
2165 void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int time, void *customdata)
2166 {
2167         wmWindow *owin;
2168         wmEvent event, *evt= win->eventstate;
2169         
2170         /* initialize and copy state (only mouse x y and modifiers) */
2171         event= *evt;
2172         
2173         switch (type) {
2174                 /* mouse move */
2175                 case GHOST_kEventCursorMove: {
2176                         if(win->active) {
2177                                 GHOST_TEventCursorData *cd= customdata;
2178                                 wmEvent *lastevent= win->queue.last;
2179                                 
2180 #if defined(__APPLE__) && defined(GHOST_COCOA)
2181                                 //Cocoa already uses coordinates with y=0 at bottom, and returns inwindow coordinates on mouse moved event
2182                                 evt->x= cd->x;
2183                                 evt->y= cd->y;
2184 #else
2185                                 int cx, cy;
2186                                 
2187                                 GHOST_ScreenToClient(win->ghostwin, cd->x, cd->y, &cx, &cy);
2188                                 evt->x= cx;
2189                                 evt->y= (win->sizey-1) - cy;
2190 #endif
2191                                 
2192                                 event.x= evt->x;
2193                                 event.y= evt->y;
2194
2195                                 event.type= MOUSEMOVE;
2196
2197                                 /* some painting operators want accurate mouse events, they can
2198                                    handle inbetween mouse move moves, others can happily ignore
2199                                    them for better performance */
2200                                 if(lastevent && lastevent->type == MOUSEMOVE)
2201                                         lastevent->type = INBETWEEN_MOUSEMOVE;
2202
2203                                 update_tablet_data(win, &event);
2204                                 wm_event_add(win, &event);
2205                                 
2206                                 /* also add to other window if event is there, this makes overdraws disappear nicely */
2207                                 /* it remaps mousecoord to other window in event */
2208                                 owin= wm_event_cursor_other_windows(wm, win, &event);
2209                                 if(owin) {
2210                                         wmEvent oevent= *(owin->eventstate);
2211                                         
2212                                         oevent.x=owin->eventstate->x= event.x;
2213                                         oevent.y=owin->eventstate->y= event.y;
2214                                         oevent.type= MOUSEMOVE;
2215                                         
2216                                         update_tablet_data(owin, &oevent);
2217                                         wm_event_add(owin, &oevent);
2218                                 }
2219                                 
2220                         }
2221                         break;
2222                 }
2223                 case GHOST_kEventTrackpad: {
2224                         GHOST_TEventTrackpadData * pd = customdata;
2225                         switch (pd->subtype) {
2226                                 case GHOST_kTrackpadEventMagnify:
2227                                         event.type = MOUSEZOOM;
2228                                         break;
2229                                 case GHOST_kTrackpadEventRotate:
2230                                         event.type = MOUSEROTATE;
2231                                         break;
2232                                 case GHOST_kTrackpadEventScroll:
2233                                 default:
2234                                         event.type= MOUSEPAN;
2235                                         break;
2236                         }
2237 #if defined(__APPLE__) && defined(GHOST_COCOA)
2238                         //Cocoa already uses coordinates with y=0 at bottom, and returns inwindow coordinates on mouse moved event
2239                         event.x= evt->x = pd->x;
2240                         event.y = evt->y = pd->y;
2241 #else
2242                         {
2243                         int cx, cy;
2244                         GHOST_ScreenToClient(win->ghostwin, pd->x, pd->y, &cx, &cy);
2245                         event.x= evt->x= cx;
2246                         event.y= evt->y= (win->sizey-1) - cy;
2247                         }
2248 #endif
2249                         // Use prevx/prevy so we can calculate the delta later
2250                         event.prevx= event.x - pd->deltaX;
2251                         event.prevy= event.y - pd->deltaY;
2252                         
2253                         update_tablet_data(win, &event);
2254                         wm_event_add(win, &event);
2255                         break;
2256                 }
2257                 /* mouse button */
2258                 case GHOST_kEventButtonDown:
2259                 case GHOST_kEventButtonUp: {
2260                         GHOST_TEventButtonData *bd= customdata;
2261                         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 */
2262                         
2263                         if (bd->button == GHOST_kButtonMaskLeft)
2264                                 event.type= LEFTMOUSE;
2265                         else if (bd->button == GHOST_kButtonMaskRight)
2266                                 event.type= RIGHTMOUSE;
2267                         else if (bd->button == GHOST_kButtonMaskButton4)
2268                                 event.type= BUTTON4MOUSE;
2269                         else if (bd->button == GHOST_kButtonMaskButton5)
2270                                 event.type= BUTTON5MOUSE;
2271                         else
2272                                 event.type= MIDDLEMOUSE;
2273                         
2274                         /* add to other window if event is there (not to both!) */
2275                         owin= wm_event_cursor_other_windows(wm, win, &event);
2276                         if(owin) {
2277                                 wmEvent oevent= *(owin->eventstate);
2278                                 
2279                                 oevent.x= event.x;
2280                                 oevent.y= event.y;
2281                                 oevent.type= event.type;
2282                                 oevent.val= event.val;
2283                                 
2284                                 update_tablet_data(owin, &oevent);
2285                                 wm_event_add(owin, &oevent);
2286                         }
2287                         else {
2288                                 update_tablet_data(win, &event);
2289                                 wm_event_add(win, &event);
2290                         }
2291                         
2292                         break;
2293                 }
2294                 /* keyboard */
2295                 case GHOST_kEventKeyDown:
2296                 case GHOST_kEventKeyUp: {
2297                         GHOST_TEventKeyData *kd= customdata;
2298                         event.type= convert_key(kd->key);
2299                         event.ascii= kd->ascii;
2300                         event.val= (type==GHOST_kEventKeyDown)?KM_PRESS:KM_RELEASE;
2301                         
2302                         /* exclude arrow keys, esc, etc from text input */
2303                         if(type==GHOST_kEventKeyUp || (event.ascii<32 && event.ascii>0))
2304                                 event.ascii= '\0';
2305                         
2306                         /* modifiers */
2307                         if (event.type==LEFTSHIFTKEY || event.type==RIGHTSHIFTKEY) {
2308                                 event.shift= evt->shift= (event.val==KM_PRESS);
2309                                 if(event.val==KM_PRESS && (evt->ctrl || evt->alt || evt->oskey))
2310                                    event.shift= evt->shift = 3;         // define?
2311                         } 
2312                         else if (event.type==LEFTCTRLKEY || event.type==RIGHTCTRLKEY) {
2313                                 event.ctrl= evt->ctrl= (event.val==KM_PRESS);
2314                                 if(event.val==KM_PRESS && (evt->shift || evt->alt || evt->oskey))
2315                                    event.ctrl= evt->ctrl = 3;           // define?
2316                         } 
2317                         else if (event.type==LEFTALTKEY || event.type==RIGHTALTKEY) {
2318                                 event.alt= evt->alt= (event.val==KM_PRESS);
2319                                 if(event.val==KM_PRESS && (evt->ctrl || evt->shift || evt->oskey))
2320                                    event.alt= evt->alt = 3;             // define?
2321                         } 
2322                         else if (event.type==COMMANDKEY) {
2323                                 event.oskey= evt->oskey= (event.val==KM_PRESS);
2324                                 if(event.val==KM_PRESS && (evt->ctrl || evt->alt || evt->shift))
2325                                    event.oskey= evt->oskey = 3;         // define?
2326                         }
2327                         else {
2328                                 if(event.val==KM_PRESS && event.keymodifier==0)
2329                                         evt->keymodifier= event.type; /* only set in eventstate, for next event */
2330                                 else if(event.val==KM_RELEASE && event.keymodifier==event.type)
2331                                         event.keymodifier= evt->keymodifier= 0;
2332                         }
2333
2334                         /* this case happens on some systems that on holding a key pressed,
2335                            generate press events without release, we still want to keep the
2336                            modifier in win->eventstate, but for the press event of the same
2337                            key we don't want the key modifier */
2338                         if(event.keymodifier == event.type)
2339                                 event.keymodifier= 0;
2340                         
2341                         /* if test_break set, it catches this. XXX Keep global for now? */
2342                         if(event.type==ESCKEY)
2343                                 G.afbreek= 1;
2344                         
2345                         wm_event_add(win, &event);
2346                         
2347                         break;
2348                 }
2349                         
2350                 case GHOST_kEventWheel: {
2351                         GHOST_TEventWheelData* wheelData = customdata;
2352                         
2353                         if (wheelData->z > 0)
2354                                 event.type= WHEELUPMOUSE;
2355                         else
2356                                 event.type= WHEELDOWNMOUSE;
2357                         
2358                         event.val= KM_PRESS;
2359                         wm_event_add(win, &event);
2360                         
2361                         break;
2362                 }
2363                 case GHOST_kEventTimer: {
2364                         event.type= TIMER;
2365                         event.custom= EVT_DATA_TIMER;
2366                         event.customdata= customdata;
2367                         wm_event_add(win, &event);
2368
2369                         break;
2370                 }
2371
2372                 case GHOST_kEventUnknown:
2373                 case GHOST_kNumEventTypes:
2374                         break;
2375
2376                 case GHOST_kEventWindowDeactivate: {
2377                         event.type= WINDEACTIVATE;
2378                         wm_event_add(win, &event);
2379
2380                         break;
2381                         
2382                 }
2383
2384         }
2385 }