2.5 MSVC9 projectfiles
[blender-staging.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_windowmanager_types.h"
35 #include "DNA_userdef_types.h"  /* U.flag & TWOBUTTONMOUSE */
36
37 #include "MEM_guardedalloc.h"
38
39 #include "GHOST_C-api.h"
40
41 #include "BLI_blenlib.h"
42
43 #include "BKE_blender.h"
44 #include "BKE_global.h"
45
46 #include "ED_screen.h"
47 #include "ED_space_api.h"
48
49 #include "RNA_access.h"
50
51 #include "WM_api.h"
52 #include "WM_types.h"
53 #include "wm.h"
54 #include "wm_window.h"
55 #include "wm_event_system.h"
56 #include "wm_event_types.h"
57
58 /* ************ event management ************** */
59
60 void wm_event_add(wmWindow *win, wmEvent *event_to_add)
61 {
62         wmEvent *event= MEM_callocN(sizeof(wmEvent), "event");
63         
64         *event= *event_to_add;
65         BLI_addtail(&win->queue, event);
66 }
67
68 wmEvent *wm_event_next(wmWindow *win)
69 {
70         wmEvent *event= win->queue.first;
71
72         if(event) BLI_remlink(&win->queue, event);
73         return event;
74 }
75
76 static void wm_event_free(wmEvent *event)
77 {
78         if(event->customdata && event->customdatafree)
79                 MEM_freeN(event->customdata);
80         MEM_freeN(event);
81 }
82
83 void wm_event_free_all(wmWindow *win)
84 {
85         wmEvent *event;
86         
87         while((event= win->queue.first)) {
88                 BLI_remlink(&win->queue, event);
89                 wm_event_free(event);
90         }
91 }
92
93 /* ********************* notifiers, listeners *************** */
94
95 /* XXX: in future, which notifiers to send to other windows? */
96 void WM_event_add_notifier(bContext *C, int type, int value, void *data)
97 {
98         wmNotifier *note= MEM_callocN(sizeof(wmNotifier), "notifier");
99         
100         BLI_addtail(&C->wm->queue, note);
101         
102         note->window= C->window;
103
104         /* catch global notifications here */
105         switch (type) {
106                 case WM_NOTE_WINDOW_REDRAW:
107                 case WM_NOTE_SCREEN_CHANGED:
108                         break;
109                 default:
110                         if(C->region) note->swinid= C->region->swinid;
111         }
112         
113         note->type= type;
114         note->value= value;
115         note->data= data;
116 }
117
118 static wmNotifier *wm_notifier_next(wmWindowManager *wm)
119 {
120         wmNotifier *note= wm->queue.first;
121         
122         if(note) BLI_remlink(&wm->queue, note);
123         return note;
124 }
125
126 /* called in mainloop */
127 void wm_event_do_notifiers(bContext *C)
128 {
129         wmNotifier *note;
130         
131         while( (note=wm_notifier_next(C->wm)) ) {
132                 wmWindow *win;
133                 
134                 for(win= C->wm->windows.first; win; win= win->next) {
135                         ScrArea *sa;
136                         ARegion *ar;
137
138                         C->window= win;
139                         C->screen= win->screen;
140                         
141                         if(note->window && note->window!=win)
142                                 continue;
143                         if(win->screen==NULL)
144                                 continue;
145
146                         /* printf("notifier win %d screen %s\n", win->winid, win->screen->id.name+2); */
147                         ED_screen_do_listen(win, note);
148
149                         for(ar=win->screen->regionbase.first; ar; ar= ar->next) {
150                                 if(note->swinid && note->swinid!=ar->swinid)
151                                         continue;
152
153                                 C->region= ar;
154                                 ED_region_do_listen(ar, note);
155                                 C->region= NULL;
156                         }
157                         
158                         for(sa= win->screen->areabase.first; sa; sa= sa->next) {
159                                 C->area= sa;
160
161                                 for(ar=sa->regionbase.first; ar; ar= ar->next) {
162                                         if(note->swinid && note->swinid!=ar->swinid)
163                                                 continue;
164
165                                         C->region= ar;
166                                         ED_region_do_listen(ar, note);
167                                         C->region= NULL;
168                                 }
169
170                                 C->area= NULL;
171                         }
172
173                         C->window= NULL;
174                         C->screen= NULL;
175                 }
176                 if(note->data)
177                         MEM_freeN(note->data);
178                 MEM_freeN(note);
179         }       
180 }
181
182 /* quick test to prevent changing window drawable */
183 static int wm_draw_update_test_window(wmWindow *win)
184 {
185         ScrArea *sa;
186         ARegion *ar;
187         
188         if(win->screen->do_refresh)
189                 return 1;
190         if(win->screen->do_draw)
191                 return 1;
192         if(win->screen->do_gesture)
193                 return 1;
194
195         for(ar=win->screen->regionbase.first; ar; ar= ar->next) {
196                 if(ar->swinid && ar->do_draw)
197                         return 1;
198         }
199
200         for(sa= win->screen->areabase.first; sa; sa= sa->next) {
201                 for(ar=sa->regionbase.first; ar; ar= ar->next) {
202                         if(ar->swinid && ar->do_draw)
203                                 return 1;
204                 }
205         }
206         return 0;
207 }
208
209 void wm_draw_update(bContext *C)
210 {
211         wmWindow *win;
212         
213         for(win= C->wm->windows.first; win; win= win->next) {
214                 if(wm_draw_update_test_window(win)) {
215                         ScrArea *sa;
216                         ARegion *ar;
217
218                         C->window= win;
219                         C->screen= win->screen;
220                         
221                         /* sets context window+screen */
222                         wm_window_make_drawable(C, win);
223                         
224                         /* notifiers for screen redraw */
225                         if(win->screen->do_refresh)
226                                 ED_screen_refresh(C->wm, win);
227
228                         for(sa= win->screen->areabase.first; sa; sa= sa->next) {
229                                 int area_do_draw= 0;
230                                 
231                                 C->area= sa;
232                                 
233                                 for(ar=sa->regionbase.first; ar; ar= ar->next) {
234                                         C->region= ar;
235                                         
236                                         if(ar->swinid && ar->do_draw) {
237                                                 ED_region_do_draw(C, ar);
238                                                 area_do_draw= 1;
239                                         }
240                                         
241                                         C->region= NULL;
242                                 }
243                                 /* only internal decoration, like AZone */
244                                 if(area_do_draw)
245                                         ED_area_do_draw(C, sa);
246                                 
247                                 C->area = NULL;
248                         }
249                         
250                         /* move this here so we can do area 'overlay' drawing */
251                         if(win->screen->do_draw)
252                                 ED_screen_draw(win);
253
254                         /* regions are menus here */
255                         for(ar=win->screen->regionbase.first; ar; ar= ar->next) {
256                                 C->region= ar;
257                                 
258                                 if(ar->swinid && ar->do_draw)
259                                         ED_region_do_draw(C, ar);
260
261                                 C->region= NULL;
262                         }
263                         
264                         if(win->screen->do_gesture)
265                                 wm_gesture_draw(win);
266
267                         wm_window_swap_buffers(win);
268
269                         C->window= NULL;
270                         C->screen= NULL;
271                 }
272         }
273 }
274
275 /* ********************* operators ******************* */
276
277
278 int WM_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event)
279 {
280         int retval= OPERATOR_PASS_THROUGH;
281
282         if(ot->poll==NULL || ot->poll(C)) {
283                 wmOperator *op= MEM_callocN(sizeof(wmOperator), "wmOperator");
284
285                 /* XXX adding new operator could be function, only happens here now */
286                 op->type= ot;
287                 BLI_strncpy(op->idname, ot->idname, OP_MAX_TYPENAME);
288                 
289                 op->ptr= MEM_callocN(sizeof(PointerRNA), "wmOperatorPtrRNA");
290                 RNA_pointer_create(&RNA_WindowManager, &C->wm->id, ot->srna, op, op->ptr);
291
292                 if(op->type->invoke)
293                         retval= (*op->type->invoke)(C, op, event);
294                 else if(op->type->exec)
295                         retval= op->type->exec(C, op);
296
297                 if((retval & OPERATOR_FINISHED) && (ot->flag & OPTYPE_REGISTER)) {
298                         wm_operator_register(C->wm, op);
299                 }
300                 else if(!(retval & OPERATOR_RUNNING_MODAL)) {
301                         wm_operator_free(op);
302                 }
303         }
304
305         return retval;
306 }
307
308 /* forces event to go to the region window, for header menus */
309 int WM_operator_call_rwin(bContext *C, const char *opstring)
310 {
311         wmOperatorType *ot= WM_operatortype_find(opstring);
312         
313         /* dummie test */
314         if(ot && C && C->window) {
315                 ARegion *ar= C->region;
316                 int retval;
317                 
318                 if(C->area) {
319                         ARegion *ar1= C->area->regionbase.first;
320                         for(; ar1; ar1= ar1->next)
321                                 if(ar1->regiontype==RGN_TYPE_WINDOW)
322                                         break;
323                         if(ar1)
324                                 C->region= ar1;
325                 }
326                 
327                 retval= WM_operator_invoke(C, ot, C->window->eventstate);
328                 
329                 /* set region back */
330                 C->region= ar;
331                 
332                 return retval;
333         }
334         
335         return 0;
336 }
337
338 /* invokes operator in context */
339 int WM_operator_call(bContext *C, const char *opstring)
340 {
341         wmOperatorType *ot= WM_operatortype_find(opstring);
342
343         /* dummie test */
344         if(ot && C && C->window) {
345                 return WM_operator_invoke(C, ot, C->window->eventstate);
346         }
347         
348         return 0;
349 }
350
351 /* ********************* handlers *************** */
352
353
354 /* not handler itself, is called by UI to move handlers to other queues, so don't close modal ones */
355 static void wm_event_free_handler(wmEventHandler *handler)
356 {
357         
358 }
359
360 /* called on exit or remove area, only here call cancel callback */
361 void WM_event_remove_handlers(bContext *C, ListBase *handlers)
362 {
363         wmEventHandler *handler;
364         
365         /* C is zero on freeing database, modal handlers then already were freed */
366         while((handler=handlers->first)) {
367                 BLI_remlink(handlers, handler);
368                 
369                 if(handler->op) {
370                         if(handler->op->type->cancel) {
371                                 ScrArea *area= C->area;
372                                 ARegion *region= C->region;
373                                 
374                                 C->area= handler->op_area;
375                                 C->region= handler->op_region;
376
377                                 handler->op->type->cancel(C, handler->op);
378
379                                 C->area= area;
380                                 C->region= region;
381                         }
382
383                         wm_operator_free(handler->op);
384                 }
385                 else if(handler->ui_remove) {
386                         ScrArea *area= C->area;
387                         ARegion *region= C->region;
388                         
389                         if(handler->ui_area) C->area= handler->ui_area;
390                         if(handler->ui_region) C->region= handler->ui_region;
391
392                         handler->ui_remove(C);
393
394                         C->area= area;
395                         C->region= region;
396                 }
397
398                 wm_event_free_handler(handler);
399                 MEM_freeN(handler);
400         }
401 }
402
403 static int wm_eventmatch(wmEvent *winevent, wmKeymapItem *kmi)
404 {
405         
406         if(winevent->type!=kmi->type) return 0;
407         
408         if(kmi->val!=KM_ANY)
409                 if(winevent->val!=kmi->val) return 0;
410         
411         if(winevent->shift!=kmi->shift) return 0;
412         if(winevent->ctrl!=kmi->ctrl) return 0;
413         if(winevent->alt!=kmi->alt) return 0;
414         if(winevent->oskey!=kmi->oskey) return 0;
415         if(kmi->keymodifier)
416                 if(winevent->keymodifier!=kmi->keymodifier) return 0;
417         
418         
419         return 1;
420 }
421
422 /* Warning: this function removes a modal handler, when finished */
423 static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHandler *handler, wmEvent *event)
424 {
425         int retval= OPERATOR_PASS_THROUGH;
426         
427         /* derived, modal or blocking operator */
428         if(handler->op) {
429                 wmOperator *op= handler->op;
430                 wmOperatorType *ot= op->type;
431
432                 if(ot->modal) {
433                         /* we set context to where modal handler came from */
434                         ScrArea *area= C->area;
435                         ARegion *region= C->region;
436                         
437                         C->area= handler->op_area;
438                         C->region= handler->op_region;
439                         
440                         retval= ot->modal(C, op, event);
441
442                         /* putting back screen context */
443                         C->area= area;
444                         C->region= region;
445                         
446                         if((retval & OPERATOR_FINISHED) && (ot->flag & OPTYPE_REGISTER)) {
447                                 wm_operator_register(C->wm, op);
448                                 handler->op= NULL;
449                         }
450                         else if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) {
451                                 wm_operator_free(op);
452                                 handler->op= NULL;
453                         }
454                         
455                         
456                         /* remove modal handler, operator itself should have been cancelled and freed */
457                         if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) {
458                                 BLI_remlink(handlers, handler);
459                                 wm_event_free_handler(handler);
460                                 MEM_freeN(handler);
461                                 
462                                 /* prevent silly errors from operator users */
463                                 retval &= ~OPERATOR_PASS_THROUGH;
464                         }
465                         
466                 }
467                 else
468                         printf("wm_handler_operator_call error\n");
469         }
470         else {
471                 wmOperatorType *ot= WM_operatortype_find(event->keymap_idname);
472
473                 if(ot)
474                         retval= WM_operator_invoke(C, ot, event);
475         }
476
477         if(retval & OPERATOR_PASS_THROUGH)
478                 return WM_HANDLER_CONTINUE;
479
480         return WM_HANDLER_BREAK;
481 }
482
483 static int wm_handler_ui_call(bContext *C, wmEventHandler *handler, wmEvent *event)
484 {
485         ScrArea *area= C->area;
486         ARegion *region= C->region;
487         int retval;
488                         
489         /* we set context to where ui handler came from */
490         if(handler->ui_area) C->area= handler->ui_area;
491         if(handler->ui_region) C->region= handler->ui_region;
492
493         retval= handler->ui_handle(C, event);
494
495         /* putting back screen context */
496         C->area= area;
497         C->region= region;
498
499         if(retval == WM_UI_HANDLER_BREAK)
500                 return WM_HANDLER_BREAK;
501
502         return WM_HANDLER_CONTINUE;
503 }
504
505 static int wm_event_always_pass(wmEvent *event)
506 {
507         /* some events we always pass on, to ensure proper communication */
508         return (event->type == TIMER);
509 }
510
511 static int handler_boundbox_test(wmEventHandler *handler, wmEvent *event)
512 {
513         if(handler->bbwin) {
514                 if(handler->bblocal) {
515                         rcti rect= *handler->bblocal;
516                         BLI_translate_rcti(&rect, handler->bbwin->xmin, handler->bbwin->ymin);
517                         return BLI_in_rcti(&rect, event->x, event->y);
518                 }
519                 else 
520                         return BLI_in_rcti(handler->bbwin, event->x, event->y);
521         }
522         return 1;
523 }
524
525 static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
526 {
527         wmEventHandler *handler, *nexthandler;
528         int action= WM_HANDLER_CONTINUE;
529
530         if(handlers==NULL) return action;
531         
532         /* modal handlers can get removed in this loop, we keep the loop this way */
533         for(handler= handlers->first; handler; handler= nexthandler) {
534                 nexthandler= handler->next;
535
536                 /* optional boundbox */
537                 if(handler_boundbox_test(handler, event)) {
538                 
539                         /* modal+blocking handler */
540                         if(handler->flag & WM_HANDLER_BLOCKING)
541                                 action= WM_HANDLER_BREAK;
542
543                         if(handler->keymap) {
544                                 wmKeymapItem *kmi;
545                                 
546                                 for(kmi= handler->keymap->first; kmi; kmi= kmi->next) {
547                                         if(wm_eventmatch(event, kmi)) {
548                                                 /* if(event->type!=MOUSEMOVE)
549                                                         printf("handle evt %d win %d op %s\n", event->type, C->window->winid, kmi->idname); */
550                                                 
551                                                 event->keymap_idname= kmi->idname;      /* weak, but allows interactive callback to not use rawkey */
552                                                 
553                                                 action= wm_handler_operator_call(C, handlers, handler, event);
554                                                 if(action==WM_HANDLER_BREAK)  /* not wm_event_always_pass(event) here, it denotes removed handler */
555                                                         break;
556                                         }
557                                 }
558                         }
559                         else if(handler->ui_handle) {
560                                 action= wm_handler_ui_call(C, handler, event);
561                         }
562                         else {
563                                 /* modal, swallows all */
564                                 action= wm_handler_operator_call(C, handlers, handler, event);
565                         }
566
567                         if(!wm_event_always_pass(event) && action==WM_HANDLER_BREAK)
568                                 break;
569                 }
570                 
571         }
572         return action;
573 }
574
575 static int wm_event_inside_i(wmEvent *event, rcti *rect)
576 {
577         return BLI_in_rcti(rect, event->x, event->y);
578 }
579
580 static int wm_event_prev_inside_i(wmEvent *event, rcti *rect)
581 {
582         if(BLI_in_rcti(rect, event->x, event->y))
583            return 1;
584         if(event->type==MOUSEMOVE) {
585                 if( BLI_in_rcti(rect, event->prevx, event->prevy)) {
586                         return 1;
587                 }
588                 return 0;
589         }
590         return 0;
591 }
592
593 static ScrArea *area_event_inside(bContext *C, wmEvent *event)
594 {
595         ScrArea *sa;
596         
597         if(C->screen)
598                 for(sa= C->screen->areabase.first; sa; sa= sa->next)
599                         if(BLI_in_rcti(&sa->totrct, event->x, event->y))
600                                 return sa;
601         return NULL;
602 }
603
604 static ARegion *region_event_inside(bContext *C, wmEvent *event)
605 {
606         ARegion *ar;
607         
608         if(C->screen && C->area)
609                 for(ar= C->area->regionbase.first; ar; ar= ar->next)
610                         if(BLI_in_rcti(&ar->winrct, event->x, event->y))
611                                 return ar;
612         return NULL;
613 }
614
615
616 /* called in main loop */
617 /* goes over entire hierarchy:  events -> window -> screen -> area -> region */
618 void wm_event_do_handlers(bContext *C)
619 {
620         wmWindow *win;
621
622         for(win= C->wm->windows.first; win; win= win->next) {
623                 wmEvent *event;
624                 
625                 if( win->screen==NULL )
626                         wm_event_free_all(win);
627                 
628                 while( (event=wm_event_next(win)) ) {
629                         int action;
630
631                         C->window= win;
632                         C->screen= win->screen;
633                         C->area= area_event_inside(C, event);
634                         C->region= region_event_inside(C, event);
635                         
636                         /* MVC demands to not draw in event handlers... for now we leave it */
637                         wm_window_make_drawable(C, win);
638                                 
639                         action= wm_handlers_do(C, event, &win->handlers);
640                         
641                         if(wm_event_always_pass(event) || action==WM_HANDLER_CONTINUE) {
642                                 ScrArea *sa;
643                                 ARegion *ar;
644                                 int doit= 0;
645
646                                 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
647                                         if(wm_event_always_pass(event) || wm_event_prev_inside_i(event, &sa->totrct)) {
648                                                 doit= 1;
649                                                 C->area= sa;
650                                                 action= wm_handlers_do(C, event, &sa->handlers);
651
652                                                 if(wm_event_always_pass(event) || action==WM_HANDLER_CONTINUE) {
653                                                         for(ar=sa->regionbase.first; ar; ar= ar->next) {
654                                                                 if(wm_event_always_pass(event) || wm_event_inside_i(event, &ar->winrct) || wm_event_prev_inside_i(event, &ar->winrct)) {
655                                                                         C->region= ar;
656                                                                         action= wm_handlers_do(C, event, &ar->handlers);
657                                                                         C->region= NULL;
658
659                                                                         if(!wm_event_always_pass(event)) {
660                                                                                 if(action==WM_HANDLER_BREAK)
661                                                                                         break;
662                                                                         }
663                                                                 }
664                                                         }
665                                                 }
666
667                                                 C->area= NULL;
668                                                 /* NOTE: do not escape on WM_HANDLER_BREAK, mousemove needs handled for previous area */
669                                         }
670                                 }
671                                 /* XXX hrmf, this gives reliable previous mouse coord for area change, feels bad? 
672                                    doing it on ghost queue gives errors when mousemoves go over area borders */
673                                 if(doit) {
674                                         C->window->eventstate->prevx= event->x;
675                                         C->window->eventstate->prevy= event->y;
676                                 }
677                         }
678                         wm_event_free(event);
679                         
680                         C->window= NULL;
681                         C->screen= NULL;
682                 }
683         }
684 }
685
686 /* lets not expose struct outside wm? */
687 void WM_event_set_handler_flag(wmEventHandler *handler, int flag)
688 {
689         handler->flag= flag;
690 }
691
692 wmEventHandler *WM_event_add_modal_handler(bContext *C, ListBase *handlers, wmOperator *op)
693 {
694         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event modal handler");
695         handler->op= op;
696         handler->op_area= C->area;              /* means frozen screen context for modal handlers! */
697         handler->op_region= C->region;
698         
699         BLI_addhead(handlers, handler);
700
701         return handler;
702 }
703
704 wmEventHandler *WM_event_add_keymap_handler(ListBase *handlers, ListBase *keymap)
705 {
706         wmEventHandler *handler;
707         
708         /* only allow same keymap once */
709         for(handler= handlers->first; handler; handler= handler->next)
710                 if(handler->keymap==keymap)
711                         return handler;
712
713         handler= MEM_callocN(sizeof(wmEventHandler), "event keymap handler");
714         BLI_addtail(handlers, handler);
715         handler->keymap= keymap;
716
717         return handler;
718 }
719
720 wmEventHandler *WM_event_add_keymap_handler_bb(ListBase *handlers, ListBase *keymap, rcti *bblocal, rcti *bbwin)
721 {
722         wmEventHandler *handler= WM_event_add_keymap_handler(handlers, keymap);
723         handler->bblocal= bblocal;
724         handler->bbwin= bbwin;
725         
726         return handler;
727 }
728
729 void WM_event_remove_keymap_handler(ListBase *handlers, ListBase *keymap)
730 {
731         wmEventHandler *handler;
732         
733         for(handler= handlers->first; handler; handler= handler->next) {
734                 if(handler->keymap==keymap) {
735                         BLI_remlink(handlers, handler);
736                         wm_event_free_handler(handler);
737                         MEM_freeN(handler);
738                         break;
739                 }
740         }
741 }
742
743 wmEventHandler *WM_event_add_ui_handler(bContext *C, ListBase *handlers, wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove)
744 {
745         wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event ui handler");
746         handler->ui_handle= func;
747         handler->ui_remove= remove;
748         handler->ui_area= (C)? C->area: NULL;
749         handler->ui_region= (C)? C->region: NULL;
750         
751         BLI_addhead(handlers, handler);
752         
753         return handler;
754 }
755
756 void WM_event_remove_ui_handler(ListBase *handlers)
757 {
758         wmEventHandler *handler;
759         
760         for(handler= handlers->first; handler; handler= handler->next) {
761                 if(handler->ui_handle) {
762                         BLI_remlink(handlers, handler);
763                         wm_event_free_handler(handler);
764                         MEM_freeN(handler);
765                         break;
766                 }
767         }
768 }
769
770 void WM_event_add_mousemove(bContext *C)
771 {
772         wmEvent event= *(C->window->eventstate);
773         event.type= MOUSEMOVE;
774         event.prevx= event.x;
775         event.prevy= event.y;
776         wm_event_add(C->window, &event);
777 }
778
779 /* ********************* ghost stuff *************** */
780
781 static int convert_key(GHOST_TKey key) 
782 {
783         if (key>=GHOST_kKeyA && key<=GHOST_kKeyZ) {
784                 return (AKEY + ((int) key - GHOST_kKeyA));
785         } else if (key>=GHOST_kKey0 && key<=GHOST_kKey9) {
786                 return (ZEROKEY + ((int) key - GHOST_kKey0));
787         } else if (key>=GHOST_kKeyNumpad0 && key<=GHOST_kKeyNumpad9) {
788                 return (PAD0 + ((int) key - GHOST_kKeyNumpad0));
789         } else if (key>=GHOST_kKeyF1 && key<=GHOST_kKeyF12) {
790                 return (F1KEY + ((int) key - GHOST_kKeyF1));
791         } else {
792                 switch (key) {
793                         case GHOST_kKeyBackSpace:               return BACKSPACEKEY;
794                         case GHOST_kKeyTab:                             return TABKEY;
795                         case GHOST_kKeyLinefeed:                return LINEFEEDKEY;
796                         case GHOST_kKeyClear:                   return 0;
797                         case GHOST_kKeyEnter:                   return RETKEY;
798                                 
799                         case GHOST_kKeyEsc:                             return ESCKEY;
800                         case GHOST_kKeySpace:                   return SPACEKEY;
801                         case GHOST_kKeyQuote:                   return QUOTEKEY;
802                         case GHOST_kKeyComma:                   return COMMAKEY;
803                         case GHOST_kKeyMinus:                   return MINUSKEY;
804                         case GHOST_kKeyPeriod:                  return PERIODKEY;
805                         case GHOST_kKeySlash:                   return SLASHKEY;
806                                 
807                         case GHOST_kKeySemicolon:               return SEMICOLONKEY;
808                         case GHOST_kKeyEqual:                   return EQUALKEY;
809                                 
810                         case GHOST_kKeyLeftBracket:             return LEFTBRACKETKEY;
811                         case GHOST_kKeyRightBracket:    return RIGHTBRACKETKEY;
812                         case GHOST_kKeyBackslash:               return BACKSLASHKEY;
813                         case GHOST_kKeyAccentGrave:             return ACCENTGRAVEKEY;
814                                 
815                         case GHOST_kKeyLeftShift:               return LEFTSHIFTKEY;
816                         case GHOST_kKeyRightShift:              return RIGHTSHIFTKEY;
817                         case GHOST_kKeyLeftControl:             return LEFTCTRLKEY;
818                         case GHOST_kKeyRightControl:    return RIGHTCTRLKEY;
819                         case GHOST_kKeyCommand:                 return COMMANDKEY;
820                         case GHOST_kKeyLeftAlt:                 return LEFTALTKEY;
821                         case GHOST_kKeyRightAlt:                return RIGHTALTKEY;
822                                 
823                         case GHOST_kKeyCapsLock:                return CAPSLOCKKEY;
824                         case GHOST_kKeyNumLock:                 return 0;
825                         case GHOST_kKeyScrollLock:              return 0;
826                                 
827                         case GHOST_kKeyLeftArrow:               return LEFTARROWKEY;
828                         case GHOST_kKeyRightArrow:              return RIGHTARROWKEY;
829                         case GHOST_kKeyUpArrow:                 return UPARROWKEY;
830                         case GHOST_kKeyDownArrow:               return DOWNARROWKEY;
831                                 
832                         case GHOST_kKeyPrintScreen:             return 0;
833                         case GHOST_kKeyPause:                   return PAUSEKEY;
834                                 
835                         case GHOST_kKeyInsert:                  return INSERTKEY;
836                         case GHOST_kKeyDelete:                  return DELKEY;
837                         case GHOST_kKeyHome:                    return HOMEKEY;
838                         case GHOST_kKeyEnd:                             return ENDKEY;
839                         case GHOST_kKeyUpPage:                  return PAGEUPKEY;
840                         case GHOST_kKeyDownPage:                return PAGEDOWNKEY;
841                                 
842                         case GHOST_kKeyNumpadPeriod:    return PADPERIOD;
843                         case GHOST_kKeyNumpadEnter:             return PADENTER;
844                         case GHOST_kKeyNumpadPlus:              return PADPLUSKEY;
845                         case GHOST_kKeyNumpadMinus:             return PADMINUS;
846                         case GHOST_kKeyNumpadAsterisk:  return PADASTERKEY;
847                         case GHOST_kKeyNumpadSlash:             return PADSLASHKEY;
848                                 
849                         case GHOST_kKeyGrLess:              return GRLESSKEY; 
850                                 
851                         default:
852                                 return UNKNOWNKEY;      /* GHOST_kKeyUnknown */
853                 }
854         }
855 }
856
857 /* adds customdata to event */
858 static void update_tablet_data(wmWindow *win, wmEvent *event)
859 {
860         const GHOST_TabletData *td= GHOST_GetTabletData(win->ghostwin);
861         
862         /* if there's tablet data from an active tablet device then add it */
863         if ((td != NULL) && td->Active) {
864                 struct wmTabletData *wmtab= MEM_mallocN(sizeof(wmTabletData), "customdata tablet");
865                 
866                 wmtab->Active = td->Active;
867                 wmtab->Pressure = td->Pressure;
868                 wmtab->Xtilt = td->Xtilt;
869                 wmtab->Ytilt = td->Ytilt;
870                 
871                 event->custom= EVT_DATA_TABLET;
872                 event->customdata= wmtab;
873                 event->customdatafree= 1;
874         } 
875 }
876
877
878 /* windows store own event queues, no bContext here */
879 void wm_event_add_ghostevent(wmWindow *win, int type, void *customdata)
880 {
881         wmEvent event, *evt= win->eventstate;
882         
883         /* initialize and copy state (only mouse x y and modifiers) */
884         event= *evt;
885         
886         switch (type) {
887                 /* mouse move */
888                 case GHOST_kEventCursorMove: {
889                         if(win->active) {
890                                 GHOST_TEventCursorData *cd= customdata;
891                                 int cx, cy;
892
893                                 GHOST_ScreenToClient(win->ghostwin, cd->x, cd->y, &cx, &cy);
894                                 
895                                 event.type= MOUSEMOVE;
896                                 event.x= evt->x= cx;
897                                 event.y= evt->y= (win->sizey-1) - cy;
898                                 
899                                 ED_screen_set_subwinactive(win);        /* state variables in screen */
900                                 
901                                 update_tablet_data(win, &event);
902                                 wm_event_add(win, &event);
903                         }
904                         break;
905                 }
906                 /* mouse button */
907                 case GHOST_kEventButtonDown:
908                 case GHOST_kEventButtonUp: {
909                         GHOST_TEventButtonData *bd= customdata;
910                         event.val= (type==GHOST_kEventButtonDown);
911                         
912                         if (bd->button == GHOST_kButtonMaskLeft)
913                                 event.type= LEFTMOUSE;
914                         else if (bd->button == GHOST_kButtonMaskRight)
915                                 event.type= RIGHTMOUSE;
916                         else
917                                 event.type= MIDDLEMOUSE;
918                         
919                         if(event.val)
920                                 event.keymodifier= evt->keymodifier= event.type;
921                         else
922                                 event.keymodifier= evt->keymodifier= 0;
923                         
924                         update_tablet_data(win, &event);
925                         wm_event_add(win, &event);
926                         
927                         break;
928                 }
929                 /* keyboard */
930                 case GHOST_kEventKeyDown:
931                 case GHOST_kEventKeyUp: {
932                         GHOST_TEventKeyData *kd= customdata;
933                         event.type= convert_key(kd->key);
934                         event.ascii= kd->ascii;
935                         event.val= (type==GHOST_kEventKeyDown); /* XXX eventmatch uses defines, bad code... */
936                         
937                         /* modifiers */
938                         if (event.type==LEFTSHIFTKEY || event.type==RIGHTSHIFTKEY) {
939                                 event.shift= evt->shift= event.val;
940                         } else if (event.type==LEFTCTRLKEY || event.type==RIGHTCTRLKEY) {
941                                 event.ctrl= evt->ctrl= event.val;
942                         } else if (event.type==LEFTALTKEY || event.type==RIGHTALTKEY) {
943                                 event.alt= evt->alt= event.val;
944                         } else if (event.type==COMMANDKEY) {
945                                 event.oskey= evt->oskey= event.val;
946                         }
947                         
948                         wm_event_add(win, &event);
949                         
950                         break;
951                 }
952                         
953                 case GHOST_kEventWheel: {
954                         GHOST_TEventWheelData* wheelData = customdata;
955                         
956                         if (wheelData->z > 0)
957                                 event.type= WHEELUPMOUSE;
958                         else
959                                 event.type= WHEELDOWNMOUSE;
960                         
961                         event.val= wheelData->z;        /* currently -1 or +1, see ghost for improvements here... */
962                         wm_event_add(win, &event);
963                         
964                         break;
965                 }
966                 case GHOST_kEventTimer: {
967                         event.type= TIMER;
968                         event.custom= EVT_DATA_TIMER;
969                         event.customdata= customdata;
970                         wm_event_add(win, &event);
971
972                         break;
973                 }
974
975                 case GHOST_kEventUnknown:
976                 case GHOST_kNumEventTypes:
977                         break;
978         }
979 }
980