commit before doing some hefty shapekey change, will break compilation
[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, 2008
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include <math.h>
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <string.h>
33
34 #include "DNA_listBase.h"       
35 #include "DNA_screen_types.h"
36 #include "DNA_windowmanager_types.h"
37
38 #include "MEM_guardedalloc.h"
39
40 #include "GHOST_C-api.h"
41
42 #include "BLI_blenlib.h"
43
44 #include "BKE_blender.h"
45 #include "BKE_context.h"
46 #include "BKE_global.h"
47 #include "BKE_utildefines.h"
48
49 #include "BIF_gl.h"
50
51 #include "WM_api.h"
52 #include "WM_types.h"
53 #include "wm.h"
54 #include "wm_draw.h"
55 #include "wm_window.h"
56 #include "wm_subwindow.h"
57 #include "wm_event_system.h"
58
59 #include "ED_screen.h"
60
61 #include "PIL_time.h"
62
63 #include "GPU_draw.h"
64
65 /* the global to talk to ghost */
66 GHOST_SystemHandle g_system= NULL;
67
68 /* set by commandline */
69 static int prefsizx= 0, prefsizy= 0, prefstax= 0, prefstay= 0;
70
71 /* ******** win open & close ************ */
72
73 /* XXX this one should correctly check for apple top header...
74  done for Cocoa : returns window contents (and not frame) max size*/
75 static void wm_get_screensize(int *width_r, int *height_r) 
76 {
77         unsigned int uiwidth;
78         unsigned int uiheight;
79         
80         GHOST_GetMainDisplayDimensions(g_system, &uiwidth, &uiheight);
81         *width_r= uiwidth;
82         *height_r= uiheight;
83 }
84
85 /* keeps offset and size within monitor bounds */
86 /* XXX solve dual screen... */
87 static void wm_window_check_position(rcti *rect)
88 {
89         int width, height, d;
90         
91         wm_get_screensize(&width, &height);
92         
93 #if defined(__APPLE__) && !defined(GHOST_COCOA)
94         height -= 70;
95 #endif
96         
97         if(rect->xmin < 0) {
98                 d= rect->xmin;
99                 rect->xmax -= d;
100                 rect->xmin -= d;
101         }
102         if(rect->ymin < 0) {
103                 d= rect->ymin;
104                 rect->ymax -= d;
105                 rect->ymin -= d;
106         }
107         if(rect->xmax > width) {
108                 d= rect->xmax - width;
109                 rect->xmax -= d;
110                 rect->xmin -= d;
111         }
112         if(rect->ymax > height) {
113                 d= rect->ymax - height;
114                 rect->ymax -= d;
115                 rect->ymin -= d;
116         }
117         
118         if(rect->xmin < 0) rect->xmin= 0;
119         if(rect->ymin < 0) rect->ymin= 0;
120 }
121
122
123 static void wm_ghostwindow_destroy(wmWindow *win) 
124 {
125         if(win->ghostwin) {
126                 GHOST_DisposeWindow(g_system, win->ghostwin);
127                 win->ghostwin= NULL;
128         }
129 }
130
131 /* including window itself, C can be NULL. 
132    ED_screen_exit should have been called */
133 void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win)
134 {
135         wmTimer *wt, *wtnext;
136         
137         /* update context */
138         if(C) {
139                 WM_event_remove_handlers(C, &win->handlers);
140                 WM_event_remove_handlers(C, &win->modalhandlers);
141
142                 if(CTX_wm_window(C)==win)
143                         CTX_wm_window_set(C, NULL);
144         }       
145
146         if(wm->windrawable==win)
147                 wm->windrawable= NULL;
148         if(wm->winactive==win)
149                 wm->winactive= NULL;
150
151         /* end running jobs, a job end also removes its timer */
152         for(wt= wm->timers.first; wt; wt= wtnext) {
153                 wtnext= wt->next;
154                 if(wt->win==win && wt->event_type==TIMERJOBS)
155                         wm_jobs_timer_ended(wm, wt);
156         }
157         
158         /* timer removing, need to call this api function */
159         for(wt= wm->timers.first; wt; wt=wtnext) {
160                 wtnext= wt->next;
161                 if(wt->win==win)
162                         WM_event_remove_timer(wm, win, wt);
163         }
164
165         if(win->eventstate) MEM_freeN(win->eventstate);
166         
167         wm_event_free_all(win);
168         wm_subwindows_free(win);
169         
170         if(win->drawdata)
171                 MEM_freeN(win->drawdata);
172         
173         wm_ghostwindow_destroy(win);
174         
175         MEM_freeN(win);
176 }
177
178 static int find_free_winid(wmWindowManager *wm)
179 {
180         wmWindow *win;
181         int id= 1;
182         
183         for(win= wm->windows.first; win; win= win->next)
184                 if(id <= win->winid)
185                         id= win->winid+1;
186         
187         return id;
188 }
189
190 /* dont change context itself */
191 wmWindow *wm_window_new(bContext *C)
192 {
193         wmWindowManager *wm= CTX_wm_manager(C);
194         wmWindow *win= MEM_callocN(sizeof(wmWindow), "window");
195         
196         BLI_addtail(&wm->windows, win);
197         win->winid= find_free_winid(wm);
198
199         return win;
200 }
201
202
203 /* part of wm_window.c api */
204 wmWindow *wm_window_copy(bContext *C, wmWindow *winorig)
205 {
206         wmWindow *win= wm_window_new(C);
207         
208         win->posx= winorig->posx+10;
209         win->posy= winorig->posy;
210         win->sizex= winorig->sizex;
211         win->sizey= winorig->sizey;
212         
213         /* duplicate assigns to window */
214         win->screen= ED_screen_duplicate(win, winorig->screen);
215         BLI_strncpy(win->screenname, win->screen->id.name+2, 21);
216         win->screen->winid= win->winid;
217
218         win->screen->do_refresh= 1;
219         win->screen->do_draw= 1;
220
221         win->drawmethod= -1;
222         win->drawdata= NULL;
223         
224         return win;
225 }
226
227 /* this is event from ghost, or exit-blender op */
228 void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win)
229 {
230         BLI_remlink(&wm->windows, win);
231         
232         wm_draw_window_clear(win);
233         ED_screen_exit(C, win, win->screen);
234         wm_window_free(C, wm, win);
235         
236         /* check remaining windows */
237         if(wm->windows.first) {
238                 for(win= wm->windows.first; win; win= win->next)
239                         if(win->screen->full!=SCREENTEMP)
240                                 break;
241                 /* in this case we close all */
242                 if(win==NULL)
243                         WM_exit(C);
244         }
245         else
246                 WM_exit(C);
247 }
248
249 void wm_window_title(wmWindowManager *wm, wmWindow *win)
250 {
251         /* handle the 'temp' window */
252         if(win->screen && win->screen->full==SCREENTEMP) {
253                 GHOST_SetTitle(win->ghostwin, "Blender");
254         }
255         else {
256                 
257                 /* this is set to 1 if you don't have .B.blend open */
258                 if(G.save_over) {
259                         char *str= MEM_mallocN(strlen(G.sce) + 16, "title");
260                         
261                         if(wm->file_saved)
262                                 sprintf(str, "Blender [%s]", G.sce);
263                         else
264                                 sprintf(str, "Blender* [%s]", G.sce);
265                         
266                         GHOST_SetTitle(win->ghostwin, str);
267                         
268                         MEM_freeN(str);
269                 }
270                 else
271                         GHOST_SetTitle(win->ghostwin, "Blender");
272
273                 /* Informs GHOST of unsaved changes, to set window modified visual indicator (MAC OS X)
274                  and to give hint of unsaved changes for a user warning mechanism
275                  in case of OS application terminate request (e.g. OS Shortcut Alt+F4, Cmd+Q, (...), or session end) */
276                 GHOST_SetWindowModifiedState(win->ghostwin, (GHOST_TUns8)!wm->file_saved);
277                 
278 #if defined(__APPLE__) && !defined(GHOST_COCOA)
279                 if(wm->file_saved)
280                         GHOST_SetWindowState(win->ghostwin, GHOST_kWindowStateUnModified);
281                 else
282                         GHOST_SetWindowState(win->ghostwin, GHOST_kWindowStateModified);
283 #endif
284         }
285 }
286
287 /* belongs to below */
288 static void wm_window_add_ghostwindow(wmWindowManager *wm, char *title, wmWindow *win)
289 {
290         GHOST_WindowHandle ghostwin;
291         GHOST_TWindowState inital_state;
292         int scr_w, scr_h, posy;
293         
294         wm_get_screensize(&scr_w, &scr_h);
295         posy= (scr_h - win->posy - win->sizey);
296         
297         //              inital_state = GHOST_kWindowStateFullScreen;
298         //              inital_state = GHOST_kWindowStateMaximized;
299         inital_state = GHOST_kWindowStateNormal;
300         
301 #if defined(__APPLE__) && !defined(GHOST_COCOA)
302         {
303                 extern int macPrefState; /* creator.c */
304                 inital_state += macPrefState;
305         }
306 #endif
307         
308         ghostwin= GHOST_CreateWindow(g_system, title, 
309                                                                  win->posx, posy, win->sizex, win->sizey, 
310                                                                  inital_state, 
311                                                                  GHOST_kDrawingContextTypeOpenGL,
312                                                                  0 /* no stereo */);
313         
314         if (ghostwin) {
315                 
316                 win->ghostwin= ghostwin;
317                 GHOST_SetWindowUserData(ghostwin, win); /* pointer back */
318                 
319                 if(win->eventstate==NULL)
320                         win->eventstate= MEM_callocN(sizeof(wmEvent), "window event state");
321                 
322                 /* until screens get drawn, make it nice grey */
323                 glClearColor(.55, .55, .55, 0.0);
324                 glClear(GL_COLOR_BUFFER_BIT);
325                 wm_window_swap_buffers(win);
326                 
327                 //GHOST_SetWindowState(ghostwin, GHOST_kWindowStateModified);
328                 
329                 /* standard state vars for window */
330                 glEnable(GL_SCISSOR_TEST);
331                 
332                 GPU_state_init();
333         }
334 }
335
336 /* for wmWindows without ghostwin, open these and clear */
337 /* window size is read from window, if 0 it uses prefsize */
338 /* called in wm_check, also inits stuff after file read */
339 void wm_window_add_ghostwindows(wmWindowManager *wm)
340 {
341         wmKeyMap *keymap;
342         wmWindow *win;
343         
344         /* no commandline prefsize? then we set this */
345         if (!prefsizx) {
346                 wm_get_screensize(&prefsizx, &prefsizy);
347                 
348 #if defined(__APPLE__) && !defined(GHOST_COCOA)
349 //Cocoa provides functions to get correct max window size
350                 {
351                         extern void wm_set_apple_prefsize(int, int);    /* wm_apple.c */
352                         
353                         wm_set_apple_prefsize(prefsizx, prefsizy);
354                 }
355 #else
356                 prefstax= 0;
357                 prefstay= 0;
358                 
359 #endif
360         }
361         
362         for(win= wm->windows.first; win; win= win->next) {
363                 if(win->ghostwin==NULL) {
364                         if(win->sizex==0) {
365                                 win->posx= prefstax;
366                                 win->posy= prefstay;
367                                 win->sizex= prefsizx;
368                                 win->sizey= prefsizy;
369                                 win->windowstate= 0;
370                         }
371                         wm_window_add_ghostwindow(wm, "Blender", win);
372                 }
373                 /* happens after fileread */
374                 if(win->eventstate==NULL)
375                    win->eventstate= MEM_callocN(sizeof(wmEvent), "window event state");
376
377                 /* add keymap handlers (1 handler for all keys in map!) */
378                 keymap= WM_keymap_find(wm->defaultconf, "Window", 0, 0);
379                 WM_event_add_keymap_handler(&win->handlers, keymap);
380                 
381                 keymap= WM_keymap_find(wm->defaultconf, "Screen", 0, 0);
382                 WM_event_add_keymap_handler(&win->handlers, keymap);
383
384                 keymap= WM_keymap_find(wm->defaultconf, "Screen Editing", 0, 0);
385                 WM_event_add_keymap_handler(&win->modalhandlers, keymap);
386                 
387                 wm_window_title(wm, win);
388         }
389 }
390
391 /* new window, no screen yet, but we open ghostwindow for it */
392 /* also gets the window level handlers */
393 /* area-rip calls this */
394 wmWindow *WM_window_open(bContext *C, rcti *rect)
395 {
396         wmWindow *win= wm_window_new(C);
397         
398         win->posx= rect->xmin;
399         win->posy= rect->ymin;
400         win->sizex= rect->xmax - rect->xmin;
401         win->sizey= rect->ymax - rect->ymin;
402
403         win->drawmethod= -1;
404         win->drawdata= NULL;
405         
406         wm_check(C);
407         
408         return win;
409 }
410
411 /* uses screen->full tag to define what to do, currently it limits
412    to only one "temp" window for render out, preferences, filewindow, etc */
413 /* type is #define in WM_api.h */
414
415 void WM_window_open_temp(bContext *C, rcti *position, int type)
416 {
417         wmWindow *win;
418         ScrArea *sa;
419         
420         /* changes rect to fit within desktop */
421         wm_window_check_position(position);
422         
423         /* test if we have a temp screen already */
424         for(win= CTX_wm_manager(C)->windows.first; win; win= win->next)
425                 if(win->screen->full == SCREENTEMP)
426                         break;
427         
428         /* add new window? */
429         if(win==NULL) {
430                 win= wm_window_new(C);
431                 
432                 win->posx= position->xmin;
433                 win->posy= position->ymin;
434         }
435         
436         win->sizex= position->xmax - position->xmin;
437         win->sizey= position->ymax - position->ymin;
438         
439         if(win->ghostwin) {
440                 wm_window_set_size(win, win->sizex, win->sizey) ;
441                 wm_window_raise(win);
442         }
443         
444         /* add new screen? */
445         if(win->screen==NULL)
446                 win->screen= ED_screen_add(win, CTX_data_scene(C), "temp");
447         win->screen->full = SCREENTEMP; 
448         
449         /* make window active, and validate/resize */
450         CTX_wm_window_set(C, win);
451         wm_check(C);
452         
453         /* ensure it shows the right spacetype editor */
454         sa= win->screen->areabase.first;
455         CTX_wm_area_set(C, sa);
456         
457         if(type==WM_WINDOW_RENDER) {
458                 ED_area_newspace(C, sa, SPACE_IMAGE);
459         }
460         else {
461                 ED_area_newspace(C, sa, SPACE_USERPREF);
462         }
463         
464         ED_screen_set(C, win->screen);
465         
466         if(sa->spacetype==SPACE_IMAGE)
467                 GHOST_SetTitle(win->ghostwin, "Blender Render");
468         else if(ELEM(sa->spacetype, SPACE_OUTLINER, SPACE_USERPREF))
469                 GHOST_SetTitle(win->ghostwin, "Blender User Preferences");
470         else if(sa->spacetype==SPACE_FILE)
471                 GHOST_SetTitle(win->ghostwin, "Blender File View");
472         else
473                 GHOST_SetTitle(win->ghostwin, "Blender");
474 }
475
476
477 /* ****************** Operators ****************** */
478
479 /* operator callback */
480 int wm_window_duplicate_op(bContext *C, wmOperator *op)
481 {
482         wm_window_copy(C, CTX_wm_window(C));
483         wm_check(C);
484         
485         return OPERATOR_FINISHED;
486 }
487
488
489 /* fullscreen operator callback */
490 int wm_window_fullscreen_toggle_op(bContext *C, wmOperator *op)
491 {
492         wmWindow *window= CTX_wm_window(C);
493         GHOST_TWindowState state = GHOST_GetWindowState(window->ghostwin);
494         if(state!=GHOST_kWindowStateFullScreen)
495                 GHOST_SetWindowState(window->ghostwin, GHOST_kWindowStateFullScreen);
496         else
497                 GHOST_SetWindowState(window->ghostwin, GHOST_kWindowStateNormal);
498
499         return OPERATOR_FINISHED;
500         
501 }
502
503
504 /* ************ events *************** */
505
506 static int query_qual(char qual) 
507 {
508         GHOST_TModifierKeyMask left, right;
509         int val= 0;
510         
511         if (qual=='s') {
512                 left= GHOST_kModifierKeyLeftShift;
513                 right= GHOST_kModifierKeyRightShift;
514         } else if (qual=='c') {
515                 left= GHOST_kModifierKeyLeftControl;
516                 right= GHOST_kModifierKeyRightControl;
517         } else if (qual=='C') {
518                 left= right= GHOST_kModifierKeyCommand;
519         } else {
520                 left= GHOST_kModifierKeyLeftAlt;
521                 right= GHOST_kModifierKeyRightAlt;
522         }
523         
524         GHOST_GetModifierKeyState(g_system, left, &val);
525         if (!val)
526                 GHOST_GetModifierKeyState(g_system, right, &val);
527         
528         return val;
529 }
530
531 void wm_window_make_drawable(bContext *C, wmWindow *win) 
532 {
533         wmWindowManager *wm= CTX_wm_manager(C);
534
535         if (win != wm->windrawable && win->ghostwin) {
536 //              win->lmbut= 0;  /* keeps hanging when mousepressed while other window opened */
537                 
538                 wm->windrawable= win;
539                 if(G.f & G_DEBUG) printf("set drawable %d\n", win->winid);
540                 GHOST_ActivateWindowDrawingContext(win->ghostwin);
541         }
542 }
543
544 /* called by ghost, here we handle events for windows themselves or send to event system */
545 static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr private) 
546 {
547         bContext *C= private;
548         wmWindowManager *wm= CTX_wm_manager(C);
549         GHOST_TEventType type= GHOST_GetEventType(evt);
550         
551         if (type == GHOST_kEventQuit) {
552                 WM_exit(C);
553         } else {
554                 GHOST_WindowHandle ghostwin= GHOST_GetEventWindow(evt);
555                 GHOST_TEventDataPtr data= GHOST_GetEventData(evt);
556                 wmWindow *win;
557                 
558                 if (!ghostwin) {
559                         // XXX - should be checked, why are we getting an event here, and
560                         //      what is it?
561                         
562                         return 1;
563                 } else if (!GHOST_ValidWindow(g_system, ghostwin)) {
564                         // XXX - should be checked, why are we getting an event here, and
565                         //      what is it?
566                         
567                         return 1;
568                 } else {
569                         win= GHOST_GetWindowUserData(ghostwin);
570                 }
571                 
572                 switch(type) {
573                         case GHOST_kEventWindowDeactivate:
574                                 win->active= 0; /* XXX */
575                                 break;
576                         case GHOST_kEventWindowActivate: 
577                         {
578                                 GHOST_TEventKeyData kdata;
579                                 int cx, cy, wx, wy;
580                                 
581                                 wm->winactive= win; /* no context change! c->wm->windrawable is drawable, or for area queues */
582                                 
583                                 win->active= 1;
584 //                              window_handle(win, INPUTCHANGE, win->active);
585                                 
586                                 /* bad ghost support for modifier keys... so on activate we set the modifiers again */
587                                 kdata.ascii= 0;
588                                 if (win->eventstate->shift && !query_qual('s')) {
589                                         kdata.key= GHOST_kKeyLeftShift;
590                                         wm_event_add_ghostevent(win, GHOST_kEventKeyUp, &kdata);
591                                 }
592                                 if (win->eventstate->ctrl && !query_qual('c')) {
593                                         kdata.key= GHOST_kKeyLeftControl;
594                                         wm_event_add_ghostevent(win, GHOST_kEventKeyUp, &kdata);
595                                 }
596                                 if (win->eventstate->alt && !query_qual('a')) {
597                                         kdata.key= GHOST_kKeyLeftAlt;
598                                         wm_event_add_ghostevent(win, GHOST_kEventKeyUp, &kdata);
599                                 }
600                                 if (win->eventstate->oskey && !query_qual('C')) {
601                                         kdata.key= GHOST_kKeyCommand;
602                                         wm_event_add_ghostevent(win, GHOST_kEventKeyUp, &kdata);
603                                 }
604                                 /* keymodifier zero, it hangs on hotkeys that open windows otherwise */
605                                 win->eventstate->keymodifier= 0;
606                                 
607                                 /* entering window, update mouse pos. but no event */
608                                 GHOST_GetCursorPosition(g_system, &wx, &wy);
609                                 
610                                 GHOST_ScreenToClient(win->ghostwin, wx, wy, &cx, &cy);
611                                 win->eventstate->x= cx;
612
613 #if defined(__APPLE__) && defined(GHOST_COCOA)
614                                 //Cocoa already uses coordinates with y=0 at bottom
615                                 win->eventstate->y= cy;
616 #else
617                                 win->eventstate->y= (win->sizey-1) - cy;
618 #endif
619                                 
620                                 wm_window_make_drawable(C, win);
621                                 break;
622                         }
623                         case GHOST_kEventWindowClose: {
624                                 wm_window_close(C, wm, win);
625                                 break;
626                         }
627                         case GHOST_kEventWindowUpdate: {
628                                 if(G.f & G_DEBUG) printf("ghost redraw\n");
629                                 
630                                 wm_window_make_drawable(C, win);
631                                 WM_event_add_notifier(C, NC_WINDOW, NULL);
632
633                                 break;
634                         }
635                         case GHOST_kEventWindowSize:
636                         case GHOST_kEventWindowMove: {
637                                 GHOST_TWindowState state;
638                                 state = GHOST_GetWindowState(win->ghostwin);
639
640                                  /* win32: gives undefined window size when minimized */
641                                 if(state!=GHOST_kWindowStateMinimized) {
642                                         GHOST_RectangleHandle client_rect;
643                                         int l, t, r, b, scr_w, scr_h;
644                                         int sizex, sizey, posx, posy;
645                                         
646                                         client_rect= GHOST_GetClientBounds(win->ghostwin);
647                                         GHOST_GetRectangle(client_rect, &l, &t, &r, &b);
648                                         
649                                         GHOST_DisposeRectangle(client_rect);
650                                         
651                                         wm_get_screensize(&scr_w, &scr_h);
652                                         sizex= r-l;
653                                         sizey= b-t;
654                                         posx= l;
655                                         posy= scr_h - t - win->sizey;
656
657                                         /*
658                                          * Ghost sometimes send size or move events when the window hasn't changed.
659                                          * One case of this is using compiz on linux. To alleviate the problem
660                                          * we ignore all such event here.
661                                          * 
662                                          * It might be good to eventually do that at Ghost level, but that is for 
663                                          * another time.
664                                          */
665                                         if (win->sizex != sizex ||
666                                                         win->sizey != sizey ||
667                                                         win->posx != posx ||
668                                                         win->posy != posy)
669                                         {
670                                                 win->sizex= sizex;
671                                                 win->sizey= sizey;
672                                                 win->posx= posx;
673                                                 win->posy= posy;
674         
675                                                 /* debug prints */
676                                                 if(0) {
677                                                         state = GHOST_GetWindowState(win->ghostwin);
678         
679                                                         if(state==GHOST_kWindowStateNormal) {
680                                                                 if(G.f & G_DEBUG) printf("window state: normal\n");
681                                                         }
682                                                         else if(state==GHOST_kWindowStateMinimized) {
683                                                                 if(G.f & G_DEBUG) printf("window state: minimized\n");
684                                                         }
685                                                         else if(state==GHOST_kWindowStateMaximized) {
686                                                                 if(G.f & G_DEBUG) printf("window state: maximized\n");
687                                                         }
688                                                         else if(state==GHOST_kWindowStateFullScreen) {
689                                                                 if(G.f & G_DEBUG) printf("window state: fullscreen\n");
690                                                         }
691                                                         
692                                                         if(type!=GHOST_kEventWindowSize) {
693                                                                 if(G.f & G_DEBUG) printf("win move event pos %d %d size %d %d\n", win->posx, win->posy, win->sizex, win->sizey);
694                                                         }
695                                                         
696                                                 }
697                                         
698                                                 wm_window_make_drawable(C, win);
699                                                 wm_draw_window_clear(win);
700                                                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
701                                         }
702                                 }
703                                 break;
704                         }
705                         default:
706                                 wm_event_add_ghostevent(win, type, data);
707                                 break;
708                 }
709
710         }
711         return 1;
712 }
713
714
715 /* This timer system only gives maximum 1 timer event per redraw cycle,
716    to prevent queues to get overloaded. 
717    Timer handlers should check for delta to decide if they just
718    update, or follow real time.
719    Timer handlers can also set duration to match frames passed
720 */
721 static int wm_window_timer(const bContext *C)
722 {
723         wmWindowManager *wm= CTX_wm_manager(C);
724         wmTimer *wt, *wtnext;
725         wmWindow *win;
726         double time= PIL_check_seconds_timer();
727         int retval= 0;
728         
729         for(wt= wm->timers.first; wt; wt= wtnext) {
730                 wtnext= wt->next; /* in case timer gets removed */
731                 win= wt->win;
732
733                 if(wt->sleep==0) {
734                         if(time > wt->ntime) {
735                                 wt->delta= time - wt->ltime;
736                                 wt->duration += wt->delta;
737                                 wt->ltime= time;
738                                 wt->ntime= wt->stime + wt->timestep*ceil(wt->duration/wt->timestep);
739
740                                 if(wt->event_type == TIMERJOBS)
741                                         wm_jobs_timer(C, wm, wt);
742                                 else if(wt->event_type == TIMERAUTOSAVE)
743                                         wm_autosave_timer(C, wm, wt);
744                                 else if(win) {
745                                         wmEvent event= *(win->eventstate);
746                                         
747                                         event.type= wt->event_type;
748                                         event.custom= EVT_DATA_TIMER;
749                                         event.customdata= wt;
750                                         wm_event_add(win, &event);
751
752                                         retval= 1;
753                                 }
754                         }
755                 }
756         }
757         return retval;
758 }
759
760 void wm_window_process_events(const bContext *C) 
761 {
762         int hasevent= GHOST_ProcessEvents(g_system, 0); /* 0 is no wait */
763         
764         if(hasevent)
765                 GHOST_DispatchEvents(g_system);
766         
767         hasevent |= wm_window_timer(C);
768
769         /* no event, we sleep 5 milliseconds */
770         if(hasevent==0)
771                 PIL_sleep_ms(5);
772 }
773
774 void wm_window_process_events_nosleep(const bContext *C) 
775 {
776         if(GHOST_ProcessEvents(g_system, 0))
777                 GHOST_DispatchEvents(g_system);
778 }
779
780 /* exported as handle callback to bke blender.c */
781 void wm_window_testbreak(void)
782 {
783         static double ltime= 0;
784         double curtime= PIL_check_seconds_timer();
785         
786         /* only check for breaks every 50 milliseconds
787                 * if we get called more often.
788                 */
789         if ((curtime-ltime)>.05) {
790                 int hasevent= GHOST_ProcessEvents(g_system, 0); /* 0 is no wait */
791                 
792                 if(hasevent)
793                         GHOST_DispatchEvents(g_system);
794                 
795                 ltime= curtime;
796         }
797 }
798
799 /* **************** init ********************** */
800
801 void wm_ghost_init(bContext *C)
802 {
803         if (!g_system) {
804                 GHOST_EventConsumerHandle consumer= GHOST_CreateEventConsumer(ghost_event_proc, C);
805                 
806                 g_system= GHOST_CreateSystem();
807                 GHOST_AddEventConsumer(g_system, consumer);
808         }       
809 }
810
811 void wm_ghost_exit(void)
812 {
813         if(g_system)
814                 GHOST_DisposeSystem(g_system);
815
816         g_system= NULL;
817 }
818
819 /* **************** timer ********************** */
820
821 /* to (de)activate running timers temporary */
822 void WM_event_timer_sleep(wmWindowManager *wm, wmWindow *win, wmTimer *timer, int dosleep)
823 {
824         wmTimer *wt;
825         
826         for(wt= wm->timers.first; wt; wt= wt->next)
827                 if(wt==timer)
828                         break;
829
830         if(wt)
831                 wt->sleep= dosleep;
832 }
833
834 wmTimer *WM_event_add_timer(wmWindowManager *wm, wmWindow *win, int event_type, double timestep)
835 {
836         wmTimer *wt= MEM_callocN(sizeof(wmTimer), "window timer");
837         
838         wt->event_type= event_type;
839         wt->ltime= PIL_check_seconds_timer();
840         wt->ntime= wt->ltime + timestep;
841         wt->stime= wt->ltime;
842         wt->timestep= timestep;
843         wt->win= win;
844         
845         BLI_addtail(&wm->timers, wt);
846         
847         return wt;
848 }
849
850 void WM_event_remove_timer(wmWindowManager *wm, wmWindow *win, wmTimer *timer)
851 {
852         wmTimer *wt;
853         
854         /* extra security check */
855         for(wt= wm->timers.first; wt; wt= wt->next)
856                 if(wt==timer)
857                         break;
858         if(wt) {
859                 
860                 BLI_remlink(&wm->timers, wt);
861                 if(wt->customdata)
862                         MEM_freeN(wt->customdata);
863                 MEM_freeN(wt);
864         }
865 }
866
867 /* ******************* clipboard **************** */
868
869 char *WM_clipboard_text_get(int selection)
870 {
871         char *p, *p2, *buf, *newbuf;
872
873         buf= (char*)GHOST_getClipboard(selection);
874         if(!buf)
875                 return NULL;
876         
877         /* always convert from \r\n to \n */
878         newbuf= MEM_callocN(strlen(buf)+1, "WM_clipboard_text_get");
879
880         for(p= buf, p2= newbuf; *p; p++) {
881                 if(*p != '\r')
882                         *(p2++)= *p;
883         }
884         *p2= '\0';
885
886         free(buf); /* ghost uses regular malloc */
887         
888         return newbuf;
889 }
890
891 void WM_clipboard_text_set(char *buf, int selection)
892 {
893 #ifdef _WIN32
894         /* do conversion from \n to \r\n on Windows */
895         char *p, *p2, *newbuf;
896         int newlen= 0;
897         
898         for(p= buf; *p; p++) {
899                 if(*p == '\n')
900                         newlen += 2;
901                 else
902                         newlen++;
903         }
904         
905         newbuf= MEM_callocN(newlen+1, "WM_clipboard_text_set");
906
907         for(p= buf, p2= newbuf; *p; p++, p2++) {
908                 if(*p == '\n') { 
909                         *(p2++)= '\r'; *p2= '\n';
910                 }
911                 else *p2= *p;
912         }
913         *p2= '\0';
914
915         GHOST_putClipboard((GHOST_TInt8*)newbuf, selection);
916         MEM_freeN(newbuf);
917 #else
918         GHOST_putClipboard((GHOST_TInt8*)buf, selection);
919 #endif
920 }
921
922 /* ************************************ */
923
924 void wm_window_get_position(wmWindow *win, int *posx_r, int *posy_r) 
925 {
926         *posx_r= win->posx;
927         *posy_r= win->posy;
928 }
929
930 void wm_window_get_size(wmWindow *win, int *width_r, int *height_r) 
931 {
932         *width_r= win->sizex;
933         *height_r= win->sizey;
934 }
935
936 void wm_window_set_size(wmWindow *win, int width, int height) 
937 {
938         GHOST_SetClientSize(win->ghostwin, width, height);
939 }
940
941 void wm_window_lower(wmWindow *win) 
942 {
943         GHOST_SetWindowOrder(win->ghostwin, GHOST_kWindowOrderBottom);
944 }
945
946 void wm_window_raise(wmWindow *win) 
947 {
948         GHOST_SetWindowOrder(win->ghostwin, GHOST_kWindowOrderTop);
949 }
950
951 void wm_window_swap_buffers(wmWindow *win)
952 {
953         
954 #ifdef WIN32
955         glDisable(GL_SCISSOR_TEST);
956         GHOST_SwapWindowBuffers(win->ghostwin);
957         glEnable(GL_SCISSOR_TEST);
958 #else
959         GHOST_SwapWindowBuffers(win->ghostwin);
960 #endif
961 }
962
963 /* ******************* exported api ***************** */
964
965
966 /* called whem no ghost system was initialized */
967 void WM_setprefsize(int stax, int stay, int sizx, int sizy)
968 {
969         prefstax= stax;
970         prefstay= stay;
971         prefsizx= sizx;
972         prefsizy= sizy;
973 }
974