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