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