2.5: Top Menu
[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)
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)
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                                 printf("internal error: handler (%s) has invalid area\n", handler->op->type->idname);
518                         else {
519                                 ARegion *ar;
520                                 CTX_wm_area_set(C, sa);
521                                 for(ar= sa->regionbase.first; ar; ar= ar->next)
522                                         if(ar==handler->op_region)
523                                                 break;
524                                 /* XXX no warning print here, after full-area and back regions are remade */
525                                 if(ar)
526                                         CTX_wm_region_set(C, ar);
527                         }
528                 }
529         }
530 }
531
532 /* called on exit or remove area, only here call cancel callback */
533 void WM_event_remove_handlers(bContext *C, ListBase *handlers)
534 {
535         wmEventHandler *handler;
536         
537         /* C is zero on freeing database, modal handlers then already were freed */
538         while((handler=handlers->first)) {
539                 BLI_remlink(handlers, handler);
540                 
541                 if(handler->op) {
542                         if(handler->op->type->cancel) {
543                                 ScrArea *area= CTX_wm_area(C);
544                                 ARegion *region= CTX_wm_region(C);
545                                 
546                                 wm_handler_op_context(C, handler);
547
548                                 handler->op->type->cancel(C, handler->op);
549
550                                 CTX_wm_area_set(C, area);
551                                 CTX_wm_region_set(C, region);
552                         }
553
554                         WM_operator_free(handler->op);
555                         WM_cursor_grab(CTX_wm_window(C), 0);
556                 }
557                 else if(handler->ui_remove) {
558                         ScrArea *area= CTX_wm_area(C);
559                         ARegion *region= CTX_wm_region(C);
560                         ARegion *menu= CTX_wm_menu(C);
561                         
562                         if(handler->ui_area) CTX_wm_area_set(C, handler->ui_area);
563                         if(handler->ui_region) CTX_wm_region_set(C, handler->ui_region);
564                         if(handler->ui_menu) CTX_wm_menu_set(C, handler->ui_menu);
565
566                         handler->ui_remove(C, handler->ui_userdata);
567
568                         CTX_wm_area_set(C, area);
569                         CTX_wm_region_set(C, region);
570                         CTX_wm_menu_set(C, menu);
571                 }
572
573                 wm_event_free_handler(handler);
574         }
575 }
576
577 /* do userdef mappings */
578 static int wm_userdef_event_map(int kmitype)
579 {
580         switch(kmitype) {
581                 case SELECTMOUSE:
582                         if(U.flag & USER_LMOUSESELECT)
583                                 return LEFTMOUSE;
584                         else
585                                 return RIGHTMOUSE;
586                         
587                 case ACTIONMOUSE:
588                         if(U.flag & USER_LMOUSESELECT)
589                                 return RIGHTMOUSE;
590                         else
591                                 return LEFTMOUSE;
592                         
593                 case WHEELOUTMOUSE:
594                         if(U.uiflag & USER_WHEELZOOMDIR)
595                                 return WHEELUPMOUSE;
596                         else
597                                 return WHEELDOWNMOUSE;
598                         
599                 case WHEELINMOUSE:
600                         if(U.uiflag & USER_WHEELZOOMDIR)
601                                 return WHEELDOWNMOUSE;
602                         else
603                                 return WHEELUPMOUSE;
604                         
605                 case EVT_TWEAK_A:
606                         if(U.flag & USER_LMOUSESELECT)
607                                 return EVT_TWEAK_R;
608                         else
609                                 return EVT_TWEAK_L;
610                         
611                 case EVT_TWEAK_S:
612                         if(U.flag & USER_LMOUSESELECT)
613                                 return EVT_TWEAK_L;
614                         else
615                                 return EVT_TWEAK_R;
616         }
617         
618         return kmitype;
619 }
620
621 static int wm_eventmatch(wmEvent *winevent, wmKeymapItem *kmi)
622 {
623         int kmitype= wm_userdef_event_map(kmi->type);
624
625         /* the matching rules */
626         if(kmitype==KM_TEXTINPUT)
627                 if(ISKEYBOARD(winevent->type)) return 1;
628         if(kmitype!=KM_ANY)
629                 if(winevent->type!=kmitype) return 0;
630         
631         if(kmi->val!=KM_ANY)
632                 if(winevent->val!=kmi->val) return 0;
633         
634         /* modifiers also check bits, so it allows modifier order */
635         if(kmi->shift!=KM_ANY)
636                 if(winevent->shift != kmi->shift && !(winevent->shift & kmi->shift)) return 0;
637         if(kmi->ctrl!=KM_ANY)
638                 if(winevent->ctrl != kmi->ctrl && !(winevent->ctrl & kmi->ctrl)) return 0;
639         if(kmi->alt!=KM_ANY)
640                 if(winevent->alt != kmi->alt && !(winevent->alt & kmi->alt)) return 0;
641         if(kmi->oskey!=KM_ANY)
642                 if(winevent->oskey != kmi->oskey && !(winevent->oskey & kmi->oskey)) return 0;
643         if(kmi->keymodifier)
644                 if(winevent->keymodifier!=kmi->keymodifier) return 0;
645         
646         return 1;
647 }
648
649 static int wm_event_always_pass(wmEvent *event)
650 {
651         /* some events we always pass on, to ensure proper communication */
652         return ELEM5(event->type, TIMER, TIMER0, TIMER1, TIMER2, TIMERJOBS);
653 }
654
655 /* operator exists */
656 static void wm_event_modalkeymap(wmOperator *op, wmEvent *event)
657 {
658         if(op->type->modalkeymap) {
659                 wmKeymapItem *kmi;
660                 
661                 for(kmi= op->type->modalkeymap->keymap.first; kmi; kmi= kmi->next) {
662                         if(wm_eventmatch(event, kmi)) {
663                                         
664                                 event->type= EVT_MODAL_MAP;
665                                 event->val= kmi->propvalue;
666                                 printf("found modal event %s %d\n", kmi->idname, kmi->propvalue);
667                         }
668                 }
669         }
670 }
671
672 /* Warning: this function removes a modal handler, when finished */
673 static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHandler *handler, wmEvent *event, PointerRNA *properties)
674 {
675         int retval= OPERATOR_PASS_THROUGH;
676         
677         /* derived, modal or blocking operator */
678         if(handler->op) {
679                 wmOperator *op= handler->op;
680                 wmOperatorType *ot= op->type;
681
682                 if(ot->modal) {
683                         /* we set context to where modal handler came from */
684                         ScrArea *area= CTX_wm_area(C);
685                         ARegion *region= CTX_wm_region(C);
686                         
687                         wm_handler_op_context(C, handler);
688                         wm_region_mouse_co(C, event);
689                         wm_event_modalkeymap(op, event);
690                         
691                         retval= ot->modal(C, op, event);
692
693                         /* putting back screen context, reval can pass trough after modal failures! */
694                         if((retval & OPERATOR_PASS_THROUGH) || wm_event_always_pass(event)) {
695                                 CTX_wm_area_set(C, area);
696                                 CTX_wm_region_set(C, region);
697                         }
698                         else {
699                                 /* this special cases is for areas and regions that get removed */
700                                 CTX_wm_area_set(C, NULL);
701                                 CTX_wm_region_set(C, NULL);
702                         }
703
704                         if(!(retval & OPERATOR_RUNNING_MODAL))
705                                 if(op->reports->list.first)
706                                         uiPupMenuReports(C, op->reports);
707
708                         if (retval & OPERATOR_FINISHED) {
709                                 if(G.f & G_DEBUG)
710                                         wm_operator_print(op); /* todo - this print may double up, might want to check more flags then the FINISHED */
711                         }                       
712
713                         if(retval & OPERATOR_FINISHED) {
714                                 if(ot->flag & OPTYPE_UNDO)
715                                         ED_undo_push_op(C, op);
716                                 
717                                 if(ot->flag & OPTYPE_REGISTER)
718                                         wm_operator_register(C, op);
719                                 else
720                                         WM_operator_free(op);
721                                 handler->op= NULL;
722                         }
723                         else if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) {
724                                 WM_operator_free(op);
725                                 handler->op= NULL;
726                         }
727                         
728                         /* remove modal handler, operator itself should have been cancelled and freed */
729                         if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) {
730                                 WM_cursor_grab(CTX_wm_window(C), 0);
731
732                                 BLI_remlink(handlers, handler);
733                                 wm_event_free_handler(handler);
734                                 
735                                 /* prevent silly errors from operator users */
736                                 //retval &= ~OPERATOR_PASS_THROUGH;
737                         }
738                         
739                 }
740                 else
741                         printf("wm_handler_operator_call error\n");
742         }
743         else {
744                 wmOperatorType *ot= WM_operatortype_find(event->keymap_idname, 0);
745
746                 if(ot)
747                         retval= wm_operator_invoke(C, ot, event, properties);
748         }
749
750         if(retval & OPERATOR_PASS_THROUGH)
751                 return WM_HANDLER_CONTINUE;
752
753         return WM_HANDLER_BREAK;
754 }
755
756 static int wm_handler_ui_call(bContext *C, wmEventHandler *handler, wmEvent *event)
757 {
758         ScrArea *area= CTX_wm_area(C);
759         ARegion *region= CTX_wm_region(C);
760         ARegion *menu= CTX_wm_menu(C);
761         int retval, always_pass;
762                         
763         /* we set context to where ui handler came from */
764         if(handler->ui_area) CTX_wm_area_set(C, handler->ui_area);
765         if(handler->ui_region) CTX_wm_region_set(C, handler->ui_region);
766         if(handler->ui_menu) CTX_wm_menu_set(C, handler->ui_menu);
767
768         /* in advance to avoid access to freed event on window close */
769         always_pass= wm_event_always_pass(event);
770
771         retval= handler->ui_handle(C, event, handler->ui_userdata);
772
773         /* putting back screen context */
774         if((retval != WM_UI_HANDLER_BREAK) || always_pass) {
775                 CTX_wm_area_set(C, area);
776                 CTX_wm_region_set(C, region);
777                 CTX_wm_menu_set(C, menu);
778         }
779         else {
780                 /* this special cases is for areas and regions that get removed */
781                 CTX_wm_area_set(C, NULL);
782                 CTX_wm_region_set(C, NULL);
783                 CTX_wm_menu_set(C, NULL);
784         }
785
786         if(retval == WM_UI_HANDLER_BREAK)
787                 return WM_HANDLER_BREAK;
788
789         return WM_HANDLER_CONTINUE;
790 }
791
792 /* fileselect handlers are only in the window queue, so it's save to switch screens or area types */
793 static int wm_handler_fileselect_call(bContext *C, ListBase *handlers, wmEventHandler *handler, wmEvent *event)
794 {
795         SpaceFile *sfile;
796         int action= WM_HANDLER_CONTINUE;
797         
798         if(event->type != EVT_FILESELECT)
799                 return action;
800         if(handler->op != (wmOperator *)event->customdata)
801                 return action;
802         
803         switch(event->val) {
804                 case EVT_FILESELECT_OPEN: 
805                 case EVT_FILESELECT_FULL_OPEN: 
806                         {
807                                 short flag =0; short display =FILE_SHORTDISPLAY; short filter =0; short sort =FILE_SORT_ALPHA;
808                                 char *dir= NULL; char *path= RNA_string_get_alloc(handler->op->ptr, "filename", NULL, 0);
809                                         
810                                 if(event->val==EVT_FILESELECT_OPEN)
811                                         ED_area_newspace(C, handler->op_area, SPACE_FILE);
812                                 else
813                                         ED_screen_full_newspace(C, handler->op_area, SPACE_FILE);
814                                 
815                                 /* settings for filebrowser, sfile is not operator owner but sends events */
816                                 sfile= (SpaceFile*)CTX_wm_space_data(C);
817                                 sfile->op= handler->op;
818                                 
819                                 /* XXX for now take the settings from the existing (previous) filebrowser 
820                                    should be stored in settings and passed via the operator */
821                                 if (sfile->params) {
822                                         flag = sfile->params->flag;
823                                         filter = sfile->params->filter;
824                                         display = sfile->params->display;
825                                         sort = sfile->params->sort;
826                                         dir = sfile->params->dir;
827                                 }
828
829                                 ED_fileselect_set_params(sfile, handler->op->type->name, dir, path, flag, display, filter, sort);
830                                 dir = NULL;
831                                 MEM_freeN(path);
832                                 
833                                 action= WM_HANDLER_BREAK;
834                         }
835                         break;
836                         
837                 case EVT_FILESELECT_EXEC:
838                 case EVT_FILESELECT_CANCEL:
839                         {
840                                 /* XXX validate area and region? */
841                                 bScreen *screen= CTX_wm_screen(C);
842                                 char *path= RNA_string_get_alloc(handler->op->ptr, "filename", NULL, 0);
843                                 
844                                 if(screen != handler->filescreen)
845                                         ED_screen_full_prevspace(C);
846                                 else
847                                         ED_area_prevspace(C);
848                                 
849                                 /* remlink now, for load file case */
850                                 BLI_remlink(handlers, handler);
851                                 
852                                 if(event->val==EVT_FILESELECT_EXEC) {
853                                         wm_handler_op_context(C, handler);
854                                 
855                                         /* a bit weak, might become arg for WM_event_fileselect? */
856                                         /* XXX also extension code in image-save doesnt work for this yet */
857                                         if(strncmp(handler->op->type->name, "Save", 4)==0) {
858                                                 /* this gives ownership to pupmenu */
859                                                 uiPupMenuSaveOver(C, handler->op, path);
860                                         }
861                                         else {
862                                                 int retval= handler->op->type->exec(C, handler->op);
863                                                 
864                                                 if (retval & OPERATOR_FINISHED)
865                                                         if(G.f & G_DEBUG)
866                                                                 wm_operator_print(handler->op);
867                                                 
868                                                 WM_operator_free(handler->op);
869                                         }
870                                         
871                                         CTX_wm_area_set(C, NULL);
872                                 }
873                                 else 
874                                         WM_operator_free(handler->op);
875                                 
876                                 wm_event_free_handler(handler);
877                                 MEM_freeN(path);
878                                 
879                                 action= WM_HANDLER_BREAK;
880                         }
881                         break;
882         }
883         
884         return action;
885 }
886
887 static int handler_boundbox_test(wmEventHandler *handler, wmEvent *event)
888 {
889         if(handler->bbwin) {
890                 if(handler->bblocal) {
891                         rcti rect= *handler->bblocal;
892                         BLI_translate_rcti(&rect, handler->bbwin->xmin, handler->bbwin->ymin);
893                         return BLI_in_rcti(&rect, event->x, event->y);
894                 }
895                 else 
896                         return BLI_in_rcti(handler->bbwin, event->x, event->y);
897         }
898         return 1;
899 }
900
901 static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
902 {
903         wmEventHandler *handler, *nexthandler;
904         int action= WM_HANDLER_CONTINUE;
905         int always_pass;
906
907         if(handlers==NULL) return action;
908         
909         /* modal handlers can get removed in this loop, we keep the loop this way */
910         for(handler= handlers->first; handler; handler= nexthandler) {
911                 nexthandler= handler->next;
912
913                 /* optional boundbox */
914                 if(handler_boundbox_test(handler, event)) {
915                         /* in advance to avoid access to freed event on window close */
916                         always_pass= wm_event_always_pass(event);
917                 
918                         /* modal+blocking handler */
919                         if(handler->flag & WM_HANDLER_BLOCKING)
920                                 action= WM_HANDLER_BREAK;
921
922                         if(handler->keymap) {
923                                 wmKeymapItem *kmi;
924                                 
925                                 for(kmi= handler->keymap->first; kmi; kmi= kmi->next) {
926                                         if(wm_eventmatch(event, kmi)) {
927                                                 
928                                                 event->keymap_idname= kmi->idname;      /* weak, but allows interactive callback to not use rawkey */
929                                                 
930                                                 action= wm_handler_operator_call(C, handlers, handler, event, kmi->ptr);
931                                                 if(action==WM_HANDLER_BREAK)  /* not wm_event_always_pass(event) here, it denotes removed handler */
932                                                         break;
933                                         }
934                                 }
935                         }
936                         else if(handler->ui_handle) {
937                                 action= wm_handler_ui_call(C, handler, event);
938                         }
939                         else if(handler->type==WM_HANDLER_FILESELECT) {
940                                 /* screen context changes here */
941                                 action= wm_handler_fileselect_call(C, handlers, handler, event);
942                         }
943                         else {
944                                 /* modal, swallows all */
945                                 action= wm_handler_operator_call(C, handlers, handler, event, NULL);
946                         }
947
948                         if(!always_pass && action==WM_HANDLER_BREAK)
949                                 break;
950                 }
951                 
952                 /* fileread case */
953                 if(CTX_wm_window(C)==NULL)
954                         break;
955         }
956         return action;
957 }
958
959 static int wm_event_inside_i(wmEvent *event, rcti *rect)
960 {
961         if(BLI_in_rcti(rect, event->x, event->y))
962            return 1;
963         if(event->type==MOUSEMOVE) {
964                 if( BLI_in_rcti(rect, event->prevx, event->prevy)) {
965                         return 1;
966                 }
967                 return 0;
968         }
969         return 0;
970 }
971
972 static ScrArea *area_event_inside(bContext *C, int x, int y)
973 {
974         bScreen *screen= CTX_wm_screen(C);
975         ScrArea *sa;
976         
977         if(screen)
978                 for(sa= screen->areabase.first; sa; sa= sa->next)
979                         if(BLI_in_rcti(&sa->totrct, x, y))
980                                 return sa;
981         return NULL;
982 }
983
984 static ARegion *region_event_inside(bContext *C, int x, int y)
985 {
986         bScreen *screen= CTX_wm_screen(C);
987         ScrArea *area= CTX_wm_area(C);
988         ARegion *ar;
989         
990         if(screen && area)
991                 for(ar= area->regionbase.first; ar; ar= ar->next)
992                         if(BLI_in_rcti(&ar->winrct, x, y))
993                                 return ar;
994         return NULL;
995 }
996
997 static void wm_paintcursor_tag(bContext *C, wmPaintCursor *pc, ARegion *ar)
998 {
999         if(ar) {
1000                 for(; pc; pc= pc->next) {
1001                         if(pc->poll(C)) {
1002                                 wmWindow *win= CTX_wm_window(C);
1003                                 win->screen->do_draw_paintcursor= 1;
1004
1005                                 if(win->drawmethod != USER_DRAW_TRIPLE)
1006                                         ED_region_tag_redraw(ar);
1007                         }
1008                 }
1009         }
1010 }
1011
1012 /* called on mousemove, check updates for paintcursors */
1013 /* context was set on active area and region */
1014 static void wm_paintcursor_test(bContext *C, wmEvent *event)
1015 {
1016         wmWindowManager *wm= CTX_wm_manager(C);
1017         
1018         if(wm->paintcursors.first) {
1019                 ARegion *ar= CTX_wm_region(C);
1020                 if(ar)
1021                         wm_paintcursor_tag(C, wm->paintcursors.first, ar);
1022                 
1023                 /* if previous position was not in current region, we have to set a temp new context */
1024                 if(ar==NULL || !BLI_in_rcti(&ar->winrct, event->prevx, event->prevy)) {
1025                         ScrArea *sa= CTX_wm_area(C);
1026                         
1027                         CTX_wm_area_set(C, area_event_inside(C, event->prevx, event->prevy));
1028                         CTX_wm_region_set(C, region_event_inside(C, event->prevx, event->prevy));
1029
1030                         wm_paintcursor_tag(C, wm->paintcursors.first, CTX_wm_region(C));
1031                         
1032                         CTX_wm_area_set(C, sa);
1033                         CTX_wm_region_set(C, ar);
1034                 }
1035         }
1036 }
1037
1038 /* called in main loop */
1039 /* goes over entire hierarchy:  events -> window -> screen -> area -> region */
1040 void wm_event_do_handlers(bContext *C)
1041 {
1042         wmWindow *win;
1043
1044         for(win= CTX_wm_manager(C)->windows.first; win; win= win->next) {
1045                 wmEvent *event;
1046                 
1047                 if( win->screen==NULL )
1048                         wm_event_free_all(win);
1049                 
1050                 while( (event= win->queue.first) ) {
1051                         int action;
1052                         
1053                         CTX_wm_window_set(C, win);
1054                         
1055                         /* we let modal handlers get active area/region, also wm_paintcursor_test needs it */
1056                         CTX_wm_area_set(C, area_event_inside(C, event->x, event->y));
1057                         CTX_wm_region_set(C, region_event_inside(C, event->x, event->y));
1058                         
1059                         /* MVC demands to not draw in event handlers... but we need to leave it for ogl selecting etc */
1060                         wm_window_make_drawable(C, win);
1061                         
1062                         action= wm_handlers_do(C, event, &win->handlers);
1063                         
1064                         /* fileread case */
1065                         if(CTX_wm_window(C)==NULL) {
1066                                 return;
1067                         }
1068                         
1069                         /* builtin tweak, if action is break it removes tweak */
1070                         if(!wm_event_always_pass(event))
1071                                 wm_tweakevent_test(C, event, action);
1072                         
1073                         if(wm_event_always_pass(event) || action==WM_HANDLER_CONTINUE) {
1074                                 ScrArea *sa;
1075                                 ARegion *ar;
1076                                 int doit= 0;
1077                                 
1078                                 /* XXX to solve, here screen handlers? */
1079                                 if(!wm_event_always_pass(event)) {
1080                                         if(event->type==MOUSEMOVE) {
1081                                                 /* state variables in screen, cursors */
1082                                                 ED_screen_set_subwinactive(win, event); 
1083                                                 /* for regions having custom cursors */
1084                                                 wm_paintcursor_test(C, event);
1085                                         }
1086                                 }
1087                                 
1088                                 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
1089                                         if(wm_event_always_pass(event) || wm_event_inside_i(event, &sa->totrct)) {
1090                                                 
1091                                                 CTX_wm_area_set(C, sa);
1092                                                 CTX_wm_region_set(C, NULL);
1093                                                 action= wm_handlers_do(C, event, &sa->handlers);
1094
1095                                                 if(wm_event_always_pass(event) || action==WM_HANDLER_CONTINUE) {
1096                                                         for(ar=sa->regionbase.first; ar; ar= ar->next) {
1097                                                                 if(wm_event_always_pass(event) || wm_event_inside_i(event, &ar->winrct)) {
1098                                                                         CTX_wm_region_set(C, ar);
1099                                                                         action= wm_handlers_do(C, event, &ar->handlers);
1100
1101                                                                         doit |= (BLI_in_rcti(&ar->winrct, event->x, event->y));
1102                                                                         
1103                                                                         if(!wm_event_always_pass(event)) {
1104                                                                                 if(action==WM_HANDLER_BREAK)
1105                                                                                         break;
1106                                                                         }
1107                                                                 }
1108                                                         }
1109                                                 }
1110                                                 /* NOTE: do not escape on WM_HANDLER_BREAK, mousemove needs handled for previous area */
1111                                         }
1112                                 }
1113                                 
1114                                 /* XXX hrmf, this gives reliable previous mouse coord for area change, feels bad? 
1115                                    doing it on ghost queue gives errors when mousemoves go over area borders */
1116                                 if(doit && win->screen->subwinactive != win->screen->mainwin) {
1117                                         win->eventstate->prevx= event->x;
1118                                         win->eventstate->prevy= event->y;
1119                                 }
1120                         }
1121                         
1122                         /* unlink and free here, blender-quit then frees all */
1123                         BLI_remlink(&win->queue, event);
1124                         wm_event_free(event);
1125                         
1126                 }
1127                 
1128                 /* only add mousemove when queue was read entirely */
1129                 if(win->addmousemove) {
1130                         wmEvent event= *(win->eventstate);
1131                         event.type= MOUSEMOVE;
1132                         event.prevx= event.x;
1133                         event.prevy= event.y;
1134                         wm_event_add(win, &event);
1135                         win->addmousemove= 0;
1136                 }
1137                 
1138                 CTX_wm_window_set(C, NULL);
1139         }
1140 }
1141
1142 /* ********** filesector handling ************ */
1143
1144 void WM_event_fileselect_event(bContext *C, void *ophandle, int eventval)
1145 {
1146         /* add to all windows! */
1147         wmWindow *win;
1148         
1149         for(win= CTX_wm_manager(C)->windows.first; win; win= win->next) {
1150                 wmEvent event= *win->eventstate;
1151                 
1152                 event.type= EVT_FILESELECT;
1153                 event.val= eventval;
1154                 event.customdata= ophandle;             // only as void pointer type check
1155
1156                 wm_event_add(win, &event);
1157         }
1158 }
1159
1160 /* operator is supposed to have a filled "filename" property */
1161 /* optional property: filetype (XXX enum?) */
1162
1163 /* Idea is to keep a handler alive on window queue, owning the operator.
1164    The filewindow can send event to make it execute, thus ensuring
1165    executing happens outside of lower level queues, with UI refreshed. 
1166    Should also allow multiwin solutions */
1167
1168 void WM_event_add_fileselect(bContext *C, wmOperator *op)
1169 {
1170         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "fileselect handler");
1171         wmWindow *win= CTX_wm_window(C);
1172         int full= 1;    // XXX preset?
1173         
1174         handler->type= WM_HANDLER_FILESELECT;
1175         handler->op= op;
1176         handler->op_area= CTX_wm_area(C);
1177         handler->op_region= CTX_wm_region(C);
1178         handler->filescreen= CTX_wm_screen(C);
1179         
1180         BLI_addhead(&win->handlers, handler);
1181         
1182         WM_event_fileselect_event(C, op, full?EVT_FILESELECT_FULL_OPEN:EVT_FILESELECT_OPEN);
1183 }
1184
1185 /* lets not expose struct outside wm? */
1186 void WM_event_set_handler_flag(wmEventHandler *handler, int flag)
1187 {
1188         handler->flag= flag;
1189 }
1190
1191 wmEventHandler *WM_event_add_modal_handler(bContext *C, ListBase *handlers, wmOperator *op)
1192 {
1193         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event modal handler");
1194         handler->op= op;
1195         handler->op_area= CTX_wm_area(C);               /* means frozen screen context for modal handlers! */
1196         handler->op_region= CTX_wm_region(C);
1197         
1198         BLI_addhead(handlers, handler);
1199
1200         return handler;
1201 }
1202
1203 wmEventHandler *WM_event_add_keymap_handler(ListBase *handlers, ListBase *keymap)
1204 {
1205         wmEventHandler *handler;
1206
1207         /* only allow same keymap once */
1208         for(handler= handlers->first; handler; handler= handler->next)
1209                 if(handler->keymap==keymap)
1210                         return handler;
1211         
1212         handler= MEM_callocN(sizeof(wmEventHandler), "event keymap handler");
1213         BLI_addtail(handlers, handler);
1214         handler->keymap= keymap;
1215
1216         return handler;
1217 }
1218
1219 /* priorities not implemented yet, for time being just insert in begin of list */
1220 wmEventHandler *WM_event_add_keymap_handler_priority(ListBase *handlers, ListBase *keymap, int priority)
1221 {
1222         wmEventHandler *handler;
1223         
1224         WM_event_remove_keymap_handler(handlers, keymap);
1225         
1226         handler= MEM_callocN(sizeof(wmEventHandler), "event keymap handler");
1227         BLI_addhead(handlers, handler);
1228         handler->keymap= keymap;
1229         
1230         return handler;
1231 }
1232
1233 wmEventHandler *WM_event_add_keymap_handler_bb(ListBase *handlers, ListBase *keymap, rcti *bblocal, rcti *bbwin)
1234 {
1235         wmEventHandler *handler= WM_event_add_keymap_handler(handlers, keymap);
1236         
1237         if(handler) {
1238                 handler->bblocal= bblocal;
1239                 handler->bbwin= bbwin;
1240         }
1241         return handler;
1242 }
1243
1244 void WM_event_remove_keymap_handler(ListBase *handlers, ListBase *keymap)
1245 {
1246         wmEventHandler *handler;
1247         
1248         for(handler= handlers->first; handler; handler= handler->next) {
1249                 if(handler->keymap==keymap) {
1250                         BLI_remlink(handlers, handler);
1251                         wm_event_free_handler(handler);
1252                         break;
1253                 }
1254         }
1255 }
1256
1257 wmEventHandler *WM_event_add_ui_handler(const bContext *C, ListBase *handlers, wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata)
1258 {
1259         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event ui handler");
1260         handler->ui_handle= func;
1261         handler->ui_remove= remove;
1262         handler->ui_userdata= userdata;
1263         handler->ui_area= (C)? CTX_wm_area(C): NULL;
1264         handler->ui_region= (C)? CTX_wm_region(C): NULL;
1265         handler->ui_menu= (C)? CTX_wm_menu(C): NULL;
1266         
1267         BLI_addhead(handlers, handler);
1268         
1269         return handler;
1270 }
1271
1272 void WM_event_remove_ui_handler(ListBase *handlers, wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata)
1273 {
1274         wmEventHandler *handler;
1275         
1276         for(handler= handlers->first; handler; handler= handler->next) {
1277                 if(handler->ui_handle == func && handler->ui_remove == remove && handler->ui_userdata == userdata) {
1278                         BLI_remlink(handlers, handler);
1279                         wm_event_free_handler(handler);
1280                         break;
1281                 }
1282         }
1283 }
1284
1285 void WM_event_add_mousemove(bContext *C)
1286 {
1287         wmWindow *window= CTX_wm_window(C);
1288         
1289         window->addmousemove= 1;
1290 }
1291
1292 /* for modal callbacks, check configuration for how to interpret exit with tweaks  */
1293 int WM_modal_tweak_exit(wmEvent *evt, int tweak_event)
1294 {
1295         /* user preset or keymap? dunno... */
1296         int tweak_modal= (U.flag & USER_DRAGIMMEDIATE)==0;
1297         
1298         switch(tweak_event) {
1299                 case EVT_TWEAK_L:
1300                 case EVT_TWEAK_M:
1301                 case EVT_TWEAK_R:
1302                         if(evt->val==tweak_modal)
1303                                 return 1;
1304                 default:
1305                         /* this case is when modal callcback didnt get started with a tweak */
1306                         if(evt->val)
1307                                 return 1;
1308         }
1309         return 0;
1310 }
1311
1312
1313 /* ********************* ghost stuff *************** */
1314
1315 static int convert_key(GHOST_TKey key) 
1316 {
1317         if (key>=GHOST_kKeyA && key<=GHOST_kKeyZ) {
1318                 return (AKEY + ((int) key - GHOST_kKeyA));
1319         } else if (key>=GHOST_kKey0 && key<=GHOST_kKey9) {
1320                 return (ZEROKEY + ((int) key - GHOST_kKey0));
1321         } else if (key>=GHOST_kKeyNumpad0 && key<=GHOST_kKeyNumpad9) {
1322                 return (PAD0 + ((int) key - GHOST_kKeyNumpad0));
1323         } else if (key>=GHOST_kKeyF1 && key<=GHOST_kKeyF12) {
1324                 return (F1KEY + ((int) key - GHOST_kKeyF1));
1325         } else {
1326                 switch (key) {
1327                         case GHOST_kKeyBackSpace:               return BACKSPACEKEY;
1328                         case GHOST_kKeyTab:                             return TABKEY;
1329                         case GHOST_kKeyLinefeed:                return LINEFEEDKEY;
1330                         case GHOST_kKeyClear:                   return 0;
1331                         case GHOST_kKeyEnter:                   return RETKEY;
1332                                 
1333                         case GHOST_kKeyEsc:                             return ESCKEY;
1334                         case GHOST_kKeySpace:                   return SPACEKEY;
1335                         case GHOST_kKeyQuote:                   return QUOTEKEY;
1336                         case GHOST_kKeyComma:                   return COMMAKEY;
1337                         case GHOST_kKeyMinus:                   return MINUSKEY;
1338                         case GHOST_kKeyPeriod:                  return PERIODKEY;
1339                         case GHOST_kKeySlash:                   return SLASHKEY;
1340                                 
1341                         case GHOST_kKeySemicolon:               return SEMICOLONKEY;
1342                         case GHOST_kKeyEqual:                   return EQUALKEY;
1343                                 
1344                         case GHOST_kKeyLeftBracket:             return LEFTBRACKETKEY;
1345                         case GHOST_kKeyRightBracket:    return RIGHTBRACKETKEY;
1346                         case GHOST_kKeyBackslash:               return BACKSLASHKEY;
1347                         case GHOST_kKeyAccentGrave:             return ACCENTGRAVEKEY;
1348                                 
1349                         case GHOST_kKeyLeftShift:               return LEFTSHIFTKEY;
1350                         case GHOST_kKeyRightShift:              return RIGHTSHIFTKEY;
1351                         case GHOST_kKeyLeftControl:             return LEFTCTRLKEY;
1352                         case GHOST_kKeyRightControl:    return RIGHTCTRLKEY;
1353                         case GHOST_kKeyCommand:                 return COMMANDKEY;
1354                         case GHOST_kKeyLeftAlt:                 return LEFTALTKEY;
1355                         case GHOST_kKeyRightAlt:                return RIGHTALTKEY;
1356                                 
1357                         case GHOST_kKeyCapsLock:                return CAPSLOCKKEY;
1358                         case GHOST_kKeyNumLock:                 return 0;
1359                         case GHOST_kKeyScrollLock:              return 0;
1360                                 
1361                         case GHOST_kKeyLeftArrow:               return LEFTARROWKEY;
1362                         case GHOST_kKeyRightArrow:              return RIGHTARROWKEY;
1363                         case GHOST_kKeyUpArrow:                 return UPARROWKEY;
1364                         case GHOST_kKeyDownArrow:               return DOWNARROWKEY;
1365                                 
1366                         case GHOST_kKeyPrintScreen:             return 0;
1367                         case GHOST_kKeyPause:                   return PAUSEKEY;
1368                                 
1369                         case GHOST_kKeyInsert:                  return INSERTKEY;
1370                         case GHOST_kKeyDelete:                  return DELKEY;
1371                         case GHOST_kKeyHome:                    return HOMEKEY;
1372                         case GHOST_kKeyEnd:                             return ENDKEY;
1373                         case GHOST_kKeyUpPage:                  return PAGEUPKEY;
1374                         case GHOST_kKeyDownPage:                return PAGEDOWNKEY;
1375                                 
1376                         case GHOST_kKeyNumpadPeriod:    return PADPERIOD;
1377                         case GHOST_kKeyNumpadEnter:             return PADENTER;
1378                         case GHOST_kKeyNumpadPlus:              return PADPLUSKEY;
1379                         case GHOST_kKeyNumpadMinus:             return PADMINUS;
1380                         case GHOST_kKeyNumpadAsterisk:  return PADASTERKEY;
1381                         case GHOST_kKeyNumpadSlash:             return PADSLASHKEY;
1382                                 
1383                         case GHOST_kKeyGrLess:              return GRLESSKEY; 
1384                                 
1385                         default:
1386                                 return UNKNOWNKEY;      /* GHOST_kKeyUnknown */
1387                 }
1388         }
1389 }
1390
1391 /* adds customdata to event */
1392 static void update_tablet_data(wmWindow *win, wmEvent *event)
1393 {
1394         const GHOST_TabletData *td= GHOST_GetTabletData(win->ghostwin);
1395         
1396         /* if there's tablet data from an active tablet device then add it */
1397         if ((td != NULL) && td->Active) {
1398                 struct wmTabletData *wmtab= MEM_mallocN(sizeof(wmTabletData), "customdata tablet");
1399                 
1400                 wmtab->Active = td->Active;
1401                 wmtab->Pressure = td->Pressure;
1402                 wmtab->Xtilt = td->Xtilt;
1403                 wmtab->Ytilt = td->Ytilt;
1404                 
1405                 event->custom= EVT_DATA_TABLET;
1406                 event->customdata= wmtab;
1407                 event->customdatafree= 1;
1408         } 
1409 }
1410
1411
1412 /* windows store own event queues, no bContext here */
1413 void wm_event_add_ghostevent(wmWindow *win, int type, void *customdata)
1414 {
1415         wmEvent event, *evt= win->eventstate;
1416         
1417         /* initialize and copy state (only mouse x y and modifiers) */
1418         event= *evt;
1419         
1420         switch (type) {
1421                 /* mouse move */
1422                 case GHOST_kEventCursorMove: {
1423                         if(win->active) {
1424                                 GHOST_TEventCursorData *cd= customdata;
1425                                 int cx, cy;
1426
1427                                 GHOST_ScreenToClient(win->ghostwin, cd->x, cd->y, &cx, &cy);
1428                                 
1429                                 event.type= MOUSEMOVE;
1430                                 event.x= evt->x= cx;
1431                                 event.y= evt->y= (win->sizey-1) - cy;
1432                                 
1433                                 update_tablet_data(win, &event);
1434                                 wm_event_add(win, &event);
1435                         }
1436                         break;
1437                 }
1438                 /* mouse button */
1439                 case GHOST_kEventButtonDown:
1440                 case GHOST_kEventButtonUp: {
1441                         GHOST_TEventButtonData *bd= customdata;
1442                         event.val= (type==GHOST_kEventButtonDown);
1443                         
1444                         if (bd->button == GHOST_kButtonMaskLeft)
1445                                 event.type= LEFTMOUSE;
1446                         else if (bd->button == GHOST_kButtonMaskRight)
1447                                 event.type= RIGHTMOUSE;
1448                         else
1449                                 event.type= MIDDLEMOUSE;
1450                         
1451                         if(event.val)
1452                                 event.keymodifier= evt->keymodifier= event.type;
1453                         else
1454                                 event.keymodifier= evt->keymodifier= 0;
1455                         
1456                         update_tablet_data(win, &event);
1457                         wm_event_add(win, &event);
1458                         
1459                         break;
1460                 }
1461                 /* keyboard */
1462                 case GHOST_kEventKeyDown:
1463                 case GHOST_kEventKeyUp: {
1464                         GHOST_TEventKeyData *kd= customdata;
1465                         event.type= convert_key(kd->key);
1466                         event.ascii= kd->ascii;
1467                         event.val= (type==GHOST_kEventKeyDown)?KM_PRESS:KM_RELEASE;
1468                         
1469                         /* exclude arrow keys, esc, etc from text input */
1470                         if(type==GHOST_kEventKeyUp || (event.ascii<32 && event.ascii>14))
1471                                 event.ascii= '\0';
1472                         
1473                         /* modifiers */
1474                         if (event.type==LEFTSHIFTKEY || event.type==RIGHTSHIFTKEY) {
1475                                 event.shift= evt->shift= (event.val==KM_PRESS);
1476                                 if(event.val==KM_PRESS && (evt->ctrl || evt->alt || evt->oskey))
1477                                    event.shift= evt->shift = 3;         // define?
1478                         } 
1479                         else if (event.type==LEFTCTRLKEY || event.type==RIGHTCTRLKEY) {
1480                                 event.ctrl= evt->ctrl= (event.val==KM_PRESS);
1481                                 if(event.val==KM_PRESS && (evt->shift || evt->alt || evt->oskey))
1482                                    event.ctrl= evt->ctrl = 3;           // define?
1483                         } 
1484                         else if (event.type==LEFTALTKEY || event.type==RIGHTALTKEY) {
1485                                 event.alt= evt->alt= (event.val==KM_PRESS);
1486                                 if(event.val==KM_PRESS && (evt->ctrl || evt->shift || evt->oskey))
1487                                    event.alt= evt->alt = 3;             // define?
1488                         } 
1489                         else if (event.type==COMMANDKEY) {
1490                                 event.oskey= evt->oskey= (event.val==KM_PRESS);
1491                                 if(event.val==KM_PRESS && (evt->ctrl || evt->alt || evt->shift))
1492                                    event.oskey= evt->oskey = 3;         // define?
1493                         }
1494                         
1495                         /* if test_break set, it catches this. XXX Keep global for now? */
1496                         if(event.type==ESCKEY)
1497                                 G.afbreek= 1;
1498
1499                         wm_event_add(win, &event);
1500                         
1501                         break;
1502                 }
1503                         
1504                 case GHOST_kEventWheel: {
1505                         GHOST_TEventWheelData* wheelData = customdata;
1506                         
1507                         if (wheelData->z > 0)
1508                                 event.type= WHEELUPMOUSE;
1509                         else
1510                                 event.type= WHEELDOWNMOUSE;
1511                         
1512                         event.val= KM_PRESS;
1513                         wm_event_add(win, &event);
1514                         
1515                         break;
1516                 }
1517                 case GHOST_kEventTimer: {
1518                         event.type= TIMER;
1519                         event.custom= EVT_DATA_TIMER;
1520                         event.customdata= customdata;
1521                         wm_event_add(win, &event);
1522
1523                         break;
1524                 }
1525
1526                 case GHOST_kEventUnknown:
1527                 case GHOST_kNumEventTypes:
1528                         break;
1529         }
1530 }