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