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