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