report errors with library linking errors.
[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_main.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_info.h"
55 #include "ED_screen.h"
56 #include "ED_space_api.h"
57 #include "ED_util.h"
58
59 #include "RNA_access.h"
60
61 #include "UI_interface.h"
62
63 #include "PIL_time.h"
64
65 #include "WM_api.h"
66 #include "WM_types.h"
67 #include "wm.h"
68 #include "wm_window.h"
69 #include "wm_event_system.h"
70 #include "wm_event_types.h"
71
72 /* ************ event management ************** */
73
74 void wm_event_add(wmWindow *win, wmEvent *event_to_add)
75 {
76         wmEvent *event= MEM_callocN(sizeof(wmEvent), "event");
77         
78         *event= *event_to_add;
79         BLI_addtail(&win->queue, event);
80 }
81
82 void wm_event_free(wmEvent *event)
83 {
84         if(event->customdata && event->customdatafree)
85                 MEM_freeN(event->customdata);
86         MEM_freeN(event);
87 }
88
89 void wm_event_free_all(wmWindow *win)
90 {
91         wmEvent *event;
92         
93         while((event= win->queue.first)) {
94                 BLI_remlink(&win->queue, event);
95                 wm_event_free(event);
96         }
97 }
98
99 /* ********************* notifiers, listeners *************** */
100
101 /* XXX: in future, which notifiers to send to other windows? */
102 void WM_event_add_notifier(const bContext *C, unsigned int type, void *reference)
103 {
104         wmNotifier *note= MEM_callocN(sizeof(wmNotifier), "notifier");
105         
106         note->wm= CTX_wm_manager(C);
107         BLI_addtail(&note->wm->queue, note);
108         
109         note->window= CTX_wm_window(C);
110         
111         if(CTX_wm_region(C))
112                 note->swinid= CTX_wm_region(C)->swinid;
113         
114         note->category= type & NOTE_CATEGORY;
115         note->data= type & NOTE_DATA;
116         note->subtype= type & NOTE_SUBTYPE;
117         note->action= type & NOTE_ACTION;
118         
119         note->reference= reference;
120 }
121
122 void WM_main_add_notifier(unsigned int type, void *reference)
123 {
124         Main *bmain= G.main;
125         wmWindowManager *wm= bmain->wm.first;
126
127         if(wm) {
128                 wmNotifier *note= MEM_callocN(sizeof(wmNotifier), "notifier");
129                 
130                 note->wm= wm;
131                 BLI_addtail(&note->wm->queue, note);
132                 
133                 note->category= type & NOTE_CATEGORY;
134                 note->data= type & NOTE_DATA;
135                 note->subtype= type & NOTE_SUBTYPE;
136                 note->action= type & NOTE_ACTION;
137                 
138                 note->reference= reference;
139         }
140 }
141
142 static wmNotifier *wm_notifier_next(wmWindowManager *wm)
143 {
144         wmNotifier *note= wm->queue.first;
145         
146         if(note) BLI_remlink(&wm->queue, note);
147         return note;
148 }
149
150 /* called in mainloop */
151 void wm_event_do_notifiers(bContext *C)
152 {
153         wmWindowManager *wm= CTX_wm_manager(C);
154         wmNotifier *note, *next;
155         wmWindow *win;
156         
157         if(wm==NULL)
158                 return;
159         
160         /* cache & catch WM level notifiers, such as frame change, scene/screen set */
161         for(win= wm->windows.first; win; win= win->next) {
162                 int do_anim= 0;
163                 
164                 CTX_wm_window_set(C, win);
165                 
166                 for(note= wm->queue.first; note; note= next) {
167                         next= note->next;
168
169                         if(note->category==NC_WM) {
170                                 if( ELEM(note->data, ND_FILEREAD, ND_FILESAVE)) {
171                                         wm->file_saved= 1;
172                                         wm_window_title(wm, win);
173                                 }
174                                 else if(note->data==ND_DATACHANGED)
175                                         wm_window_title(wm, win);
176                         }
177                         if(note->window==win) {
178                                 if(note->category==NC_SCREEN) {
179                                         if(note->data==ND_SCREENBROWSE) {
180                                                 ED_screen_set(C, note->reference);      // XXX hrms, think this over!
181                                                 if(G.f & G_DEBUG)
182                                                         printf("screen set %p\n", note->reference);
183                                         }
184                                         else if(note->data==ND_SCREENDELETE) {
185                                                 ED_screen_delete(C, note->reference);   // XXX hrms, think this over!
186                                                 if(G.f & G_DEBUG)
187                                                         printf("screen delete %p\n", note->reference);
188                                         }
189                                 }
190                                 else if(note->category==NC_SCENE) {
191                                         if(note->data==ND_SCENEBROWSE) {
192                                                 ED_screen_set_scene(C, note->reference);        // XXX hrms, think this over!
193                                                 if(G.f & G_DEBUG)
194                                                         printf("scene set %p\n", note->reference);
195                                         }
196                                         if(note->data==ND_SCENEDELETE) {
197                                                 ED_screen_delete_scene(C, note->reference);     // XXX hrms, think this over!
198                                                 if(G.f & G_DEBUG)
199                                                         printf("scene delete %p\n", note->reference);
200                                         }
201                                         else if(note->data==ND_FRAME)
202                                                 do_anim= 1;
203                                 }
204                         }
205                         if(ELEM4(note->category, NC_SCENE, NC_OBJECT, NC_GEOM, NC_SCENE)) {
206                                 ED_info_stats_clear(CTX_data_scene(C));
207                                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_INFO, NULL);
208                         }
209                 }
210                 if(do_anim) {
211                         /* depsgraph gets called, might send more notifiers */
212                         ED_update_for_newframe(C, 1);
213                 }
214         }
215         
216         /* the notifiers are sent without context, to keep it clean */
217         while( (note=wm_notifier_next(wm)) ) {
218                 wmWindow *win;
219                 
220                 for(win= wm->windows.first; win; win= win->next) {
221                         
222                         /* filter out notifiers */
223                         if(note->category==NC_SCREEN && note->reference && note->reference!=win->screen);
224                         else if(note->category==NC_SCENE && note->reference && note->reference!=win->screen->scene);
225                         else {
226                                 ScrArea *sa;
227                                 ARegion *ar;
228
229                                 /* XXX context in notifiers? */
230                                 CTX_wm_window_set(C, win);
231
232                                 /* printf("notifier win %d screen %s cat %x\n", win->winid, win->screen->id.name+2, note->category); */
233                                 ED_screen_do_listen(win, note);
234
235                                 for(ar=win->screen->regionbase.first; ar; ar= ar->next) {
236                                         ED_region_do_listen(ar, note);
237                                 }
238                                 
239                                 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
240                                         ED_area_do_listen(sa, note);
241                                         for(ar=sa->regionbase.first; ar; ar= ar->next) {
242                                                 ED_region_do_listen(ar, note);
243                                         }
244                                 }
245                         }
246                 }
247                 
248                 MEM_freeN(note);
249         }
250         
251         /* cached: editor refresh callbacks now, they get context */
252         for(win= wm->windows.first; win; win= win->next) {
253                 ScrArea *sa;
254                 
255                 CTX_wm_window_set(C, win);
256                 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
257                         if(sa->do_refresh) {
258                                 CTX_wm_area_set(C, sa);
259                                 ED_area_do_refresh(C, sa);
260                         }
261                 }
262                 
263                 /* XXX make lock in future, or separated derivedmesh users in scene */
264                 if(!G.rendering)
265                         /* depsgraph & animation: update tagged datablocks */
266                         scene_update_tagged(win->screen->scene);
267         }
268
269         CTX_wm_window_set(C, NULL);
270 }
271
272 /* ********************* operators ******************* */
273
274 int WM_operator_poll(bContext *C, wmOperatorType *ot)
275 {
276         wmOperatorTypeMacro *otmacro;
277         
278         for(otmacro= ot->macro.first; otmacro; otmacro= otmacro->next) {
279                 wmOperatorType *ot= WM_operatortype_find(otmacro->idname, 0);
280                 
281                 if(0==WM_operator_poll(C, ot))
282                         return 0;
283         }
284         
285         /* python needs operator type, so we added exception for it */
286         if(ot->pyop_poll)
287                 return ot->pyop_poll(C, ot);
288         else if(ot->poll)
289                 return ot->poll(C);
290
291         return 1;
292 }
293
294 /* if repeat is true, it doesn't register again, nor does it free */
295 static int wm_operator_exec(bContext *C, wmOperator *op, int repeat)
296 {
297         int retval= OPERATOR_CANCELLED;
298         
299         if(op==NULL || op->type==NULL)
300                 return retval;
301         
302         if(0==WM_operator_poll(C, op->type))
303                 return retval;
304         
305         if(op->type->exec)
306                 retval= op->type->exec(C, op);
307         
308         if(retval & (OPERATOR_FINISHED|OPERATOR_CANCELLED))
309                 if(op->reports->list.first)
310                         uiPupMenuReports(C, op->reports);
311         
312         if(retval & OPERATOR_FINISHED) {
313                 op->customdata= NULL;
314
315                 if(op->type->flag & OPTYPE_UNDO)
316                         ED_undo_push_op(C, op);
317                 
318                 if(repeat==0) {
319                         if(G.f & G_DEBUG) {
320                                 char *buf = WM_operator_pystring(C, op->type, op->ptr, 1);
321                                 BKE_report(CTX_wm_reports(C), RPT_OPERATOR, buf);
322                                 MEM_freeN(buf);
323                         }
324
325                         if((op->type->flag & OPTYPE_REGISTER))
326                                 wm_operator_register(C, op);
327                         else
328                                 WM_operator_free(op);
329                 }
330         }
331         else if(repeat==0)
332                 WM_operator_free(op);
333         
334         return retval;
335         
336 }
337
338 /* for running operators with frozen context (modal handlers, menus) */
339 int WM_operator_call(bContext *C, wmOperator *op)
340 {
341         return wm_operator_exec(C, op, 0);
342 }
343
344 /* do this operator again, put here so it can share above code */
345 int WM_operator_repeat(bContext *C, wmOperator *op)
346 {
347         return wm_operator_exec(C, op, 1);
348 }
349
350 static wmOperator *wm_operator_create(wmWindowManager *wm, wmOperatorType *ot, PointerRNA *properties, ReportList *reports)
351 {
352         wmOperator *op= MEM_callocN(sizeof(wmOperator), ot->idname);    /* XXX operatortype names are static still. for debug */
353         
354         /* XXX adding new operator could be function, only happens here now */
355         op->type= ot;
356         BLI_strncpy(op->idname, ot->idname, OP_MAX_TYPENAME);
357         
358         /* initialize properties, either copy or create */
359         op->ptr= MEM_callocN(sizeof(PointerRNA), "wmOperatorPtrRNA");
360         if(properties && properties->data) {
361                 op->properties= IDP_CopyProperty(properties->data);
362         }
363         else {
364                 IDPropertyTemplate val = {0};
365                 op->properties= IDP_New(IDP_GROUP, val, "wmOperatorProperties");
366         }
367         RNA_pointer_create(&wm->id, ot->srna, op->properties, op->ptr);
368
369         /* initialize error reports */
370         if (reports) {
371                 op->reports= reports; /* must be initialized already */
372         }
373         else {
374                 op->reports= MEM_mallocN(sizeof(ReportList), "wmOperatorReportList");
375                 BKE_reports_init(op->reports, RPT_STORE|RPT_FREE);
376         }
377         
378         /* recursive filling of operator macro list */
379         if(ot->macro.first) {
380                 static wmOperator *motherop= NULL;
381                 wmOperatorTypeMacro *otmacro;
382                 int root = 0;
383                 
384                 /* ensure all ops are in execution order in 1 list */
385                 if(motherop==NULL) {
386                         motherop = op;
387                         root = 1;
388                 }
389                 
390                 for(otmacro= ot->macro.first; otmacro; otmacro= otmacro->next) {
391                         wmOperatorType *otm= WM_operatortype_find(otmacro->idname, 0);
392                         wmOperator *opm= wm_operator_create(wm, otm, otmacro->ptr, NULL);
393                         
394                         IDP_ReplaceGroupInGroup(opm->properties, motherop->properties);
395
396                         BLI_addtail(&motherop->macro, opm);
397                         opm->opm= motherop; /* pointer to mom, for modal() */
398                 }
399                 
400                 if (root)
401                         motherop= NULL;
402         }
403         
404         return op;
405 }
406
407 static void wm_operator_print(wmOperator *op)
408 {
409         char *buf = WM_operator_pystring(NULL, op->type, op->ptr, 1);
410         printf("%s\n", buf);
411         MEM_freeN(buf);
412 }
413
414 static void wm_region_mouse_co(bContext *C, wmEvent *event)
415 {
416         ARegion *ar= CTX_wm_region(C);
417         if(ar) {
418                 /* compatibility convention */
419                 event->mval[0]= event->x - ar->winrct.xmin;
420                 event->mval[1]= event->y - ar->winrct.ymin;
421         }
422 }
423
424 static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, PointerRNA *properties, ReportList *reports)
425 {
426         wmWindowManager *wm= CTX_wm_manager(C);
427         int retval= OPERATOR_PASS_THROUGH;
428
429         if(WM_operator_poll(C, ot)) {
430                 wmOperator *op= wm_operator_create(wm, ot, properties, reports); /* if reports==NULL, theyll be initialized */
431                 
432                 if((G.f & G_DEBUG) && event && event->type!=MOUSEMOVE)
433                         printf("handle evt %d win %d op %s\n", event?event->type:0, CTX_wm_screen(C)->subwinactive, ot->idname); 
434                 
435                 if(op->type->invoke && event) {
436                         wm_region_mouse_co(C, event);
437                         retval= op->type->invoke(C, op, event);
438                 }
439                 else if(op->type->exec)
440                         retval= op->type->exec(C, op);
441                 else
442                         printf("invalid operator call %s\n", ot->idname); /* debug, important to leave a while, should never happen */
443
444                 /* Note, if the report is given as an argument then assume the caller will deal with displaying them
445                  * currently python only uses this */
446                 if((retval & (OPERATOR_FINISHED|OPERATOR_CANCELLED)) && reports==NULL)
447                         if(op->reports->list.first) /* only show the report if the report list was not given in the function */
448                                 uiPupMenuReports(C, op->reports);
449                 
450                 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 */
451                         if(G.f & G_DEBUG)
452                                 wm_operator_print(op);
453                 }
454
455                 if(retval & OPERATOR_FINISHED) {
456                         op->customdata= NULL;
457
458                         if(ot->flag & OPTYPE_UNDO)
459                                 ED_undo_push_op(C, op);
460                         
461                         if(G.f & G_DEBUG) {
462                                 char *buf = WM_operator_pystring(C, op->type, op->ptr, 1);
463                                 BKE_report(CTX_wm_reports(C), RPT_OPERATOR, buf);
464                                 MEM_freeN(buf);
465                         }
466                         
467                         if((ot->flag & OPTYPE_REGISTER))
468                                 wm_operator_register(C, op);
469                         else
470                                 WM_operator_free(op);
471                 }
472                 else if(retval & OPERATOR_RUNNING_MODAL) {
473                         /* grab cursor during blocking modal ops (X11)
474                          * Also check for macro
475                          * */
476                         if(ot->flag & OPTYPE_BLOCKING || (op->opm && op->opm->type->flag & OPTYPE_BLOCKING)) {
477                                 int bounds[4] = {-1,-1,-1,-1};
478                                 int wrap;
479
480                                 if (op->opm) {
481                                         wrap = (U.uiflag & USER_CONTINUOUS_MOUSE) && ((op->opm->flag & OP_GRAB_POINTER) || (op->opm->type->flag & OPTYPE_GRAB_POINTER));
482                                 } else {
483                                         wrap = (U.uiflag & USER_CONTINUOUS_MOUSE) && ((op->flag & OP_GRAB_POINTER) || (ot->flag & OPTYPE_GRAB_POINTER));
484                                 }
485
486                                 if(wrap) {
487                                         ARegion *ar= CTX_wm_region(C);
488                                         if(ar) {
489                                                 bounds[0]= ar->winrct.xmin;
490                                                 bounds[1]= ar->winrct.ymax;
491                                                 bounds[2]= ar->winrct.xmax;
492                                                 bounds[3]= ar->winrct.ymin;
493                                         }
494                                 }
495
496                                 WM_cursor_grab(CTX_wm_window(C), wrap, FALSE, bounds);
497                         }
498                 }
499                 else
500                         WM_operator_free(op);
501         }
502
503         return retval;
504 }
505
506 /* WM_operator_name_call is the main accessor function
507  * this is for python to access since its done the operator lookup
508  * 
509  * invokes operator in context */
510 static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, int context, PointerRNA *properties, ReportList *reports)
511 {
512         wmWindow *window= CTX_wm_window(C);
513         wmEvent *event;
514         
515         int retval;
516
517         /* dummie test */
518         if(ot && C) {
519                 switch(context) {
520                         case WM_OP_INVOKE_DEFAULT:
521                         case WM_OP_INVOKE_REGION_WIN:
522                         case WM_OP_INVOKE_AREA:
523                         case WM_OP_INVOKE_SCREEN:
524                                 /* window is needed for invoke, cancel operator */
525                                 if (window == NULL)
526                                         return 0;
527                                 else
528                                         event= window->eventstate;
529                                 break;
530                         default:
531                                 event = NULL;
532                 }
533
534                 switch(context) {
535                         
536                         case WM_OP_EXEC_REGION_WIN:
537                         case WM_OP_INVOKE_REGION_WIN: 
538                         {
539                                 /* forces operator to go to the region window, for header menus */
540                                 ARegion *ar= CTX_wm_region(C);
541                                 ScrArea *area= CTX_wm_area(C);
542                                 
543                                 if(area) {
544                                         ARegion *ar1= area->regionbase.first;
545                                         for(; ar1; ar1= ar1->next)
546                                                 if(ar1->regiontype==RGN_TYPE_WINDOW)
547                                                         break;
548                                         if(ar1)
549                                                 CTX_wm_region_set(C, ar1);
550                                 }
551                                 
552                                 retval= wm_operator_invoke(C, ot, event, properties, reports);
553                                 
554                                 /* set region back */
555                                 CTX_wm_region_set(C, ar);
556                                 
557                                 return retval;
558                         }
559                         case WM_OP_EXEC_AREA:
560                         case WM_OP_INVOKE_AREA:
561                         {
562                                         /* remove region from context */
563                                 ARegion *ar= CTX_wm_region(C);
564
565                                 CTX_wm_region_set(C, NULL);
566                                 retval= wm_operator_invoke(C, ot, event, properties, reports);
567                                 CTX_wm_region_set(C, ar);
568
569                                 return retval;
570                         }
571                         case WM_OP_EXEC_SCREEN:
572                         case WM_OP_INVOKE_SCREEN:
573                         {
574                                 /* remove region + area from context */
575                                 ARegion *ar= CTX_wm_region(C);
576                                 ScrArea *area= CTX_wm_area(C);
577
578                                 CTX_wm_region_set(C, NULL);
579                                 CTX_wm_area_set(C, NULL);
580                                 retval= wm_operator_invoke(C, ot, event, properties, reports);
581                                 CTX_wm_region_set(C, ar);
582                                 CTX_wm_area_set(C, area);
583
584                                 return retval;
585                         }
586                         case WM_OP_EXEC_DEFAULT:
587                         case WM_OP_INVOKE_DEFAULT:
588                                 return wm_operator_invoke(C, ot, event, properties, reports);
589                 }
590         }
591         
592         return 0;
593 }
594
595
596 /* invokes operator in context */
597 int WM_operator_name_call(bContext *C, const char *opstring, int context, PointerRNA *properties)
598 {
599         wmOperatorType *ot= WM_operatortype_find(opstring, 0);
600         if(ot)
601                 return wm_operator_call_internal(C, ot, context, properties, NULL);
602
603         return 0;
604 }
605
606 /* Similar to WM_operator_name_call called with WM_OP_EXEC_DEFAULT context.
607    - wmOperatorType is used instead of operator name since python alredy has the operator type
608    - poll() must be called by python before this runs.
609    - reports can be passed to this function (so python can report them as exceptions)
610 */
611 int WM_operator_call_py(bContext *C, wmOperatorType *ot, int context, PointerRNA *properties, ReportList *reports)
612 {
613         int retval= OPERATOR_CANCELLED;
614
615 #if 0
616         wmOperator *op;
617         wmWindowManager *wm=    CTX_wm_manager(C);
618         op= wm_operator_create(wm, ot, properties, reports);
619
620         if (op->type->exec)
621                 retval= op->type->exec(C, op);
622         else
623                 printf("error \"%s\" operator has no exec function, python cannot call it\n", op->type->name);
624 #endif
625
626         retval= wm_operator_call_internal(C, ot, context, properties, reports);
627         
628         /* keep the reports around if needed later */
629         if (retval & OPERATOR_RUNNING_MODAL || ot->flag & OPTYPE_REGISTER)
630         {
631                 reports->flag |= RPT_FREE;
632         }
633         
634         return retval;
635 }
636
637
638 /* ********************* handlers *************** */
639
640 /* future extra customadata free? */
641 void wm_event_free_handler(wmEventHandler *handler)
642 {
643         MEM_freeN(handler);
644 }
645
646 /* only set context when area/region is part of screen */
647 static void wm_handler_op_context(bContext *C, wmEventHandler *handler)
648 {
649         bScreen *screen= CTX_wm_screen(C);
650         
651         if(screen && handler->op) {
652                 if(handler->op_area==NULL)
653                         CTX_wm_area_set(C, NULL);
654                 else {
655                         ScrArea *sa;
656                         
657                         for(sa= screen->areabase.first; sa; sa= sa->next)
658                                 if(sa==handler->op_area)
659                                         break;
660                         if(sa==NULL) {
661                                 /* when changing screen layouts with running modal handlers (like render display), this
662                                    is not an error to print */
663                                 if(handler->op==NULL)
664                                         printf("internal error: handler (%s) has invalid area\n", handler->op->type->idname);
665                         }
666                         else {
667                                 ARegion *ar;
668                                 CTX_wm_area_set(C, sa);
669                                 for(ar= sa->regionbase.first; ar; ar= ar->next)
670                                         if(ar==handler->op_region)
671                                                 break;
672                                 /* XXX no warning print here, after full-area and back regions are remade */
673                                 if(ar)
674                                         CTX_wm_region_set(C, ar);
675                         }
676                 }
677         }
678 }
679
680 /* called on exit or remove area, only here call cancel callback */
681 void WM_event_remove_handlers(bContext *C, ListBase *handlers)
682 {
683         wmEventHandler *handler;
684         
685         /* C is zero on freeing database, modal handlers then already were freed */
686         while((handler=handlers->first)) {
687                 BLI_remlink(handlers, handler);
688                 
689                 if(handler->op) {
690                         if(handler->op->type->cancel) {
691                                 ScrArea *area= CTX_wm_area(C);
692                                 ARegion *region= CTX_wm_region(C);
693                                 
694                                 wm_handler_op_context(C, handler);
695
696                                 handler->op->type->cancel(C, handler->op);
697
698                                 CTX_wm_area_set(C, area);
699                                 CTX_wm_region_set(C, region);
700                         }
701
702                         WM_cursor_ungrab(CTX_wm_window(C));
703                         WM_operator_free(handler->op);
704                 }
705                 else if(handler->ui_remove) {
706                         ScrArea *area= CTX_wm_area(C);
707                         ARegion *region= CTX_wm_region(C);
708                         ARegion *menu= CTX_wm_menu(C);
709                         
710                         if(handler->ui_area) CTX_wm_area_set(C, handler->ui_area);
711                         if(handler->ui_region) CTX_wm_region_set(C, handler->ui_region);
712                         if(handler->ui_menu) CTX_wm_menu_set(C, handler->ui_menu);
713
714                         handler->ui_remove(C, handler->ui_userdata);
715
716                         CTX_wm_area_set(C, area);
717                         CTX_wm_region_set(C, region);
718                         CTX_wm_menu_set(C, menu);
719                 }
720
721                 wm_event_free_handler(handler);
722         }
723 }
724
725 /* do userdef mappings */
726 int WM_userdef_event_map(int kmitype)
727 {
728         switch(kmitype) {
729                 case SELECTMOUSE:
730                         if(U.flag & USER_LMOUSESELECT)
731                                 return LEFTMOUSE;
732                         else
733                                 return RIGHTMOUSE;
734                         
735                 case ACTIONMOUSE:
736                         if(U.flag & USER_LMOUSESELECT)
737                                 return RIGHTMOUSE;
738                         else
739                                 return LEFTMOUSE;
740                         
741                 case WHEELOUTMOUSE:
742                         if(U.uiflag & USER_WHEELZOOMDIR)
743                                 return WHEELUPMOUSE;
744                         else
745                                 return WHEELDOWNMOUSE;
746                         
747                 case WHEELINMOUSE:
748                         if(U.uiflag & USER_WHEELZOOMDIR)
749                                 return WHEELDOWNMOUSE;
750                         else
751                                 return WHEELUPMOUSE;
752                         
753                 case EVT_TWEAK_A:
754                         if(U.flag & USER_LMOUSESELECT)
755                                 return EVT_TWEAK_R;
756                         else
757                                 return EVT_TWEAK_L;
758                         
759                 case EVT_TWEAK_S:
760                         if(U.flag & USER_LMOUSESELECT)
761                                 return EVT_TWEAK_L;
762                         else
763                                 return EVT_TWEAK_R;
764         }
765         
766         return kmitype;
767 }
768
769 static int wm_eventmatch(wmEvent *winevent, wmKeyMapItem *kmi)
770 {
771         int kmitype= WM_userdef_event_map(kmi->type);
772
773         if(kmi->flag & KMI_INACTIVE) return 0;
774
775         /* exception for middlemouse emulation */
776         if((U.flag & USER_TWOBUTTONMOUSE) && (kmi->type == MIDDLEMOUSE)) {
777                 if(winevent->type == LEFTMOUSE && winevent->alt) {
778                         wmKeyMapItem tmp= *kmi;
779
780                         tmp.type= winevent->type;
781                         tmp.alt= winevent->alt;
782                         if(wm_eventmatch(winevent, &tmp))
783                                 return 1;
784                 }
785         }
786         /* exception for numpad emulation */
787         else if(U.flag & USER_NONUMPAD) {
788                 wmKeyMapItem tmp= *kmi;
789
790                 switch(kmi->type) {
791                         case PAD0: tmp.type = ZEROKEY; break;
792                         case PAD1: tmp.type = ONEKEY; break;
793                         case PAD2: tmp.type = TWOKEY; break;
794                         case PAD3: tmp.type = THREEKEY; break;
795                         case PAD4: tmp.type = FOURKEY; break;
796                         case PAD5: tmp.type = FIVEKEY; break;
797                         case PAD6: tmp.type = SIXKEY; break;
798                         case PAD7: tmp.type = SEVENKEY; break;
799                         case PAD8: tmp.type = EIGHTKEY; break;
800                         case PAD9: tmp.type = NINEKEY; break;
801                         case PADMINUS: tmp.type = MINUSKEY; break;
802                         case PADPLUSKEY: tmp.type = EQUALKEY; break;
803                         case PADSLASHKEY: tmp.type = BACKSLASHKEY; break;
804                 }
805
806                 if(tmp.type != kmi->type)
807                         if(wm_eventmatch(winevent, &tmp))
808                                 return 1;
809         }
810
811         /* the matching rules */
812         if(kmitype==KM_TEXTINPUT)
813                 if(ISTEXTINPUT(winevent->type) && winevent->ascii) return 1;
814         if(kmitype!=KM_ANY)
815                 if(winevent->type!=kmitype) return 0;
816         
817         if(kmi->val!=KM_ANY)
818                 if(winevent->val!=kmi->val) return 0;
819         
820         /* modifiers also check bits, so it allows modifier order */
821         if(kmi->shift!=KM_ANY)
822                 if(winevent->shift != kmi->shift && !(winevent->shift & kmi->shift)) return 0;
823         if(kmi->ctrl!=KM_ANY)
824                 if(winevent->ctrl != kmi->ctrl && !(winevent->ctrl & kmi->ctrl)) return 0;
825         if(kmi->alt!=KM_ANY)
826                 if(winevent->alt != kmi->alt && !(winevent->alt & kmi->alt)) return 0;
827         if(kmi->oskey!=KM_ANY)
828                 if(winevent->oskey != kmi->oskey && !(winevent->oskey & kmi->oskey)) return 0;
829         
830         if(kmi->keymodifier)
831                 if(winevent->keymodifier!=kmi->keymodifier) return 0;
832                 
833         /* key modifiers always check when event has it */
834         /* otherwise regular keypresses with keymodifier still work */
835         if(winevent->keymodifier)
836                 if(ISTEXTINPUT(winevent->type)) 
837                         if(winevent->keymodifier!=kmi->keymodifier) return 0;
838         
839         return 1;
840 }
841
842 static int wm_event_always_pass(wmEvent *event)
843 {
844         /* some events we always pass on, to ensure proper communication */
845         return ISTIMER(event->type) || (event->type == WINDEACTIVATE);
846 }
847
848 /* operator exists */
849 static void wm_event_modalkeymap(const bContext *C, wmOperator *op, wmEvent *event)
850 {
851         /* support for modal keymap in macros */
852         if (op->opm)
853                 op = op->opm;
854
855         if(op->type->modalkeymap) {
856                 wmKeyMap *keymap= WM_keymap_active(CTX_wm_manager(C), op->type->modalkeymap);
857                 wmKeyMapItem *kmi;
858
859                 for(kmi= keymap->items.first; kmi; kmi= kmi->next) {
860                         if(wm_eventmatch(event, kmi)) {
861                                         
862                                 event->type= EVT_MODAL_MAP;
863                                 event->val= kmi->propvalue;
864                         }
865                 }
866         }
867 }
868
869 /* Warning: this function removes a modal handler, when finished */
870 static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHandler *handler, wmEvent *event, PointerRNA *properties)
871 {
872         int retval= OPERATOR_PASS_THROUGH;
873         
874         /* derived, modal or blocking operator */
875         if(handler->op) {
876                 wmOperator *op= handler->op;
877                 wmOperatorType *ot= op->type;
878
879                 if(ot->modal) {
880                         /* we set context to where modal handler came from */
881                         ScrArea *area= CTX_wm_area(C);
882                         ARegion *region= CTX_wm_region(C);
883                         
884                         wm_handler_op_context(C, handler);
885                         wm_region_mouse_co(C, event);
886                         wm_event_modalkeymap(C, op, event);
887                         
888                         retval= ot->modal(C, op, event);
889
890                         /* putting back screen context, reval can pass trough after modal failures! */
891                         if((retval & OPERATOR_PASS_THROUGH) || wm_event_always_pass(event)) {
892                                 CTX_wm_area_set(C, area);
893                                 CTX_wm_region_set(C, region);
894                         }
895                         else {
896                                 /* this special cases is for areas and regions that get removed */
897                                 CTX_wm_area_set(C, NULL);
898                                 CTX_wm_region_set(C, NULL);
899                         }
900
901                         if(retval & (OPERATOR_FINISHED|OPERATOR_CANCELLED))
902                                 if(op->reports->list.first)
903                                         uiPupMenuReports(C, op->reports);
904
905                         if (retval & OPERATOR_FINISHED) {
906                                 if(G.f & G_DEBUG)
907                                         wm_operator_print(op); /* todo - this print may double up, might want to check more flags then the FINISHED */
908                         }                       
909
910                         if(retval & OPERATOR_FINISHED) {
911                                 op->customdata= NULL;
912
913                                 if(ot->flag & OPTYPE_UNDO)
914                                         ED_undo_push_op(C, op);
915                                 
916                                 if(G.f & G_DEBUG) {
917                                         char *buf = WM_operator_pystring(C, op->type, op->ptr, 1);
918                                         BKE_report(CTX_wm_reports(C), RPT_OPERATOR, buf);
919                                         MEM_freeN(buf);
920                                 }
921                                 
922                                 if((ot->flag & OPTYPE_REGISTER))
923                                         wm_operator_register(C, op);
924                                 else
925                                         WM_operator_free(op);
926                                 handler->op= NULL;
927                         }
928                         else if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) {
929                                 WM_operator_free(op);
930                                 handler->op= NULL;
931                         }
932                         
933                         /* remove modal handler, operator itself should have been cancelled and freed */
934                         if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) {
935                                 WM_cursor_ungrab(CTX_wm_window(C));
936
937                                 BLI_remlink(handlers, handler);
938                                 wm_event_free_handler(handler);
939                                 
940                                 /* prevent silly errors from operator users */
941                                 //retval &= ~OPERATOR_PASS_THROUGH;
942                         }
943                         
944                 }
945                 else
946                         printf("wm_handler_operator_call error\n");
947         }
948         else {
949                 wmOperatorType *ot= WM_operatortype_find(event->keymap_idname, 0);
950
951                 if(ot)
952                         retval= wm_operator_invoke(C, ot, event, properties, NULL);
953         }
954
955         /* Finished and pass through flag as handled */
956         if(retval == (OPERATOR_FINISHED|OPERATOR_PASS_THROUGH))
957                 return WM_HANDLER_HANDLED;
958
959         /* Modal unhandled, break */
960         if(retval == (OPERATOR_PASS_THROUGH|OPERATOR_RUNNING_MODAL))
961                 return (WM_HANDLER_BREAK|WM_HANDLER_MODAL);
962
963         if(retval & OPERATOR_PASS_THROUGH)
964                 return WM_HANDLER_CONTINUE;
965
966         return WM_HANDLER_BREAK;
967 }
968
969 static int wm_handler_ui_call(bContext *C, wmEventHandler *handler, wmEvent *event)
970 {
971         ScrArea *area= CTX_wm_area(C);
972         ARegion *region= CTX_wm_region(C);
973         ARegion *menu= CTX_wm_menu(C);
974         int retval, always_pass;
975                         
976         /* we set context to where ui handler came from */
977         if(handler->ui_area) CTX_wm_area_set(C, handler->ui_area);
978         if(handler->ui_region) CTX_wm_region_set(C, handler->ui_region);
979         if(handler->ui_menu) CTX_wm_menu_set(C, handler->ui_menu);
980
981         /* in advance to avoid access to freed event on window close */
982         always_pass= wm_event_always_pass(event);
983
984         retval= handler->ui_handle(C, event, handler->ui_userdata);
985
986         /* putting back screen context */
987         if((retval != WM_UI_HANDLER_BREAK) || always_pass) {
988                 CTX_wm_area_set(C, area);
989                 CTX_wm_region_set(C, region);
990                 CTX_wm_menu_set(C, menu);
991         }
992         else {
993                 /* this special cases is for areas and regions that get removed */
994                 CTX_wm_area_set(C, NULL);
995                 CTX_wm_region_set(C, NULL);
996                 CTX_wm_menu_set(C, NULL);
997         }
998
999         if(retval == WM_UI_HANDLER_BREAK)
1000                 return WM_HANDLER_BREAK;
1001
1002         return WM_HANDLER_CONTINUE;
1003 }
1004
1005 /* fileselect handlers are only in the window queue, so it's save to switch screens or area types */
1006 static int wm_handler_fileselect_call(bContext *C, ListBase *handlers, wmEventHandler *handler, wmEvent *event)
1007 {
1008         SpaceFile *sfile;
1009         int action= WM_HANDLER_CONTINUE;
1010         
1011         if(event->type != EVT_FILESELECT)
1012                 return action;
1013         if(handler->op != (wmOperator *)event->customdata)
1014                 return action;
1015         
1016         switch(event->val) {
1017                 case EVT_FILESELECT_OPEN: 
1018                 case EVT_FILESELECT_FULL_OPEN: 
1019                         {       
1020                                 ScrArea *sa;
1021                                 
1022                                 /* sa can be null when window A is active, but mouse is over window B */
1023                                 /* in this case, open file select in original window A */
1024                                 if (handler->op_area == NULL) {
1025                                         bScreen *screen = CTX_wm_screen(C);
1026                                         sa = (ScrArea *)screen->areabase.first;
1027                                 } else
1028                                         sa = handler->op_area;
1029                                         
1030                                 if(event->val==EVT_FILESELECT_OPEN)
1031                                         ED_area_newspace(C, sa, SPACE_FILE);
1032                                 else
1033                                         ED_screen_full_newspace(C, sa, SPACE_FILE);     /* sets context */
1034                                 
1035                                 /* settings for filebrowser, sfile is not operator owner but sends events */
1036                                 sa = CTX_wm_area(C);
1037                                 sfile= (SpaceFile*)sa->spacedata.first;
1038                                 sfile->op= handler->op;
1039
1040                                 ED_fileselect_set_params(sfile);
1041                                 
1042                                 action= WM_HANDLER_BREAK;
1043                         }
1044                         break;
1045                         
1046                 case EVT_FILESELECT_EXEC:
1047                 case EVT_FILESELECT_CANCEL:
1048                         {
1049                                 /* XXX validate area and region? */
1050                                 bScreen *screen= CTX_wm_screen(C);
1051                                 char *path= RNA_string_get_alloc(handler->op->ptr, "path", NULL, 0);
1052                                 
1053                                 if(screen != handler->filescreen)
1054                                         ED_screen_full_prevspace(C, CTX_wm_area(C));
1055                                 else
1056                                         ED_area_prevspace(C, CTX_wm_area(C));
1057                                 
1058                                 /* remlink now, for load file case */
1059                                 BLI_remlink(handlers, handler);
1060                                 
1061                                 wm_handler_op_context(C, handler);
1062
1063                                 /* needed for uiPupMenuReports */
1064
1065                                 if(event->val==EVT_FILESELECT_EXEC) {
1066                                         /* a bit weak, might become arg for WM_event_fileselect? */
1067                                         /* XXX also extension code in image-save doesnt work for this yet */
1068                                         if(strncmp(handler->op->type->name, "Save", 4)==0) {
1069                                                 /* this gives ownership to pupmenu */
1070                                                 uiPupMenuSaveOver(C, handler->op, (path)? path: "");
1071                                         }
1072                                         else {
1073                                                 int retval= handler->op->type->exec(C, handler->op);
1074                                                 
1075                                                 if (retval & OPERATOR_FINISHED)
1076                                                         if(G.f & G_DEBUG)
1077                                                                 wm_operator_print(handler->op);
1078                                                 
1079                                                 if(handler->op->reports->list.first) {
1080
1081                                                         /* FIXME, temp setting window, this is really bad!
1082                                                          * only have because lib linking errors need to be seen by users :(
1083                                                          * it can be removed without breaking anything but then no linking errors - campbell */
1084                                                         wmWindow *win_prev= CTX_wm_window(C);
1085                                                         if(win_prev==NULL)
1086                                                                 CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first);
1087
1088                                                         handler->op->reports->printlevel = RPT_WARNING;
1089                                                         uiPupMenuReports(C, handler->op->reports);
1090
1091                                                         CTX_wm_window_set(C, win_prev);
1092                                                 }
1093
1094                                                 WM_operator_free(handler->op);
1095                                         }
1096                                 }
1097                                 else {
1098                                         if(handler->op->type->cancel)
1099                                                 handler->op->type->cancel(C, handler->op);
1100
1101                                         WM_operator_free(handler->op);
1102                                 }
1103
1104                                 CTX_wm_area_set(C, NULL);
1105                                 
1106                                 wm_event_free_handler(handler);
1107                                 if(path)
1108                                         MEM_freeN(path);
1109                                 
1110                                 action= WM_HANDLER_BREAK;
1111                         }
1112                         break;
1113         }
1114         
1115         return action;
1116 }
1117
1118 static int handler_boundbox_test(wmEventHandler *handler, wmEvent *event)
1119 {
1120         if(handler->bbwin) {
1121                 if(handler->bblocal) {
1122                         rcti rect= *handler->bblocal;
1123                         BLI_translate_rcti(&rect, handler->bbwin->xmin, handler->bbwin->ymin);
1124
1125                         if(BLI_in_rcti(&rect, event->x, event->y))
1126                                 return 1;
1127                         else if(event->type==MOUSEMOVE && BLI_in_rcti(&rect, event->prevx, event->prevy))
1128                                 return 1;
1129                         else
1130                                 return 0;
1131                 }
1132                 else {
1133                         if(BLI_in_rcti(handler->bbwin, event->x, event->y))
1134                                 return 1;
1135                         else if(event->type==MOUSEMOVE && BLI_in_rcti(handler->bbwin, event->prevx, event->prevy))
1136                                 return 1;
1137                         else
1138                                 return 0;
1139                 }
1140         }
1141         return 1;
1142 }
1143
1144 static int wm_action_not_handled(int action)
1145 {
1146         return action == WM_HANDLER_CONTINUE || action == (WM_HANDLER_BREAK|WM_HANDLER_MODAL);
1147 }
1148
1149 static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
1150 {
1151         wmWindowManager *wm= CTX_wm_manager(C);
1152         wmEventHandler *handler, *nexthandler;
1153         int action= WM_HANDLER_CONTINUE;
1154         int always_pass;
1155
1156         if(handlers==NULL) return action;
1157
1158         /* modal handlers can get removed in this loop, we keep the loop this way */
1159         for(handler= handlers->first; handler; handler= nexthandler) {
1160                 nexthandler= handler->next;
1161
1162                 /* optional boundbox */
1163                 if(handler_boundbox_test(handler, event)) {
1164                         /* in advance to avoid access to freed event on window close */
1165                         always_pass= wm_event_always_pass(event);
1166                 
1167                         /* modal+blocking handler */
1168                         if(handler->flag & WM_HANDLER_BLOCKING)
1169                                 action |= WM_HANDLER_BREAK;
1170
1171                         if(handler->keymap) {
1172                                 wmKeyMap *keymap= WM_keymap_active(wm, handler->keymap);
1173                                 wmKeyMapItem *kmi;
1174                                 
1175                                 if(!keymap->poll || keymap->poll(C)) {
1176                                         for(kmi= keymap->items.first; kmi; kmi= kmi->next) {
1177                                                 if(wm_eventmatch(event, kmi)) {
1178                                                         
1179                                                         event->keymap_idname= kmi->idname;      /* weak, but allows interactive callback to not use rawkey */
1180                                                         
1181                                                         action |= wm_handler_operator_call(C, handlers, handler, event, kmi->ptr);
1182                                                         if(action & WM_HANDLER_BREAK)  /* not always_pass here, it denotes removed handler */
1183                                                                 break;
1184                                                 }
1185                                         }
1186                                 }
1187                         }
1188                         else if(handler->ui_handle) {
1189                                 action |= wm_handler_ui_call(C, handler, event);
1190                         }
1191                         else if(handler->type==WM_HANDLER_FILESELECT) {
1192                                 /* screen context changes here */
1193                                 action |= wm_handler_fileselect_call(C, handlers, handler, event);
1194                         }
1195                         else {
1196                                 /* modal, swallows all */
1197                                 action |= wm_handler_operator_call(C, handlers, handler, event, NULL);
1198                         }
1199
1200                         if(action & WM_HANDLER_BREAK) {
1201                                 if(always_pass)
1202                                         action &= ~WM_HANDLER_BREAK;
1203                                 else
1204                                         break;
1205                         }
1206                 }
1207                 
1208                 /* fileread case */
1209                 if(CTX_wm_window(C)==NULL)
1210                         return action;
1211         }
1212
1213         /* test for CLICK event */
1214         if (wm_action_not_handled(action) && event->val == KM_RELEASE) {
1215                 wmWindow *win = CTX_wm_window(C);
1216
1217                 if (win && win->eventstate->prevtype == event->type && win->eventstate->prevval == KM_PRESS) {
1218                         /* test for double click first */
1219                         if ((PIL_check_seconds_timer() - win->eventstate->prevclicktime) * 1000 < U.dbl_click_time) {
1220                                 event->val = KM_DBL_CLICK;
1221                                 action |= wm_handlers_do(C, event, handlers);
1222                         }
1223
1224                         if (wm_action_not_handled(action)) {
1225                                 event->val = KM_CLICK;
1226                                 action |= wm_handlers_do(C, event, handlers);
1227                         }
1228
1229
1230                         /* revert value if not handled */
1231                         if (wm_action_not_handled(action)) {
1232                                 event->val = KM_RELEASE;
1233                         }
1234                 }
1235         }
1236
1237         return action;
1238 }
1239
1240 static int wm_event_inside_i(wmEvent *event, rcti *rect)
1241 {
1242         if(wm_event_always_pass(event))
1243                 return 1;
1244         if(BLI_in_rcti(rect, event->x, event->y))
1245            return 1;
1246         if(event->type==MOUSEMOVE) {
1247                 if( BLI_in_rcti(rect, event->prevx, event->prevy)) {
1248                         return 1;
1249                 }
1250                 return 0;
1251         }
1252         return 0;
1253 }
1254
1255 static ScrArea *area_event_inside(bContext *C, int x, int y)
1256 {
1257         bScreen *screen= CTX_wm_screen(C);
1258         ScrArea *sa;
1259         
1260         if(screen)
1261                 for(sa= screen->areabase.first; sa; sa= sa->next)
1262                         if(BLI_in_rcti(&sa->totrct, x, y))
1263                                 return sa;
1264         return NULL;
1265 }
1266
1267 static ARegion *region_event_inside(bContext *C, int x, int y)
1268 {
1269         bScreen *screen= CTX_wm_screen(C);
1270         ScrArea *area= CTX_wm_area(C);
1271         ARegion *ar;
1272         
1273         if(screen && area)
1274                 for(ar= area->regionbase.first; ar; ar= ar->next)
1275                         if(BLI_in_rcti(&ar->winrct, x, y))
1276                                 return ar;
1277         return NULL;
1278 }
1279
1280 static void wm_paintcursor_tag(bContext *C, wmPaintCursor *pc, ARegion *ar)
1281 {
1282         if(ar) {
1283                 for(; pc; pc= pc->next) {
1284                         if(pc->poll(C)) {
1285                                 wmWindow *win= CTX_wm_window(C);
1286                                 win->screen->do_draw_paintcursor= 1;
1287
1288                                 if(win->drawmethod != USER_DRAW_TRIPLE)
1289                                         ED_region_tag_redraw(ar);
1290                         }
1291                 }
1292         }
1293 }
1294
1295 /* called on mousemove, check updates for paintcursors */
1296 /* context was set on active area and region */
1297 static void wm_paintcursor_test(bContext *C, wmEvent *event)
1298 {
1299         wmWindowManager *wm= CTX_wm_manager(C);
1300         
1301         if(wm->paintcursors.first) {
1302                 ARegion *ar= CTX_wm_region(C);
1303                 if(ar)
1304                         wm_paintcursor_tag(C, wm->paintcursors.first, ar);
1305                 
1306                 /* if previous position was not in current region, we have to set a temp new context */
1307                 if(ar==NULL || !BLI_in_rcti(&ar->winrct, event->prevx, event->prevy)) {
1308                         ScrArea *sa= CTX_wm_area(C);
1309                         
1310                         CTX_wm_area_set(C, area_event_inside(C, event->prevx, event->prevy));
1311                         CTX_wm_region_set(C, region_event_inside(C, event->prevx, event->prevy));
1312
1313                         wm_paintcursor_tag(C, wm->paintcursors.first, CTX_wm_region(C));
1314                         
1315                         CTX_wm_area_set(C, sa);
1316                         CTX_wm_region_set(C, ar);
1317                 }
1318         }
1319 }
1320
1321 /* called in main loop */
1322 /* goes over entire hierarchy:  events -> window -> screen -> area -> region */
1323 void wm_event_do_handlers(bContext *C)
1324 {
1325         wmWindow *win;
1326
1327         for(win= CTX_wm_manager(C)->windows.first; win; win= win->next) {
1328                 wmEvent *event;
1329                 
1330                 if( win->screen==NULL )
1331                         wm_event_free_all(win);
1332                 
1333                 while( (event= win->queue.first) ) {
1334                         int action = WM_HANDLER_CONTINUE;
1335
1336                         CTX_wm_window_set(C, win);
1337                         
1338                         /* we let modal handlers get active area/region, also wm_paintcursor_test needs it */
1339                         CTX_wm_area_set(C, area_event_inside(C, event->x, event->y));
1340                         CTX_wm_region_set(C, region_event_inside(C, event->x, event->y));
1341                         
1342                         /* MVC demands to not draw in event handlers... but we need to leave it for ogl selecting etc */
1343                         wm_window_make_drawable(C, win);
1344                         
1345                         /* first we do priority handlers, modal + some limited keymaps */
1346                         action |= wm_handlers_do(C, event, &win->modalhandlers);
1347                         
1348                         /* fileread case */
1349                         if(CTX_wm_window(C)==NULL)
1350                                 return;
1351                         
1352                         /* builtin tweak, if action is break it removes tweak */
1353                         wm_tweakevent_test(C, event, action);
1354
1355                         if((action & WM_HANDLER_BREAK) == 0) {
1356                                 ScrArea *sa;
1357                                 ARegion *ar;
1358                                 int doit= 0;
1359                                 
1360                                 /* XXX to solve, here screen handlers? */
1361                                 if(event->type==MOUSEMOVE) {
1362                                         /* state variables in screen, cursors */
1363                                         ED_screen_set_subwinactive(win, event); 
1364                                         /* for regions having custom cursors */
1365                                         wm_paintcursor_test(C, event);
1366                                 }
1367
1368                                 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
1369                                         if(wm_event_inside_i(event, &sa->totrct)) {
1370                                                 CTX_wm_area_set(C, sa);
1371
1372                                                 if((action & WM_HANDLER_BREAK) == 0) {
1373                                                         for(ar=sa->regionbase.first; ar; ar= ar->next) {
1374                                                                 if(wm_event_inside_i(event, &ar->winrct)) {
1375                                                                         CTX_wm_region_set(C, ar);
1376                                                                         action |= wm_handlers_do(C, event, &ar->handlers);
1377
1378                                                                         doit |= (BLI_in_rcti(&ar->winrct, event->x, event->y));
1379                                                                         
1380                                                                         if(action & WM_HANDLER_BREAK)
1381                                                                                 break;
1382                                                                 }
1383                                                         }
1384                                                 }
1385
1386                                                 CTX_wm_region_set(C, NULL);
1387
1388                                                 if((action & WM_HANDLER_BREAK) == 0)
1389                                                         action |= wm_handlers_do(C, event, &sa->handlers);
1390
1391                                                 CTX_wm_area_set(C, NULL);
1392
1393                                                 /* NOTE: do not escape on WM_HANDLER_BREAK, mousemove needs handled for previous area */
1394                                         }
1395                                 }
1396                                 
1397                                 if((action & WM_HANDLER_BREAK) == 0) {
1398                                         /* also some non-modal handlers need active area/region */
1399                                         CTX_wm_area_set(C, area_event_inside(C, event->x, event->y));
1400                                         CTX_wm_region_set(C, region_event_inside(C, event->x, event->y));
1401
1402                                         action |= wm_handlers_do(C, event, &win->handlers);
1403
1404                                         /* fileread case */
1405                                         if(CTX_wm_window(C)==NULL)
1406                                                 return;
1407                                 }
1408
1409                                 /* XXX hrmf, this gives reliable previous mouse coord for area change, feels bad? 
1410                                    doing it on ghost queue gives errors when mousemoves go over area borders */
1411                                 if(doit && win->screen && win->screen->subwinactive != win->screen->mainwin) {
1412                                         win->eventstate->prevx= event->x;
1413                                         win->eventstate->prevy= event->y;
1414                                 }
1415                         }
1416                         
1417                         /* store last event for this window */
1418                         /* mousemove and timer events don't overwrite last type */
1419                         if (event->type != MOUSEMOVE && !ISTIMER(event->type)) {
1420                                 if (wm_action_not_handled(action)) {
1421                                         if (win->eventstate->prevtype == event->type) {
1422                                                 /* set click time on first click (press -> release) */
1423                                                 if (win->eventstate->prevval == KM_PRESS && event->val == KM_RELEASE) {
1424                                                         win->eventstate->prevclicktime = PIL_check_seconds_timer();
1425                                                 }
1426                                         } else {
1427                                                 /* reset click time if event type not the same */
1428                                                 win->eventstate->prevclicktime = 0;
1429                                         }
1430
1431                                         win->eventstate->prevval = event->val;
1432                                         win->eventstate->prevtype = event->type;
1433                                 } else if (event->val == KM_CLICK) { /* keep click for double click later */
1434                                         win->eventstate->prevtype = event->type;
1435                                         win->eventstate->prevval = event->val;
1436                                         win->eventstate->prevclicktime = PIL_check_seconds_timer();
1437                                 } else { /* reset if not */
1438                                         win->eventstate->prevtype = -1;
1439                                         win->eventstate->prevval = 0;
1440                                         win->eventstate->prevclicktime = 0;
1441                                 }
1442                         }
1443
1444                         /* unlink and free here, blender-quit then frees all */
1445                         BLI_remlink(&win->queue, event);
1446                         wm_event_free(event);
1447                         
1448                 }
1449                 
1450                 /* only add mousemove when queue was read entirely */
1451                 if(win->addmousemove && win->eventstate) {
1452                         wmEvent event= *(win->eventstate);
1453                         event.type= MOUSEMOVE;
1454                         event.prevx= event.x;
1455                         event.prevy= event.y;
1456                         wm_event_add(win, &event);
1457                         win->addmousemove= 0;
1458                 }
1459                 
1460                 CTX_wm_window_set(C, NULL);
1461         }
1462 }
1463
1464 /* ********** filesector handling ************ */
1465
1466 void WM_event_fileselect_event(bContext *C, void *ophandle, int eventval)
1467 {
1468         /* add to all windows! */
1469         wmWindow *win;
1470         
1471         for(win= CTX_wm_manager(C)->windows.first; win; win= win->next) {
1472                 wmEvent event= *win->eventstate;
1473                 
1474                 event.type= EVT_FILESELECT;
1475                 event.val= eventval;
1476                 event.customdata= ophandle;             // only as void pointer type check
1477
1478                 wm_event_add(win, &event);
1479         }
1480 }
1481
1482 /* operator is supposed to have a filled "path" property */
1483 /* optional property: filetype (XXX enum?) */
1484
1485 /* Idea is to keep a handler alive on window queue, owning the operator.
1486    The filewindow can send event to make it execute, thus ensuring
1487    executing happens outside of lower level queues, with UI refreshed. 
1488    Should also allow multiwin solutions */
1489
1490 void WM_event_add_fileselect(bContext *C, wmOperator *op)
1491 {
1492         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "fileselect handler");
1493         wmWindow *win= CTX_wm_window(C);
1494         int full= 1;    // XXX preset?
1495         
1496         handler->type= WM_HANDLER_FILESELECT;
1497         handler->op= op;
1498         handler->op_area= CTX_wm_area(C);
1499         handler->op_region= CTX_wm_region(C);
1500         handler->filescreen= CTX_wm_screen(C);
1501         
1502         BLI_addhead(&win->modalhandlers, handler);
1503         
1504         WM_event_fileselect_event(C, op, full?EVT_FILESELECT_FULL_OPEN:EVT_FILESELECT_OPEN);
1505 }
1506
1507 /* lets not expose struct outside wm? */
1508 void WM_event_set_handler_flag(wmEventHandler *handler, int flag)
1509 {
1510         handler->flag= flag;
1511 }
1512
1513 wmEventHandler *WM_event_add_modal_handler(bContext *C, wmOperator *op)
1514 {
1515         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event modal handler");
1516         wmWindow *win= CTX_wm_window(C);
1517         
1518         /* operator was part of macro */
1519         if(op->opm) {
1520                 /* give the mother macro to the handler */
1521                 handler->op= op->opm;
1522                 /* mother macro opm becomes the macro element */
1523                 handler->op->opm= op;
1524         }
1525         else
1526                 handler->op= op;
1527         
1528         handler->op_area= CTX_wm_area(C);               /* means frozen screen context for modal handlers! */
1529         handler->op_region= CTX_wm_region(C);
1530         
1531         BLI_addhead(&win->modalhandlers, handler);
1532
1533         return handler;
1534 }
1535
1536 wmEventHandler *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
1537 {
1538         wmEventHandler *handler;
1539
1540         if(!keymap) {
1541                 printf("WM_event_add_keymap_handler called with NULL keymap\n");
1542                 return NULL;
1543         }
1544
1545         /* only allow same keymap once */
1546         for(handler= handlers->first; handler; handler= handler->next)
1547                 if(handler->keymap==keymap)
1548                         return handler;
1549         
1550         handler= MEM_callocN(sizeof(wmEventHandler), "event keymap handler");
1551         BLI_addtail(handlers, handler);
1552         handler->keymap= keymap;
1553
1554         return handler;
1555 }
1556
1557 /* priorities not implemented yet, for time being just insert in begin of list */
1558 wmEventHandler *WM_event_add_keymap_handler_priority(ListBase *handlers, wmKeyMap *keymap, int priority)
1559 {
1560         wmEventHandler *handler;
1561         
1562         WM_event_remove_keymap_handler(handlers, keymap);
1563         
1564         handler= MEM_callocN(sizeof(wmEventHandler), "event keymap handler");
1565         BLI_addhead(handlers, handler);
1566         handler->keymap= keymap;
1567         
1568         return handler;
1569 }
1570
1571 wmEventHandler *WM_event_add_keymap_handler_bb(ListBase *handlers, wmKeyMap *keymap, rcti *bblocal, rcti *bbwin)
1572 {
1573         wmEventHandler *handler= WM_event_add_keymap_handler(handlers, keymap);
1574         
1575         if(handler) {
1576                 handler->bblocal= bblocal;
1577                 handler->bbwin= bbwin;
1578         }
1579         return handler;
1580 }
1581
1582 void WM_event_remove_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
1583 {
1584         wmEventHandler *handler;
1585         
1586         for(handler= handlers->first; handler; handler= handler->next) {
1587                 if(handler->keymap==keymap) {
1588                         BLI_remlink(handlers, handler);
1589                         wm_event_free_handler(handler);
1590                         break;
1591                 }
1592         }
1593 }
1594
1595 wmEventHandler *WM_event_add_ui_handler(const bContext *C, ListBase *handlers, wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata)
1596 {
1597         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event ui handler");
1598         handler->ui_handle= func;
1599         handler->ui_remove= remove;
1600         handler->ui_userdata= userdata;
1601         handler->ui_area= (C)? CTX_wm_area(C): NULL;
1602         handler->ui_region= (C)? CTX_wm_region(C): NULL;
1603         handler->ui_menu= (C)? CTX_wm_menu(C): NULL;
1604         
1605         BLI_addhead(handlers, handler);
1606         
1607         return handler;
1608 }
1609
1610 void WM_event_remove_ui_handler(ListBase *handlers, wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata)
1611 {
1612         wmEventHandler *handler;
1613         
1614         for(handler= handlers->first; handler; handler= handler->next) {
1615                 if(handler->ui_handle == func && handler->ui_remove == remove && handler->ui_userdata == userdata) {
1616                         BLI_remlink(handlers, handler);
1617                         wm_event_free_handler(handler);
1618                         break;
1619                 }
1620         }
1621 }
1622
1623 void WM_event_add_mousemove(bContext *C)
1624 {
1625         wmWindow *window= CTX_wm_window(C);
1626         
1627         window->addmousemove= 1;
1628 }
1629
1630 /* for modal callbacks, check configuration for how to interpret exit with tweaks  */
1631 int WM_modal_tweak_exit(wmEvent *evt, int tweak_event)
1632 {
1633         /* user preset or keymap? dunno... */
1634         int tweak_modal= (U.flag & USER_DRAGIMMEDIATE)==0;
1635         
1636         switch(tweak_event) {
1637                 case EVT_TWEAK_L:
1638                 case EVT_TWEAK_M:
1639                 case EVT_TWEAK_R:
1640                         if(evt->val==tweak_modal)
1641                                 return 1;
1642                 default:
1643                         /* this case is when modal callcback didnt get started with a tweak */
1644                         if(evt->val)
1645                                 return 1;
1646         }
1647         return 0;
1648 }
1649
1650
1651 /* ********************* ghost stuff *************** */
1652
1653 static int convert_key(GHOST_TKey key) 
1654 {
1655         if (key>=GHOST_kKeyA && key<=GHOST_kKeyZ) {
1656                 return (AKEY + ((int) key - GHOST_kKeyA));
1657         } else if (key>=GHOST_kKey0 && key<=GHOST_kKey9) {
1658                 return (ZEROKEY + ((int) key - GHOST_kKey0));
1659         } else if (key>=GHOST_kKeyNumpad0 && key<=GHOST_kKeyNumpad9) {
1660                 return (PAD0 + ((int) key - GHOST_kKeyNumpad0));
1661         } else if (key>=GHOST_kKeyF1 && key<=GHOST_kKeyF12) {
1662                 return (F1KEY + ((int) key - GHOST_kKeyF1));
1663         } else {
1664                 switch (key) {
1665                         case GHOST_kKeyBackSpace:               return BACKSPACEKEY;
1666                         case GHOST_kKeyTab:                             return TABKEY;
1667                         case GHOST_kKeyLinefeed:                return LINEFEEDKEY;
1668                         case GHOST_kKeyClear:                   return 0;
1669                         case GHOST_kKeyEnter:                   return RETKEY;
1670                                 
1671                         case GHOST_kKeyEsc:                             return ESCKEY;
1672                         case GHOST_kKeySpace:                   return SPACEKEY;
1673                         case GHOST_kKeyQuote:                   return QUOTEKEY;
1674                         case GHOST_kKeyComma:                   return COMMAKEY;
1675                         case GHOST_kKeyMinus:                   return MINUSKEY;
1676                         case GHOST_kKeyPeriod:                  return PERIODKEY;
1677                         case GHOST_kKeySlash:                   return SLASHKEY;
1678                                 
1679                         case GHOST_kKeySemicolon:               return SEMICOLONKEY;
1680                         case GHOST_kKeyEqual:                   return EQUALKEY;
1681                                 
1682                         case GHOST_kKeyLeftBracket:             return LEFTBRACKETKEY;
1683                         case GHOST_kKeyRightBracket:    return RIGHTBRACKETKEY;
1684                         case GHOST_kKeyBackslash:               return BACKSLASHKEY;
1685                         case GHOST_kKeyAccentGrave:             return ACCENTGRAVEKEY;
1686                                 
1687                         case GHOST_kKeyLeftShift:               return LEFTSHIFTKEY;
1688                         case GHOST_kKeyRightShift:              return RIGHTSHIFTKEY;
1689                         case GHOST_kKeyLeftControl:             return LEFTCTRLKEY;
1690                         case GHOST_kKeyRightControl:    return RIGHTCTRLKEY;
1691                         case GHOST_kKeyCommand:                 return COMMANDKEY;
1692                         case GHOST_kKeyLeftAlt:                 return LEFTALTKEY;
1693                         case GHOST_kKeyRightAlt:                return RIGHTALTKEY;
1694                                 
1695                         case GHOST_kKeyCapsLock:                return CAPSLOCKKEY;
1696                         case GHOST_kKeyNumLock:                 return 0;
1697                         case GHOST_kKeyScrollLock:              return 0;
1698                                 
1699                         case GHOST_kKeyLeftArrow:               return LEFTARROWKEY;
1700                         case GHOST_kKeyRightArrow:              return RIGHTARROWKEY;
1701                         case GHOST_kKeyUpArrow:                 return UPARROWKEY;
1702                         case GHOST_kKeyDownArrow:               return DOWNARROWKEY;
1703                                 
1704                         case GHOST_kKeyPrintScreen:             return 0;
1705                         case GHOST_kKeyPause:                   return PAUSEKEY;
1706                                 
1707                         case GHOST_kKeyInsert:                  return INSERTKEY;
1708                         case GHOST_kKeyDelete:                  return DELKEY;
1709                         case GHOST_kKeyHome:                    return HOMEKEY;
1710                         case GHOST_kKeyEnd:                             return ENDKEY;
1711                         case GHOST_kKeyUpPage:                  return PAGEUPKEY;
1712                         case GHOST_kKeyDownPage:                return PAGEDOWNKEY;
1713                                 
1714                         case GHOST_kKeyNumpadPeriod:    return PADPERIOD;
1715                         case GHOST_kKeyNumpadEnter:             return PADENTER;
1716                         case GHOST_kKeyNumpadPlus:              return PADPLUSKEY;
1717                         case GHOST_kKeyNumpadMinus:             return PADMINUS;
1718                         case GHOST_kKeyNumpadAsterisk:  return PADASTERKEY;
1719                         case GHOST_kKeyNumpadSlash:             return PADSLASHKEY;
1720                                 
1721                         case GHOST_kKeyGrLess:              return GRLESSKEY; 
1722                                 
1723                         default:
1724                                 return UNKNOWNKEY;      /* GHOST_kKeyUnknown */
1725                 }
1726         }
1727 }
1728
1729 /* adds customdata to event */
1730 static void update_tablet_data(wmWindow *win, wmEvent *event)
1731 {
1732         const GHOST_TabletData *td= GHOST_GetTabletData(win->ghostwin);
1733         
1734         /* if there's tablet data from an active tablet device then add it */
1735         if ((td != NULL) && td->Active != GHOST_kTabletModeNone) {
1736                 struct wmTabletData *wmtab= MEM_mallocN(sizeof(wmTabletData), "customdata tablet");
1737                 
1738                 wmtab->Active = (int)td->Active;
1739                 wmtab->Pressure = td->Pressure;
1740                 wmtab->Xtilt = td->Xtilt;
1741                 wmtab->Ytilt = td->Ytilt;
1742                 
1743                 event->custom= EVT_DATA_TABLET;
1744                 event->customdata= wmtab;
1745                 event->customdatafree= 1;
1746         } 
1747 }
1748
1749
1750 /* windows store own event queues, no bContext here */
1751 void wm_event_add_ghostevent(wmWindow *win, int type, void *customdata)
1752 {
1753         wmEvent event, *evt= win->eventstate;
1754         
1755         /* initialize and copy state (only mouse x y and modifiers) */
1756         event= *evt;
1757         
1758         switch (type) {
1759                 /* mouse move */
1760                 case GHOST_kEventCursorMove: {
1761                         if(win->active) {
1762                                 GHOST_TEventCursorData *cd= customdata;
1763 #if defined(__APPLE__) && defined(GHOST_COCOA)
1764                                 //Cocoa already uses coordinates with y=0 at bottom, and returns inwindow coordinates on mouse moved event
1765                                 event.type= MOUSEMOVE;
1766                                 event.x= evt->x = cd->x;
1767                                 event.y = evt->y = cd->y;
1768 #else
1769                                 int cx, cy;
1770                                 GHOST_ScreenToClient(win->ghostwin, cd->x, cd->y, &cx, &cy);
1771                                 event.type= MOUSEMOVE;
1772                                 event.x= evt->x= cx;
1773                                 event.y= evt->y= (win->sizey-1) - cy;
1774 #endif
1775                                 update_tablet_data(win, &event);
1776                                 wm_event_add(win, &event);
1777                         }
1778                         break;
1779                 }
1780                 case GHOST_kEventTrackpad: {
1781                         if (win->active) {
1782                                 GHOST_TEventTrackpadData * pd = customdata;
1783                                 switch (pd->subtype) {
1784                                         case GHOST_kTrackpadEventMagnify:
1785                                                 event.type = MOUSEZOOM;
1786                                                 break;
1787                                         case GHOST_kTrackpadEventRotate:
1788                                                 event.type = MOUSEROTATE;
1789                                                 break;
1790                                         case GHOST_kTrackpadEventScroll:
1791                                         default:
1792                                                 event.type= MOUSEPAN;
1793                                                 break;
1794                                 }
1795 #if defined(__APPLE__) && defined(GHOST_COCOA)
1796                                 //Cocoa already uses coordinates with y=0 at bottom, and returns inwindow coordinates on mouse moved event
1797                                 event.x= evt->x = pd->x;
1798                                 event.y = evt->y = pd->y;
1799 #else
1800                                 int cx, cy;
1801                                 GHOST_ScreenToClient(win->ghostwin, pd->x, pd->y, &cx, &cy);
1802                                 event.x= evt->x= cx;
1803                                 event.y= evt->y= (win->sizey-1) - cy;
1804 #endif
1805                                 // Use prevx/prevy so we can calculate the delta later
1806                                 event.prevx= event.x - pd->deltaX;
1807                                 event.prevy= event.y - pd->deltaY;
1808                                 
1809                                 update_tablet_data(win, &event);
1810                                 wm_event_add(win, &event);
1811                         }                       
1812                         break;
1813                 }
1814                 /* mouse button */
1815                 case GHOST_kEventButtonDown:
1816                 case GHOST_kEventButtonUp: {
1817                         GHOST_TEventButtonData *bd= customdata;
1818                         event.val= (type==GHOST_kEventButtonDown) ? KM_PRESS:KM_RELEASE; /* Note!, this starts as 0/1 but later is converted to KM_PRESS/KM_RELEASE by tweak */
1819                         
1820                         if (bd->button == GHOST_kButtonMaskLeft)
1821                                 event.type= LEFTMOUSE;
1822                         else if (bd->button == GHOST_kButtonMaskRight)
1823                                 event.type= RIGHTMOUSE;
1824                         else if (bd->button == GHOST_kButtonMaskButton4)
1825                                 event.type= BUTTON4MOUSE;
1826                         else if (bd->button == GHOST_kButtonMaskButton5)
1827                                 event.type= BUTTON5MOUSE;
1828                         else
1829                                 event.type= MIDDLEMOUSE;
1830                         
1831                         update_tablet_data(win, &event);
1832                         wm_event_add(win, &event);
1833                         
1834                         break;
1835                 }
1836                 /* keyboard */
1837                 case GHOST_kEventKeyDown:
1838                 case GHOST_kEventKeyUp: {
1839                         GHOST_TEventKeyData *kd= customdata;
1840                         event.type= convert_key(kd->key);
1841                         event.ascii= kd->ascii;
1842                         event.val= (type==GHOST_kEventKeyDown)?KM_PRESS:KM_RELEASE;
1843                         
1844                         /* exclude arrow keys, esc, etc from text input */
1845                         if(type==GHOST_kEventKeyUp || (event.ascii<32 && event.ascii>0))
1846                                 event.ascii= '\0';
1847                         
1848                         /* modifiers */
1849                         if (event.type==LEFTSHIFTKEY || event.type==RIGHTSHIFTKEY) {
1850                                 event.shift= evt->shift= (event.val==KM_PRESS);
1851                                 if(event.val==KM_PRESS && (evt->ctrl || evt->alt || evt->oskey))
1852                                    event.shift= evt->shift = 3;         // define?
1853                         } 
1854                         else if (event.type==LEFTCTRLKEY || event.type==RIGHTCTRLKEY) {
1855                                 event.ctrl= evt->ctrl= (event.val==KM_PRESS);
1856                                 if(event.val==KM_PRESS && (evt->shift || evt->alt || evt->oskey))
1857                                    event.ctrl= evt->ctrl = 3;           // define?
1858                         } 
1859                         else if (event.type==LEFTALTKEY || event.type==RIGHTALTKEY) {
1860                                 event.alt= evt->alt= (event.val==KM_PRESS);
1861                                 if(event.val==KM_PRESS && (evt->ctrl || evt->shift || evt->oskey))
1862                                    event.alt= evt->alt = 3;             // define?
1863                         } 
1864                         else if (event.type==COMMANDKEY) {
1865                                 event.oskey= evt->oskey= (event.val==KM_PRESS);
1866                                 if(event.val==KM_PRESS && (evt->ctrl || evt->alt || evt->shift))
1867                                    event.oskey= evt->oskey = 3;         // define?
1868                         }
1869                         else {
1870                                 if(event.val==KM_PRESS && event.keymodifier==0)
1871                                         evt->keymodifier= event.type; /* only set in eventstate, for next event */
1872                                 else if(event.val==KM_RELEASE && event.keymodifier==event.type)
1873                                         event.keymodifier= evt->keymodifier= 0;
1874                         }
1875
1876                         /* this case happens on some systems that on holding a key pressed,
1877                            generate press events without release, we still want to keep the
1878                            modifier in win->eventstate, but for the press event of the same
1879                            key we don't want the key modifier */
1880                         if(event.keymodifier == event.type)
1881                                 event.keymodifier= 0;
1882                         
1883                         /* if test_break set, it catches this. XXX Keep global for now? */
1884                         if(event.type==ESCKEY)
1885                                 G.afbreek= 1;
1886
1887                         wm_event_add(win, &event);
1888                         
1889                         break;
1890                 }
1891                         
1892                 case GHOST_kEventWheel: {
1893                         GHOST_TEventWheelData* wheelData = customdata;
1894                         
1895                         if (wheelData->z > 0)
1896                                 event.type= WHEELUPMOUSE;
1897                         else
1898                                 event.type= WHEELDOWNMOUSE;
1899                         
1900                         event.val= KM_PRESS;
1901                         wm_event_add(win, &event);
1902                         
1903                         break;
1904                 }
1905                 case GHOST_kEventTimer: {
1906                         event.type= TIMER;
1907                         event.custom= EVT_DATA_TIMER;
1908                         event.customdata= customdata;
1909                         wm_event_add(win, &event);
1910
1911                         break;
1912                 }
1913
1914                 case GHOST_kEventUnknown:
1915                 case GHOST_kNumEventTypes:
1916                         break;
1917
1918                 case GHOST_kEventWindowDeactivate: {
1919                         event.type= WINDEACTIVATE;
1920                         wm_event_add(win, &event);
1921
1922                         break;
1923                 }
1924
1925         }
1926 }