added a fullscreen button in the top header (windows only)
[blender.git] / source / blender / src / ghostwinlay.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL 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. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  */
32 #include <stdlib.h>
33 #include <stdio.h>
34
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
38
39 #ifdef WIN32
40 #include "BLI_winstuff.h"
41 #endif
42
43 #include "MEM_guardedalloc.h"
44
45 #include "BLI_blenlib.h"
46
47 #include "GHOST_C-api.h"
48
49 #include "BKE_utildefines.h"
50 #include "BKE_global.h"
51
52 #include "BIF_gl.h"
53 #include "BIF_graphics.h"
54 #include "BIF_mywindow.h"
55 #include "BIF_screen.h"
56 #include "BIF_usiblender.h"
57
58 #include "mydevice.h"
59 #include "blendef.h"
60
61 #include "winlay.h"
62
63 static GHOST_SystemHandle g_system= 0;
64
65         /* Some simple ghost <-> blender conversions */
66         
67 static GHOST_TStandardCursor convert_cursor(int curs) {
68         switch(curs) {
69         default:
70         case CURSOR_STD:                return GHOST_kStandardCursorDefault;
71         case CURSOR_VPAINT:             return GHOST_kStandardCursorLeftArrow;
72         case CURSOR_FACESEL:    return GHOST_kStandardCursorRightArrow;
73         case CURSOR_WAIT:               return GHOST_kStandardCursorWait;
74         case CURSOR_EDIT:               return GHOST_kStandardCursorCrosshair;
75         case CURSOR_HELP:               return GHOST_kStandardCursorHelp;
76         case CURSOR_X_MOVE:             return GHOST_kStandardCursorLeftRight;
77         case CURSOR_Y_MOVE:             return GHOST_kStandardCursorUpDown;
78         }
79 }
80
81 static int convert_mbut(GHOST_TButtonMask but) {
82         if (but == GHOST_kButtonMaskLeft) {
83                 return LEFTMOUSE;
84         } else if (but == GHOST_kButtonMaskRight) {
85                 return RIGHTMOUSE;
86         } else {
87                 return MIDDLEMOUSE;
88         }
89 }
90
91 static int convert_key(GHOST_TKey key) {
92         if (key>=GHOST_kKeyA && key<=GHOST_kKeyZ) {
93                 return (AKEY + ((int) key - GHOST_kKeyA));
94         } else if (key>=GHOST_kKey0 && key<=GHOST_kKey9) {
95                 return (ZEROKEY + ((int) key - GHOST_kKey0));
96         } else if (key>=GHOST_kKeyNumpad0 && key<=GHOST_kKeyNumpad9) {
97                 return (PAD0 + ((int) key - GHOST_kKeyNumpad0));
98         } else if (key>=GHOST_kKeyF1 && key<=GHOST_kKeyF12) {
99                 return (F1KEY + ((int) key - GHOST_kKeyF1));
100         } else {
101                 switch (key) {
102                 case GHOST_kKeyBackSpace:               return BACKSPACEKEY;
103                 case GHOST_kKeyTab:                             return TABKEY;
104                 case GHOST_kKeyLinefeed:                return LINEFEEDKEY;
105                 case GHOST_kKeyClear:                   return 0;
106                 case GHOST_kKeyEnter:                   return RETKEY;
107         
108                 case GHOST_kKeyEsc:                             return ESCKEY;
109                 case GHOST_kKeySpace:                   return SPACEKEY;
110                 case GHOST_kKeyQuote:                   return QUOTEKEY;
111                 case GHOST_kKeyComma:                   return COMMAKEY;
112                 case GHOST_kKeyMinus:                   return MINUSKEY;
113                 case GHOST_kKeyPeriod:                  return PERIODKEY;
114                 case GHOST_kKeySlash:                   return SLASHKEY;
115
116                 case GHOST_kKeySemicolon:               return SEMICOLONKEY;
117                 case GHOST_kKeyEqual:                   return EQUALKEY;
118
119                 case GHOST_kKeyLeftBracket:             return LEFTBRACKETKEY;
120                 case GHOST_kKeyRightBracket:    return RIGHTBRACKETKEY;
121                 case GHOST_kKeyBackslash:               return BACKSLASHKEY;
122                 case GHOST_kKeyAccentGrave:             return ACCENTGRAVEKEY;
123
124                 case GHOST_kKeyLeftShift:               return LEFTSHIFTKEY;
125                 case GHOST_kKeyRightShift:              return RIGHTSHIFTKEY;
126                 case GHOST_kKeyLeftControl:             return LEFTCTRLKEY;
127                 case GHOST_kKeyRightControl:    return RIGHTCTRLKEY;
128                 case GHOST_kKeyLeftAlt:                 return LEFTALTKEY;
129                 case GHOST_kKeyRightAlt:                return RIGHTALTKEY;
130
131                 case GHOST_kKeyCapsLock:                return CAPSLOCKKEY;
132                 case GHOST_kKeyNumLock:                 return 0;
133                 case GHOST_kKeyScrollLock:              return 0;
134
135                 case GHOST_kKeyLeftArrow:               return LEFTARROWKEY;
136                 case GHOST_kKeyRightArrow:              return RIGHTARROWKEY;
137                 case GHOST_kKeyUpArrow:                 return UPARROWKEY;
138                 case GHOST_kKeyDownArrow:               return DOWNARROWKEY;
139
140                 case GHOST_kKeyPrintScreen:             return 0;
141                 case GHOST_kKeyPause:                   return PAUSEKEY;
142
143                 case GHOST_kKeyInsert:                  return INSERTKEY;
144                 case GHOST_kKeyDelete:                  return DELKEY;
145                 case GHOST_kKeyHome:                    return HOMEKEY;
146                 case GHOST_kKeyEnd:                             return ENDKEY;
147                 case GHOST_kKeyUpPage:                  return PAGEUPKEY;
148                 case GHOST_kKeyDownPage:                return PAGEDOWNKEY;
149
150                 case GHOST_kKeyNumpadPeriod:    return PADPERIOD;
151                 case GHOST_kKeyNumpadEnter:             return PADENTER;
152                 case GHOST_kKeyNumpadPlus:              return PADPLUSKEY;
153                 case GHOST_kKeyNumpadMinus:             return PADMINUS;
154                 case GHOST_kKeyNumpadAsterisk:  return PADASTERKEY;
155                 case GHOST_kKeyNumpadSlash:             return PADSLASHKEY;
156                 case GHOST_kKeyUnknown:                 return UNKNOWNKEY;
157
158                 default:
159                         return 0;
160                 }
161         }
162 }
163
164         /***/
165         
166 struct _Window {
167         GHOST_WindowHandle      ghostwin;
168         
169                 /* Handler and private data for handler */
170         WindowHandlerFP         handler;
171         void                            *user_data;
172         
173                 /* Window state */
174         int             size[2], position[2];
175         int             active, visible;
176         
177                 /* Last known mouse/button/qualifier state */
178         int             lmouse[2];
179         int             lqual;          /* (LR_SHFTKEY, LR_CTRLKEY, LR_ALTKEY) */
180         int             lmbut;          /* (L_MOUSE, M_MOUSE, R_MOUSE) */
181         int             commandqual;
182
183                 /* Tracks the faked mouse button, if non-zero it is
184                  * the event number of the last faked button.
185                  */
186         int             faked_mbut;
187
188         GHOST_TimerTaskHandle   timer;
189         int                                             timer_event;
190 };
191
192 static Window *window_new(GHOST_WindowHandle ghostwin)
193 {
194         Window *win= MEM_callocN(sizeof(*win), "Window");
195         win->ghostwin= ghostwin;
196         
197         return win;
198 }
199
200 static void window_handle(Window *win, short event, short val)
201 {
202         if (win->handler) {
203                 win->handler(win, win->user_data, event, val, 0);
204         }
205 }
206
207 static void window_handle_ext(Window *win, short event, short val, short extra)
208 {
209         if (win->handler) {
210                 win->handler(win, win->user_data, event, val, extra);
211         }
212 }
213
214 static void window_free(Window *win) 
215 {
216         MEM_freeN(win);
217 }
218
219         /***/
220
221 static Window *active_gl_window= NULL;
222
223 Window *window_open(char *title, int posx, int posy, int sizex, int sizey, int start_maximized)
224 {
225         GHOST_WindowHandle ghostwin;
226         GHOST_TWindowState inital_state;
227         int scr_w, scr_h;
228
229         winlay_get_screensize(&scr_w, &scr_h);
230         posy= (scr_h-posy-sizey);
231         
232         /* create a fullscreen window on unix by default*/
233 #if !defined(WIN32) && !defined(__APPLE__)
234         inital_state= start_maximized?
235                 GHOST_kWindowStateFullScreen:GHOST_kWindowStateNormal;
236 #else
237 #ifdef _WIN32   // FULLSCREEN
238         if (start_maximized == G_WINDOWSTATE_FULLSCREEN)
239                 inital_state= GHOST_kWindowStateFullScreen;
240         else
241                 inital_state= start_maximized?GHOST_kWindowStateMaximized:GHOST_kWindowStateNormal;
242 #else
243         inital_state= start_maximized?GHOST_kWindowStateMaximized:GHOST_kWindowStateNormal;
244 #endif
245 #endif
246
247         ghostwin= GHOST_CreateWindow(g_system, 
248                                                                 title, 
249                                                                 posx, posy, sizex, sizey, 
250                                                                 inital_state, 
251                                                                 GHOST_kDrawingContextTypeOpenGL,
252                                                                 0 /* no stereo */);
253         
254         if (ghostwin) {
255                 Window *win= window_new(ghostwin);
256                 
257                 if (win) {
258                         GHOST_SetWindowUserData(ghostwin, win);
259                         
260                         win->position[0]= posx;
261                         win->position[1]= posy;
262                         win->size[0]= sizex;
263                         win->size[1]= sizey;
264                         
265                         win->lmouse[0]= win->size[0]/2;
266                         win->lmouse[1]= win->size[1]/2;
267                 } else {
268                         GHOST_DisposeWindow(g_system, ghostwin);
269                 }
270                 
271                 return win;
272         } else {
273                 return NULL;
274         }
275 }
276
277 void window_set_handler(Window *win, WindowHandlerFP handler, void *user_data)
278 {
279         win->handler= handler;
280         win->user_data= user_data;
281 }
282
283 static void window_timer_proc(GHOST_TimerTaskHandle timer, GHOST_TUns64 time)
284 {
285         Window *win= GHOST_GetTimerTaskUserData(timer);
286
287         win->handler(win, win->user_data, win->timer_event, 0, 0);
288 }
289
290 void window_set_timer(Window *win, int delay_ms, int event)
291 {
292         if (win->timer) GHOST_RemoveTimer(g_system, win->timer);
293
294         win->timer_event= event;
295         win->timer= GHOST_InstallTimer(g_system, delay_ms, delay_ms, window_timer_proc, win);
296 }
297
298 void window_destroy(Window *win) {
299         if (active_gl_window==win) {
300                 active_gl_window= NULL;
301         }
302         
303         if (win->timer) {
304                 GHOST_RemoveTimer(g_system, win->timer);
305                 win->timer= NULL;
306         }
307
308         GHOST_DisposeWindow(g_system, win->ghostwin);
309         window_free(win);
310 }
311
312 void window_set_cursor(Window *win, int curs) {
313         if (curs==CURSOR_NONE) {
314                 GHOST_SetCursorVisibility(win->ghostwin, 0);
315         } else {
316                 GHOST_SetCursorVisibility(win->ghostwin, 1);
317                 GHOST_SetCursorShape(win->ghostwin, convert_cursor(curs));
318         }
319 }
320
321 void window_set_custom_cursor(Window *win, unsigned char mask[16][2], unsigned char bitmap[16][2]) {
322         GHOST_SetCustomCursorShape(win->ghostwin, bitmap, mask, 7, 7);
323 }
324
325 void window_make_active(Window *win) {
326         if (win != active_gl_window) {
327                 active_gl_window= win;
328                 GHOST_ActivateWindowDrawingContext(win->ghostwin);
329         }
330 }
331
332 void window_swap_buffers(Window *win) {
333         GHOST_SwapWindowBuffers(win->ghostwin);
334 }
335
336 static int query_qual(char qual) {
337         GHOST_TModifierKeyMask left, right;
338         int val= 0;
339         
340         if (qual=='s') {
341                 left= GHOST_kModifierKeyLeftShift;
342                 right= GHOST_kModifierKeyRightShift;
343         } else if (qual=='c') {
344                 left= GHOST_kModifierKeyLeftControl;
345                 right= GHOST_kModifierKeyRightControl;
346         } else if (qual=='C') {
347                 left= right= GHOST_kModifierKeyCommand;
348         } else {
349                 left= GHOST_kModifierKeyLeftAlt;
350                 right= GHOST_kModifierKeyRightAlt;
351         }
352
353         GHOST_GetModifierKeyState(g_system, left, &val);
354         if (!val)
355                 GHOST_GetModifierKeyState(g_system, right, &val);
356         
357         return val;
358 }
359
360 static int change_bit(int val, int bit, int to_on) {
361         return to_on?(val|bit):(val&~bit);
362 }
363
364 static int event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr private) {
365         GHOST_TEventType type= GHOST_GetEventType(evt);
366
367         if (type == GHOST_kEventQuit) {
368                 exit_usiblender();
369         } else {
370                 GHOST_WindowHandle ghostwin= GHOST_GetEventWindow(evt);
371                 GHOST_TEventDataPtr data= GHOST_GetEventData(evt);
372                 Window *win;
373                 
374                 if (!ghostwin) {
375                         printf("GHOST event error - no window - type: %d\n", type);
376                         return 1;
377                 } else if (!GHOST_ValidWindow(g_system, ghostwin)) {
378                         printf("GHOST event error - invalid window - win: %p\n", ghostwin);
379                         return 1;
380                 } else {
381                         win= GHOST_GetWindowUserData(ghostwin);
382                 }
383                 
384                 switch (type) {
385                 case GHOST_kEventCursorMove: {
386                         GHOST_TEventCursorData *cd= data;
387                         int cx, cy;
388                         
389                         GHOST_ScreenToClient(win->ghostwin, cd->x, cd->y, &cx, &cy);
390                         win->lmouse[0]= cx;
391                         win->lmouse[1]= (win->size[1]-1) - cy;
392
393                         window_handle(win, MOUSEX, win->lmouse[0]);
394                         window_handle(win, MOUSEY, win->lmouse[1]);
395                         
396                         break;
397                 }
398                 case GHOST_kEventButtonDown:
399                 case GHOST_kEventButtonUp: {
400                         GHOST_TEventButtonData *bd= data;
401                         int val= (type==GHOST_kEventButtonDown);
402                         int bbut= convert_mbut(bd->button);
403                 
404                         if (bbut==LEFTMOUSE) {
405                                 if (val) {
406                                         if (win->commandqual) {
407                                                 bbut= win->faked_mbut= RIGHTMOUSE;
408                                         } else if (win->lqual & LR_ALTKEY) {
409                                                 bbut= win->faked_mbut= MIDDLEMOUSE;
410                                         }
411                                 } else {
412                                         if (win->faked_mbut) {
413                                                 bbut= win->faked_mbut;
414                                                 win->faked_mbut= 0;
415                                         }
416                                 }
417                         }
418
419                         if (bbut==LEFTMOUSE) {
420                                 win->lmbut= change_bit(win->lmbut, L_MOUSE, val);
421                         } else if (bbut==MIDDLEMOUSE) {
422                                 win->lmbut= change_bit(win->lmbut, M_MOUSE, val);
423                         } else {
424                                 win->lmbut= change_bit(win->lmbut, R_MOUSE, val);
425                         }
426                         window_handle(win, bbut, val);
427                         
428                         break;
429                 }
430         
431                 case GHOST_kEventKeyDown:
432                 case GHOST_kEventKeyUp: {
433                         GHOST_TEventKeyData *kd= data;
434                         int val= (type==GHOST_kEventKeyDown);
435                         int bkey= convert_key(kd->key);
436
437                         if (kd->key == GHOST_kKeyCommand) {
438                                 win->commandqual= val;
439                         }
440
441                         if (bkey) {
442                                 if (bkey==LEFTSHIFTKEY || bkey==RIGHTSHIFTKEY) {
443                                         win->lqual= change_bit(win->lqual, LR_SHIFTKEY, val);
444                                 } else if (bkey==LEFTCTRLKEY || bkey==RIGHTCTRLKEY) {
445                                         win->lqual= change_bit(win->lqual, LR_CTRLKEY, val);
446                                 } else if (bkey==LEFTALTKEY || bkey==RIGHTALTKEY) {
447                                         win->lqual= change_bit(win->lqual, LR_ALTKEY, val);
448                                 }
449
450                                 window_handle_ext(win, bkey, val, kd->ascii);
451                         }
452                         
453                         break;
454                 }
455
456                 case GHOST_kEventWheel: {
457                         GHOST_TEventWheelData* wheelData = (GHOST_TEventWheelData*) data;
458                         if (wheelData->z > 0) {
459                                 window_handle(win, WHEELUPMOUSE, 1);
460                         } else {
461                                 window_handle(win, WHEELDOWNMOUSE, 1);
462                         }
463                         break;
464                 }
465
466                 case GHOST_kEventWindowDeactivate:
467                 case GHOST_kEventWindowActivate: {
468                         win->active= (type==GHOST_kEventWindowActivate);
469                         window_handle(win, INPUTCHANGE, win->active);
470                         
471                         if (win->active) {
472                                 if ((win->lqual & LR_SHIFTKEY) && !query_qual('s')) {
473                                         win->lqual= change_bit(win->lqual, LR_SHIFTKEY, 0);
474                                         window_handle(win, LEFTSHIFTKEY, 0);
475                                 }
476                                 if ((win->lqual & LR_CTRLKEY) && !query_qual('c')) {
477                                         win->lqual= change_bit(win->lqual, LR_CTRLKEY, 0);
478                                         window_handle(win, LEFTCTRLKEY, 0);
479                                 }
480                                 if ((win->lqual & LR_ALTKEY) && !query_qual('a')) {
481                                         win->lqual= change_bit(win->lqual, LR_ALTKEY, 0);
482                                         window_handle(win, LEFTALTKEY, 0);
483                                 }
484                                 win->commandqual= query_qual('C');
485
486                                 /* 
487                                  * XXX quick hack so OSX version works better
488                                  * when the window is clicked on (focused). 
489                                  */
490                                 window_handle(win, MOUSEX, win->lmouse[0]);
491                                 window_handle(win, MOUSEY, win->lmouse[1]);
492                         }
493                         
494                         break;
495                 }
496                 case GHOST_kEventWindowClose: {
497                         window_handle(win, WINCLOSE, 1);
498                         break;
499                 }
500                 case GHOST_kEventWindowUpdate: {
501                         window_handle(win, REDRAW, 1);
502                         break;
503                 }
504                 case GHOST_kEventWindowSize: {
505                         GHOST_RectangleHandle client_rect;
506                         int l, t, r, b, scr_w, scr_h;
507
508                         client_rect= GHOST_GetClientBounds(win->ghostwin);
509                         GHOST_GetRectangle(client_rect, &l, &t, &r, &b);
510                         
511                         GHOST_DisposeRectangle(client_rect);
512                         
513                         winlay_get_screensize(&scr_w, &scr_h);
514                         win->position[0]= l;
515                         win->position[1]= scr_h - b - 1;
516                         win->size[0]= r-l;
517                         win->size[1]= b-t;
518
519                         window_handle(win, RESHAPE, 1);
520                         break;
521                 }
522                 }
523         }
524
525         return 1;
526 }
527
528 char *window_get_title(Window *win) {
529         char *title= GHOST_GetTitle(win->ghostwin);
530         char *mem_title= BLI_strdup(title);
531         free(title);
532
533         return mem_title;
534 }
535
536 void window_set_title(Window *win, char *title) {
537         GHOST_SetTitle(win->ghostwin, title);
538 }
539
540 short window_get_qual(Window *win) {
541         return win->lqual;
542 }
543
544 short window_get_mbut(Window *win) {
545         return win->lmbut;
546 }
547
548 void window_get_mouse(Window *win, short *mval) {
549         mval[0]= win->lmouse[0];
550         mval[1]= win->lmouse[1];
551 }
552
553 void window_get_position(Window *win, int *posx_r, int *posy_r) {
554         *posx_r= win->position[0];
555         *posy_r= win->position[1];
556 }
557
558 void window_get_size(Window *win, int *width_r, int *height_r) {
559         *width_r= win->size[0];
560         *height_r= win->size[1];
561 }
562
563 void window_set_size(Window *win, int width, int height) {
564         GHOST_SetClientSize(win->ghostwin, width, height);
565 }
566
567 void window_lower(Window *win) {
568         GHOST_SetWindowOrder(win->ghostwin, GHOST_kWindowOrderBottom);
569 }
570
571 void window_raise(Window *win) {
572         GHOST_SetWindowOrder(win->ghostwin, GHOST_kWindowOrderTop);
573 }
574
575 #ifdef _WIN32   //FULLSCREEN
576 void window_toggle_fullscreen(Window *win, int fullscreen) {
577         if(fullscreen)
578                 GHOST_SetWindowState(win->ghostwin, GHOST_kWindowStateFullScreen);
579         else
580                 GHOST_SetWindowState(win->ghostwin, GHOST_kWindowStateMaximized);
581 }
582 #endif
583
584 void window_warp_pointer(Window *win, int x, int y) {
585         y= win->size[1] - y - 1;
586         GHOST_ClientToScreen(win->ghostwin, x, y, &x, &y);
587         GHOST_SetCursorPosition(g_system, x, y);
588 }
589
590 void window_queue_redraw(Window *win) {
591         GHOST_InvalidateWindow(win->ghostwin);
592 }
593
594 /***/
595
596 void winlay_process_events(int wait_for_event) {
597         GHOST_ProcessEvents(g_system, wait_for_event);
598         GHOST_DispatchEvents(g_system);
599 }
600
601 void winlay_get_screensize(int *width_r, int *height_r) {
602         unsigned int uiwidth;
603         unsigned int uiheight;
604         
605         if (!g_system) {
606                 GHOST_EventConsumerHandle consumer= GHOST_CreateEventConsumer(event_proc, NULL);
607         
608                 g_system= GHOST_CreateSystem();
609                 GHOST_AddEventConsumer(g_system, consumer);
610         }
611         
612         GHOST_GetMainDisplayDimensions(g_system, &uiwidth, &uiheight);
613         *width_r= uiwidth;
614         *height_r= uiheight;
615 }
616
617 Window *winlay_get_active_window(void) {
618         return active_gl_window;
619 }