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