2.5: gesture code in WM
[blender-staging.git] / source / blender / windowmanager / intern / wm_window.c
1 /**
2  * $Id: wm_window.c
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 but based 
21  * on ghostwinlay.c (C) 2001-2002 by NaN Holding BV
22  * All rights reserved.
23  *
24  * Contributor(s): Blender Foundation, 2008
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include <stdlib.h>
30 #include <stdio.h>
31
32 #include "DNA_listBase.h"       
33 #include "DNA_screen_types.h"
34 #include "DNA_windowmanager_types.h"
35
36 #include "MEM_guardedalloc.h"
37
38 #include "GHOST_C-api.h"
39
40 #include "BLI_blenlib.h"
41
42 #include "BKE_blender.h"
43 #include "BKE_global.h"
44 #include "BKE_utildefines.h"
45
46 #include "BIF_gl.h"
47
48 #include "WM_api.h"
49 #include "WM_types.h"
50 #include "wm.h"
51 #include "wm_window.h"
52 #include "wm_subwindow.h"
53 #include "wm_event_system.h"
54
55 #include "ED_screen.h"
56
57 /* the global to talk to ghost */
58 GHOST_SystemHandle g_system= NULL;
59
60 /* set by commandline */
61 static int prefsizx= 0, prefsizy= 0, prefstax= 0, prefstay= 0;
62
63
64 /* ******** win open & close ************ */
65
66
67 static void wm_get_screensize(int *width_r, int *height_r) 
68 {
69         unsigned int uiwidth;
70         unsigned int uiheight;
71         
72         GHOST_GetMainDisplayDimensions(g_system, &uiwidth, &uiheight);
73         *width_r= uiwidth;
74         *height_r= uiheight;
75 }
76
77 static void wm_ghostwindow_destroy(wmWindow *win) 
78 {
79         if(win->ghostwin) {
80                 GHOST_DisposeWindow(g_system, win->ghostwin);
81                 win->ghostwin= NULL;
82         }
83 }
84
85 /* including window itself */
86 void wm_window_free(bContext *C, wmWindow *win)
87 {
88         ED_screen_exit(C, win, win->screen);
89         
90         /* update context */
91         if(C) {
92                 if(C->wm->windrawable==win)
93                         C->wm->windrawable= NULL;
94                 if(C->wm->winactive==win)
95                         C->wm->winactive= NULL;
96                 if(C->window==win)
97                         C->window= NULL;
98                 if(C->screen==win->screen)
99                         C->screen= NULL;
100         }       
101
102         /* XXX free screens */
103         
104         if(win->eventstate) MEM_freeN(win->eventstate);
105
106         wm_event_free_all(win);
107         wm_subwindows_free(win);
108         
109         wm_ghostwindow_destroy(win);
110         
111         MEM_freeN(win);
112 }
113
114 static int find_free_winid(wmWindowManager *wm)
115 {
116         wmWindow *win;
117         int id= 0;
118         
119         for(win= wm->windows.first; win; win= win->next)
120                 if(id <= win->winid)
121                         id= win->winid+1;
122         
123         return id;
124 }
125
126 /* dont change context itself */
127 wmWindow *wm_window_new(bContext *C)
128 {
129         wmWindow *win= MEM_callocN(sizeof(wmWindow), "window");
130         
131         BLI_addtail(&C->wm->windows, win);
132         win->winid= find_free_winid(C->wm);
133
134         return win;
135 }
136
137
138 /* part of wm_window.c api */
139 wmWindow *wm_window_copy(bContext *C, wmWindow *winorig)
140 {
141         wmWindow *win= wm_window_new(C);
142         
143         win->posx= winorig->posx+10;
144         win->posy= winorig->posy;
145         win->sizex= winorig->sizex;
146         win->sizey= winorig->sizey;
147         
148         win->screen= ED_screen_duplicate(win, winorig->screen);
149         win->screen->do_refresh= 1;
150         win->screen->do_draw= 1;
151         
152         return win;
153 }
154
155 /* this is event from ghost */
156 static void wm_window_close(bContext *C, wmWindow *win)
157 {
158         BLI_remlink(&C->wm->windows, win);
159         wm_window_free(C, win);
160         
161         if(C->wm->windows.first==NULL)
162                 WM_exit(C);
163 }
164
165 /* belongs to below */
166 static void wm_window_add_ghostwindow(wmWindowManager *wm, char *title, wmWindow *win)
167 {
168         GHOST_WindowHandle ghostwin;
169         GHOST_TWindowState inital_state;
170         int scr_w, scr_h, posy;
171         
172         wm_get_screensize(&scr_w, &scr_h);
173         posy= (scr_h - win->posy - win->sizey);
174         
175         //              inital_state = GHOST_kWindowStateFullScreen;
176         //              inital_state = GHOST_kWindowStateMaximized;
177         inital_state = GHOST_kWindowStateNormal;
178         
179 #ifdef __APPLE__
180         {
181                 extern int macPrefState; /* creator.c */
182                 inital_state += macPrefState;
183         }
184 #endif
185         
186         ghostwin= GHOST_CreateWindow(g_system, title, 
187                                                                  win->posx, posy, win->sizex, win->sizey, 
188                                                                  inital_state, 
189                                                                  GHOST_kDrawingContextTypeOpenGL,
190                                                                  0 /* no stereo */);
191         
192         if (ghostwin) {
193                 
194                 win->ghostwin= ghostwin;
195                 GHOST_SetWindowUserData(ghostwin, win); /* pointer back */
196                 
197                 if(win->eventstate==NULL)
198                         win->eventstate= MEM_callocN(sizeof(wmEvent), "window event state");
199                 
200                 /* add keymap handlers (1 for all keys in map!) */
201                 WM_event_add_keymap_handler(&win->handlers, &wm->windowkeymap);
202                 WM_event_add_keymap_handler(&win->handlers, &wm->screenkeymap);
203                 
204                 /* until screens get drawn, make it nice grey */
205                 glClearColor(.55, .55, .55, 0.0);
206                 glClear(GL_COLOR_BUFFER_BIT);
207                 wm_window_swap_buffers(win);
208                 
209                 /* standard state vars for window */
210                 glEnable(GL_SCISSOR_TEST);
211         }
212 }
213
214 /* for wmWindows without ghostwin, open these and clear */
215 /* window size is read from window, if 0 it uses prefsize */
216 void wm_window_add_ghostwindows(wmWindowManager *wm)
217 {
218         wmWindow *win;
219         
220         /* no commandline prefsize? then we set this */
221         if (!prefsizx) {
222                 wm_get_screensize(&prefsizx, &prefsizy);
223                 
224 #ifdef __APPLE__
225                 {
226                         extern void wm_set_apple_prefsize(int, int);    /* wm_apple.c */
227                         
228                         wm_set_apple_prefsize(prefsizx, prefsizy);
229                 }
230 #else
231                 prefstax= 0;
232                 prefstay= 0;
233                 
234 #endif
235         }
236         
237         for(win= wm->windows.first; win; win= win->next) {
238                 if(win->ghostwin==NULL) {
239                         if(win->sizex==0) {
240                                 win->posx= prefstax;
241                                 win->posy= prefstay;
242                                 win->sizex= prefsizx;
243                                 win->sizey= prefsizy;
244                                 win->windowstate= 0;
245                         }
246                         wm_window_add_ghostwindow(wm, "Blender", win);
247                 }
248         }
249 }
250
251 /* new window, no screen yet, but we open ghostwindow for it */
252 /* also gets the window level handlers */
253 /* area-rip calls this */
254 wmWindow *WM_window_open(bContext *C, rcti *rect)
255 {
256         wmWindow *win= wm_window_new(C);
257         
258         win->posx= rect->xmin;
259         win->posy= rect->ymin;
260         win->sizex= rect->xmax - rect->xmin;
261         win->sizey= rect->ymax - rect->ymin;
262         
263         wm_window_add_ghostwindow(C->wm, "Blender", win);
264         
265         return win;
266 }
267
268
269 /* ****************** Operators ****************** */
270
271 /* operator callback */
272 int wm_window_duplicate_op(bContext *C, wmOperator *op)
273 {
274         wm_window_copy(C, C->window);
275         wm_check(C);
276         
277         return OPERATOR_FINISHED;
278 }
279
280
281 /* fullscreen operator callback */
282 int wm_window_fullscreen_toggle_op(bContext *C, wmOperator *op)
283 {
284         GHOST_TWindowState state = GHOST_GetWindowState(C->window->ghostwin);
285         if(state!=GHOST_kWindowStateFullScreen)
286                 GHOST_SetWindowState(C->window->ghostwin, GHOST_kWindowStateFullScreen);
287         else
288                 GHOST_SetWindowState(C->window->ghostwin, GHOST_kWindowStateNormal);
289
290         return OPERATOR_FINISHED;
291         
292 }
293
294         
295 /* exit blender */
296 int wm_exit_blender_op(bContext *C, wmOperator *op)
297 {
298         wmWindow *win= C->wm->windows.first;
299         while(win) {
300                 wm_window_close(C, win);
301                 win= win->next;
302         }
303
304         return OPERATOR_FINISHED;
305 }
306
307
308 /* ************ events *************** */
309
310 static int query_qual(char qual) 
311 {
312         GHOST_TModifierKeyMask left, right;
313         int val= 0;
314         
315         if (qual=='s') {
316                 left= GHOST_kModifierKeyLeftShift;
317                 right= GHOST_kModifierKeyRightShift;
318         } else if (qual=='c') {
319                 left= GHOST_kModifierKeyLeftControl;
320                 right= GHOST_kModifierKeyRightControl;
321         } else if (qual=='C') {
322                 left= right= GHOST_kModifierKeyCommand;
323         } else {
324                 left= GHOST_kModifierKeyLeftAlt;
325                 right= GHOST_kModifierKeyRightAlt;
326         }
327         
328         GHOST_GetModifierKeyState(g_system, left, &val);
329         if (!val)
330                 GHOST_GetModifierKeyState(g_system, right, &val);
331         
332         return val;
333 }
334
335 void wm_window_make_drawable(bContext *C, wmWindow *win) 
336 {
337         if (win != C->wm->windrawable && win->ghostwin) {
338 //              win->lmbut= 0;  /* keeps hanging when mousepressed while other window opened */
339                 
340                 C->wm->windrawable= win;
341                 if(G.f & G_DEBUG) printf("set drawable %d\n", win->winid);
342                 GHOST_ActivateWindowDrawingContext(win->ghostwin);
343         }
344 }
345
346 /* called by ghost, here we handle events for windows themselves or send to event system */
347 static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr private) 
348 {
349         bContext *C= private;
350         GHOST_TEventType type= GHOST_GetEventType(evt);
351         
352         if (type == GHOST_kEventQuit) {
353                 WM_exit(C);
354         } else {
355                 GHOST_WindowHandle ghostwin= GHOST_GetEventWindow(evt);
356                 GHOST_TEventDataPtr data= GHOST_GetEventData(evt);
357                 wmWindow *win;
358                 
359                 if (!ghostwin) {
360                         // XXX - should be checked, why are we getting an event here, and
361                         //      what is it?
362                         
363                         return 1;
364                 } else if (!GHOST_ValidWindow(g_system, ghostwin)) {
365                         // XXX - should be checked, why are we getting an event here, and
366                         //      what is it?
367                         
368                         return 1;
369                 } else {
370                         win= GHOST_GetWindowUserData(ghostwin);
371                 }
372                 
373                 switch(type) {
374                         case GHOST_kEventWindowDeactivate:
375                                 win->active= 0; /* XXX */
376                                 break;
377                         case GHOST_kEventWindowActivate: 
378                         {
379                                 GHOST_TEventKeyData kdata;
380                                 int cx, cy, wx, wy;
381                                 
382                                 C->wm->winactive= win; /* no context change! c->wm->windrawable is drawable, or for area queues */
383                                 
384                                 win->active= 1;
385 //                              window_handle(win, INPUTCHANGE, win->active);
386                                 
387                                 /* bad ghost support for modifier keys... so on activate we set the modifiers again */
388                                 kdata.ascii= 0;
389                                 if (win->eventstate->shift && !query_qual('s')) {
390                                         kdata.key= GHOST_kKeyLeftShift;
391                                         wm_event_add_ghostevent(win, GHOST_kEventKeyUp, &kdata);
392                                 }
393                                 if (win->eventstate->ctrl && !query_qual('c')) {
394                                         kdata.key= GHOST_kKeyLeftControl;
395                                         wm_event_add_ghostevent(win, GHOST_kEventKeyUp, &kdata);
396                                 }
397                                 if (win->eventstate->alt && !query_qual('a')) {
398                                         kdata.key= GHOST_kKeyLeftAlt;
399                                         wm_event_add_ghostevent(win, GHOST_kEventKeyUp, &kdata);
400                                 }
401                                 if (win->eventstate->oskey && !query_qual('C')) {
402                                         kdata.key= GHOST_kKeyCommand;
403                                         wm_event_add_ghostevent(win, GHOST_kEventKeyUp, &kdata);
404                                 }
405                                 
406                                 /* entering window, update mouse pos. but no event */
407                                 GHOST_GetCursorPosition(g_system, &wx, &wy);
408                                 
409                                 GHOST_ScreenToClient(win->ghostwin, wx, wy, &cx, &cy);
410                                 win->eventstate->x= cx;
411                                 win->eventstate->y= (win->sizey-1) - cy;
412                                 
413                                 ED_screen_set_subwinactive(win);        /* active subwindow in screen */
414                                 
415                                 wm_window_make_drawable(C, win);
416                                 break;
417                         }
418                         case GHOST_kEventWindowClose: {
419                                 wm_window_close(C, win);
420                                 break;
421                         }
422                         case GHOST_kEventWindowUpdate: {
423                                 if(G.f & G_DEBUG) printf("ghost redraw\n");
424                                 
425                                 wm_window_make_drawable(C, win);
426                                 WM_event_add_notifier(C->wm, win, 0, WM_NOTE_WINDOW_REDRAW, 0, NULL);
427
428                                 break;
429                         }
430                         case GHOST_kEventWindowSize:
431                         case GHOST_kEventWindowMove: {
432                                 GHOST_RectangleHandle client_rect;
433                                 int l, t, r, b, scr_w, scr_h;
434                                 
435                                 client_rect= GHOST_GetClientBounds(win->ghostwin);
436                                 GHOST_GetRectangle(client_rect, &l, &t, &r, &b);
437                                 
438                                 GHOST_DisposeRectangle(client_rect);
439                                 
440                                 wm_get_screensize(&scr_w, &scr_h);
441                                 win->sizex= r-l;
442                                 win->sizey= b-t;
443                                 win->posx= l;
444                                 win->posy= scr_h - t - win->sizey;
445
446                                 /* debug prints */
447                                 if(0) {
448                                         GHOST_TWindowState state;
449                                         state = GHOST_GetWindowState(win->ghostwin);
450
451                                         if(state==GHOST_kWindowStateNormal) {
452                                                 if(G.f & G_DEBUG) printf("window state: normal\n");
453                                         }
454                                         else if(state==GHOST_kWindowStateMinimized) {
455                                                 if(G.f & G_DEBUG) printf("window state: minimized\n");
456                                         }
457                                         else if(state==GHOST_kWindowStateMaximized) {
458                                                 if(G.f & G_DEBUG) printf("window state: maximized\n");
459                                         }
460                                         else if(state==GHOST_kWindowStateFullScreen) {
461                                                 if(G.f & G_DEBUG) printf("window state: fullscreen\n");
462                                         }
463                                         
464                                         if(type!=GHOST_kEventWindowSize) {
465                                                 if(G.f & G_DEBUG) printf("win move event pos %d %d size %d %d\n", win->posx, win->posy, win->sizex, win->sizey);
466                                         }
467                                         
468                                 }
469                                 
470                                 wm_window_make_drawable(C, win);
471                                 WM_event_add_notifier(C->wm, win, 0, WM_NOTE_SCREEN_CHANGED, 0, NULL);
472                                 
473                                 break;
474                         }
475                         default:
476                                 if(type==GHOST_kEventKeyDown) // XXX debug
477                                         WM_event_add_notifier(C->wm, win, 0, WM_NOTE_WINDOW_REDRAW, 0, NULL);
478                                 wm_event_add_ghostevent(win, type, data);
479                                 break;
480                 }
481
482         }
483         return 1;
484 }
485
486 void wm_window_process_events(int wait_for_event) 
487 {
488         GHOST_ProcessEvents(g_system, wait_for_event);
489         GHOST_DispatchEvents(g_system);
490 }
491
492 /* **************** init ********************** */
493
494 void wm_ghost_init(bContext *C)
495 {
496         if (!g_system) {
497                 GHOST_EventConsumerHandle consumer= GHOST_CreateEventConsumer(ghost_event_proc, C);
498                 
499                 g_system= GHOST_CreateSystem();
500                 GHOST_AddEventConsumer(g_system, consumer);
501         }       
502 }
503
504 /* **************** timer ********************** */
505
506 static void window_event_timer_proc(GHOST_TimerTaskHandle timer, GHOST_TUns64 time)
507 {
508         wmWindow *window;
509
510         window= GHOST_GetTimerTaskUserData(timer);
511
512         wm_event_add_ghostevent(window, GHOST_kEventTimer, (wmTimerHandle*)timer);
513 }
514
515 wmTimerHandle *WM_event_add_window_timer(wmWindow *win, int delay_ms, int interval_ms)
516 {
517         return (wmTimerHandle*)GHOST_InstallTimer(g_system, delay_ms, interval_ms,
518                 window_event_timer_proc, win);
519 }
520
521 void WM_event_remove_window_timer(wmWindow *wm, wmTimerHandle *handle)
522 {
523         GHOST_RemoveTimer(g_system, (GHOST_TimerTaskHandle)handle);
524 }
525
526 /* ************************************ */
527
528 void wm_window_set_title(wmWindow *win, char *title) 
529 {
530         GHOST_SetTitle(win->ghostwin, title);
531 }
532
533 void wm_window_get_position(wmWindow *win, int *posx_r, int *posy_r) 
534 {
535         *posx_r= win->posx;
536         *posy_r= win->posy;
537 }
538
539 void wm_window_get_size(wmWindow *win, int *width_r, int *height_r) 
540 {
541         *width_r= win->sizex;
542         *height_r= win->sizey;
543 }
544
545 void wm_window_set_size(wmWindow *win, int width, int height) 
546 {
547         GHOST_SetClientSize(win->ghostwin, width, height);
548 }
549
550 void wm_window_lower(wmWindow *win) 
551 {
552         GHOST_SetWindowOrder(win->ghostwin, GHOST_kWindowOrderBottom);
553 }
554
555 void wm_window_raise(wmWindow *win) 
556 {
557         GHOST_SetWindowOrder(win->ghostwin, GHOST_kWindowOrderTop);
558 #ifdef _WIN32
559 //      markdirty_all(); /* to avoid redraw errors in fullscreen mode (aphex) */
560 #endif
561 }
562
563 void wm_window_swap_buffers(wmWindow *win)
564 {
565         GHOST_SwapWindowBuffers(win->ghostwin);
566 }
567
568 /* ******************* exported api ***************** */
569
570
571 /* called whem no ghost system was initialized */
572 void WM_setprefsize(int stax, int stay, int sizx, int sizy)
573 {
574         prefstax= stax;
575         prefstay= stay;
576         prefsizx= sizx;
577         prefsizy= sizy;
578 }
579