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