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