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