* add fullscreen toggle operator (for testing fullscreen states in win32). hotkey...
[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
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.h"
50 #include "wm_window.h"
51 #include "wm_event_system.h"
52
53 /* the global to talk to ghost */
54 GHOST_SystemHandle g_system= NULL;
55
56 /* set by commandline */
57 static int prefsizx= 0, prefsizy= 0, prefstax= 0, prefstay= 0;
58
59
60 /* ******** win open & close ************ */
61
62
63 static void wm_get_screensize(int *width_r, int *height_r) 
64 {
65         unsigned int uiwidth;
66         unsigned int uiheight;
67         
68         GHOST_GetMainDisplayDimensions(g_system, &uiwidth, &uiheight);
69         *width_r= uiwidth;
70         *height_r= uiheight;
71 }
72
73 static void wm_ghostwindow_destroy(wmWindow *win) 
74 {
75         
76         if (win->timer) {
77                 GHOST_RemoveTimer(g_system, (GHOST_TimerTaskHandle)win->timer);
78                 win->timer= NULL;
79         }
80         
81         if(win->ghostwin) {
82                 GHOST_DisposeWindow(g_system, win->ghostwin);
83                 win->ghostwin= NULL;
84         }
85 }
86
87 /* including window itself */
88 void wm_window_free(bContext *C, wmWindow *win)
89 {
90         
91         /* update context */
92         if(C) {
93                 if(C->wm->windrawable==win)
94                         C->wm->windrawable= NULL;
95                 if(C->wm->winactive==win)
96                         C->wm->winactive= NULL;
97                 if(C->window==win)
98                         C->window= NULL;
99                 if(C->screen==win->screen)
100                         C->screen= NULL;
101         }       
102         /* XXX free screens */
103         
104         if(win->eventstate) MEM_freeN(win->eventstate);
105         
106         BLI_freelistN(&win->queue);
107         wm_event_free_handlers(&win->handlers);
108         
109         wm_event_free_all(win);
110         wm_ghostwindow_destroy(win);
111         
112         MEM_freeN(win);
113 }
114
115 static int find_free_winid(wmWindowManager *wm)
116 {
117         wmWindow *win;
118         int id= 0;
119         
120         for(win= wm->windows.first; win; win= win->next)
121                 if(id <= win->winid)
122                         id= win->winid+1;
123         
124         return id;
125 }
126
127 /* dont change context itself */
128 wmWindow *wm_window_new(bContext *C, bScreen *screen)
129 {
130         wmWindow *win= MEM_callocN(sizeof(wmWindow), "window");
131         
132         BLI_addtail(&C->wm->windows, win);
133         win->winid= find_free_winid(C->wm);
134
135         win->screen= screen;
136         return win;
137 }
138
139 /* part of wm_window.c api */
140 wmWindow *wm_window_copy(bContext *C, wmWindow *winorig)
141 {
142         wmWindow *win= wm_window_new(C, winorig->screen); /* XXX need copy */
143         
144         win->posx= winorig->posx+10;
145         win->posy= winorig->posy;
146         win->sizex= winorig->sizex;
147         win->sizey= winorig->sizey;
148         
149         return win;
150 }
151
152 /* operator callback */
153 int wm_window_duplicate_op(bContext *C, wmOperator *op)
154 {
155         
156         wm_window_copy(C, C->window);
157         wm_check(C);
158         
159         return 1;
160 }
161
162 /* fullscreen operator callback */
163 int wm_window_fullscreen_toggle_op(bContext *C, wmOperator *op)
164 {
165         GHOST_TWindowState state = GHOST_GetWindowState(C->window->ghostwin);
166         if(state!=GHOST_kWindowStateFullScreen)
167                 GHOST_SetWindowState(C->window->ghostwin, GHOST_kWindowStateFullScreen);
168         else
169                 GHOST_SetWindowState(C->window->ghostwin, GHOST_kWindowStateNormal);
170
171         return 1;
172         
173 }
174
175 /* this is event from ghost */
176 static void wm_window_close(bContext *C, wmWindow *win)
177 {
178         BLI_remlink(&C->wm->windows, win);
179         wm_window_free(C, win);
180         
181         if(C->wm->windows.first==NULL)
182                 WM_exit(C);
183 }
184
185 static void wm_window_open(wmWindowManager *wm, char *title, wmWindow *win)
186 {
187         GHOST_WindowHandle ghostwin;
188         GHOST_TWindowState inital_state;
189         int scr_w, scr_h, posy;
190         
191         wm_get_screensize(&scr_w, &scr_h);
192         posy= (scr_h - win->posy - win->sizey);
193         
194 //              inital_state = GHOST_kWindowStateFullScreen;
195 //              inital_state = GHOST_kWindowStateMaximized;
196                 inital_state = GHOST_kWindowStateNormal;
197
198 #ifdef __APPLE__
199         {
200                 extern int macPrefState; /* creator.c */
201                 inital_state += macPrefState;
202         }
203 #endif
204         
205         ghostwin= GHOST_CreateWindow(g_system, title, 
206                                                                  win->posx, posy, win->sizex, win->sizey, 
207                                                                  inital_state, 
208                                                                  GHOST_kDrawingContextTypeOpenGL,
209                                                                  0 /* no stereo */);
210         
211         if (ghostwin) {
212
213                 win->ghostwin= ghostwin;
214                 GHOST_SetWindowUserData(ghostwin, win); /* pointer back */
215                 
216                 if(win->eventstate==NULL)
217                         win->eventstate= MEM_callocN(sizeof(wmEvent), "window event state");
218                 
219                 /* add keymap handler (1 for all keys in map!) */
220                 WM_event_add_keymap_handler(&wm->windowkeymap, &win->handlers);
221                 
222                 /* until screens get drawn, make it nice grey */
223                 glClearColor(.55, .55, .55, 0.0);
224                 glClear(GL_COLOR_BUFFER_BIT);
225                 wm_window_swap_buffers(win);
226         }
227         
228         
229 }
230
231 /* for wmWindows without ghostwin, open these and clear */
232 void wm_window_add_ghostwindows(wmWindowManager *wm)
233 {
234         wmWindow *win;
235         
236         /* no commandline prefsize? then we set this */
237         if (!prefsizx) {
238                 wm_get_screensize(&prefsizx, &prefsizy);
239                 
240 #ifdef __APPLE__
241                 extern void wm_set_apple_prefsize(int, int);    /* wm_apple.c */
242                 
243                 wm_set_apple_prefsize(prefsizx, prefsizy);
244 #else
245                 prefstax= 0;
246                 prefstay= 0;
247                 
248 #endif
249         }
250         
251         for(win= wm->windows.first; win; win= win->next) {
252                 if(win->ghostwin==NULL) {
253                         if(win->sizex==0) {
254                                 win->posx= prefstax;
255                                 win->posy= prefstay;
256                                 win->sizex= prefsizx;
257                                 win->sizey= prefsizy;
258                                 win->windowstate= 0;
259                         }
260                         wm_window_open(wm, "Blender", win);
261                 }
262         }
263 }
264
265 /* ************ events *************** */
266
267 static int query_qual(char qual) 
268 {
269         GHOST_TModifierKeyMask left, right;
270         int val= 0;
271         
272         if (qual=='s') {
273                 left= GHOST_kModifierKeyLeftShift;
274                 right= GHOST_kModifierKeyRightShift;
275         } else if (qual=='c') {
276                 left= GHOST_kModifierKeyLeftControl;
277                 right= GHOST_kModifierKeyRightControl;
278         } else if (qual=='C') {
279                 left= right= GHOST_kModifierKeyCommand;
280         } else {
281                 left= GHOST_kModifierKeyLeftAlt;
282                 right= GHOST_kModifierKeyRightAlt;
283         }
284         
285         GHOST_GetModifierKeyState(g_system, left, &val);
286         if (!val)
287                 GHOST_GetModifierKeyState(g_system, right, &val);
288         
289         return val;
290 }
291
292 void wm_window_make_drawable(bContext *C, wmWindow *win) 
293 {
294         if (win != C->window && win->ghostwin) {
295 //              win->lmbut= 0;  /* keeps hanging when mousepressed while other window opened */
296                 
297                 C->wm->windrawable= win;
298                 C->window= win;
299                 C->screen= win->screen;
300                 
301                 GHOST_ActivateWindowDrawingContext(win->ghostwin);
302         }
303 }
304
305 /* called by ghost, here we handle events for windows themselves or send to event system */
306 int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr private) 
307 {
308         bContext *C= private;
309         GHOST_TEventType type= GHOST_GetEventType(evt);
310         
311         if (type == GHOST_kEventQuit) {
312                 WM_exit(C);
313         } else {
314                 GHOST_WindowHandle ghostwin= GHOST_GetEventWindow(evt);
315                 GHOST_TEventDataPtr data= GHOST_GetEventData(evt);
316                 wmWindow *win;
317                 
318                 if (!ghostwin) {
319                         // XXX - should be checked, why are we getting an event here, and
320                         //      what is it?
321                         
322                         return 1;
323                 } else if (!GHOST_ValidWindow(g_system, ghostwin)) {
324                         // XXX - should be checked, why are we getting an event here, and
325                         //      what is it?
326                         
327                         return 1;
328                 } else {
329                         win= GHOST_GetWindowUserData(ghostwin);
330                 }
331                 
332                 switch(type) {
333                         case GHOST_kEventWindowDeactivate:
334                                 win->active= 0; /* XXX */
335                                 break;
336                         case GHOST_kEventWindowActivate: 
337                         {
338                                 GHOST_TEventKeyData kdata;
339                                 int cx, cy, wx, wy;
340                                 
341                                 C->wm->winactive= win; /* no context change! c->window is drawable, or for area queues */
342                                 
343                                 win->active= 1;
344 //                              window_handle(win, INPUTCHANGE, win->active);
345                                 
346                                 /* bad ghost support for modifier keys... */
347                                 kdata.ascii= 0;
348                                 if (win->eventstate->shift && !query_qual('s')) {
349                                         kdata.key= GHOST_kKeyLeftShift;
350                                         wm_event_add_ghostevent(win, GHOST_kEventKeyUp, &kdata);
351                                 }
352                                 if (win->eventstate->ctrl && !query_qual('c')) {
353                                         kdata.key= GHOST_kKeyLeftControl;
354                                         wm_event_add_ghostevent(win, GHOST_kEventKeyUp, &kdata);
355                                 }
356                                 if (win->eventstate->alt && !query_qual('a')) {
357                                         kdata.key= GHOST_kKeyLeftAlt;
358                                         wm_event_add_ghostevent(win, GHOST_kEventKeyUp, &kdata);
359                                 }
360                                 if (win->eventstate->oskey && !query_qual('C')) {
361                                         kdata.key= GHOST_kKeyCommand;
362                                         wm_event_add_ghostevent(win, GHOST_kEventKeyUp, &kdata);
363                                 }
364                                 
365                                 /* entering window, update mouse pos. but no event */
366                                 GHOST_GetCursorPosition(g_system, &wx, &wy);
367                                 
368                                 GHOST_ScreenToClient(win->ghostwin, wx, wy, &cx, &cy);
369                                 win->eventstate->x= cx;
370                                 win->eventstate->y= (win->sizey-1) - cy;
371                                 
372                                 break;
373                         }
374                         case GHOST_kEventWindowClose: {
375                                 wm_window_close(C, win);
376                                 break;
377                         }
378                         case GHOST_kEventWindowUpdate: {
379 //                              window_handle(win, REDRAW, 1);
380                                 break;
381                         }
382                         case GHOST_kEventWindowSize:
383                         case GHOST_kEventWindowMove: {
384                                 GHOST_RectangleHandle client_rect;
385                                 int l, t, r, b, scr_w, scr_h;
386                                 GHOST_TWindowState state;
387                                 
388                                 client_rect= GHOST_GetClientBounds(win->ghostwin);
389                                 GHOST_GetRectangle(client_rect, &l, &t, &r, &b);
390                                 
391                                 GHOST_DisposeRectangle(client_rect);
392                                 
393                                 wm_get_screensize(&scr_w, &scr_h);
394                                 win->sizex= r-l;
395                                 win->sizey= b-t;
396                                 win->posx= l;
397                                 win->posy= scr_h - t - win->sizey;
398
399                                 if(type!=GHOST_kEventWindowSize)
400                                         printf("win move event pos %d %d size %d %d\n", win->posx, win->posy, win->sizex, win->sizey);
401
402                                 state = GHOST_GetWindowState(win->ghostwin);
403
404                                 if(state==GHOST_kWindowStateNormal)
405                                         printf("window state: normal\n");
406                                 else if(state==GHOST_kWindowStateMinimized)
407                                         printf("window state: minimized\n");
408                                 else if(state==GHOST_kWindowStateMaximized)
409                                         printf("window state: maximized\n");
410                                 else if(state==GHOST_kWindowStateFullScreen)
411                                         printf("window state: fullscreen\n");
412                                 
413 //                              window_handle(win, RESHAPE, 1);
414                                 break;
415                         }
416                         default:
417                                 wm_event_add_ghostevent(win, type, data);
418                                 break;
419                 }
420
421         }
422         return 1;
423 }
424
425 void wm_window_process_events(int wait_for_event) 
426 {
427         GHOST_ProcessEvents(g_system, wait_for_event);
428         GHOST_DispatchEvents(g_system);
429 }
430
431 /* **************** init ********************** */
432
433 void wm_ghost_init(bContext *C)
434 {
435         if (!g_system) {
436                 GHOST_EventConsumerHandle consumer= GHOST_CreateEventConsumer(ghost_event_proc, C);
437                 
438                 g_system= GHOST_CreateSystem();
439                 GHOST_AddEventConsumer(g_system, consumer);
440         }       
441 }
442
443 /* **************** timer ********************** */
444
445 static void window_timer_proc(GHOST_TimerTaskHandle timer, GHOST_TUns64 time)
446 {
447         wmWindow *win= GHOST_GetTimerTaskUserData(timer);
448         
449         wm_event_add_ghostevent(win, win->timer_event, NULL);
450 }
451
452 void wm_window_set_timer(wmWindow *win, int delay_ms, int event)
453 {
454         if (win->timer) GHOST_RemoveTimer(g_system, win->timer);
455         
456         win->timer_event= event;
457         win->timer= GHOST_InstallTimer(g_system, delay_ms, delay_ms, window_timer_proc, win);
458 }
459
460 /* ************************************ */
461
462 void wm_window_set_title(wmWindow *win, char *title) 
463 {
464         GHOST_SetTitle(win->ghostwin, title);
465 }
466
467 void wm_window_get_position(wmWindow *win, int *posx_r, int *posy_r) 
468 {
469         *posx_r= win->posx;
470         *posy_r= win->posy;
471 }
472
473 void wm_window_get_size(wmWindow *win, int *width_r, int *height_r) 
474 {
475         *width_r= win->sizex;
476         *height_r= win->sizey;
477 }
478
479 void wm_window_set_size(wmWindow *win, int width, int height) 
480 {
481         GHOST_SetClientSize(win->ghostwin, width, height);
482 }
483
484 void wm_window_lower(wmWindow *win) 
485 {
486         GHOST_SetWindowOrder(win->ghostwin, GHOST_kWindowOrderBottom);
487 }
488
489 void wm_window_raise(wmWindow *win) 
490 {
491         GHOST_SetWindowOrder(win->ghostwin, GHOST_kWindowOrderTop);
492 #ifdef _WIN32
493 //      markdirty_all(); /* to avoid redraw errors in fullscreen mode (aphex) */
494 #endif
495 }
496
497 void wm_window_swap_buffers(wmWindow *win)
498 {
499         GHOST_SwapWindowBuffers(win->ghostwin);
500 }
501
502 /* ******************* exported api ***************** */
503
504
505 /* called whem no ghost system was initialized */
506 void WM_setprefsize(int stax, int stay, int sizx, int sizy)
507 {
508         prefstax= stax;
509         prefstay= stay;
510         prefsizx= sizx;
511         prefsizy= sizy;
512 }
513