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