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