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