2.5: File browser
[blender.git] / source / blender / windowmanager / intern / wm_event_system.c
1 /**
2  * $Id:
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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_object.h"
49 #include "BKE_report.h"
50 #include "BKE_scene.h"
51 #include "BKE_utildefines.h"
52 #include "BKE_pointcache.h"
53
54 #include "ED_fileselect.h"
55 #include "ED_screen.h"
56 #include "ED_space_api.h"
57 #include "ED_util.h"
58
59 #include "RNA_access.h"
60
61 #include "UI_interface.h"
62
63 #include "WM_api.h"
64 #include "WM_types.h"
65 #include "wm.h"
66 #include "wm_window.h"
67 #include "wm_event_system.h"
68 #include "wm_event_types.h"
69
70 /* ************ event management ************** */
71
72 void wm_event_add(wmWindow *win, wmEvent *event_to_add)
73 {
74         wmEvent *event= MEM_callocN(sizeof(wmEvent), "event");
75         
76         *event= *event_to_add;
77         BLI_addtail(&win->queue, event);
78 }
79
80 void wm_event_free(wmEvent *event)
81 {
82         if(event->customdata && event->customdatafree)
83                 MEM_freeN(event->customdata);
84         MEM_freeN(event);
85 }
86
87 void wm_event_free_all(wmWindow *win)
88 {
89         wmEvent *event;
90         
91         while((event= win->queue.first)) {
92                 BLI_remlink(&win->queue, event);
93                 wm_event_free(event);
94         }
95 }
96
97 /* ********************* notifiers, listeners *************** */
98
99 /* XXX: in future, which notifiers to send to other windows? */
100 void WM_event_add_notifier(const bContext *C, unsigned int type, void *reference)
101 {
102         wmNotifier *note= MEM_callocN(sizeof(wmNotifier), "notifier");
103         
104         note->wm= CTX_wm_manager(C);
105         BLI_addtail(&note->wm->queue, note);
106         
107         note->window= CTX_wm_window(C);
108         
109         if(CTX_wm_region(C))
110                 note->swinid= CTX_wm_region(C)->swinid;
111         
112         note->category= type & NOTE_CATEGORY;
113         note->data= type & NOTE_DATA;
114         note->subtype= type & NOTE_SUBTYPE;
115         note->action= type & NOTE_ACTION;
116         
117         note->reference= reference;
118 }
119
120 static wmNotifier *wm_notifier_next(wmWindowManager *wm)
121 {
122         wmNotifier *note= wm->queue.first;
123         
124         if(note) BLI_remlink(&wm->queue, note);
125         return note;
126 }
127
128 /* called in mainloop */
129 void wm_event_do_notifiers(bContext *C)
130 {
131         wmWindowManager *wm= CTX_wm_manager(C);
132         wmNotifier *note;
133         wmWindow *win;
134         
135         if(wm==NULL)
136                 return;
137         
138         /* cache & catch WM level notifiers, such as frame change, scene/screen set */
139         for(win= wm->windows.first; win; win= win->next) {
140                 int do_anim= 0;
141                 
142                 CTX_wm_window_set(C, win);
143                 
144                 for(note= wm->queue.first; note; note= note->next) {
145                         if(note->category==NC_WM) {
146                                 if( ELEM(note->data, ND_FILEREAD, ND_FILESAVE)) {
147                                         wm->file_saved= 1;
148                                         wm_window_title(wm, win);
149                                 }
150                                 else if(note->data==ND_DATACHANGED)
151                                         wm_window_title(wm, win);
152                         }
153                         if(note->window==win) {
154                                 if(note->category==NC_SCREEN) {
155                                         if(note->data==ND_SCREENBROWSE) {
156                                                 ED_screen_set(C, note->reference);      // XXX hrms, think this over!
157                                                 printf("screen set %p\n", note->reference);
158                                         }
159                                 }
160                                 else if(note->category==NC_SCENE) {
161                                         if(note->data==ND_SCENEBROWSE) {
162                                                 ED_screen_set_scene(C, note->reference);        // XXX hrms, think this over!
163                                                 printf("scene set %p\n", note->reference);
164                                         }
165                                         else if(note->data==ND_FRAME)
166                                                 do_anim= 1;
167                                 }
168                         }
169                 }
170                 if(do_anim) {
171                         /* depsgraph gets called, might send more notifiers */
172                         ED_update_for_newframe(C, 1);
173                 }
174         }
175         
176         /* the notifiers are sent without context, to keep it clean */
177         while( (note=wm_notifier_next(wm)) ) {
178                 wmWindow *win;
179                 
180                 for(win= wm->windows.first; win; win= win->next) {
181                         
182                         /* filter out notifiers */
183                         if(note->category==NC_SCREEN && note->reference && note->reference!=win->screen);
184                         else if(note->category==NC_SCENE && note->reference && note->reference!=win->screen->scene);
185                         else {
186                                 ScrArea *sa;
187                                 ARegion *ar;
188
189                                 /* XXX context in notifiers? */
190                                 CTX_wm_window_set(C, win);
191
192                                 /* printf("notifier win %d screen %s cat %x\n", win->winid, win->screen->id.name+2, note->category); */
193                                 ED_screen_do_listen(win, note);
194
195                                 for(ar=win->screen->regionbase.first; ar; ar= ar->next) {
196                                         ED_region_do_listen(ar, note);
197                                 }
198                                 
199                                 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
200                                         ED_area_do_listen(sa, note);
201                                         for(ar=sa->regionbase.first; ar; ar= ar->next) {
202                                                 ED_region_do_listen(ar, note);
203                                         }
204                                 }
205                         }
206                 }
207                 
208                 MEM_freeN(note);
209         }
210         
211         /* cached: editor refresh callbacks now, they get context */
212         for(win= wm->windows.first; win; win= win->next) {
213                 Scene *sce, *scene= win->screen->scene;
214                 ScrArea *sa;
215                 Base *base;
216                 
217                 CTX_wm_window_set(C, win);
218                 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
219                         if(sa->do_refresh) {
220                                 CTX_wm_area_set(C, sa);
221                                 ED_area_do_refresh(C, sa);
222                         }
223                 }
224                 
225                 if(G.rendering==0) { // XXX make lock in future, or separated derivedmesh users in scene
226                         
227                         /* update all objects, ipos, matrices, displists, etc. Flags set by depgraph or manual, 
228                                 no layer check here, gets correct flushed */
229                         /* sets first, we allow per definition current scene to have dependencies on sets */
230                         if(scene->set) {
231                                 for(SETLOOPER(scene->set, base))
232                                         object_handle_update(scene, base->object);
233                         }
234                         
235                         for(base= scene->base.first; base; base= base->next) {
236                                 object_handle_update(scene, base->object);
237                         }
238
239                         BKE_ptcache_quick_cache_all(scene);
240                 }               
241         }
242         CTX_wm_window_set(C, NULL);
243 }
244
245 /* ********************* operators ******************* */
246
247 /* if repeat is true, it doesn't register again, nor does it free */
248 static int wm_operator_exec(bContext *C, wmOperator *op, int repeat)
249 {
250         int retval= OPERATOR_CANCELLED;
251         
252         if(op==NULL || op->type==NULL)
253                 return retval;
254         
255         if(op->type->poll && op->type->poll(C)==0)
256                 return retval;
257         
258         if(op->type->exec)
259                 retval= op->type->exec(C, op);
260         
261         if(!(retval & OPERATOR_RUNNING_MODAL))
262                 if(op->reports->list.first)
263                         uiPupMenuReports(C, op->reports);
264         
265         if(retval & OPERATOR_FINISHED) {
266                 if(op->type->flag & OPTYPE_UNDO)
267                         ED_undo_push_op(C, op);
268                 
269                 if(repeat==0) {
270                         if((op->type->flag & OPTYPE_REGISTER) || (G.f & G_DEBUG))
271                                 wm_operator_register(C, op);
272                         else
273                                 WM_operator_free(op);
274                 }
275         }
276         else if(repeat==0)
277                 WM_operator_free(op);
278         
279         return retval;
280         
281 }
282
283 /* for running operators with frozen context (modal handlers, menus) */
284 int WM_operator_call(bContext *C, wmOperator *op)
285 {
286         return wm_operator_exec(C, op, 0);
287 }
288
289 /* do this operator again, put here so it can share above code */
290 int WM_operator_repeat(bContext *C, wmOperator *op)
291 {
292         return wm_operator_exec(C, op, 1);
293 }
294
295 static wmOperator *wm_operator_create(wmWindowManager *wm, wmOperatorType *ot, PointerRNA *properties, ReportList *reports)
296 {
297         wmOperator *op= MEM_callocN(sizeof(wmOperator), ot->idname);    /* XXX operatortype names are static still. for debug */
298         
299         /* XXX adding new operator could be function, only happens here now */
300         op->type= ot;
301         BLI_strncpy(op->idname, ot->idname, OP_MAX_TYPENAME);
302         
303         /* initialize properties, either copy or create */
304         op->ptr= MEM_callocN(sizeof(PointerRNA), "wmOperatorPtrRNA");
305         if(properties && properties->data) {
306                 op->properties= IDP_CopyProperty(properties->data);
307         }
308         else {
309                 IDPropertyTemplate val = {0};
310                 op->properties= IDP_New(IDP_GROUP, val, "wmOperatorProperties");
311         }
312         RNA_pointer_create(&wm->id, ot->srna, op->properties, op->ptr);
313
314         /* initialize error reports */
315         if (reports) {
316                 op->reports= reports; /* must be initialized alredy */
317         }
318         else {
319                 op->reports= MEM_mallocN(sizeof(ReportList), "wmOperatorReportList");
320                 BKE_reports_init(op->reports, RPT_STORE);
321         }
322         
323         return op;
324 }
325
326 static void wm_operator_print(wmOperator *op)
327 {
328         char *buf = WM_operator_pystring(op);
329         printf("%s\n", buf);
330         MEM_freeN(buf);
331 }
332
333 static void wm_region_mouse_co(bContext *C, wmEvent *event)
334 {
335         ARegion *ar= CTX_wm_region(C);
336         if(ar) {
337                 /* compatibility convention */
338                 event->mval[0]= event->x - ar->winrct.xmin;
339                 event->mval[1]= event->y - ar->winrct.ymin;
340         }
341 }
342
343 static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, PointerRNA *properties)
344 {
345         wmWindowManager *wm= CTX_wm_manager(C);
346         int retval= OPERATOR_PASS_THROUGH;
347
348         if(ot->poll==NULL || ot->poll(C)) {
349                 wmOperator *op= wm_operator_create(wm, ot, properties, NULL);
350                 
351                 if((G.f & G_DEBUG) && event && event->type!=MOUSEMOVE)
352                         printf("handle evt %d win %d op %s\n", event?event->type:0, CTX_wm_screen(C)->subwinactive, ot->idname); 
353                 
354                 if(op->type->invoke && event) {
355                         wm_region_mouse_co(C, event);
356                         retval= op->type->invoke(C, op, event);
357                 }
358                 else if(op->type->exec)
359                         retval= op->type->exec(C, op);
360                 else
361                         printf("invalid operator call %s\n", ot->idname); /* debug, important to leave a while, should never happen */
362
363                 if(!(retval & OPERATOR_RUNNING_MODAL)) {
364                         if(op->reports->list.first) /* only show the report if the report list was not given in the function */
365                                 uiPupMenuReports(C, op->reports);
366                 
367                 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 */
368                         if(G.f & G_DEBUG)
369                                 wm_operator_print(op);
370                 }
371
372                 if(retval & OPERATOR_FINISHED) {
373                         if(ot->flag & OPTYPE_UNDO)
374                                 ED_undo_push_op(C, op);
375                         
376                         if((ot->flag & OPTYPE_REGISTER) || (G.f & G_DEBUG))
377                                 wm_operator_register(C, op);
378                         else
379                                 WM_operator_free(op);
380                 }
381                 else if(retval & OPERATOR_RUNNING_MODAL) {
382                         /* grab cursor during blocking modal ops (X11) */
383                         if(ot->flag & OPTYPE_BLOCKING)
384                                 WM_cursor_grab(CTX_wm_window(C), 1);
385                 }
386                 else
387                         WM_operator_free(op);
388         }
389
390         return retval;
391 }
392
393 /* invokes operator in context */
394 int WM_operator_name_call(bContext *C, const char *opstring, int context, PointerRNA *properties)
395 {
396         wmOperatorType *ot= WM_operatortype_find(opstring, 0);
397         wmWindow *window= CTX_wm_window(C);
398         wmEvent *event;
399         
400         int retval;
401
402         /* dummie test */
403         if(ot && C && window) {
404                 event= window->eventstate;
405                 switch(context) {
406                         
407                         case WM_OP_EXEC_REGION_WIN:
408                                 event= NULL;    /* pass on without break */
409                         case WM_OP_INVOKE_REGION_WIN: 
410                         {
411                                 /* forces operator to go to the region window, for header menus */
412                                 ARegion *ar= CTX_wm_region(C);
413                                 ScrArea *area= CTX_wm_area(C);
414                                 
415                                 if(area) {
416                                         ARegion *ar1= area->regionbase.first;
417                                         for(; ar1; ar1= ar1->next)
418                                                 if(ar1->regiontype==RGN_TYPE_WINDOW)
419                                                         break;
420                                         if(ar1)
421                                                 CTX_wm_region_set(C, ar1);
422                                 }
423                                 
424                                 retval= wm_operator_invoke(C, ot, event, properties);
425                                 
426                                 /* set region back */
427                                 CTX_wm_region_set(C, ar);
428                                 
429                                 return retval;
430                         }
431                         case WM_OP_EXEC_AREA:
432                                 event= NULL;    /* pass on without break */
433                         case WM_OP_INVOKE_AREA:
434                         {
435                                         /* remove region from context */
436                                 ARegion *ar= CTX_wm_region(C);
437
438                                 CTX_wm_region_set(C, NULL);
439                                 retval= wm_operator_invoke(C, ot, event, properties);
440                                 CTX_wm_region_set(C, ar);
441
442                                 return retval;
443                         }
444                         case WM_OP_EXEC_SCREEN:
445                                 event= NULL;    /* pass on without break */
446                         case WM_OP_INVOKE_SCREEN:
447                         {
448                                 /* remove region + area from context */
449                                 ARegion *ar= CTX_wm_region(C);
450                                 ScrArea *area= CTX_wm_area(C);
451
452                                 CTX_wm_region_set(C, NULL);
453                                 CTX_wm_area_set(C, NULL);
454                                 retval= wm_operator_invoke(C, ot, event, properties);
455                                 CTX_wm_region_set(C, ar);
456                                 CTX_wm_area_set(C, area);
457
458                                 return retval;
459                         }
460                         case WM_OP_EXEC_DEFAULT:
461                                 event= NULL;    /* pass on without break */
462                         case WM_OP_INVOKE_DEFAULT:
463                                 return wm_operator_invoke(C, ot, event, properties);
464                 }
465         }
466         
467         return 0;
468 }
469
470 /* Similar to WM_operator_name_call called with WM_OP_EXEC_DEFAULT context.
471    - wmOperatorType is used instead of operator name since python alredy has the operator type
472    - poll() must be called by python before this runs.
473    - reports can be passed to this function (so python can report them as exceptions)
474 */
475 int WM_operator_call_py(bContext *C, wmOperatorType *ot, PointerRNA *properties, ReportList *reports)
476 {
477         wmWindowManager *wm=    CTX_wm_manager(C);
478         wmOperator *op=                 wm_operator_create(wm, ot, properties, reports);
479         int retval= OPERATOR_CANCELLED;
480         
481         if (op->type->exec)
482                 retval= op->type->exec(C, op);
483         else
484                 printf("error \"%s\" operator has no exec function, python cannot call it\n", op->type->name);
485         
486         if (reports)
487                 op->reports= NULL; /* dont let the operator free reports passed to this function */
488         WM_operator_free(op);
489         
490         return retval;
491 }
492
493
494 /* ********************* handlers *************** */
495
496 /* future extra customadata free? */
497 static void wm_event_free_handler(wmEventHandler *handler)
498 {
499         MEM_freeN(handler);
500 }
501
502 /* only set context when area/region is part of screen */
503 static void wm_handler_op_context(bContext *C, wmEventHandler *handler)
504 {
505         bScreen *screen= CTX_wm_screen(C);
506         
507         if(screen && handler->op) {
508                 if(handler->op_area==NULL)
509                         CTX_wm_area_set(C, NULL);
510                 else {
511                         ScrArea *sa;
512                         
513                         for(sa= screen->areabase.first; sa; sa= sa->next)
514                                 if(sa==handler->op_area)
515                                         break;
516                         if(sa==NULL) {
517                                 /* when changing screen layouts with running modal handlers (like render display), this
518                                    is not an error to print */
519                                 if(handler->op==NULL)
520                                         printf("internal error: handler (%s) has invalid area\n", handler->op->type->idname);
521                         }
522                         else {
523                                 ARegion *ar;
524                                 CTX_wm_area_set(C, sa);
525                                 for(ar= sa->regionbase.first; ar; ar= ar->next)
526                                         if(ar==handler->op_region)
527                                                 break;
528                                 /* XXX no warning print here, after full-area and back regions are remade */
529                                 if(ar)
530                                         CTX_wm_region_set(C, ar);
531                         }
532                 }
533         }
534 }
535
536 /* called on exit or remove area, only here call cancel callback */
537 void WM_event_remove_handlers(bContext *C, ListBase *handlers)
538 {
539         wmEventHandler *handler;
540         
541         /* C is zero on freeing database, modal handlers then already were freed */
542         while((handler=handlers->first)) {
543                 BLI_remlink(handlers, handler);
544                 
545                 if(handler->op) {
546                         if(handler->op->type->cancel) {
547                                 ScrArea *area= CTX_wm_area(C);
548                                 ARegion *region= CTX_wm_region(C);
549                                 
550                                 wm_handler_op_context(C, handler);
551
552                                 handler->op->type->cancel(C, handler->op);
553
554                                 CTX_wm_area_set(C, area);
555                                 CTX_wm_region_set(C, region);
556                         }
557
558                         WM_operator_free(handler->op);
559                         WM_cursor_grab(CTX_wm_window(C), 0);
560                 }
561                 else if(handler->ui_remove) {
562                         ScrArea *area= CTX_wm_area(C);
563                         ARegion *region= CTX_wm_region(C);
564                         ARegion *menu= CTX_wm_menu(C);
565                         
566                         if(handler->ui_area) CTX_wm_area_set(C, handler->ui_area);
567                         if(handler->ui_region) CTX_wm_region_set(C, handler->ui_region);
568                         if(handler->ui_menu) CTX_wm_menu_set(C, handler->ui_menu);
569
570                         handler->ui_remove(C, handler->ui_userdata);
571
572                         CTX_wm_area_set(C, area);
573                         CTX_wm_region_set(C, region);
574                         CTX_wm_menu_set(C, menu);
575                 }
576
577                 wm_event_free_handler(handler);
578         }
579 }
580
581 /* do userdef mappings */
582 static int wm_userdef_event_map(int kmitype)
583 {
584         switch(kmitype) {
585                 case SELECTMOUSE:
586                         if(U.flag & USER_LMOUSESELECT)
587                                 return LEFTMOUSE;
588                         else
589                                 return RIGHTMOUSE;
590                         
591                 case ACTIONMOUSE:
592                         if(U.flag & USER_LMOUSESELECT)
593                                 return RIGHTMOUSE;
594                         else
595                                 return LEFTMOUSE;
596                         
597                 case WHEELOUTMOUSE:
598                         if(U.uiflag & USER_WHEELZOOMDIR)
599                                 return WHEELUPMOUSE;
600                         else
601                                 return WHEELDOWNMOUSE;
602                         
603                 case WHEELINMOUSE:
604                         if(U.uiflag & USER_WHEELZOOMDIR)
605                                 return WHEELDOWNMOUSE;
606                         else
607                                 return WHEELUPMOUSE;
608                         
609                 case EVT_TWEAK_A:
610                         if(U.flag & USER_LMOUSESELECT)
611                                 return EVT_TWEAK_R;
612                         else
613                                 return EVT_TWEAK_L;
614                         
615                 case EVT_TWEAK_S:
616                         if(U.flag & USER_LMOUSESELECT)
617                                 return EVT_TWEAK_L;
618                         else
619                                 return EVT_TWEAK_R;
620         }
621         
622         return kmitype;
623 }
624
625 static int wm_eventmatch(wmEvent *winevent, wmKeymapItem *kmi)
626 {
627         int kmitype= wm_userdef_event_map(kmi->type);
628
629         if(kmi->inactive) return 0;
630         
631         /* the matching rules */
632         if(kmitype==KM_TEXTINPUT)
633                 if(ISKEYBOARD(winevent->type)) return 1;
634         if(kmitype!=KM_ANY)
635                 if(winevent->type!=kmitype) return 0;
636         
637         if(kmi->val!=KM_ANY)
638                 if(winevent->val!=kmi->val) return 0;
639         
640         /* modifiers also check bits, so it allows modifier order */
641         if(kmi->shift!=KM_ANY)
642                 if(winevent->shift != kmi->shift && !(winevent->shift & kmi->shift)) return 0;
643         if(kmi->ctrl!=KM_ANY)
644                 if(winevent->ctrl != kmi->ctrl && !(winevent->ctrl & kmi->ctrl)) return 0;
645         if(kmi->alt!=KM_ANY)
646                 if(winevent->alt != kmi->alt && !(winevent->alt & kmi->alt)) return 0;
647         if(kmi->oskey!=KM_ANY)
648                 if(winevent->oskey != kmi->oskey && !(winevent->oskey & kmi->oskey)) return 0;
649         if(kmi->keymodifier)
650                 if(winevent->keymodifier!=kmi->keymodifier) return 0;
651         
652         return 1;
653 }
654
655 static int wm_event_always_pass(wmEvent *event)
656 {
657         /* some events we always pass on, to ensure proper communication */
658         return ELEM5(event->type, TIMER, TIMER0, TIMER1, TIMER2, TIMERJOBS);
659 }
660
661 /* operator exists */
662 static void wm_event_modalkeymap(wmOperator *op, wmEvent *event)
663 {
664         if(op->type->modalkeymap) {
665                 wmKeymapItem *kmi;
666                 
667                 for(kmi= op->type->modalkeymap->keymap.first; kmi; kmi= kmi->next) {
668                         if(wm_eventmatch(event, kmi)) {
669                                         
670                                 event->type= EVT_MODAL_MAP;
671                                 event->val= kmi->propvalue;
672                         }
673                 }
674         }
675 }
676
677 /* Warning: this function removes a modal handler, when finished */
678 static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHandler *handler, wmEvent *event, PointerRNA *properties)
679 {
680         int retval= OPERATOR_PASS_THROUGH;
681         
682         /* derived, modal or blocking operator */
683         if(handler->op) {
684                 wmOperator *op= handler->op;
685                 wmOperatorType *ot= op->type;
686
687                 if(ot->modal) {
688                         /* we set context to where modal handler came from */
689                         ScrArea *area= CTX_wm_area(C);
690                         ARegion *region= CTX_wm_region(C);
691                         
692                         wm_handler_op_context(C, handler);
693                         wm_region_mouse_co(C, event);
694                         wm_event_modalkeymap(op, event);
695                         
696                         retval= ot->modal(C, op, event);
697
698                         /* putting back screen context, reval can pass trough after modal failures! */
699                         if((retval & OPERATOR_PASS_THROUGH) || wm_event_always_pass(event)) {
700                                 CTX_wm_area_set(C, area);
701                                 CTX_wm_region_set(C, region);
702                         }
703                         else {
704                                 /* this special cases is for areas and regions that get removed */
705                                 CTX_wm_area_set(C, NULL);
706                                 CTX_wm_region_set(C, NULL);
707                         }
708
709                         if(!(retval & OPERATOR_RUNNING_MODAL))
710                                 if(op->reports->list.first)
711                                         uiPupMenuReports(C, op->reports);
712
713                         if (retval & OPERATOR_FINISHED) {
714                                 if(G.f & G_DEBUG)
715                                         wm_operator_print(op); /* todo - this print may double up, might want to check more flags then the FINISHED */
716                         }                       
717
718                         if(retval & OPERATOR_FINISHED) {
719                                 if(ot->flag & OPTYPE_UNDO)
720                                         ED_undo_push_op(C, op);
721                                 
722                                 if((ot->flag & OPTYPE_REGISTER) || (G.f & G_DEBUG))
723                                         wm_operator_register(C, op);
724                                 else
725                                         WM_operator_free(op);
726                                 handler->op= NULL;
727                         }
728                         else if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) {
729                                 WM_operator_free(op);
730                                 handler->op= NULL;
731                         }
732                         
733                         /* remove modal handler, operator itself should have been cancelled and freed */
734                         if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) {
735                                 WM_cursor_grab(CTX_wm_window(C), 0);
736
737                                 BLI_remlink(handlers, handler);
738                                 wm_event_free_handler(handler);
739                                 
740                                 /* prevent silly errors from operator users */
741                                 //retval &= ~OPERATOR_PASS_THROUGH;
742                         }
743                         
744                 }
745                 else
746                         printf("wm_handler_operator_call error\n");
747         }
748         else {
749                 wmOperatorType *ot= WM_operatortype_find(event->keymap_idname, 0);
750
751                 if(ot)
752                         retval= wm_operator_invoke(C, ot, event, properties);
753         }
754
755         if(retval & OPERATOR_PASS_THROUGH)
756                 return WM_HANDLER_CONTINUE;
757
758         return WM_HANDLER_BREAK;
759 }
760
761 static int wm_handler_ui_call(bContext *C, wmEventHandler *handler, wmEvent *event)
762 {
763         ScrArea *area= CTX_wm_area(C);
764         ARegion *region= CTX_wm_region(C);
765         ARegion *menu= CTX_wm_menu(C);
766         int retval, always_pass;
767                         
768         /* we set context to where ui handler came from */
769         if(handler->ui_area) CTX_wm_area_set(C, handler->ui_area);
770         if(handler->ui_region) CTX_wm_region_set(C, handler->ui_region);
771         if(handler->ui_menu) CTX_wm_menu_set(C, handler->ui_menu);
772
773         /* in advance to avoid access to freed event on window close */
774         always_pass= wm_event_always_pass(event);
775
776         retval= handler->ui_handle(C, event, handler->ui_userdata);
777
778         /* putting back screen context */
779         if((retval != WM_UI_HANDLER_BREAK) || always_pass) {
780                 CTX_wm_area_set(C, area);
781                 CTX_wm_region_set(C, region);
782                 CTX_wm_menu_set(C, menu);
783         }
784         else {
785                 /* this special cases is for areas and regions that get removed */
786                 CTX_wm_area_set(C, NULL);
787                 CTX_wm_region_set(C, NULL);
788                 CTX_wm_menu_set(C, NULL);
789         }
790
791         if(retval == WM_UI_HANDLER_BREAK)
792                 return WM_HANDLER_BREAK;
793
794         return WM_HANDLER_CONTINUE;
795 }
796
797 /* fileselect handlers are only in the window queue, so it's save to switch screens or area types */
798 static int wm_handler_fileselect_call(bContext *C, ListBase *handlers, wmEventHandler *handler, wmEvent *event)
799 {
800         SpaceFile *sfile;
801         int action= WM_HANDLER_CONTINUE;
802         
803         if(event->type != EVT_FILESELECT)
804                 return action;
805         if(handler->op != (wmOperator *)event->customdata)
806                 return action;
807         
808         switch(event->val) {
809                 case EVT_FILESELECT_OPEN: 
810                 case EVT_FILESELECT_FULL_OPEN: 
811                         {
812                                 short flag =0; short display =FILE_SHORTDISPLAY; short filter =0; short sort =FILE_SORT_ALPHA;
813                                 char *dir= NULL; char *path= RNA_string_get_alloc(handler->op->ptr, "filename", NULL, 0);
814                                         
815                                 if(event->val==EVT_FILESELECT_OPEN)
816                                         ED_area_newspace(C, handler->op_area, SPACE_FILE);
817                                 else
818                                         ED_screen_full_newspace(C, handler->op_area, SPACE_FILE);
819                                 
820                                 /* settings for filebrowser, sfile is not operator owner but sends events */
821                                 sfile= (SpaceFile*)CTX_wm_space_data(C);
822                                 sfile->op= handler->op;
823
824                                 ED_fileselect_set_params(sfile);
825                                 dir = NULL;
826                                 MEM_freeN(path);
827                                 
828                                 action= WM_HANDLER_BREAK;
829                         }
830                         break;
831                         
832                 case EVT_FILESELECT_EXEC:
833                 case EVT_FILESELECT_CANCEL:
834                         {
835                                 /* XXX validate area and region? */
836                                 bScreen *screen= CTX_wm_screen(C);
837                                 char *path= RNA_string_get_alloc(handler->op->ptr, "filename", NULL, 0);
838                                 
839                                 if(screen != handler->filescreen)
840                                         ED_screen_full_prevspace(C);
841                                 else
842                                         ED_area_prevspace(C);
843                                 
844                                 /* remlink now, for load file case */
845                                 BLI_remlink(handlers, handler);
846                                 
847                                 if(event->val==EVT_FILESELECT_EXEC) {
848                                         wm_handler_op_context(C, handler);
849                                 
850                                         /* a bit weak, might become arg for WM_event_fileselect? */
851                                         /* XXX also extension code in image-save doesnt work for this yet */
852                                         if(strncmp(handler->op->type->name, "Save", 4)==0) {
853                                                 /* this gives ownership to pupmenu */
854                                                 uiPupMenuSaveOver(C, handler->op, path);
855                                         }
856                                         else {
857                                                 int retval= handler->op->type->exec(C, handler->op);
858                                                 
859                                                 if (retval & OPERATOR_FINISHED)
860                                                         if(G.f & G_DEBUG)
861                                                                 wm_operator_print(handler->op);
862                                                 
863                                                 WM_operator_free(handler->op);
864                                         }
865                                         
866                                         CTX_wm_area_set(C, NULL);
867                                 }
868                                 else 
869                                         WM_operator_free(handler->op);
870                                 
871                                 wm_event_free_handler(handler);
872                                 MEM_freeN(path);
873                                 
874                                 action= WM_HANDLER_BREAK;
875                         }
876                         break;
877         }
878         
879         return action;
880 }
881
882 static int handler_boundbox_test(wmEventHandler *handler, wmEvent *event)
883 {
884         if(handler->bbwin) {
885                 if(handler->bblocal) {
886                         rcti rect= *handler->bblocal;
887                         BLI_translate_rcti(&rect, handler->bbwin->xmin, handler->bbwin->ymin);
888
889                         if(BLI_in_rcti(&rect, event->x, event->y))
890                                 return 1;
891                         else if(event->type==MOUSEMOVE && BLI_in_rcti(&rect, event->prevx, event->prevy))
892                                 return 1;
893                         else
894                                 return 0;
895                 }
896                 else {
897                         if(BLI_in_rcti(handler->bbwin, event->x, event->y))
898                                 return 1;
899                         else if(event->type==MOUSEMOVE && BLI_in_rcti(handler->bbwin, event->prevx, event->prevy))
900                                 return 1;
901                         else
902                                 return 0;
903                 }
904         }
905         return 1;
906 }
907
908 static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
909 {
910         wmEventHandler *handler, *nexthandler;
911         int action= WM_HANDLER_CONTINUE;
912         int always_pass;
913
914         if(handlers==NULL) return action;
915         
916         /* modal handlers can get removed in this loop, we keep the loop this way */
917         for(handler= handlers->first; handler; handler= nexthandler) {
918                 nexthandler= handler->next;
919
920                 /* optional boundbox */
921                 if(handler_boundbox_test(handler, event)) {
922                         /* in advance to avoid access to freed event on window close */
923                         always_pass= wm_event_always_pass(event);
924                 
925                         /* modal+blocking handler */
926                         if(handler->flag & WM_HANDLER_BLOCKING)
927                                 action= WM_HANDLER_BREAK;
928
929                         if(handler->keymap) {
930                                 wmKeymapItem *kmi;
931                                 
932                                 for(kmi= handler->keymap->first; kmi; kmi= kmi->next) {
933                                         if(wm_eventmatch(event, kmi)) {
934                                                 
935                                                 event->keymap_idname= kmi->idname;      /* weak, but allows interactive callback to not use rawkey */
936                                                 
937                                                 action= wm_handler_operator_call(C, handlers, handler, event, kmi->ptr);
938                                                 if(action==WM_HANDLER_BREAK)  /* not wm_event_always_pass(event) here, it denotes removed handler */
939                                                         break;
940                                         }
941                                 }
942                         }
943                         else if(handler->ui_handle) {
944                                 action= wm_handler_ui_call(C, handler, event);
945                         }
946                         else if(handler->type==WM_HANDLER_FILESELECT) {
947                                 /* screen context changes here */
948                                 action= wm_handler_fileselect_call(C, handlers, handler, event);
949                         }
950                         else {
951                                 /* modal, swallows all */
952                                 action= wm_handler_operator_call(C, handlers, handler, event, NULL);
953                         }
954
955                         if(!always_pass && action==WM_HANDLER_BREAK)
956                                 break;
957                 }
958                 
959                 /* fileread case */
960                 if(CTX_wm_window(C)==NULL)
961                         break;
962         }
963         return action;
964 }
965
966 static int wm_event_inside_i(wmEvent *event, rcti *rect)
967 {
968         if(BLI_in_rcti(rect, event->x, event->y))
969            return 1;
970         if(event->type==MOUSEMOVE) {
971                 if( BLI_in_rcti(rect, event->prevx, event->prevy)) {
972                         return 1;
973                 }
974                 return 0;
975         }
976         return 0;
977 }
978
979 static ScrArea *area_event_inside(bContext *C, int x, int y)
980 {
981         bScreen *screen= CTX_wm_screen(C);
982         ScrArea *sa;
983         
984         if(screen)
985                 for(sa= screen->areabase.first; sa; sa= sa->next)
986                         if(BLI_in_rcti(&sa->totrct, x, y))
987                                 return sa;
988         return NULL;
989 }
990
991 static ARegion *region_event_inside(bContext *C, int x, int y)
992 {
993         bScreen *screen= CTX_wm_screen(C);
994         ScrArea *area= CTX_wm_area(C);
995         ARegion *ar;
996         
997         if(screen && area)
998                 for(ar= area->regionbase.first; ar; ar= ar->next)
999                         if(BLI_in_rcti(&ar->winrct, x, y))
1000                                 return ar;
1001         return NULL;
1002 }
1003
1004 static void wm_paintcursor_tag(bContext *C, wmPaintCursor *pc, ARegion *ar)
1005 {
1006         if(ar) {
1007                 for(; pc; pc= pc->next) {
1008                         if(pc->poll(C)) {
1009                                 wmWindow *win= CTX_wm_window(C);
1010                                 win->screen->do_draw_paintcursor= 1;
1011
1012                                 if(win->drawmethod != USER_DRAW_TRIPLE)
1013                                         ED_region_tag_redraw(ar);
1014                         }
1015                 }
1016         }
1017 }
1018
1019 /* called on mousemove, check updates for paintcursors */
1020 /* context was set on active area and region */
1021 static void wm_paintcursor_test(bContext *C, wmEvent *event)
1022 {
1023         wmWindowManager *wm= CTX_wm_manager(C);
1024         
1025         if(wm->paintcursors.first) {
1026                 ARegion *ar= CTX_wm_region(C);
1027                 if(ar)
1028                         wm_paintcursor_tag(C, wm->paintcursors.first, ar);
1029                 
1030                 /* if previous position was not in current region, we have to set a temp new context */
1031                 if(ar==NULL || !BLI_in_rcti(&ar->winrct, event->prevx, event->prevy)) {
1032                         ScrArea *sa= CTX_wm_area(C);
1033                         
1034                         CTX_wm_area_set(C, area_event_inside(C, event->prevx, event->prevy));
1035                         CTX_wm_region_set(C, region_event_inside(C, event->prevx, event->prevy));
1036
1037                         wm_paintcursor_tag(C, wm->paintcursors.first, CTX_wm_region(C));
1038                         
1039                         CTX_wm_area_set(C, sa);
1040                         CTX_wm_region_set(C, ar);
1041                 }
1042         }
1043 }
1044
1045 /* called in main loop */
1046 /* goes over entire hierarchy:  events -> window -> screen -> area -> region */
1047 void wm_event_do_handlers(bContext *C)
1048 {
1049         wmWindow *win;
1050
1051         for(win= CTX_wm_manager(C)->windows.first; win; win= win->next) {
1052                 wmEvent *event;
1053                 
1054                 if( win->screen==NULL )
1055                         wm_event_free_all(win);
1056                 
1057                 while( (event= win->queue.first) ) {
1058                         int action;
1059                         
1060                         CTX_wm_window_set(C, win);
1061                         
1062                         /* we let modal handlers get active area/region, also wm_paintcursor_test needs it */
1063                         CTX_wm_area_set(C, area_event_inside(C, event->x, event->y));
1064                         CTX_wm_region_set(C, region_event_inside(C, event->x, event->y));
1065                         
1066                         /* MVC demands to not draw in event handlers... but we need to leave it for ogl selecting etc */
1067                         wm_window_make_drawable(C, win);
1068                         
1069                         action= wm_handlers_do(C, event, &win->handlers);
1070                         
1071                         /* fileread case */
1072                         if(CTX_wm_window(C)==NULL) {
1073                                 return;
1074                         }
1075                         
1076                         /* builtin tweak, if action is break it removes tweak */
1077                         if(!wm_event_always_pass(event))
1078                                 wm_tweakevent_test(C, event, action);
1079                         
1080                         if(wm_event_always_pass(event) || action==WM_HANDLER_CONTINUE) {
1081                                 ScrArea *sa;
1082                                 ARegion *ar;
1083                                 int doit= 0;
1084                                 
1085                                 /* XXX to solve, here screen handlers? */
1086                                 if(!wm_event_always_pass(event)) {
1087                                         if(event->type==MOUSEMOVE) {
1088                                                 /* state variables in screen, cursors */
1089                                                 ED_screen_set_subwinactive(win, event); 
1090                                                 /* for regions having custom cursors */
1091                                                 wm_paintcursor_test(C, event);
1092                                         }
1093                                 }
1094                                 
1095                                 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
1096                                         if(wm_event_always_pass(event) || wm_event_inside_i(event, &sa->totrct)) {
1097                                                 
1098                                                 CTX_wm_area_set(C, sa);
1099                                                 CTX_wm_region_set(C, NULL);
1100                                                 action= wm_handlers_do(C, event, &sa->handlers);
1101
1102                                                 if(wm_event_always_pass(event) || action==WM_HANDLER_CONTINUE) {
1103                                                         for(ar=sa->regionbase.first; ar; ar= ar->next) {
1104                                                                 if(wm_event_always_pass(event) || wm_event_inside_i(event, &ar->winrct)) {
1105                                                                         CTX_wm_region_set(C, ar);
1106                                                                         action= wm_handlers_do(C, event, &ar->handlers);
1107
1108                                                                         doit |= (BLI_in_rcti(&ar->winrct, event->x, event->y));
1109                                                                         
1110                                                                         if(!wm_event_always_pass(event)) {
1111                                                                                 if(action==WM_HANDLER_BREAK)
1112                                                                                         break;
1113                                                                         }
1114                                                                 }
1115                                                         }
1116                                                 }
1117                                                 /* NOTE: do not escape on WM_HANDLER_BREAK, mousemove needs handled for previous area */
1118                                         }
1119                                 }
1120                                 
1121                                 /* XXX hrmf, this gives reliable previous mouse coord for area change, feels bad? 
1122                                    doing it on ghost queue gives errors when mousemoves go over area borders */
1123                                 if(doit && win->screen->subwinactive != win->screen->mainwin) {
1124                                         win->eventstate->prevx= event->x;
1125                                         win->eventstate->prevy= event->y;
1126                                 }
1127                         }
1128                         
1129                         /* unlink and free here, blender-quit then frees all */
1130                         BLI_remlink(&win->queue, event);
1131                         wm_event_free(event);
1132                         
1133                 }
1134                 
1135                 /* only add mousemove when queue was read entirely */
1136                 if(win->addmousemove) {
1137                         wmEvent event= *(win->eventstate);
1138                         event.type= MOUSEMOVE;
1139                         event.prevx= event.x;
1140                         event.prevy= event.y;
1141                         wm_event_add(win, &event);
1142                         win->addmousemove= 0;
1143                 }
1144                 
1145                 CTX_wm_window_set(C, NULL);
1146         }
1147 }
1148
1149 /* ********** filesector handling ************ */
1150
1151 void WM_event_fileselect_event(bContext *C, void *ophandle, int eventval)
1152 {
1153         /* add to all windows! */
1154         wmWindow *win;
1155         
1156         for(win= CTX_wm_manager(C)->windows.first; win; win= win->next) {
1157                 wmEvent event= *win->eventstate;
1158                 
1159                 event.type= EVT_FILESELECT;
1160                 event.val= eventval;
1161                 event.customdata= ophandle;             // only as void pointer type check
1162
1163                 wm_event_add(win, &event);
1164         }
1165 }
1166
1167 /* operator is supposed to have a filled "filename" property */
1168 /* optional property: filetype (XXX enum?) */
1169
1170 /* Idea is to keep a handler alive on window queue, owning the operator.
1171    The filewindow can send event to make it execute, thus ensuring
1172    executing happens outside of lower level queues, with UI refreshed. 
1173    Should also allow multiwin solutions */
1174
1175 void WM_event_add_fileselect(bContext *C, wmOperator *op)
1176 {
1177         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "fileselect handler");
1178         wmWindow *win= CTX_wm_window(C);
1179         int full= 1;    // XXX preset?
1180         
1181         handler->type= WM_HANDLER_FILESELECT;
1182         handler->op= op;
1183         handler->op_area= CTX_wm_area(C);
1184         handler->op_region= CTX_wm_region(C);
1185         handler->filescreen= CTX_wm_screen(C);
1186         
1187         BLI_addhead(&win->handlers, handler);
1188         
1189         WM_event_fileselect_event(C, op, full?EVT_FILESELECT_FULL_OPEN:EVT_FILESELECT_OPEN);
1190 }
1191
1192 /* lets not expose struct outside wm? */
1193 void WM_event_set_handler_flag(wmEventHandler *handler, int flag)
1194 {
1195         handler->flag= flag;
1196 }
1197
1198 wmEventHandler *WM_event_add_modal_handler(bContext *C, ListBase *handlers, wmOperator *op)
1199 {
1200         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event modal handler");
1201         handler->op= op;
1202         handler->op_area= CTX_wm_area(C);               /* means frozen screen context for modal handlers! */
1203         handler->op_region= CTX_wm_region(C);
1204         
1205         BLI_addhead(handlers, handler);
1206
1207         return handler;
1208 }
1209
1210 wmEventHandler *WM_event_add_keymap_handler(ListBase *handlers, ListBase *keymap)
1211 {
1212         wmEventHandler *handler;
1213
1214         /* only allow same keymap once */
1215         for(handler= handlers->first; handler; handler= handler->next)
1216                 if(handler->keymap==keymap)
1217                         return handler;
1218         
1219         handler= MEM_callocN(sizeof(wmEventHandler), "event keymap handler");
1220         BLI_addtail(handlers, handler);
1221         handler->keymap= keymap;
1222
1223         return handler;
1224 }
1225
1226 /* priorities not implemented yet, for time being just insert in begin of list */
1227 wmEventHandler *WM_event_add_keymap_handler_priority(ListBase *handlers, ListBase *keymap, int priority)
1228 {
1229         wmEventHandler *handler;
1230         
1231         WM_event_remove_keymap_handler(handlers, keymap);
1232         
1233         handler= MEM_callocN(sizeof(wmEventHandler), "event keymap handler");
1234         BLI_addhead(handlers, handler);
1235         handler->keymap= keymap;
1236         
1237         return handler;
1238 }
1239
1240 wmEventHandler *WM_event_add_keymap_handler_bb(ListBase *handlers, ListBase *keymap, rcti *bblocal, rcti *bbwin)
1241 {
1242         wmEventHandler *handler= WM_event_add_keymap_handler(handlers, keymap);
1243         
1244         if(handler) {
1245                 handler->bblocal= bblocal;
1246                 handler->bbwin= bbwin;
1247         }
1248         return handler;
1249 }
1250
1251 void WM_event_remove_keymap_handler(ListBase *handlers, ListBase *keymap)
1252 {
1253         wmEventHandler *handler;
1254         
1255         for(handler= handlers->first; handler; handler= handler->next) {
1256                 if(handler->keymap==keymap) {
1257                         BLI_remlink(handlers, handler);
1258                         wm_event_free_handler(handler);
1259                         break;
1260                 }
1261         }
1262 }
1263
1264 wmEventHandler *WM_event_add_ui_handler(const bContext *C, ListBase *handlers, wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata)
1265 {
1266         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event ui handler");
1267         handler->ui_handle= func;
1268         handler->ui_remove= remove;
1269         handler->ui_userdata= userdata;
1270         handler->ui_area= (C)? CTX_wm_area(C): NULL;
1271         handler->ui_region= (C)? CTX_wm_region(C): NULL;
1272         handler->ui_menu= (C)? CTX_wm_menu(C): NULL;
1273         
1274         BLI_addhead(handlers, handler);
1275         
1276         return handler;
1277 }
1278
1279 void WM_event_remove_ui_handler(ListBase *handlers, wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata)
1280 {
1281         wmEventHandler *handler;
1282         
1283         for(handler= handlers->first; handler; handler= handler->next) {
1284                 if(handler->ui_handle == func && handler->ui_remove == remove && handler->ui_userdata == userdata) {
1285                         BLI_remlink(handlers, handler);
1286                         wm_event_free_handler(handler);
1287                         break;
1288                 }
1289         }
1290 }
1291
1292 void WM_event_add_mousemove(bContext *C)
1293 {
1294         wmWindow *window= CTX_wm_window(C);
1295         
1296         window->addmousemove= 1;
1297 }
1298
1299 /* for modal callbacks, check configuration for how to interpret exit with tweaks  */
1300 int WM_modal_tweak_exit(wmEvent *evt, int tweak_event)
1301 {
1302         /* user preset or keymap? dunno... */
1303         int tweak_modal= (U.flag & USER_DRAGIMMEDIATE)==0;
1304         
1305         switch(tweak_event) {
1306                 case EVT_TWEAK_L:
1307                 case EVT_TWEAK_M:
1308                 case EVT_TWEAK_R:
1309                         if(evt->val==tweak_modal)
1310                                 return 1;
1311                 default:
1312                         /* this case is when modal callcback didnt get started with a tweak */
1313                         if(evt->val)
1314                                 return 1;
1315         }
1316         return 0;
1317 }
1318
1319
1320 /* ********************* ghost stuff *************** */
1321
1322 static int convert_key(GHOST_TKey key) 
1323 {
1324         if (key>=GHOST_kKeyA && key<=GHOST_kKeyZ) {
1325                 return (AKEY + ((int) key - GHOST_kKeyA));
1326         } else if (key>=GHOST_kKey0 && key<=GHOST_kKey9) {
1327                 return (ZEROKEY + ((int) key - GHOST_kKey0));
1328         } else if (key>=GHOST_kKeyNumpad0 && key<=GHOST_kKeyNumpad9) {
1329                 return (PAD0 + ((int) key - GHOST_kKeyNumpad0));
1330         } else if (key>=GHOST_kKeyF1 && key<=GHOST_kKeyF12) {
1331                 return (F1KEY + ((int) key - GHOST_kKeyF1));
1332         } else {
1333                 switch (key) {
1334                         case GHOST_kKeyBackSpace:               return BACKSPACEKEY;
1335                         case GHOST_kKeyTab:                             return TABKEY;
1336                         case GHOST_kKeyLinefeed:                return LINEFEEDKEY;
1337                         case GHOST_kKeyClear:                   return 0;
1338                         case GHOST_kKeyEnter:                   return RETKEY;
1339                                 
1340                         case GHOST_kKeyEsc:                             return ESCKEY;
1341                         case GHOST_kKeySpace:                   return SPACEKEY;
1342                         case GHOST_kKeyQuote:                   return QUOTEKEY;
1343                         case GHOST_kKeyComma:                   return COMMAKEY;
1344                         case GHOST_kKeyMinus:                   return MINUSKEY;
1345                         case GHOST_kKeyPeriod:                  return PERIODKEY;
1346                         case GHOST_kKeySlash:                   return SLASHKEY;
1347                                 
1348                         case GHOST_kKeySemicolon:               return SEMICOLONKEY;
1349                         case GHOST_kKeyEqual:                   return EQUALKEY;
1350                                 
1351                         case GHOST_kKeyLeftBracket:             return LEFTBRACKETKEY;
1352                         case GHOST_kKeyRightBracket:    return RIGHTBRACKETKEY;
1353                         case GHOST_kKeyBackslash:               return BACKSLASHKEY;
1354                         case GHOST_kKeyAccentGrave:             return ACCENTGRAVEKEY;
1355                                 
1356                         case GHOST_kKeyLeftShift:               return LEFTSHIFTKEY;
1357                         case GHOST_kKeyRightShift:              return RIGHTSHIFTKEY;
1358                         case GHOST_kKeyLeftControl:             return LEFTCTRLKEY;
1359                         case GHOST_kKeyRightControl:    return RIGHTCTRLKEY;
1360                         case GHOST_kKeyCommand:                 return COMMANDKEY;
1361                         case GHOST_kKeyLeftAlt:                 return LEFTALTKEY;
1362                         case GHOST_kKeyRightAlt:                return RIGHTALTKEY;
1363                                 
1364                         case GHOST_kKeyCapsLock:                return CAPSLOCKKEY;
1365                         case GHOST_kKeyNumLock:                 return 0;
1366                         case GHOST_kKeyScrollLock:              return 0;
1367                                 
1368                         case GHOST_kKeyLeftArrow:               return LEFTARROWKEY;
1369                         case GHOST_kKeyRightArrow:              return RIGHTARROWKEY;
1370                         case GHOST_kKeyUpArrow:                 return UPARROWKEY;
1371                         case GHOST_kKeyDownArrow:               return DOWNARROWKEY;
1372                                 
1373                         case GHOST_kKeyPrintScreen:             return 0;
1374                         case GHOST_kKeyPause:                   return PAUSEKEY;
1375                                 
1376                         case GHOST_kKeyInsert:                  return INSERTKEY;
1377                         case GHOST_kKeyDelete:                  return DELKEY;
1378                         case GHOST_kKeyHome:                    return HOMEKEY;
1379                         case GHOST_kKeyEnd:                             return ENDKEY;
1380                         case GHOST_kKeyUpPage:                  return PAGEUPKEY;
1381                         case GHOST_kKeyDownPage:                return PAGEDOWNKEY;
1382                                 
1383                         case GHOST_kKeyNumpadPeriod:    return PADPERIOD;
1384                         case GHOST_kKeyNumpadEnter:             return PADENTER;
1385                         case GHOST_kKeyNumpadPlus:              return PADPLUSKEY;
1386                         case GHOST_kKeyNumpadMinus:             return PADMINUS;
1387                         case GHOST_kKeyNumpadAsterisk:  return PADASTERKEY;
1388                         case GHOST_kKeyNumpadSlash:             return PADSLASHKEY;
1389                                 
1390                         case GHOST_kKeyGrLess:              return GRLESSKEY; 
1391                                 
1392                         default:
1393                                 return UNKNOWNKEY;      /* GHOST_kKeyUnknown */
1394                 }
1395         }
1396 }
1397
1398 /* adds customdata to event */
1399 static void update_tablet_data(wmWindow *win, wmEvent *event)
1400 {
1401         const GHOST_TabletData *td= GHOST_GetTabletData(win->ghostwin);
1402         
1403         /* if there's tablet data from an active tablet device then add it */
1404         if ((td != NULL) && td->Active) {
1405                 struct wmTabletData *wmtab= MEM_mallocN(sizeof(wmTabletData), "customdata tablet");
1406                 
1407                 wmtab->Active = td->Active;
1408                 wmtab->Pressure = td->Pressure;
1409                 wmtab->Xtilt = td->Xtilt;
1410                 wmtab->Ytilt = td->Ytilt;
1411                 
1412                 event->custom= EVT_DATA_TABLET;
1413                 event->customdata= wmtab;
1414                 event->customdatafree= 1;
1415         } 
1416 }
1417
1418
1419 /* windows store own event queues, no bContext here */
1420 void wm_event_add_ghostevent(wmWindow *win, int type, void *customdata)
1421 {
1422         wmEvent event, *evt= win->eventstate;
1423         
1424         /* initialize and copy state (only mouse x y and modifiers) */
1425         event= *evt;
1426         
1427         switch (type) {
1428                 /* mouse move */
1429                 case GHOST_kEventCursorMove: {
1430                         if(win->active) {
1431                                 GHOST_TEventCursorData *cd= customdata;
1432                                 int cx, cy;
1433
1434                                 GHOST_ScreenToClient(win->ghostwin, cd->x, cd->y, &cx, &cy);
1435                                 
1436                                 event.type= MOUSEMOVE;
1437                                 event.x= evt->x= cx;
1438                                 event.y= evt->y= (win->sizey-1) - cy;
1439                                 
1440                                 update_tablet_data(win, &event);
1441                                 wm_event_add(win, &event);
1442
1443                                 cx = abs((win->downx - event.x));
1444                                 cy = abs((win->downy - event.y));
1445
1446                                 /* probably minimum drag size should be #defined instead of hardcoded 3
1447                                  * also, cy seems always to be 6 pixels off, not sure why
1448                                  */
1449                                 if ((win->downstate == LEFTMOUSE || win->downstate == MOUSEDRAG) && (cx > 3 || cy > 9)) {
1450                                         wmEvent dragevt= *evt;
1451                                         dragevt.type= MOUSEDRAG;
1452                                         dragevt.customdata= NULL;
1453                                         dragevt.customdatafree= 0;
1454
1455                                         win->downstate= MOUSEDRAG;
1456
1457                                         wm_event_add(win, &dragevt);
1458                                 }
1459                         }
1460                         break;
1461                 }
1462                 /* mouse button */
1463                 case GHOST_kEventButtonDown:
1464                 case GHOST_kEventButtonUp: {
1465                         GHOST_TEventButtonData *bd= customdata;
1466                         event.val= (type==GHOST_kEventButtonDown);
1467                         
1468                         if (bd->button == GHOST_kButtonMaskLeft)
1469                                 event.type= LEFTMOUSE;
1470                         else if (bd->button == GHOST_kButtonMaskRight)
1471                                 event.type= RIGHTMOUSE;
1472                         else
1473                                 event.type= MIDDLEMOUSE;
1474                         
1475                         if(event.val)
1476                                 event.keymodifier= evt->keymodifier= event.type;
1477                         else
1478                                 event.keymodifier= evt->keymodifier= 0;
1479                         
1480                         update_tablet_data(win, &event);
1481                         wm_event_add(win, &event);
1482
1483                         if (event.val) {
1484                                 win->downstate= event.type;
1485                                 win->downx= event.x;
1486                                 win->downy= event.y;
1487                         }
1488                         else {
1489                                 short downstate= win->downstate;
1490
1491                                 win->downstate= 0;
1492                                 win->downx= 0;
1493                                 win->downy= 0;
1494
1495                                 if (downstate == MOUSEDRAG) {
1496                                         wmEvent dropevt= *evt;
1497                                         dropevt.type= MOUSEDROP;
1498                                         dropevt.customdata= NULL;
1499                                         dropevt.customdatafree= 0;
1500
1501                                         wm_event_add(win, &dropevt);
1502                                 }
1503                         }
1504                         
1505                         break;
1506                 }
1507                 /* keyboard */
1508                 case GHOST_kEventKeyDown:
1509                 case GHOST_kEventKeyUp: {
1510                         GHOST_TEventKeyData *kd= customdata;
1511                         event.type= convert_key(kd->key);
1512                         event.ascii= kd->ascii;
1513                         event.val= (type==GHOST_kEventKeyDown)?KM_PRESS:KM_RELEASE;
1514                         
1515                         /* exclude arrow keys, esc, etc from text input */
1516                         if(type==GHOST_kEventKeyUp || (event.ascii<32 && event.ascii>14))
1517                                 event.ascii= '\0';
1518                         
1519                         /* modifiers */
1520                         if (event.type==LEFTSHIFTKEY || event.type==RIGHTSHIFTKEY) {
1521                                 event.shift= evt->shift= (event.val==KM_PRESS);
1522                                 if(event.val==KM_PRESS && (evt->ctrl || evt->alt || evt->oskey))
1523                                    event.shift= evt->shift = 3;         // define?
1524                         } 
1525                         else if (event.type==LEFTCTRLKEY || event.type==RIGHTCTRLKEY) {
1526                                 event.ctrl= evt->ctrl= (event.val==KM_PRESS);
1527                                 if(event.val==KM_PRESS && (evt->shift || evt->alt || evt->oskey))
1528                                    event.ctrl= evt->ctrl = 3;           // define?
1529                         } 
1530                         else if (event.type==LEFTALTKEY || event.type==RIGHTALTKEY) {
1531                                 event.alt= evt->alt= (event.val==KM_PRESS);
1532                                 if(event.val==KM_PRESS && (evt->ctrl || evt->shift || evt->oskey))
1533                                    event.alt= evt->alt = 3;             // define?
1534                         } 
1535                         else if (event.type==COMMANDKEY) {
1536                                 event.oskey= evt->oskey= (event.val==KM_PRESS);
1537                                 if(event.val==KM_PRESS && (evt->ctrl || evt->alt || evt->shift))
1538                                    event.oskey= evt->oskey = 3;         // define?
1539                         }
1540                         
1541                         /* if test_break set, it catches this. XXX Keep global for now? */
1542                         if(event.type==ESCKEY)
1543                                 G.afbreek= 1;
1544
1545                         wm_event_add(win, &event);
1546                         
1547                         break;
1548                 }
1549                         
1550                 case GHOST_kEventWheel: {
1551                         GHOST_TEventWheelData* wheelData = customdata;
1552                         
1553                         if (wheelData->z > 0)
1554                                 event.type= WHEELUPMOUSE;
1555                         else
1556                                 event.type= WHEELDOWNMOUSE;
1557                         
1558                         event.val= KM_PRESS;
1559                         wm_event_add(win, &event);
1560                         
1561                         break;
1562                 }
1563                 case GHOST_kEventTimer: {
1564                         event.type= TIMER;
1565                         event.custom= EVT_DATA_TIMER;
1566                         event.customdata= customdata;
1567                         wm_event_add(win, &event);
1568
1569                         break;
1570                 }
1571
1572                 case GHOST_kEventUnknown:
1573                 case GHOST_kNumEventTypes:
1574                         break;
1575         }
1576 }