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