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