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