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