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