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