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