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