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