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