Drag and drop 2.5 integration! Finally, slashdot regulars can use
[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         /* middlemouse emulation */
812         if(U.flag & USER_TWOBUTTONMOUSE) {
813                 if(event->type == LEFTMOUSE && event->alt) {
814                         event->type = MIDDLEMOUSE;
815                         event->alt = 0;
816                 }
817         }
818
819 #ifdef __APPLE__
820         /* rightmouse emulation */
821         if(U.flag & USER_TWOBUTTONMOUSE) {
822                 if(event->type == LEFTMOUSE && event->oskey) {
823                         event->type = RIGHTMOUSE;
824                         event->oskey = 0;
825                 }
826         }
827 #endif
828
829         /* numpad emulation */
830         if(U.flag & USER_NONUMPAD) {
831                 switch(event->type) {
832                         case ZEROKEY: event->type = PAD0; break;
833                         case ONEKEY: event->type = PAD1; break;
834                         case TWOKEY: event->type = PAD2; break;
835                         case THREEKEY: event->type = PAD3; break;
836                         case FOURKEY: event->type = PAD4; break;
837                         case FIVEKEY: event->type = PAD5; break;
838                         case SIXKEY: event->type = PAD6; break;
839                         case SEVENKEY: event->type = PAD7; break;
840                         case EIGHTKEY: event->type = PAD8; break;
841                         case NINEKEY: event->type = PAD9; break;
842                         case MINUSKEY: event->type = PADMINUS; break;
843                         case EQUALKEY: event->type = PADPLUSKEY; break;
844                         case BACKSLASHKEY: event->type = PADSLASHKEY; break;
845                 }
846         }
847 }
848
849 static int wm_eventmatch(wmEvent *winevent, wmKeyMapItem *kmi)
850 {
851         int kmitype= WM_userdef_event_map(kmi->type);
852
853         if(kmi->flag & KMI_INACTIVE) return 0;
854
855         /* the matching rules */
856         if(kmitype==KM_TEXTINPUT)
857                 if(ISTEXTINPUT(winevent->type) && winevent->ascii) return 1;
858         if(kmitype!=KM_ANY)
859                 if(winevent->type!=kmitype) return 0;
860         
861         if(kmi->val!=KM_ANY)
862                 if(winevent->val!=kmi->val) return 0;
863         
864         /* modifiers also check bits, so it allows modifier order */
865         if(kmi->shift!=KM_ANY)
866                 if(winevent->shift != kmi->shift && !(winevent->shift & kmi->shift)) return 0;
867         if(kmi->ctrl!=KM_ANY)
868                 if(winevent->ctrl != kmi->ctrl && !(winevent->ctrl & kmi->ctrl)) return 0;
869         if(kmi->alt!=KM_ANY)
870                 if(winevent->alt != kmi->alt && !(winevent->alt & kmi->alt)) return 0;
871         if(kmi->oskey!=KM_ANY)
872                 if(winevent->oskey != kmi->oskey && !(winevent->oskey & kmi->oskey)) return 0;
873         
874         if(kmi->keymodifier)
875                 if(winevent->keymodifier!=kmi->keymodifier) return 0;
876                 
877         /* key modifiers always check when event has it */
878         /* otherwise regular keypresses with keymodifier still work */
879         if(winevent->keymodifier)
880                 if(ISTEXTINPUT(winevent->type)) 
881                         if(winevent->keymodifier!=kmi->keymodifier) return 0;
882         
883         return 1;
884 }
885
886 static int wm_event_always_pass(wmEvent *event)
887 {
888         /* some events we always pass on, to ensure proper communication */
889         return ISTIMER(event->type) || (event->type == WINDEACTIVATE);
890 }
891
892 /* operator exists */
893 static void wm_event_modalkeymap(const bContext *C, wmOperator *op, wmEvent *event)
894 {
895         /* support for modal keymap in macros */
896         if (op->opm)
897                 op = op->opm;
898
899         if(op->type->modalkeymap) {
900                 wmKeyMap *keymap= WM_keymap_active(CTX_wm_manager(C), op->type->modalkeymap);
901                 wmKeyMapItem *kmi;
902
903                 for(kmi= keymap->items.first; kmi; kmi= kmi->next) {
904                         if(wm_eventmatch(event, kmi)) {
905                                         
906                                 event->type= EVT_MODAL_MAP;
907                                 event->val= kmi->propvalue;
908                         }
909                 }
910         }
911 }
912
913 /* Warning: this function removes a modal handler, when finished */
914 static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHandler *handler, wmEvent *event, PointerRNA *properties)
915 {
916         int retval= OPERATOR_PASS_THROUGH;
917         
918         /* derived, modal or blocking operator */
919         if(handler->op) {
920                 wmOperator *op= handler->op;
921                 wmOperatorType *ot= op->type;
922
923                 if(ot->modal) {
924                         /* we set context to where modal handler came from */
925                         ScrArea *area= CTX_wm_area(C);
926                         ARegion *region= CTX_wm_region(C);
927                         
928                         wm_handler_op_context(C, handler);
929                         wm_region_mouse_co(C, event);
930                         wm_event_modalkeymap(C, op, event);
931                         
932                         retval= ot->modal(C, op, event);
933
934                         /* putting back screen context, reval can pass trough after modal failures! */
935                         if((retval & OPERATOR_PASS_THROUGH) || wm_event_always_pass(event)) {
936                                 CTX_wm_area_set(C, area);
937                                 CTX_wm_region_set(C, region);
938                         }
939                         else {
940                                 /* this special cases is for areas and regions that get removed */
941                                 CTX_wm_area_set(C, NULL);
942                                 CTX_wm_region_set(C, NULL);
943                         }
944
945                         if(retval & (OPERATOR_FINISHED|OPERATOR_CANCELLED))
946                                 if(op->reports->list.first)
947                                         uiPupMenuReports(C, op->reports);
948
949                         if (retval & OPERATOR_FINISHED) {
950                                 if(G.f & G_DEBUG)
951                                         wm_operator_print(op); /* todo - this print may double up, might want to check more flags then the FINISHED */
952                         }                       
953
954                         if(retval & OPERATOR_FINISHED) {
955                                 op->customdata= NULL;
956
957                                 if(ot->flag & OPTYPE_UNDO)
958                                         ED_undo_push_op(C, op);
959                                 
960                                 if(G.f & G_DEBUG) {
961                                         char *buf = WM_operator_pystring(C, op->type, op->ptr, 1);
962                                         BKE_report(CTX_wm_reports(C), RPT_OPERATOR, buf);
963                                         MEM_freeN(buf);
964                                 }
965                                 
966                                 if((ot->flag & OPTYPE_REGISTER))
967                                         wm_operator_register(C, op);
968                                 else
969                                         WM_operator_free(op);
970                                 handler->op= NULL;
971                         }
972                         else if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) {
973                                 WM_operator_free(op);
974                                 handler->op= NULL;
975                         }
976                         
977                         /* remove modal handler, operator itself should have been cancelled and freed */
978                         if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) {
979                                 WM_cursor_ungrab(CTX_wm_window(C));
980
981                                 BLI_remlink(handlers, handler);
982                                 wm_event_free_handler(handler);
983                                 
984                                 /* prevent silly errors from operator users */
985                                 //retval &= ~OPERATOR_PASS_THROUGH;
986                         }
987                         
988                 }
989                 else
990                         printf("wm_handler_operator_call error\n");
991         }
992         else {
993                 wmOperatorType *ot= WM_operatortype_find(event->keymap_idname, 0);
994
995                 if(ot)
996                         retval= wm_operator_invoke(C, ot, event, properties, NULL);
997         }
998
999         /* Finished and pass through flag as handled */
1000         if(retval == (OPERATOR_FINISHED|OPERATOR_PASS_THROUGH))
1001                 return WM_HANDLER_HANDLED;
1002
1003         /* Modal unhandled, break */
1004         if(retval == (OPERATOR_PASS_THROUGH|OPERATOR_RUNNING_MODAL))
1005                 return (WM_HANDLER_BREAK|WM_HANDLER_MODAL);
1006
1007         if(retval & OPERATOR_PASS_THROUGH)
1008                 return WM_HANDLER_CONTINUE;
1009
1010         return WM_HANDLER_BREAK;
1011 }
1012
1013 static int wm_handler_ui_call(bContext *C, wmEventHandler *handler, wmEvent *event)
1014 {
1015         ScrArea *area= CTX_wm_area(C);
1016         ARegion *region= CTX_wm_region(C);
1017         ARegion *menu= CTX_wm_menu(C);
1018         int retval, always_pass;
1019                         
1020         /* we set context to where ui handler came from */
1021         if(handler->ui_area) CTX_wm_area_set(C, handler->ui_area);
1022         if(handler->ui_region) CTX_wm_region_set(C, handler->ui_region);
1023         if(handler->ui_menu) CTX_wm_menu_set(C, handler->ui_menu);
1024
1025         /* in advance to avoid access to freed event on window close */
1026         always_pass= wm_event_always_pass(event);
1027
1028         retval= handler->ui_handle(C, event, handler->ui_userdata);
1029
1030         /* putting back screen context */
1031         if((retval != WM_UI_HANDLER_BREAK) || always_pass) {
1032                 CTX_wm_area_set(C, area);
1033                 CTX_wm_region_set(C, region);
1034                 CTX_wm_menu_set(C, menu);
1035         }
1036         else {
1037                 /* this special cases is for areas and regions that get removed */
1038                 CTX_wm_area_set(C, NULL);
1039                 CTX_wm_region_set(C, NULL);
1040                 CTX_wm_menu_set(C, NULL);
1041         }
1042
1043         if(retval == WM_UI_HANDLER_BREAK)
1044                 return WM_HANDLER_BREAK;
1045
1046         return WM_HANDLER_CONTINUE;
1047 }
1048
1049 /* fileselect handlers are only in the window queue, so it's save to switch screens or area types */
1050 static int wm_handler_fileselect_call(bContext *C, ListBase *handlers, wmEventHandler *handler, wmEvent *event)
1051 {
1052         SpaceFile *sfile;
1053         int action= WM_HANDLER_CONTINUE;
1054         
1055         if(event->type != EVT_FILESELECT)
1056                 return action;
1057         if(handler->op != (wmOperator *)event->customdata)
1058                 return action;
1059         
1060         switch(event->val) {
1061                 case EVT_FILESELECT_OPEN: 
1062                 case EVT_FILESELECT_FULL_OPEN: 
1063                         {       
1064                                 ScrArea *sa;
1065                                 
1066                                 /* sa can be null when window A is active, but mouse is over window B */
1067                                 /* in this case, open file select in original window A */
1068                                 if (handler->op_area == NULL) {
1069                                         bScreen *screen = CTX_wm_screen(C);
1070                                         sa = (ScrArea *)screen->areabase.first;
1071                                 } else
1072                                         sa = handler->op_area;
1073                                         
1074                                 if(event->val==EVT_FILESELECT_OPEN)
1075                                         ED_area_newspace(C, sa, SPACE_FILE);
1076                                 else
1077                                         ED_screen_full_newspace(C, sa, SPACE_FILE);     /* sets context */
1078                                 
1079                                 /* settings for filebrowser, sfile is not operator owner but sends events */
1080                                 sa = CTX_wm_area(C);
1081                                 sfile= (SpaceFile*)sa->spacedata.first;
1082                                 sfile->op= handler->op;
1083
1084                                 ED_fileselect_set_params(sfile);
1085                                 
1086                                 action= WM_HANDLER_BREAK;
1087                         }
1088                         break;
1089                         
1090                 case EVT_FILESELECT_EXEC:
1091                 case EVT_FILESELECT_CANCEL:
1092                         {
1093                                 /* XXX validate area and region? */
1094                                 bScreen *screen= CTX_wm_screen(C);
1095                                 char *path= RNA_string_get_alloc(handler->op->ptr, "path", NULL, 0);
1096                                 
1097                                 if(screen != handler->filescreen)
1098                                         ED_screen_full_prevspace(C, CTX_wm_area(C));
1099                                 else
1100                                         ED_area_prevspace(C, CTX_wm_area(C));
1101                                 
1102                                 /* remlink now, for load file case */
1103                                 BLI_remlink(handlers, handler);
1104                                 
1105                                 wm_handler_op_context(C, handler);
1106
1107                                 /* needed for uiPupMenuReports */
1108
1109                                 if(event->val==EVT_FILESELECT_EXEC) {
1110                                         /* a bit weak, might become arg for WM_event_fileselect? */
1111                                         /* XXX also extension code in image-save doesnt work for this yet */
1112                                         if(strncmp(handler->op->type->name, "Save", 4)==0) {
1113                                                 /* this gives ownership to pupmenu */
1114                                                 uiPupMenuSaveOver(C, handler->op, (path)? path: "");
1115                                         }
1116                                         else {
1117                                                 int retval= handler->op->type->exec(C, handler->op);
1118                                                 
1119                                                 if (retval & OPERATOR_FINISHED)
1120                                                         if(G.f & G_DEBUG)
1121                                                                 wm_operator_print(handler->op);
1122                                                 
1123                                                 if(handler->op->reports->list.first) {
1124
1125                                                         /* FIXME, temp setting window, this is really bad!
1126                                                          * only have because lib linking errors need to be seen by users :(
1127                                                          * it can be removed without breaking anything but then no linking errors - campbell */
1128                                                         wmWindow *win_prev= CTX_wm_window(C);
1129                                                         if(win_prev==NULL)
1130                                                                 CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first);
1131
1132                                                         handler->op->reports->printlevel = RPT_WARNING;
1133                                                         uiPupMenuReports(C, handler->op->reports);
1134
1135                                                         CTX_wm_window_set(C, win_prev);
1136                                                 }
1137
1138                                                 WM_operator_free(handler->op);
1139                                         }
1140                                 }
1141                                 else {
1142                                         if(handler->op->type->cancel)
1143                                                 handler->op->type->cancel(C, handler->op);
1144
1145                                         WM_operator_free(handler->op);
1146                                 }
1147
1148                                 CTX_wm_area_set(C, NULL);
1149                                 
1150                                 wm_event_free_handler(handler);
1151                                 if(path)
1152                                         MEM_freeN(path);
1153                                 
1154                                 action= WM_HANDLER_BREAK;
1155                         }
1156                         break;
1157         }
1158         
1159         return action;
1160 }
1161
1162 static int handler_boundbox_test(wmEventHandler *handler, wmEvent *event)
1163 {
1164         if(handler->bbwin) {
1165                 if(handler->bblocal) {
1166                         rcti rect= *handler->bblocal;
1167                         BLI_translate_rcti(&rect, handler->bbwin->xmin, handler->bbwin->ymin);
1168
1169                         if(BLI_in_rcti(&rect, event->x, event->y))
1170                                 return 1;
1171                         else if(event->type==MOUSEMOVE && BLI_in_rcti(&rect, event->prevx, event->prevy))
1172                                 return 1;
1173                         else
1174                                 return 0;
1175                 }
1176                 else {
1177                         if(BLI_in_rcti(handler->bbwin, event->x, event->y))
1178                                 return 1;
1179                         else if(event->type==MOUSEMOVE && BLI_in_rcti(handler->bbwin, event->prevx, event->prevy))
1180                                 return 1;
1181                         else
1182                                 return 0;
1183                 }
1184         }
1185         return 1;
1186 }
1187
1188 static int wm_action_not_handled(int action)
1189 {
1190         return action == WM_HANDLER_CONTINUE || action == (WM_HANDLER_BREAK|WM_HANDLER_MODAL);
1191 }
1192
1193 static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
1194 {
1195         wmWindowManager *wm= CTX_wm_manager(C);
1196         wmEventHandler *handler, *nexthandler;
1197         int action= WM_HANDLER_CONTINUE;
1198         int always_pass;
1199
1200         if(handlers==NULL) return action;
1201
1202         /* modal handlers can get removed in this loop, we keep the loop this way */
1203         for(handler= handlers->first; handler; handler= nexthandler) {
1204                 nexthandler= handler->next;
1205
1206                 /* optional boundbox */
1207                 if(handler_boundbox_test(handler, event)) {
1208                         /* in advance to avoid access to freed event on window close */
1209                         always_pass= wm_event_always_pass(event);
1210                 
1211                         /* modal+blocking handler */
1212                         if(handler->flag & WM_HANDLER_BLOCKING)
1213                                 action |= WM_HANDLER_BREAK;
1214
1215                         if(handler->keymap) {
1216                                 wmKeyMap *keymap= WM_keymap_active(wm, handler->keymap);
1217                                 wmKeyMapItem *kmi;
1218                                 
1219                                 if(!keymap->poll || keymap->poll(C)) {
1220                                         for(kmi= keymap->items.first; kmi; kmi= kmi->next) {
1221                                                 if(wm_eventmatch(event, kmi)) {
1222                                                         
1223                                                         event->keymap_idname= kmi->idname;      /* weak, but allows interactive callback to not use rawkey */
1224                                                         
1225                                                         action |= wm_handler_operator_call(C, handlers, handler, event, kmi->ptr);
1226                                                         if(action & WM_HANDLER_BREAK)  /* not always_pass here, it denotes removed handler */
1227                                                                 break;
1228                                                 }
1229                                         }
1230                                 }
1231                         }
1232                         else if(handler->ui_handle) {
1233                                 action |= wm_handler_ui_call(C, handler, event);
1234                         }
1235                         else if(handler->type==WM_HANDLER_FILESELECT) {
1236                                 /* screen context changes here */
1237                                 action |= wm_handler_fileselect_call(C, handlers, handler, event);
1238                         }
1239                         else if(handler->dropboxes) {
1240                                 if(event->type==EVT_DROP) {
1241                                         wmDropBox *drop= handler->dropboxes->first;
1242                                         for(; drop; drop= drop->next) {
1243                                                 /* other drop custom types allowed */
1244                                                 if(event->custom==EVT_DATA_LISTBASE) {
1245                                                         ListBase *lb= (ListBase *)event->customdata;
1246                                                         wmDrag *drag;
1247                                                         for(drag= lb->first; drag; drag= drag->next) {
1248                                                                 if(drop->poll(C, drag, event)) {
1249                                                                         drop->copy(drag, drop);
1250                                                                         
1251                                                                         wm_operator_invoke(C, drop->ot, event, drop->ptr, NULL);
1252                                                                         action |= WM_HANDLER_BREAK;
1253                                                                 }
1254                                                         }
1255                                                 }
1256                                         }
1257                                 }
1258                         }
1259                         else {
1260                                 /* modal, swallows all */
1261                                 action |= wm_handler_operator_call(C, handlers, handler, event, NULL);
1262                         }
1263
1264                         if(action & WM_HANDLER_BREAK) {
1265                                 if(always_pass)
1266                                         action &= ~WM_HANDLER_BREAK;
1267                                 else
1268                                         break;
1269                         }
1270                 }
1271                 
1272                 /* fileread case */
1273                 if(CTX_wm_window(C)==NULL)
1274                         return action;
1275         }
1276
1277         /* test for CLICK event */
1278         if (wm_action_not_handled(action) && event->val == KM_RELEASE) {
1279                 wmWindow *win = CTX_wm_window(C);
1280
1281                 if (win && win->eventstate->prevtype == event->type && win->eventstate->prevval == KM_PRESS) {
1282                         /* test for double click first */
1283                         if ((PIL_check_seconds_timer() - win->eventstate->prevclicktime) * 1000 < U.dbl_click_time) {
1284                                 event->val = KM_DBL_CLICK;
1285                                 action |= wm_handlers_do(C, event, handlers);
1286                         }
1287
1288                         if (wm_action_not_handled(action)) {
1289                                 event->val = KM_CLICK;
1290                                 action |= wm_handlers_do(C, event, handlers);
1291                         }
1292
1293
1294                         /* revert value if not handled */
1295                         if (wm_action_not_handled(action)) {
1296                                 event->val = KM_RELEASE;
1297                         }
1298                 }
1299         }
1300
1301         return action;
1302 }
1303
1304 static int wm_event_inside_i(wmEvent *event, rcti *rect)
1305 {
1306         if(wm_event_always_pass(event))
1307                 return 1;
1308         if(BLI_in_rcti(rect, event->x, event->y))
1309            return 1;
1310         if(event->type==MOUSEMOVE) {
1311                 if( BLI_in_rcti(rect, event->prevx, event->prevy)) {
1312                         return 1;
1313                 }
1314                 return 0;
1315         }
1316         return 0;
1317 }
1318
1319 static ScrArea *area_event_inside(bContext *C, int x, int y)
1320 {
1321         bScreen *screen= CTX_wm_screen(C);
1322         ScrArea *sa;
1323         
1324         if(screen)
1325                 for(sa= screen->areabase.first; sa; sa= sa->next)
1326                         if(BLI_in_rcti(&sa->totrct, x, y))
1327                                 return sa;
1328         return NULL;
1329 }
1330
1331 static ARegion *region_event_inside(bContext *C, int x, int y)
1332 {
1333         bScreen *screen= CTX_wm_screen(C);
1334         ScrArea *area= CTX_wm_area(C);
1335         ARegion *ar;
1336         
1337         if(screen && area)
1338                 for(ar= area->regionbase.first; ar; ar= ar->next)
1339                         if(BLI_in_rcti(&ar->winrct, x, y))
1340                                 return ar;
1341         return NULL;
1342 }
1343
1344 static void wm_paintcursor_tag(bContext *C, wmPaintCursor *pc, ARegion *ar)
1345 {
1346         if(ar) {
1347                 for(; pc; pc= pc->next) {
1348                         if(pc->poll(C)) {
1349                                 wmWindow *win= CTX_wm_window(C);
1350                                 win->screen->do_draw_paintcursor= 1;
1351
1352                                 if(win->drawmethod != USER_DRAW_TRIPLE)
1353                                         ED_region_tag_redraw(ar);
1354                         }
1355                 }
1356         }
1357 }
1358
1359 /* called on mousemove, check updates for paintcursors */
1360 /* context was set on active area and region */
1361 static void wm_paintcursor_test(bContext *C, wmEvent *event)
1362 {
1363         wmWindowManager *wm= CTX_wm_manager(C);
1364         
1365         if(wm->paintcursors.first) {
1366                 ARegion *ar= CTX_wm_region(C);
1367                 if(ar)
1368                         wm_paintcursor_tag(C, wm->paintcursors.first, ar);
1369                 
1370                 /* if previous position was not in current region, we have to set a temp new context */
1371                 if(ar==NULL || !BLI_in_rcti(&ar->winrct, event->prevx, event->prevy)) {
1372                         ScrArea *sa= CTX_wm_area(C);
1373                         
1374                         CTX_wm_area_set(C, area_event_inside(C, event->prevx, event->prevy));
1375                         CTX_wm_region_set(C, region_event_inside(C, event->prevx, event->prevy));
1376
1377                         wm_paintcursor_tag(C, wm->paintcursors.first, CTX_wm_region(C));
1378                         
1379                         CTX_wm_area_set(C, sa);
1380                         CTX_wm_region_set(C, ar);
1381                 }
1382         }
1383 }
1384
1385 static void wm_event_drag_test(wmWindowManager *wm, wmWindow *win, wmEvent *event)
1386 {
1387         if(wm->drags.first==NULL) return;
1388         
1389         if(event->type==MOUSEMOVE)
1390                 win->screen->do_draw_drag= 1;
1391         else if(event->type==ESCKEY) {
1392                 BLI_freelistN(&wm->drags);
1393                 win->screen->do_draw_drag= 1;
1394         }
1395         else if(event->type==LEFTMOUSE && event->val==KM_RELEASE) {
1396                 event->type= EVT_DROP;
1397                 
1398                 /* create customdata, first free existing */
1399                 if(event->customdata) {
1400                         if(event->customdatafree)
1401                                 MEM_freeN(event->customdata);
1402                 }
1403                 
1404                 event->custom= EVT_DATA_LISTBASE;
1405                 event->customdata= &wm->drags;
1406                 event->customdatafree= 1;
1407                 
1408                 /* clear drop icon */
1409                 win->screen->do_draw_drag= 1;
1410                 
1411                 /* restore cursor (disabled, see wm_dragdrop.c) */
1412                 // WM_cursor_restore(win);
1413         }
1414         
1415         /* overlap fails otherwise */
1416         if(win->screen->do_draw_drag)
1417                 if(win->drawmethod == USER_DRAW_OVERLAP)
1418                         win->screen->do_draw= 1;
1419         
1420 }
1421
1422 /* called in main loop */
1423 /* goes over entire hierarchy:  events -> window -> screen -> area -> region */
1424 void wm_event_do_handlers(bContext *C)
1425 {
1426         wmWindowManager *wm= CTX_wm_manager(C);
1427         wmWindow *win;
1428
1429         for(win= wm->windows.first; win; win= win->next) {
1430                 wmEvent *event;
1431                 
1432                 if( win->screen==NULL )
1433                         wm_event_free_all(win);
1434                 
1435                 while( (event= win->queue.first) ) {
1436                         int action = WM_HANDLER_CONTINUE;
1437
1438                         wm_eventemulation(event);
1439
1440                         CTX_wm_window_set(C, win);
1441                         
1442                         /* we let modal handlers get active area/region, also wm_paintcursor_test needs it */
1443                         CTX_wm_area_set(C, area_event_inside(C, event->x, event->y));
1444                         CTX_wm_region_set(C, region_event_inside(C, event->x, event->y));
1445                         
1446                         /* MVC demands to not draw in event handlers... but we need to leave it for ogl selecting etc */
1447                         wm_window_make_drawable(C, win);
1448                         
1449                         /* first we do priority handlers, modal + some limited keymaps */
1450                         action |= wm_handlers_do(C, event, &win->modalhandlers);
1451                         
1452                         /* fileread case */
1453                         if(CTX_wm_window(C)==NULL)
1454                                 return;
1455                         
1456                         /* check dragging, creates new event or frees, adds draw tag */
1457                         wm_event_drag_test(wm, win, event);
1458                         
1459                         /* builtin tweak, if action is break it removes tweak */
1460                         wm_tweakevent_test(C, event, action);
1461
1462                         if((action & WM_HANDLER_BREAK) == 0) {
1463                                 ScrArea *sa;
1464                                 ARegion *ar;
1465                                 int doit= 0;
1466                                 
1467                                 /* XXX to solve, here screen handlers? */
1468                                 if(event->type==MOUSEMOVE) {
1469                                         /* state variables in screen, cursors */
1470                                         ED_screen_set_subwinactive(win, event); 
1471                                         /* for regions having custom cursors */
1472                                         wm_paintcursor_test(C, event);
1473                                 }
1474
1475                                 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
1476                                         if(wm_event_inside_i(event, &sa->totrct)) {
1477                                                 CTX_wm_area_set(C, sa);
1478
1479                                                 if((action & WM_HANDLER_BREAK) == 0) {
1480                                                         for(ar=sa->regionbase.first; ar; ar= ar->next) {
1481                                                                 if(wm_event_inside_i(event, &ar->winrct)) {
1482                                                                         CTX_wm_region_set(C, ar);
1483                                                                         
1484                                                                         /* does polls for drop regions and checks uibuts */
1485                                                                         /* need to be here to make sure region context is true */
1486                                                                         if(event->type==MOUSEMOVE) {
1487                                                                                 wm_region_mouse_co(C, event);
1488                                                                                 wm_drags_check_ops(C, event);
1489                                                                         }
1490                                                                         
1491                                                                         action |= wm_handlers_do(C, event, &ar->handlers);
1492                                                                         
1493                                                                         doit |= (BLI_in_rcti(&ar->winrct, event->x, event->y));
1494                                                                         
1495                                                                         if(action & WM_HANDLER_BREAK)
1496                                                                                 break;
1497                                                                 }
1498                                                         }
1499                                                 }
1500
1501                                                 CTX_wm_region_set(C, NULL);
1502
1503                                                 if((action & WM_HANDLER_BREAK) == 0)
1504                                                         action |= wm_handlers_do(C, event, &sa->handlers);
1505
1506                                                 CTX_wm_area_set(C, NULL);
1507
1508                                                 /* NOTE: do not escape on WM_HANDLER_BREAK, mousemove needs handled for previous area */
1509                                         }
1510                                 }
1511                                 
1512                                 if((action & WM_HANDLER_BREAK) == 0) {
1513                                         /* also some non-modal handlers need active area/region */
1514                                         CTX_wm_area_set(C, area_event_inside(C, event->x, event->y));
1515                                         CTX_wm_region_set(C, region_event_inside(C, event->x, event->y));
1516
1517                                         action |= wm_handlers_do(C, event, &win->handlers);
1518
1519                                         /* fileread case */
1520                                         if(CTX_wm_window(C)==NULL)
1521                                                 return;
1522                                 }
1523
1524                                 /* XXX hrmf, this gives reliable previous mouse coord for area change, feels bad? 
1525                                    doing it on ghost queue gives errors when mousemoves go over area borders */
1526                                 if(doit && win->screen && win->screen->subwinactive != win->screen->mainwin) {
1527                                         win->eventstate->prevx= event->x;
1528                                         win->eventstate->prevy= event->y;
1529                                 }
1530                         }
1531                         
1532                         /* store last event for this window */
1533                         /* mousemove and timer events don't overwrite last type */
1534                         if (event->type != MOUSEMOVE && !ISTIMER(event->type)) {
1535                                 if (wm_action_not_handled(action)) {
1536                                         if (win->eventstate->prevtype == event->type) {
1537                                                 /* set click time on first click (press -> release) */
1538                                                 if (win->eventstate->prevval == KM_PRESS && event->val == KM_RELEASE) {
1539                                                         win->eventstate->prevclicktime = PIL_check_seconds_timer();
1540                                                 }
1541                                         } else {
1542                                                 /* reset click time if event type not the same */
1543                                                 win->eventstate->prevclicktime = 0;
1544                                         }
1545
1546                                         win->eventstate->prevval = event->val;
1547                                         win->eventstate->prevtype = event->type;
1548                                 } else if (event->val == KM_CLICK) { /* keep click for double click later */
1549                                         win->eventstate->prevtype = event->type;
1550                                         win->eventstate->prevval = event->val;
1551                                         win->eventstate->prevclicktime = PIL_check_seconds_timer();
1552                                 } else { /* reset if not */
1553                                         win->eventstate->prevtype = -1;
1554                                         win->eventstate->prevval = 0;
1555                                         win->eventstate->prevclicktime = 0;
1556                                 }
1557                         }
1558
1559                         /* unlink and free here, blender-quit then frees all */
1560                         BLI_remlink(&win->queue, event);
1561                         wm_event_free(event);
1562                         
1563                 }
1564                 
1565                 /* only add mousemove when queue was read entirely */
1566                 if(win->addmousemove && win->eventstate) {
1567                         wmEvent event= *(win->eventstate);
1568                         event.type= MOUSEMOVE;
1569                         event.prevx= event.x;
1570                         event.prevy= event.y;
1571                         wm_event_add(win, &event);
1572                         win->addmousemove= 0;
1573                 }
1574                 
1575                 CTX_wm_window_set(C, NULL);
1576         }
1577 }
1578
1579 /* ********** filesector handling ************ */
1580
1581 void WM_event_fileselect_event(bContext *C, void *ophandle, int eventval)
1582 {
1583         /* add to all windows! */
1584         wmWindow *win;
1585         
1586         for(win= CTX_wm_manager(C)->windows.first; win; win= win->next) {
1587                 wmEvent event= *win->eventstate;
1588                 
1589                 event.type= EVT_FILESELECT;
1590                 event.val= eventval;
1591                 event.customdata= ophandle;             // only as void pointer type check
1592
1593                 wm_event_add(win, &event);
1594         }
1595 }
1596
1597 /* operator is supposed to have a filled "path" property */
1598 /* optional property: filetype (XXX enum?) */
1599
1600 /* Idea is to keep a handler alive on window queue, owning the operator.
1601    The filewindow can send event to make it execute, thus ensuring
1602    executing happens outside of lower level queues, with UI refreshed. 
1603    Should also allow multiwin solutions */
1604
1605 void WM_event_add_fileselect(bContext *C, wmOperator *op)
1606 {
1607         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "fileselect handler");
1608         wmWindow *win= CTX_wm_window(C);
1609         int full= 1;    // XXX preset?
1610         
1611         handler->type= WM_HANDLER_FILESELECT;
1612         handler->op= op;
1613         handler->op_area= CTX_wm_area(C);
1614         handler->op_region= CTX_wm_region(C);
1615         handler->filescreen= CTX_wm_screen(C);
1616         
1617         BLI_addhead(&win->modalhandlers, handler);
1618         
1619         WM_event_fileselect_event(C, op, full?EVT_FILESELECT_FULL_OPEN:EVT_FILESELECT_OPEN);
1620 }
1621
1622 /* lets not expose struct outside wm? */
1623 void WM_event_set_handler_flag(wmEventHandler *handler, int flag)
1624 {
1625         handler->flag= flag;
1626 }
1627
1628 wmEventHandler *WM_event_add_modal_handler(bContext *C, wmOperator *op)
1629 {
1630         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event modal handler");
1631         wmWindow *win= CTX_wm_window(C);
1632         
1633         /* operator was part of macro */
1634         if(op->opm) {
1635                 /* give the mother macro to the handler */
1636                 handler->op= op->opm;
1637                 /* mother macro opm becomes the macro element */
1638                 handler->op->opm= op;
1639         }
1640         else
1641                 handler->op= op;
1642         
1643         handler->op_area= CTX_wm_area(C);               /* means frozen screen context for modal handlers! */
1644         handler->op_region= CTX_wm_region(C);
1645         
1646         BLI_addhead(&win->modalhandlers, handler);
1647
1648         return handler;
1649 }
1650
1651 wmEventHandler *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
1652 {
1653         wmEventHandler *handler;
1654
1655         if(!keymap) {
1656                 printf("WM_event_add_keymap_handler called with NULL keymap\n");
1657                 return NULL;
1658         }
1659
1660         /* only allow same keymap once */
1661         for(handler= handlers->first; handler; handler= handler->next)
1662                 if(handler->keymap==keymap)
1663                         return handler;
1664         
1665         handler= MEM_callocN(sizeof(wmEventHandler), "event keymap handler");
1666         BLI_addtail(handlers, handler);
1667         handler->keymap= keymap;
1668
1669         return handler;
1670 }
1671
1672 /* priorities not implemented yet, for time being just insert in begin of list */
1673 wmEventHandler *WM_event_add_keymap_handler_priority(ListBase *handlers, wmKeyMap *keymap, int priority)
1674 {
1675         wmEventHandler *handler;
1676         
1677         WM_event_remove_keymap_handler(handlers, keymap);
1678         
1679         handler= MEM_callocN(sizeof(wmEventHandler), "event keymap handler");
1680         BLI_addhead(handlers, handler);
1681         handler->keymap= keymap;
1682         
1683         return handler;
1684 }
1685
1686 wmEventHandler *WM_event_add_keymap_handler_bb(ListBase *handlers, wmKeyMap *keymap, rcti *bblocal, rcti *bbwin)
1687 {
1688         wmEventHandler *handler= WM_event_add_keymap_handler(handlers, keymap);
1689         
1690         if(handler) {
1691                 handler->bblocal= bblocal;
1692                 handler->bbwin= bbwin;
1693         }
1694         return handler;
1695 }
1696
1697 void WM_event_remove_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
1698 {
1699         wmEventHandler *handler;
1700         
1701         for(handler= handlers->first; handler; handler= handler->next) {
1702                 if(handler->keymap==keymap) {
1703                         BLI_remlink(handlers, handler);
1704                         wm_event_free_handler(handler);
1705                         break;
1706                 }
1707         }
1708 }
1709
1710 wmEventHandler *WM_event_add_ui_handler(const bContext *C, ListBase *handlers, wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata)
1711 {
1712         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event ui handler");
1713         handler->ui_handle= func;
1714         handler->ui_remove= remove;
1715         handler->ui_userdata= userdata;
1716         handler->ui_area= (C)? CTX_wm_area(C): NULL;
1717         handler->ui_region= (C)? CTX_wm_region(C): NULL;
1718         handler->ui_menu= (C)? CTX_wm_menu(C): NULL;
1719         
1720         BLI_addhead(handlers, handler);
1721         
1722         return handler;
1723 }
1724
1725 void WM_event_remove_ui_handler(ListBase *handlers, wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata)
1726 {
1727         wmEventHandler *handler;
1728         
1729         for(handler= handlers->first; handler; handler= handler->next) {
1730                 if(handler->ui_handle == func && handler->ui_remove == remove && handler->ui_userdata == userdata) {
1731                         BLI_remlink(handlers, handler);
1732                         wm_event_free_handler(handler);
1733                         break;
1734                 }
1735         }
1736 }
1737
1738 wmEventHandler *WM_event_add_dropbox_handler(ListBase *handlers, ListBase *dropboxes)
1739 {
1740         wmEventHandler *handler;
1741
1742         /* only allow same dropbox once */
1743         for(handler= handlers->first; handler; handler= handler->next)
1744                 if(handler->dropboxes==dropboxes)
1745                         return handler;
1746         
1747         handler= MEM_callocN(sizeof(wmEventHandler), "dropbox handler");
1748         
1749         /* dropbox stored static, no free or copy */
1750         handler->dropboxes= dropboxes;
1751         BLI_addhead(handlers, handler);
1752         
1753         return handler;
1754 }
1755
1756 /* XXX solution works, still better check the real cause (ton) */
1757 void WM_event_remove_area_handler(ListBase *handlers, void *area)
1758 {
1759         wmEventHandler *handler, *nexthandler;
1760
1761         for(handler = handlers->first; handler; handler= nexthandler) {
1762                 nexthandler = handler->next;
1763                 if (handler->type != WM_HANDLER_FILESELECT) {
1764                         if (handler->ui_area == area) {
1765                                 BLI_remlink(handlers, handler);
1766                                 wm_event_free_handler(handler);
1767                         }
1768                 }
1769         }
1770 }
1771
1772 void WM_event_remove_handler(ListBase *handlers, wmEventHandler *handler)
1773 {
1774         BLI_remlink(handlers, handler);
1775         wm_event_free_handler(handler);
1776 }
1777
1778 void WM_event_add_mousemove(bContext *C)
1779 {
1780         wmWindow *window= CTX_wm_window(C);
1781         
1782         window->addmousemove= 1;
1783 }
1784
1785 /* for modal callbacks, check configuration for how to interpret exit with tweaks  */
1786 int WM_modal_tweak_exit(wmEvent *evt, int tweak_event)
1787 {
1788         /* user preset or keymap? dunno... */
1789         int tweak_modal= (U.flag & USER_DRAGIMMEDIATE)==0;
1790         
1791         switch(tweak_event) {
1792                 case EVT_TWEAK_L:
1793                 case EVT_TWEAK_M:
1794                 case EVT_TWEAK_R:
1795                         if(evt->val==tweak_modal)
1796                                 return 1;
1797                 default:
1798                         /* this case is when modal callcback didnt get started with a tweak */
1799                         if(evt->val)
1800                                 return 1;
1801         }
1802         return 0;
1803 }
1804
1805 /* ********************* ghost stuff *************** */
1806
1807 static int convert_key(GHOST_TKey key) 
1808 {
1809         if (key>=GHOST_kKeyA && key<=GHOST_kKeyZ) {
1810                 return (AKEY + ((int) key - GHOST_kKeyA));
1811         } else if (key>=GHOST_kKey0 && key<=GHOST_kKey9) {
1812                 return (ZEROKEY + ((int) key - GHOST_kKey0));
1813         } else if (key>=GHOST_kKeyNumpad0 && key<=GHOST_kKeyNumpad9) {
1814                 return (PAD0 + ((int) key - GHOST_kKeyNumpad0));
1815         } else if (key>=GHOST_kKeyF1 && key<=GHOST_kKeyF12) {
1816                 return (F1KEY + ((int) key - GHOST_kKeyF1));
1817         } else {
1818                 switch (key) {
1819                         case GHOST_kKeyBackSpace:               return BACKSPACEKEY;
1820                         case GHOST_kKeyTab:                             return TABKEY;
1821                         case GHOST_kKeyLinefeed:                return LINEFEEDKEY;
1822                         case GHOST_kKeyClear:                   return 0;
1823                         case GHOST_kKeyEnter:                   return RETKEY;
1824                                 
1825                         case GHOST_kKeyEsc:                             return ESCKEY;
1826                         case GHOST_kKeySpace:                   return SPACEKEY;
1827                         case GHOST_kKeyQuote:                   return QUOTEKEY;
1828                         case GHOST_kKeyComma:                   return COMMAKEY;
1829                         case GHOST_kKeyMinus:                   return MINUSKEY;
1830                         case GHOST_kKeyPeriod:                  return PERIODKEY;
1831                         case GHOST_kKeySlash:                   return SLASHKEY;
1832                                 
1833                         case GHOST_kKeySemicolon:               return SEMICOLONKEY;
1834                         case GHOST_kKeyEqual:                   return EQUALKEY;
1835                                 
1836                         case GHOST_kKeyLeftBracket:             return LEFTBRACKETKEY;
1837                         case GHOST_kKeyRightBracket:    return RIGHTBRACKETKEY;
1838                         case GHOST_kKeyBackslash:               return BACKSLASHKEY;
1839                         case GHOST_kKeyAccentGrave:             return ACCENTGRAVEKEY;
1840                                 
1841                         case GHOST_kKeyLeftShift:               return LEFTSHIFTKEY;
1842                         case GHOST_kKeyRightShift:              return RIGHTSHIFTKEY;
1843                         case GHOST_kKeyLeftControl:             return LEFTCTRLKEY;
1844                         case GHOST_kKeyRightControl:    return RIGHTCTRLKEY;
1845                         case GHOST_kKeyCommand:                 return COMMANDKEY;
1846                         case GHOST_kKeyLeftAlt:                 return LEFTALTKEY;
1847                         case GHOST_kKeyRightAlt:                return RIGHTALTKEY;
1848                                 
1849                         case GHOST_kKeyCapsLock:                return CAPSLOCKKEY;
1850                         case GHOST_kKeyNumLock:                 return 0;
1851                         case GHOST_kKeyScrollLock:              return 0;
1852                                 
1853                         case GHOST_kKeyLeftArrow:               return LEFTARROWKEY;
1854                         case GHOST_kKeyRightArrow:              return RIGHTARROWKEY;
1855                         case GHOST_kKeyUpArrow:                 return UPARROWKEY;
1856                         case GHOST_kKeyDownArrow:               return DOWNARROWKEY;
1857                                 
1858                         case GHOST_kKeyPrintScreen:             return 0;
1859                         case GHOST_kKeyPause:                   return PAUSEKEY;
1860                                 
1861                         case GHOST_kKeyInsert:                  return INSERTKEY;
1862                         case GHOST_kKeyDelete:                  return DELKEY;
1863                         case GHOST_kKeyHome:                    return HOMEKEY;
1864                         case GHOST_kKeyEnd:                             return ENDKEY;
1865                         case GHOST_kKeyUpPage:                  return PAGEUPKEY;
1866                         case GHOST_kKeyDownPage:                return PAGEDOWNKEY;
1867                                 
1868                         case GHOST_kKeyNumpadPeriod:    return PADPERIOD;
1869                         case GHOST_kKeyNumpadEnter:             return PADENTER;
1870                         case GHOST_kKeyNumpadPlus:              return PADPLUSKEY;
1871                         case GHOST_kKeyNumpadMinus:             return PADMINUS;
1872                         case GHOST_kKeyNumpadAsterisk:  return PADASTERKEY;
1873                         case GHOST_kKeyNumpadSlash:             return PADSLASHKEY;
1874                                 
1875                         case GHOST_kKeyGrLess:              return GRLESSKEY; 
1876                                 
1877                         default:
1878                                 return UNKNOWNKEY;      /* GHOST_kKeyUnknown */
1879                 }
1880         }
1881 }
1882
1883 /* adds customdata to event */
1884 static void update_tablet_data(wmWindow *win, wmEvent *event)
1885 {
1886         const GHOST_TabletData *td= GHOST_GetTabletData(win->ghostwin);
1887         
1888         /* if there's tablet data from an active tablet device then add it */
1889         if ((td != NULL) && td->Active != GHOST_kTabletModeNone) {
1890                 struct wmTabletData *wmtab= MEM_mallocN(sizeof(wmTabletData), "customdata tablet");
1891                 
1892                 wmtab->Active = (int)td->Active;
1893                 wmtab->Pressure = td->Pressure;
1894                 wmtab->Xtilt = td->Xtilt;
1895                 wmtab->Ytilt = td->Ytilt;
1896                 
1897                 event->custom= EVT_DATA_TABLET;
1898                 event->customdata= wmtab;
1899                 event->customdatafree= 1;
1900         } 
1901 }
1902
1903 /* imperfect but probably usable... draw/enable drags to other windows */
1904 static wmWindow *wm_event_cursor_other_windows(wmWindowManager *wm, wmWindow *win, wmEvent *evt)
1905 {
1906         short mx= evt->x, my= evt->y;
1907         
1908         if(wm->windows.first== wm->windows.last)
1909                 return NULL;
1910         
1911         /* top window bar... */
1912         if(mx<0 || my<0 || mx>win->sizex || my>win->sizey+30) { 
1913                 wmWindow *owin;
1914                 
1915                 /* to desktop space */
1916                 mx+= win->posx;
1917                 my+= win->posy;
1918                 
1919                 /* check other windows to see if it has mouse inside */
1920                 for(owin= wm->windows.first; owin; owin= owin->next) {
1921                         if(owin!=win) {
1922                                 if(mx-owin->posx >= 0 && my-owin->posy >= 0 &&
1923                                    mx-owin->posx <= owin->sizex && my-owin->posy <= owin->sizey) {
1924                                         evt->x= mx-owin->posx;
1925                                         evt->y= my-owin->posy;
1926                                         
1927                                         return owin;
1928                                 }
1929                         }
1930                 }
1931         }
1932         return NULL;
1933 }
1934
1935 /* windows store own event queues, no bContext here */
1936 /* time is in 1000s of seconds, from ghost */
1937 void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int time, void *customdata)
1938 {
1939         wmWindow *owin;
1940         wmEvent event, *evt= win->eventstate;
1941         
1942         /* initialize and copy state (only mouse x y and modifiers) */
1943         event= *evt;
1944         
1945         switch (type) {
1946                 /* mouse move */
1947                 case GHOST_kEventCursorMove: {
1948                         if(win->active) {
1949                                 GHOST_TEventCursorData *cd= customdata;
1950                                 
1951 #if defined(__APPLE__) && defined(GHOST_COCOA)
1952                                 //Cocoa already uses coordinates with y=0 at bottom, and returns inwindow coordinates on mouse moved event
1953                                 evt->x= cd->x;
1954                                 evt->y= cd->y;
1955 #else
1956                                 int cx, cy;
1957                                 
1958                                 GHOST_ScreenToClient(win->ghostwin, cd->x, cd->y, &cx, &cy);
1959                                 evt->x= cx;
1960                                 evt->y= (win->sizey-1) - cy;
1961 #endif
1962                                 
1963                                 event.x= evt->x;
1964                                 event.y= evt->y;
1965
1966                                 event.type= MOUSEMOVE;
1967
1968                                 update_tablet_data(win, &event);
1969                                 wm_event_add(win, &event);
1970                                 
1971                                 /* also add to other window if event is there, this makes overdraws disappear nicely */
1972                                 /* it remaps mousecoord to other window in event */
1973                                 owin= wm_event_cursor_other_windows(wm, win, &event);
1974                                 if(owin) {
1975                                         wmEvent oevent= *(owin->eventstate);
1976                                         
1977                                         oevent.x= event.x;
1978                                         oevent.y= event.y;
1979                                         oevent.type= MOUSEMOVE;
1980                                         
1981                                         *(owin->eventstate)= oevent;
1982                                         update_tablet_data(owin, &oevent);
1983                                         wm_event_add(owin, &oevent);
1984                                 }
1985                                 
1986                         }
1987                         break;
1988                 }
1989                 case GHOST_kEventTrackpad: {
1990                         if (win->active) {
1991                                 GHOST_TEventTrackpadData * pd = customdata;
1992                                 switch (pd->subtype) {
1993                                         case GHOST_kTrackpadEventMagnify:
1994                                                 event.type = MOUSEZOOM;
1995                                                 break;
1996                                         case GHOST_kTrackpadEventRotate:
1997                                                 event.type = MOUSEROTATE;
1998                                                 break;
1999                                         case GHOST_kTrackpadEventScroll:
2000                                         default:
2001                                                 event.type= MOUSEPAN;
2002                                                 break;
2003                                 }
2004 #if defined(__APPLE__) && defined(GHOST_COCOA)
2005                                 //Cocoa already uses coordinates with y=0 at bottom, and returns inwindow coordinates on mouse moved event
2006                                 event.x= evt->x = pd->x;
2007                                 event.y = evt->y = pd->y;
2008 #else
2009                 {
2010                                 int cx, cy;
2011                                 GHOST_ScreenToClient(win->ghostwin, pd->x, pd->y, &cx, &cy);
2012                                 event.x= evt->x= cx;
2013                                 event.y= evt->y= (win->sizey-1) - cy;
2014                 }
2015 #endif
2016                                 // Use prevx/prevy so we can calculate the delta later
2017                                 event.prevx= event.x - pd->deltaX;
2018                                 event.prevy= event.y - pd->deltaY;
2019                                 
2020                                 update_tablet_data(win, &event);
2021                                 wm_event_add(win, &event);
2022                         }                       
2023                         break;
2024                 }
2025                 /* mouse button */
2026                 case GHOST_kEventButtonDown:
2027                 case GHOST_kEventButtonUp: {
2028                         GHOST_TEventButtonData *bd= customdata;
2029                         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 */
2030                         
2031                         if (bd->button == GHOST_kButtonMaskLeft)
2032                                 event.type= LEFTMOUSE;
2033                         else if (bd->button == GHOST_kButtonMaskRight)
2034                                 event.type= RIGHTMOUSE;
2035                         else if (bd->button == GHOST_kButtonMaskButton4)
2036                                 event.type= BUTTON4MOUSE;
2037                         else if (bd->button == GHOST_kButtonMaskButton5)
2038                                 event.type= BUTTON5MOUSE;
2039                         else
2040                                 event.type= MIDDLEMOUSE;
2041                         
2042                         /* add to other window if event is there (not to both!) */
2043                         owin= wm_event_cursor_other_windows(wm, win, &event);
2044                         if(owin) {
2045                                 wmEvent oevent= *(owin->eventstate);
2046                                 
2047                                 oevent.x= event.x;
2048                                 oevent.y= event.y;
2049                                 oevent.type= event.type;
2050                                 oevent.val= event.val;
2051                                 
2052                                 update_tablet_data(owin, &oevent);
2053                                 wm_event_add(owin, &oevent);
2054                         }
2055                         else {
2056                                 update_tablet_data(win, &event);
2057                                 wm_event_add(win, &event);
2058                         }
2059                         
2060                         break;
2061                 }
2062                 /* keyboard */
2063                 case GHOST_kEventKeyDown:
2064                 case GHOST_kEventKeyUp: {
2065                         GHOST_TEventKeyData *kd= customdata;
2066                         event.type= convert_key(kd->key);
2067                         event.ascii= kd->ascii;
2068                         event.val= (type==GHOST_kEventKeyDown)?KM_PRESS:KM_RELEASE;
2069                         
2070                         /* exclude arrow keys, esc, etc from text input */
2071                         if(type==GHOST_kEventKeyUp || (event.ascii<32 && event.ascii>0))
2072                                 event.ascii= '\0';
2073                         
2074                         /* modifiers */
2075                         if (event.type==LEFTSHIFTKEY || event.type==RIGHTSHIFTKEY) {
2076                                 event.shift= evt->shift= (event.val==KM_PRESS);
2077                                 if(event.val==KM_PRESS && (evt->ctrl || evt->alt || evt->oskey))
2078                                    event.shift= evt->shift = 3;         // define?
2079                         } 
2080                         else if (event.type==LEFTCTRLKEY || event.type==RIGHTCTRLKEY) {
2081                                 event.ctrl= evt->ctrl= (event.val==KM_PRESS);
2082                                 if(event.val==KM_PRESS && (evt->shift || evt->alt || evt->oskey))
2083                                    event.ctrl= evt->ctrl = 3;           // define?
2084                         } 
2085                         else if (event.type==LEFTALTKEY || event.type==RIGHTALTKEY) {
2086                                 event.alt= evt->alt= (event.val==KM_PRESS);
2087                                 if(event.val==KM_PRESS && (evt->ctrl || evt->shift || evt->oskey))
2088                                    event.alt= evt->alt = 3;             // define?
2089                         } 
2090                         else if (event.type==COMMANDKEY) {
2091                                 event.oskey= evt->oskey= (event.val==KM_PRESS);
2092                                 if(event.val==KM_PRESS && (evt->ctrl || evt->alt || evt->shift))
2093                                    event.oskey= evt->oskey = 3;         // define?
2094                         }
2095                         else {
2096                                 if(event.val==KM_PRESS && event.keymodifier==0)
2097                                         evt->keymodifier= event.type; /* only set in eventstate, for next event */
2098                                 else if(event.val==KM_RELEASE && event.keymodifier==event.type)
2099                                         event.keymodifier= evt->keymodifier= 0;
2100                         }
2101
2102                         /* this case happens on some systems that on holding a key pressed,
2103                            generate press events without release, we still want to keep the
2104                            modifier in win->eventstate, but for the press event of the same
2105                            key we don't want the key modifier */
2106                         if(event.keymodifier == event.type)
2107                                 event.keymodifier= 0;
2108                         
2109                         /* if test_break set, it catches this. XXX Keep global for now? */
2110                         if(event.type==ESCKEY)
2111                                 G.afbreek= 1;
2112                         
2113                         wm_event_add(win, &event);
2114                         
2115                         break;
2116                 }
2117                         
2118                 case GHOST_kEventWheel: {
2119                         GHOST_TEventWheelData* wheelData = customdata;
2120                         
2121                         if (wheelData->z > 0)
2122                                 event.type= WHEELUPMOUSE;
2123                         else
2124                                 event.type= WHEELDOWNMOUSE;
2125                         
2126                         event.val= KM_PRESS;
2127                         wm_event_add(win, &event);
2128                         
2129                         break;
2130                 }
2131                 case GHOST_kEventTimer: {
2132                         event.type= TIMER;
2133                         event.custom= EVT_DATA_TIMER;
2134                         event.customdata= customdata;
2135                         wm_event_add(win, &event);
2136
2137                         break;
2138                 }
2139
2140                 case GHOST_kEventUnknown:
2141                 case GHOST_kNumEventTypes:
2142                         break;
2143
2144                 case GHOST_kEventWindowDeactivate: {
2145                         event.type= WINDEACTIVATE;
2146                         wm_event_add(win, &event);
2147
2148                         break;
2149                         
2150                 }
2151
2152         }
2153 }