Cleanup: use r_* prefix for return args
[blender.git] / source / blender / windowmanager / intern / wm_window.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2007 Blender Foundation but based 
19  * on ghostwinlay.c (C) 2001-2002 by NaN Holding BV
20  * All rights reserved.
21  *
22  * Contributor(s): Blender Foundation, 2008
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file blender/windowmanager/intern/wm_window.c
28  *  \ingroup wm
29  *
30  * Window management, wrap GHOST.
31  */
32
33 #include <math.h>
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <string.h>
37
38 #include "DNA_listBase.h"       
39 #include "DNA_screen_types.h"
40 #include "DNA_windowmanager_types.h"
41
42 #include "MEM_guardedalloc.h"
43
44 #include "GHOST_C-api.h"
45
46 #include "BLI_math.h"
47 #include "BLI_blenlib.h"
48 #include "BLI_utildefines.h"
49
50 #include "BLF_translation.h"
51
52 #include "BKE_blender.h"
53 #include "BKE_context.h"
54 #include "BKE_library.h"
55 #include "BKE_global.h"
56 #include "BKE_main.h"
57
58
59 #include "RNA_access.h"
60
61 #include "WM_api.h"
62 #include "WM_types.h"
63 #include "wm.h"
64 #include "wm_draw.h"
65 #include "wm_window.h"
66 #include "wm_subwindow.h"
67 #include "wm_event_system.h"
68
69 #include "ED_screen.h"
70 #include "ED_fileselect.h"
71
72 #include "PIL_time.h"
73
74 #include "GPU_draw.h"
75 #include "GPU_extensions.h"
76 #include "GPU_init_exit.h"
77 #include "GPU_glew.h"
78
79 #include "UI_interface.h"
80
81 /* for assert */
82 #ifndef NDEBUG
83 #  include "BLI_threads.h"
84 #endif
85
86 /* the global to talk to ghost */
87 static GHOST_SystemHandle g_system = NULL;
88
89 typedef enum WinOverrideFlag {
90         WIN_OVERRIDE_GEOM     = (1 << 0),
91         WIN_OVERRIDE_WINSTATE = (1 << 1)
92 } WinOverrideFlag;
93
94 /* set by commandline */
95 static struct WMInitStruct {
96         /* window geometry */
97         int size_x, size_y;
98         int start_x, start_y;
99
100         int windowstate;
101         WinOverrideFlag override_flag;
102         
103         bool native_pixels;
104 } wm_init_state = {0, 0, 0, 0, GHOST_kWindowStateNormal, 0, true};
105
106 /* ******** win open & close ************ */
107
108 /* XXX this one should correctly check for apple top header...
109  * done for Cocoa : returns window contents (and not frame) max size*/
110 void wm_get_screensize(int *r_width, int *r_height)
111 {
112         unsigned int uiwidth;
113         unsigned int uiheight;
114         
115         GHOST_GetMainDisplayDimensions(g_system, &uiwidth, &uiheight);
116         *r_width = uiwidth;
117         *r_height = uiheight;
118 }
119
120 /* size of all screens (desktop), useful since the mouse is bound by this */
121 void wm_get_desktopsize(int *r_width, int *r_height)
122 {
123         unsigned int uiwidth;
124         unsigned int uiheight;
125
126         GHOST_GetAllDisplayDimensions(g_system, &uiwidth, &uiheight);
127         *r_width = uiwidth;
128         *r_height = uiheight;
129 }
130
131 /* keeps offset and size within monitor bounds */
132 /* XXX solve dual screen... */
133 static void wm_window_check_position(rcti *rect)
134 {
135         int width, height, d;
136         
137         wm_get_screensize(&width, &height);
138         
139         if (rect->xmin < 0) {
140                 rect->xmax -= rect->xmin;
141                 rect->xmin  = 0;
142         }
143         if (rect->ymin < 0) {
144                 rect->ymax -= rect->ymin;
145                 rect->ymin  = 0;
146         }
147         if (rect->xmax > width) {
148                 d = rect->xmax - width;
149                 rect->xmax -= d;
150                 rect->xmin -= d;
151         }
152         if (rect->ymax > height) {
153                 d = rect->ymax - height;
154                 rect->ymax -= d;
155                 rect->ymin -= d;
156         }
157         
158         if (rect->xmin < 0) rect->xmin = 0;
159         if (rect->ymin < 0) rect->ymin = 0;
160 }
161
162
163 static void wm_ghostwindow_destroy(wmWindow *win) 
164 {
165         if (win->ghostwin) {
166                 GHOST_DisposeWindow(g_system, win->ghostwin);
167                 win->ghostwin = NULL;
168         }
169 }
170
171 /* including window itself, C can be NULL. 
172  * ED_screen_exit should have been called */
173 void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win)
174 {
175         wmTimer *wt, *wtnext;
176         
177         /* update context */
178         if (C) {
179                 WM_event_remove_handlers(C, &win->handlers);
180                 WM_event_remove_handlers(C, &win->modalhandlers);
181
182                 if (CTX_wm_window(C) == win)
183                         CTX_wm_window_set(C, NULL);
184         }
185
186         /* always set drawable and active to NULL,
187          * prevents non-drawable state of main windows (bugs #22967 and #25071, possibly #22477 too) */
188         wm->windrawable = NULL;
189         wm->winactive = NULL;
190
191         /* end running jobs, a job end also removes its timer */
192         for (wt = wm->timers.first; wt; wt = wtnext) {
193                 wtnext = wt->next;
194                 if (wt->win == win && wt->event_type == TIMERJOBS)
195                         wm_jobs_timer_ended(wm, wt);
196         }
197         
198         /* timer removing, need to call this api function */
199         for (wt = wm->timers.first; wt; wt = wtnext) {
200                 wtnext = wt->next;
201                 if (wt->win == win)
202                         WM_event_remove_timer(wm, win, wt);
203         }
204
205         if (win->eventstate) MEM_freeN(win->eventstate);
206         
207         wm_event_free_all(win);
208         wm_subwindows_free(win);
209
210         wm_draw_data_free(win);
211
212         wm_ghostwindow_destroy(win);
213
214         MEM_freeN(win->stereo3d_format);
215
216         MEM_freeN(win);
217 }
218
219 static int find_free_winid(wmWindowManager *wm)
220 {
221         wmWindow *win;
222         int id = 1;
223         
224         for (win = wm->windows.first; win; win = win->next)
225                 if (id <= win->winid)
226                         id = win->winid + 1;
227         
228         return id;
229 }
230
231 /* don't change context itself */
232 wmWindow *wm_window_new(bContext *C)
233 {
234         wmWindowManager *wm = CTX_wm_manager(C);
235         wmWindow *win = MEM_callocN(sizeof(wmWindow), "window");
236         
237         BLI_addtail(&wm->windows, win);
238         win->winid = find_free_winid(wm);
239
240         win->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Stereo 3D Format (window)");
241
242         return win;
243 }
244
245
246 /* part of wm_window.c api */
247 wmWindow *wm_window_copy(bContext *C, wmWindow *winorig)
248 {
249         wmWindow *win = wm_window_new(C);
250         
251         win->posx = winorig->posx + 10;
252         win->posy = winorig->posy;
253         win->sizex = winorig->sizex;
254         win->sizey = winorig->sizey;
255         
256         /* duplicate assigns to window */
257         win->screen = ED_screen_duplicate(win, winorig->screen);
258         BLI_strncpy(win->screenname, win->screen->id.name + 2, sizeof(win->screenname));
259         win->screen->winid = win->winid;
260
261         win->screen->do_refresh = true;
262         win->screen->do_draw = true;
263
264         win->drawmethod = U.wmdrawmethod;
265
266         BLI_listbase_clear(&win->drawdata);
267
268         *win->stereo3d_format = *winorig->stereo3d_format;
269
270         return win;
271 }
272
273 /* this is event from ghost, or exit-blender op */
274 void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win)
275 {
276         wmWindow *tmpwin;
277         bool do_exit = false;
278         
279         /* first check if we have to quit (there are non-temp remaining windows) */
280         for (tmpwin = wm->windows.first; tmpwin; tmpwin = tmpwin->next) {
281                 if (tmpwin == win)
282                         continue;
283                 if (tmpwin->screen->temp == 0)
284                         break;
285         }
286
287         if (tmpwin == NULL)
288                 do_exit = 1;
289         
290         if ((U.uiflag & USER_QUIT_PROMPT) && !wm->file_saved) {
291                 if (do_exit) {
292                         if (!GHOST_confirmQuit(win->ghostwin))
293                                 return;
294                 }
295         }
296
297         /* let WM_exit do all freeing, for correct quit.blend save */
298         if (do_exit) {
299                 WM_exit(C);
300         }
301         else {
302                 bScreen *screen = win->screen;
303                 
304                 BLI_remlink(&wm->windows, win);
305                 
306                 wm_draw_window_clear(win);
307                 
308                 CTX_wm_window_set(C, win);  /* needed by handlers */
309                 WM_event_remove_handlers(C, &win->handlers);
310                 WM_event_remove_handlers(C, &win->modalhandlers);
311                 ED_screen_exit(C, win, win->screen); 
312                 
313                 wm_window_free(C, wm, win);
314         
315                 /* if temp screen, delete it after window free (it stops jobs that can access it) */
316                 if (screen->temp) {
317                         Main *bmain = CTX_data_main(C);
318                         BKE_libblock_free(bmain, screen);
319                 }
320         }               
321 }
322
323 void wm_window_title(wmWindowManager *wm, wmWindow *win)
324 {
325         if (win->screen && win->screen->temp) {
326                 /* nothing to do for 'temp' windows,
327                  * because WM_window_open_temp always sets window title  */
328         }
329         else if (win->ghostwin) {
330                 /* this is set to 1 if you don't have startup.blend open */
331                 if (G.save_over && G.main->name[0]) {
332                         char str[sizeof(G.main->name) + 24];
333                         BLI_snprintf(str, sizeof(str), "Blender%s [%s%s]", wm->file_saved ? "" : "*", G.main->name,
334                                      G.main->recovered ? " (Recovered)" : "");
335                         GHOST_SetTitle(win->ghostwin, str);
336                 }
337                 else
338                         GHOST_SetTitle(win->ghostwin, "Blender");
339
340                 /* Informs GHOST of unsaved changes, to set window modified visual indicator (MAC OS X)
341                  * and to give hint of unsaved changes for a user warning mechanism
342                  * in case of OS application terminate request (e.g. OS Shortcut Alt+F4, Cmd+Q, (...), or session end) */
343                 GHOST_SetWindowModifiedState(win->ghostwin, (GHOST_TUns8) !wm->file_saved);
344                 
345         }
346 }
347
348 float wm_window_pixelsize(wmWindow *win)
349 {
350         float pixelsize = GHOST_GetNativePixelSize(win->ghostwin);
351         
352         switch (U.virtual_pixel) {
353                 default:
354                 case VIRTUAL_PIXEL_NATIVE:
355                         return pixelsize;
356                 case VIRTUAL_PIXEL_DOUBLE:
357                         return 2.0f * pixelsize;
358         }
359 }
360
361 /* belongs to below */
362 static void wm_window_add_ghostwindow(wmWindowManager *wm, const char *title, wmWindow *win)
363 {
364         GHOST_WindowHandle ghostwin;
365         GHOST_GLSettings glSettings = {0};
366         static int multisamples = -1;
367         int scr_w, scr_h, posy;
368         
369         /* force setting multisamples only once, it requires restart - and you cannot 
370          * mix it, either all windows have it, or none (tested in OSX opengl) */
371         if (multisamples == -1)
372                 multisamples = U.ogl_multisamples;
373
374         glSettings.numOfAASamples = multisamples;
375
376         /* a new window is created when pageflip mode is required for a window */
377         if (win->stereo3d_format->display_mode == S3D_DISPLAY_PAGEFLIP)
378                 glSettings.flags |= GHOST_glStereoVisual;
379
380         if (!(U.uiflag2 & USER_OPENGL_NO_WARN_SUPPORT))
381                 glSettings.flags |= GHOST_glWarnSupport;
382
383         wm_get_screensize(&scr_w, &scr_h);
384         posy = (scr_h - win->posy - win->sizey);
385         
386         ghostwin = GHOST_CreateWindow(g_system, title,
387                                       win->posx, posy, win->sizex, win->sizey,
388                                       (GHOST_TWindowState)win->windowstate,
389                                       GHOST_kDrawingContextTypeOpenGL,
390                                       glSettings);
391         
392         if (ghostwin) {
393                 GHOST_RectangleHandle bounds;
394                 
395                 /* the new window has already been made drawable upon creation */
396                 wm->windrawable = win;
397
398                 /* needed so we can detect the graphics card below */
399                 GPU_init();
400                 
401                 win->ghostwin = ghostwin;
402                 GHOST_SetWindowUserData(ghostwin, win); /* pointer back */
403                 
404                 if (win->eventstate == NULL)
405                         win->eventstate = MEM_callocN(sizeof(wmEvent), "window event state");
406                 
407 #ifdef __APPLE__
408                 /* set the state here, else OSX would not recognize changed screen resolution */
409                 /* we agreed to not set any fullscreen or iconized state on startup */
410                 GHOST_SetWindowState(ghostwin, GHOST_kWindowStateNormal);
411 #endif
412                 /* store actual window size in blender window */
413                 bounds = GHOST_GetClientBounds(win->ghostwin);
414                 win->sizex = GHOST_GetWidthRectangle(bounds);
415                 win->sizey = GHOST_GetHeightRectangle(bounds);
416                 GHOST_DisposeRectangle(bounds);
417                 
418 #ifndef __APPLE__
419                 /* set the state here, so minimized state comes up correct on windows */
420                 GHOST_SetWindowState(ghostwin, (GHOST_TWindowState)win->windowstate);
421 #endif
422                 /* until screens get drawn, make it nice gray */
423                 glClearColor(0.55, 0.55, 0.55, 0.0);
424                 /* Crash on OSS ATI: bugs.launchpad.net/ubuntu/+source/mesa/+bug/656100 */
425                 if (!GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE)) {
426                         glClear(GL_COLOR_BUFFER_BIT);
427                 }
428                 
429                 /* displays with larger native pixels, like Macbook. Used to scale dpi with */
430                 /* needed here, because it's used before it reads userdef */
431                 U.pixelsize = wm_window_pixelsize(win);
432                 BKE_userdef_state();
433                 
434                 wm_window_swap_buffers(win);
435                 
436                 //GHOST_SetWindowState(ghostwin, GHOST_kWindowStateModified);
437                 
438                 /* standard state vars for window */
439                 glEnable(GL_SCISSOR_TEST);
440                 GPU_state_init();
441         }
442 }
443
444 /* for wmWindows without ghostwin, open these and clear */
445 /* window size is read from window, if 0 it uses prefsize */
446 /* called in WM_check, also inits stuff after file read */
447 void wm_window_add_ghostwindows(wmWindowManager *wm)
448 {
449         wmKeyMap *keymap;
450         wmWindow *win;
451         
452         /* no commandline prefsize? then we set this.
453          * Note that these values will be used only
454          * when there is no startup.blend yet.
455          */
456         if (wm_init_state.size_x == 0) {
457                 wm_get_screensize(&wm_init_state.size_x, &wm_init_state.size_y);
458                 
459         /* note!, this isnt quite correct, active screen maybe offset 1000s if PX,
460          * we'd need a wm_get_screensize like function that gives offset,
461          * in practice the window manager will likely move to the correct monitor */
462         wm_init_state.start_x = 0;
463         wm_init_state.start_y = 0;
464
465 #ifdef WITH_X11 /* X11 */
466                 /* X11, start maximized but use default sane size */
467                 wm_init_state.size_x = min_ii(wm_init_state.size_x, WM_WIN_INIT_SIZE_X);
468                 wm_init_state.size_y = min_ii(wm_init_state.size_y, WM_WIN_INIT_SIZE_Y);
469                 /* pad */
470                 wm_init_state.start_x = WM_WIN_INIT_PAD;
471                 wm_init_state.start_y = WM_WIN_INIT_PAD;
472                 wm_init_state.size_x -= WM_WIN_INIT_PAD * 2;
473                 wm_init_state.size_y -= WM_WIN_INIT_PAD * 2;
474 #endif
475         }
476         
477         for (win = wm->windows.first; win; win = win->next) {
478                 if (win->ghostwin == NULL) {
479                         if ((win->sizex == 0) || (wm_init_state.override_flag & WIN_OVERRIDE_GEOM)) {
480                                 win->posx = wm_init_state.start_x;
481                                 win->posy = wm_init_state.start_y;
482                                 win->sizex = wm_init_state.size_x;
483                                 win->sizey = wm_init_state.size_y;
484
485                                 win->windowstate = GHOST_kWindowStateNormal;
486                                 wm_init_state.override_flag &= ~WIN_OVERRIDE_GEOM;
487                         }
488
489                         if (wm_init_state.override_flag & WIN_OVERRIDE_WINSTATE) {
490                                 win->windowstate = wm_init_state.windowstate;
491                                 wm_init_state.override_flag &= ~WIN_OVERRIDE_WINSTATE;
492                         }
493
494                         wm_window_add_ghostwindow(wm, "Blender", win);
495                 }
496                 /* happens after fileread */
497                 if (win->eventstate == NULL)
498                         win->eventstate = MEM_callocN(sizeof(wmEvent), "window event state");
499
500                 /* add keymap handlers (1 handler for all keys in map!) */
501                 keymap = WM_keymap_find(wm->defaultconf, "Window", 0, 0);
502                 WM_event_add_keymap_handler(&win->handlers, keymap);
503                 
504                 keymap = WM_keymap_find(wm->defaultconf, "Screen", 0, 0);
505                 WM_event_add_keymap_handler(&win->handlers, keymap);
506
507                 keymap = WM_keymap_find(wm->defaultconf, "Screen Editing", 0, 0);
508                 WM_event_add_keymap_handler(&win->modalhandlers, keymap);
509                 
510                 /* add drop boxes */
511                 {
512                         ListBase *lb = WM_dropboxmap_find("Window", 0, 0);
513                         WM_event_add_dropbox_handler(&win->handlers, lb);
514                 }
515                 wm_window_title(wm, win);
516         }
517 }
518
519 /* new window, no screen yet, but we open ghostwindow for it */
520 /* also gets the window level handlers */
521 /* area-rip calls this */
522 wmWindow *WM_window_open(bContext *C, const rcti *rect)
523 {
524         wmWindow *win = wm_window_new(C);
525         
526         win->posx = rect->xmin;
527         win->posy = rect->ymin;
528         win->sizex = BLI_rcti_size_x(rect);
529         win->sizey = BLI_rcti_size_y(rect);
530
531         win->drawmethod = U.wmdrawmethod;
532
533         WM_check(C);
534         
535         return win;
536 }
537
538 /* uses screen->temp tag to define what to do, currently it limits
539  * to only one "temp" window for render out, preferences, filewindow, etc */
540 /* type is defined in WM_api.h */
541
542 void WM_window_open_temp(bContext *C, rcti *position, int type)
543 {
544         wmWindow *win;
545         ScrArea *sa;
546         Scene *scene = CTX_data_scene(C);
547         
548         /* changes rect to fit within desktop */
549         wm_window_check_position(position);
550         
551         /* test if we have a temp screen already */
552         for (win = CTX_wm_manager(C)->windows.first; win; win = win->next)
553                 if (win->screen->temp)
554                         break;
555         
556         /* add new window? */
557         if (win == NULL) {
558                 win = wm_window_new(C);
559                 
560                 win->posx = position->xmin;
561                 win->posy = position->ymin;
562         }
563         
564         win->sizex = BLI_rcti_size_x(position);
565         win->sizey = BLI_rcti_size_y(position);
566         
567         if (win->ghostwin) {
568                 wm_window_set_size(win, win->sizex, win->sizey);
569                 wm_window_raise(win);
570         }
571         
572         if (win->screen == NULL) {
573                 /* add new screen */
574                 win->screen = ED_screen_add(win, scene, "temp");
575         }
576         else {
577                 /* switch scene for rendering */
578                 if (win->screen->scene != scene)
579                         ED_screen_set_scene(C, win->screen, scene);
580         }
581
582         win->screen->temp = 1; 
583         
584         /* make window active, and validate/resize */
585         CTX_wm_window_set(C, win);
586         WM_check(C);
587         
588         /* ensure it shows the right spacetype editor */
589         sa = win->screen->areabase.first;
590         CTX_wm_area_set(C, sa);
591         
592         if (type == WM_WINDOW_RENDER) {
593                 ED_area_newspace(C, sa, SPACE_IMAGE);
594         }
595         else {
596                 ED_area_newspace(C, sa, SPACE_USERPREF);
597         }
598         
599         ED_screen_set(C, win->screen);
600         ED_screen_refresh(CTX_wm_manager(C), win); /* test scale */
601         
602         if (sa->spacetype == SPACE_IMAGE)
603                 GHOST_SetTitle(win->ghostwin, IFACE_("Blender Render"));
604         else if (ELEM(sa->spacetype, SPACE_OUTLINER, SPACE_USERPREF))
605                 GHOST_SetTitle(win->ghostwin, IFACE_("Blender User Preferences"));
606         else if (sa->spacetype == SPACE_FILE)
607                 GHOST_SetTitle(win->ghostwin, IFACE_("Blender File View"));
608         else
609                 GHOST_SetTitle(win->ghostwin, "Blender");
610 }
611
612
613 /* ****************** Operators ****************** */
614
615 /* operator callback */
616 int wm_window_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
617 {
618         wm_window_copy(C, CTX_wm_window(C));
619         WM_check(C);
620         
621         WM_event_add_notifier(C, NC_WINDOW | NA_ADDED, NULL);
622         
623         return OPERATOR_FINISHED;
624 }
625
626
627 /* fullscreen operator callback */
628 int wm_window_fullscreen_toggle_exec(bContext *C, wmOperator *UNUSED(op))
629 {
630         wmWindow *window = CTX_wm_window(C);
631         GHOST_TWindowState state;
632
633         if (G.background)
634                 return OPERATOR_CANCELLED;
635
636         state = GHOST_GetWindowState(window->ghostwin);
637         if (state != GHOST_kWindowStateFullScreen)
638                 GHOST_SetWindowState(window->ghostwin, GHOST_kWindowStateFullScreen);
639         else
640                 GHOST_SetWindowState(window->ghostwin, GHOST_kWindowStateNormal);
641
642         return OPERATOR_FINISHED;
643         
644 }
645
646
647 /* ************ events *************** */
648
649 static void wm_convert_cursor_position(wmWindow *win, int *x, int *y)
650 {
651         float fac = GHOST_GetNativePixelSize(win->ghostwin);
652         
653         GHOST_ScreenToClient(win->ghostwin, *x, *y, x, y);
654         *x *= fac;
655         
656         *y = (win->sizey - 1) - *y;
657         *y *= fac;
658 }
659
660
661 void wm_get_cursor_position(wmWindow *win, int *x, int *y)
662 {
663         GHOST_GetCursorPosition(g_system, x, y);
664         wm_convert_cursor_position(win, x, y);
665 }
666
667 typedef enum {
668         SHIFT    = 's',
669         CONTROL  = 'c',
670         ALT      = 'a',
671         OS       = 'C'
672 } modifierKeyType;
673
674 /* check if specified modifier key type is pressed */
675 static int query_qual(modifierKeyType qual) 
676 {
677         GHOST_TModifierKeyMask left, right;
678         int val = 0;
679         
680         switch (qual) {
681                 case SHIFT:
682                         left = GHOST_kModifierKeyLeftShift;
683                         right = GHOST_kModifierKeyRightShift;
684                         break;
685                 case CONTROL:
686                         left = GHOST_kModifierKeyLeftControl;
687                         right = GHOST_kModifierKeyRightControl;
688                         break;
689                 case OS:
690                         left = right = GHOST_kModifierKeyOS;
691                         break;
692                 case ALT:
693                 default:
694                         left = GHOST_kModifierKeyLeftAlt;
695                         right = GHOST_kModifierKeyRightAlt;
696                         break;
697         }
698         
699         GHOST_GetModifierKeyState(g_system, left, &val);
700         if (!val)
701                 GHOST_GetModifierKeyState(g_system, right, &val);
702         
703         return val;
704 }
705
706 void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win) 
707 {
708         if (win != wm->windrawable && win->ghostwin) {
709 //              win->lmbut = 0; /* keeps hanging when mousepressed while other window opened */
710                 
711                 wm->windrawable = win;
712                 if (G.debug & G_DEBUG_EVENTS) {
713                         printf("%s: set drawable %d\n", __func__, win->winid);
714                 }
715                 GHOST_ActivateWindowDrawingContext(win->ghostwin);
716                 
717                 /* this can change per window */
718                 U.pixelsize = wm_window_pixelsize(win);
719                 BKE_userdef_state();
720         }
721 }
722
723 /* called by ghost, here we handle events for windows themselves or send to event system */
724 /* mouse coordinate converversion happens here */
725 static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr)
726 {
727         bContext *C = C_void_ptr;
728         wmWindowManager *wm = CTX_wm_manager(C);
729         GHOST_TEventType type = GHOST_GetEventType(evt);
730         int time = GHOST_GetEventTime(evt);
731         
732         if (type == GHOST_kEventQuit) {
733                 WM_exit(C);
734         }
735         else {
736                 GHOST_WindowHandle ghostwin = GHOST_GetEventWindow(evt);
737                 GHOST_TEventDataPtr data = GHOST_GetEventData(evt);
738                 wmWindow *win;
739                 
740                 /* Ghost now can call this function for life resizes, but it should return if WM didn't initialize yet.
741                  * Can happen on file read (especially full size window)  */
742                 if ((wm->initialized & WM_INIT_WINDOW) == 0) {
743                         return 1;
744                 }
745                 if (!ghostwin) {
746                         /* XXX - should be checked, why are we getting an event here, and */
747                         /* what is it? */
748                         puts("<!> event has no window");
749                         return 1;
750                 }
751                 else if (!GHOST_ValidWindow(g_system, ghostwin)) {
752                         /* XXX - should be checked, why are we getting an event here, and */
753                         /* what is it? */
754                         puts("<!> event has invalid window");
755                         return 1;
756                 }
757                 else {
758                         win = GHOST_GetWindowUserData(ghostwin);
759                 }
760                 
761                 switch (type) {
762                         case GHOST_kEventWindowDeactivate:
763                                 wm_event_add_ghostevent(wm, win, type, time, data);
764                                 win->active = 0; /* XXX */
765                                 
766                                 /* clear modifiers for inactive windows */
767                                 win->eventstate->alt = 0;
768                                 win->eventstate->ctrl = 0;
769                                 win->eventstate->shift = 0;
770                                 win->eventstate->oskey = 0;
771                                 win->eventstate->keymodifier = 0;
772
773                                 break;
774                         case GHOST_kEventWindowActivate: 
775                         {
776                                 GHOST_TEventKeyData kdata;
777                                 wmEvent event;
778                                 int wx, wy;
779                                 const int keymodifier = ((query_qual(SHIFT)     ? KM_SHIFT : 0) |
780                                                          (query_qual(CONTROL)   ? KM_CTRL  : 0) |
781                                                          (query_qual(ALT)       ? KM_ALT   : 0) |
782                                                          (query_qual(OS)        ? KM_OSKEY : 0));
783
784                                 /* Win23/GHOST modifier bug, see T40317 */
785 #ifndef WIN32
786 //#  define USE_WIN_ACTIVATE
787 #endif
788
789                                 wm->winactive = win; /* no context change! c->wm->windrawable is drawable, or for area queues */
790                                 
791                                 win->active = 1;
792 //                              window_handle(win, INPUTCHANGE, win->active);
793                                 
794                                 /* bad ghost support for modifier keys... so on activate we set the modifiers again */
795
796                                 /* TODO: This is not correct since a modifier may be held when a window is activated...
797                                  * better solve this at ghost level. attempted fix r54450 but it caused bug [#34255]
798                                  *
799                                  * For now don't send GHOST_kEventKeyDown events, just set the 'eventstate'.
800                                  */
801                                 kdata.ascii = '\0';
802                                 kdata.utf8_buf[0] = '\0';
803
804                                 if (win->eventstate->shift) {
805                                         if ((keymodifier & KM_SHIFT) == 0) {
806                                                 kdata.key = GHOST_kKeyLeftShift;
807                                                 wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, time, &kdata);
808                                         }
809                                 }
810 #ifdef USE_WIN_ACTIVATE
811                                 else {
812                                         if (keymodifier & KM_SHIFT) {
813                                                 win->eventstate->shift = KM_MOD_FIRST;
814                                         }
815                                 }
816 #endif
817                                 if (win->eventstate->ctrl) {
818                                         if ((keymodifier & KM_CTRL) == 0) {
819                                                 kdata.key = GHOST_kKeyLeftControl;
820                                                 wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, time, &kdata);
821                                         }
822                                 }
823 #ifdef USE_WIN_ACTIVATE
824                                 else {
825                                         if (keymodifier & KM_CTRL) {
826                                                 win->eventstate->ctrl = KM_MOD_FIRST;
827                                         }
828                                 }
829 #endif
830                                 if (win->eventstate->alt) {
831                                         if ((keymodifier & KM_ALT) == 0) {
832                                                 kdata.key = GHOST_kKeyLeftAlt;
833                                                 wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, time, &kdata);
834                                         }
835                                 }
836 #ifdef USE_WIN_ACTIVATE
837                                 else {
838                                         if (keymodifier & KM_ALT) {
839                                                 win->eventstate->alt = KM_MOD_FIRST;
840                                         }
841                                 }
842 #endif
843                                 if (win->eventstate->oskey) {
844                                         if ((keymodifier & KM_OSKEY) == 0) {
845                                                 kdata.key = GHOST_kKeyOS;
846                                                 wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, time, &kdata);
847                                         }
848                                 }
849 #ifdef USE_WIN_ACTIVATE
850                                 else {
851                                         if (keymodifier & KM_OSKEY) {
852                                                 win->eventstate->oskey = KM_MOD_FIRST;
853                                         }
854                                 }
855 #endif
856
857 #undef USE_WIN_ACTIVATE
858
859
860                                 /* keymodifier zero, it hangs on hotkeys that open windows otherwise */
861                                 win->eventstate->keymodifier = 0;
862                                 
863                                 /* entering window, update mouse pos. but no event */
864                                 wm_get_cursor_position(win,  &wx, &wy);
865
866                                 win->eventstate->x = wx;
867                                 win->eventstate->y = wy;
868                                 
869                                 win->addmousemove = 1;   /* enables highlighted buttons */
870                                 
871                                 wm_window_make_drawable(wm, win);
872
873                                 /* window might be focused by mouse click in configuration of window manager
874                                  * when focus is not following mouse
875                                  * click could have been done on a button and depending on window manager settings
876                                  * click would be passed to blender or not, but in any case button under cursor
877                                  * should be activated, so at max next click on button without moving mouse
878                                  * would trigger it's handle function
879                                  * currently it seems to be common practice to generate new event for, but probably
880                                  * we'll need utility function for this? (sergey)
881                                  */
882                                 wm_event_init_from_window(win, &event);
883                                 event.type = MOUSEMOVE;
884                                 event.prevx = event.x;
885                                 event.prevy = event.y;
886
887                                 wm_event_add(win, &event);
888
889                                 break;
890                         }
891                         case GHOST_kEventWindowClose:
892                         {
893                                 wm_window_close(C, wm, win);
894                                 break;
895                         }
896                         case GHOST_kEventWindowUpdate:
897                         {
898                                 if (G.debug & G_DEBUG_EVENTS) {
899                                         printf("%s: ghost redraw %d\n", __func__, win->winid);
900                                 }
901                                 
902                                 wm_window_make_drawable(wm, win);
903                                 WM_event_add_notifier(C, NC_WINDOW, NULL);
904
905                                 break;
906                         }
907                         case GHOST_kEventWindowSize:
908                         case GHOST_kEventWindowMove:
909                         {
910                                 GHOST_TWindowState state;
911                                 state = GHOST_GetWindowState(win->ghostwin);
912                                 win->windowstate = state;
913
914                                 /* stop screencast if resize */
915                                 if (type == GHOST_kEventWindowSize) {
916                                         WM_jobs_stop(wm, win->screen, NULL);
917                                 }
918                                 
919                                 /* win32: gives undefined window size when minimized */
920                                 if (state != GHOST_kWindowStateMinimized) {
921                                         GHOST_RectangleHandle client_rect;
922                                         int l, t, r, b, scr_w, scr_h;
923                                         int sizex, sizey, posx, posy;
924                                         
925                                         client_rect = GHOST_GetClientBounds(win->ghostwin);
926                                         GHOST_GetRectangle(client_rect, &l, &t, &r, &b);
927                                         
928                                         GHOST_DisposeRectangle(client_rect);
929                                         
930                                         wm_get_desktopsize(&scr_w, &scr_h);
931                                         sizex = r - l;
932                                         sizey = b - t;
933                                         posx = l;
934                                         posy = scr_h - t - win->sizey;
935
936                                         /*
937                                          * Ghost sometimes send size or move events when the window hasn't changed.
938                                          * One case of this is using compiz on linux. To alleviate the problem
939                                          * we ignore all such event here.
940                                          * 
941                                          * It might be good to eventually do that at Ghost level, but that is for 
942                                          * another time.
943                                          */
944                                         if (win->sizex != sizex ||
945                                             win->sizey != sizey ||
946                                             win->posx != posx ||
947                                             win->posy != posy)
948                                         {
949                                                 win->sizex = sizex;
950                                                 win->sizey = sizey;
951                                                 win->posx = posx;
952                                                 win->posy = posy;
953
954                                                 /* debug prints */
955                                                 if (G.debug & G_DEBUG_EVENTS) {
956                                                         const char *state_str;
957                                                         state = GHOST_GetWindowState(win->ghostwin);
958
959                                                         if (state == GHOST_kWindowStateNormal) {
960                                                                 state_str = "normal";
961                                                         }
962                                                         else if (state == GHOST_kWindowStateMinimized) {
963                                                                 state_str = "minimized";
964                                                         }
965                                                         else if (state == GHOST_kWindowStateMaximized) {
966                                                                 state_str = "maximized";
967                                                         }
968                                                         else if (state == GHOST_kWindowStateFullScreen) {
969                                                                 state_str = "fullscreen";
970                                                         }
971                                                         else {
972                                                                 state_str = "<unknown>";
973                                                         }
974
975                                                         printf("%s: window %d state = %s\n", __func__, win->winid, state_str);
976
977                                                         if (type != GHOST_kEventWindowSize) {
978                                                                 printf("win move event pos %d %d size %d %d\n",
979                                                                        win->posx, win->posy, win->sizex, win->sizey);
980                                                         }
981                                                 }
982                                         
983                                                 wm_window_make_drawable(wm, win);
984                                                 wm_draw_window_clear(win);
985                                                 WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
986                                                 WM_event_add_notifier(C, NC_WINDOW | NA_EDITED, NULL);
987                                                 
988 #if defined(__APPLE__) || defined(WIN32)
989                                                 /* OSX and Win32 don't return to the mainloop while resize */
990                                                 wm_event_do_handlers(C);
991                                                 wm_event_do_notifiers(C);
992                                                 wm_draw_update(C);
993 #endif
994                                         }
995                                 }
996                                 break;
997                         }
998                                 
999                         case GHOST_kEventOpenMainFile:
1000                         {
1001                                 PointerRNA props_ptr;
1002                                 wmWindow *oldWindow;
1003                                 const char *path = GHOST_GetEventData(evt);
1004                                 
1005                                 if (path) {
1006                                         wmOperatorType *ot = WM_operatortype_find("WM_OT_open_mainfile", false);
1007                                         /* operator needs a valid window in context, ensures
1008                                          * it is correctly set */
1009                                         oldWindow = CTX_wm_window(C);
1010                                         CTX_wm_window_set(C, win);
1011                                         
1012                                         WM_operator_properties_create_ptr(&props_ptr, ot);
1013                                         RNA_string_set(&props_ptr, "filepath", path);
1014                                         WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &props_ptr);
1015                                         WM_operator_properties_free(&props_ptr);
1016                                         
1017                                         CTX_wm_window_set(C, oldWindow);
1018                                 }
1019                                 break;
1020                         }
1021                         case GHOST_kEventDraggingDropDone:
1022                         {
1023                                 wmEvent event;
1024                                 GHOST_TEventDragnDropData *ddd = GHOST_GetEventData(evt);
1025                                 int wx, wy;
1026                                 
1027                                 /* entering window, update mouse pos */
1028                                 wm_get_cursor_position(win, &wx, &wy);
1029                                 win->eventstate->x = wx;
1030                                 win->eventstate->y = wy;
1031                                 
1032                                 wm_event_init_from_window(win, &event);  /* copy last state, like mouse coords */
1033                                 
1034                                 /* activate region */
1035                                 event.type = MOUSEMOVE;
1036                                 event.prevx = event.x;
1037                                 event.prevy = event.y;
1038                                 
1039                                 wm->winactive = win; /* no context change! c->wm->windrawable is drawable, or for area queues */
1040                                 win->active = 1;
1041                                 
1042                                 wm_event_add(win, &event);
1043                                 
1044                                 
1045                                 /* make blender drop event with custom data pointing to wm drags */
1046                                 event.type = EVT_DROP;
1047                                 event.val = KM_RELEASE;
1048                                 event.custom = EVT_DATA_DRAGDROP;
1049                                 event.customdata = &wm->drags;
1050                                 event.customdatafree = 1;
1051                                 
1052                                 wm_event_add(win, &event);
1053                                 
1054                                 /* printf("Drop detected\n"); */
1055                                 
1056                                 /* add drag data to wm for paths: */
1057                                 
1058                                 if (ddd->dataType == GHOST_kDragnDropTypeFilenames) {
1059                                         GHOST_TStringArray *stra = ddd->data;
1060                                         int a, icon;
1061                                         
1062                                         for (a = 0; a < stra->count; a++) {
1063                                                 printf("drop file %s\n", stra->strings[a]);
1064                                                 /* try to get icon type from extension */
1065                                                 icon = ED_file_extension_icon((char *)stra->strings[a]);
1066                                                 
1067                                                 WM_event_start_drag(C, icon, WM_DRAG_PATH, stra->strings[a], 0.0, WM_DRAG_NOP);
1068                                                 /* void poin should point to string, it makes a copy */
1069                                                 break; /* only one drop element supported now */
1070                                         }
1071                                 }
1072                                 
1073                                 break;
1074                         }
1075                         case GHOST_kEventNativeResolutionChange:
1076                                 // printf("change, pixel size %f\n", GHOST_GetNativePixelSize(win->ghostwin));
1077                                 
1078                                 U.pixelsize = wm_window_pixelsize(win);
1079                                 BKE_userdef_state();
1080                                 WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
1081                                 WM_event_add_notifier(C, NC_WINDOW | NA_EDITED, NULL);
1082
1083                                 break;
1084                         case GHOST_kEventTrackpad:
1085                         {
1086                                 GHOST_TEventTrackpadData *pd = data;
1087                                 
1088                                 wm_convert_cursor_position(win, &pd->x, &pd->y);
1089                                 wm_event_add_ghostevent(wm, win, type, time, data);
1090                                 break;
1091                         }
1092                         case GHOST_kEventCursorMove:
1093                         {
1094                                 GHOST_TEventCursorData *cd = data;
1095                                 
1096                                 wm_convert_cursor_position(win, &cd->x, &cd->y);
1097                                 wm_event_add_ghostevent(wm, win, type, time, data);
1098                                 break;
1099                         }
1100                         default:
1101                                 wm_event_add_ghostevent(wm, win, type, time, data);
1102                                 break;
1103                 }
1104
1105         }
1106         return 1;
1107 }
1108
1109
1110 /* This timer system only gives maximum 1 timer event per redraw cycle,
1111  * to prevent queues to get overloaded.
1112  * Timer handlers should check for delta to decide if they just
1113  * update, or follow real time.
1114  * Timer handlers can also set duration to match frames passed
1115  */
1116 static int wm_window_timer(const bContext *C)
1117 {
1118         wmWindowManager *wm = CTX_wm_manager(C);
1119         wmTimer *wt, *wtnext;
1120         wmWindow *win;
1121         double time = PIL_check_seconds_timer();
1122         int retval = 0;
1123         
1124         for (wt = wm->timers.first; wt; wt = wtnext) {
1125                 wtnext = wt->next; /* in case timer gets removed */
1126                 win = wt->win;
1127
1128                 if (wt->sleep == 0) {
1129                         if (time > wt->ntime) {
1130                                 wt->delta = time - wt->ltime;
1131                                 wt->duration += wt->delta;
1132                                 wt->ltime = time;
1133                                 wt->ntime = wt->stime + wt->timestep * ceil(wt->duration / wt->timestep);
1134
1135                                 if (wt->event_type == TIMERJOBS)
1136                                         wm_jobs_timer(C, wm, wt);
1137                                 else if (wt->event_type == TIMERAUTOSAVE)
1138                                         wm_autosave_timer(C, wm, wt);
1139                                 else if (win) {
1140                                         wmEvent event;
1141                                         wm_event_init_from_window(win, &event);
1142                                         
1143                                         event.type = wt->event_type;
1144                                         event.val = KM_NOTHING;
1145                                         event.keymodifier = 0;
1146                                         event.custom = EVT_DATA_TIMER;
1147                                         event.customdata = wt;
1148                                         wm_event_add(win, &event);
1149
1150                                         retval = 1;
1151                                 }
1152                         }
1153                 }
1154         }
1155         return retval;
1156 }
1157
1158 void wm_window_process_events(const bContext *C) 
1159 {
1160         int hasevent;
1161
1162         BLI_assert(BLI_thread_is_main());
1163
1164         hasevent = GHOST_ProcessEvents(g_system, 0); /* 0 is no wait */
1165
1166         if (hasevent)
1167                 GHOST_DispatchEvents(g_system);
1168         
1169         hasevent |= wm_window_timer(C);
1170
1171         /* no event, we sleep 5 milliseconds */
1172         if (hasevent == 0)
1173                 PIL_sleep_ms(5);
1174 }
1175
1176 void wm_window_process_events_nosleep(void) 
1177 {
1178         if (GHOST_ProcessEvents(g_system, 0))
1179                 GHOST_DispatchEvents(g_system);
1180 }
1181
1182 /* exported as handle callback to bke blender.c */
1183 void wm_window_testbreak(void)
1184 {
1185         static double ltime = 0;
1186         double curtime = PIL_check_seconds_timer();
1187
1188         BLI_assert(BLI_thread_is_main());
1189
1190         /* only check for breaks every 50 milliseconds
1191          * if we get called more often.
1192          */
1193         if ((curtime - ltime) > 0.05) {
1194                 int hasevent = GHOST_ProcessEvents(g_system, 0); /* 0 is no wait */
1195                 
1196                 if (hasevent)
1197                         GHOST_DispatchEvents(g_system);
1198                 
1199                 ltime = curtime;
1200         }
1201 }
1202
1203 /* **************** init ********************** */
1204
1205 void wm_ghost_init(bContext *C)
1206 {
1207         if (!g_system) {
1208                 GHOST_EventConsumerHandle consumer = GHOST_CreateEventConsumer(ghost_event_proc, C);
1209                 
1210                 g_system = GHOST_CreateSystem();
1211                 GHOST_AddEventConsumer(g_system, consumer);
1212                 
1213                 if (wm_init_state.native_pixels) {
1214                         GHOST_UseNativePixels();
1215                 }
1216         }
1217 }
1218
1219 void wm_ghost_exit(void)
1220 {
1221         if (g_system)
1222                 GHOST_DisposeSystem(g_system);
1223
1224         g_system = NULL;
1225 }
1226
1227 /* **************** timer ********************** */
1228
1229 /* to (de)activate running timers temporary */
1230 void WM_event_timer_sleep(wmWindowManager *wm, wmWindow *UNUSED(win), wmTimer *timer, bool do_sleep)
1231 {
1232         wmTimer *wt;
1233         
1234         for (wt = wm->timers.first; wt; wt = wt->next)
1235                 if (wt == timer)
1236                         break;
1237
1238         if (wt)
1239                 wt->sleep = do_sleep;
1240 }
1241
1242 wmTimer *WM_event_add_timer(wmWindowManager *wm, wmWindow *win, int event_type, double timestep)
1243 {
1244         wmTimer *wt = MEM_callocN(sizeof(wmTimer), "window timer");
1245         
1246         wt->event_type = event_type;
1247         wt->ltime = PIL_check_seconds_timer();
1248         wt->ntime = wt->ltime + timestep;
1249         wt->stime = wt->ltime;
1250         wt->timestep = timestep;
1251         wt->win = win;
1252         
1253         BLI_addtail(&wm->timers, wt);
1254         
1255         return wt;
1256 }
1257
1258 void WM_event_remove_timer(wmWindowManager *wm, wmWindow *UNUSED(win), wmTimer *timer)
1259 {
1260         wmTimer *wt;
1261         
1262         /* extra security check */
1263         for (wt = wm->timers.first; wt; wt = wt->next)
1264                 if (wt == timer)
1265                         break;
1266         if (wt) {
1267                 wmWindow *win;
1268                 
1269                 if (wm->reports.reporttimer == wt)
1270                         wm->reports.reporttimer = NULL;
1271                 
1272                 BLI_remlink(&wm->timers, wt);
1273                 if (wt->customdata)
1274                         MEM_freeN(wt->customdata);
1275                 MEM_freeN(wt);
1276                 
1277                 /* there might be events in queue with this timer as customdata */
1278                 for (win = wm->windows.first; win; win = win->next) {
1279                         wmEvent *event;
1280                         for (event = win->queue.first; event; event = event->next) {
1281                                 if (event->customdata == wt) {
1282                                         event->customdata = NULL;
1283                                         event->type = EVENT_NONE;       /* timer users customdata, dont want NULL == NULL */
1284                                 }
1285                         }
1286                 }
1287         }
1288 }
1289
1290 /* ******************* clipboard **************** */
1291
1292 static char *wm_clipboard_text_get_ex(bool selection, int *r_len,
1293                                       bool firstline)
1294 {
1295         char *p, *p2, *buf, *newbuf;
1296
1297         if (G.background) {
1298                 *r_len = 0;
1299                 return NULL;
1300         }
1301
1302         buf = (char *)GHOST_getClipboard(selection);
1303         if (!buf) {
1304                 *r_len = 0;
1305                 return NULL;
1306         }
1307         
1308         /* always convert from \r\n to \n */
1309         p2 = newbuf = MEM_mallocN(strlen(buf) + 1, __func__);
1310
1311         if (firstline) {
1312                 /* will return an over-alloc'ed value in the case there are newlines */
1313                 for (p = buf; *p; p++) {
1314                         if ((*p != '\n') && (*p != '\r')) {
1315                                 *(p2++) = *p;
1316                         }
1317                         else {
1318                                 break;
1319                         }
1320                 }
1321         }
1322         else {
1323                 for (p = buf; *p; p++) {
1324                         if (*p != '\r') {
1325                                 *(p2++) = *p;
1326                         }
1327                 }
1328         }
1329
1330         *p2 = '\0';
1331
1332         free(buf); /* ghost uses regular malloc */
1333         
1334         *r_len = (p2 - newbuf);
1335
1336         return newbuf;
1337 }
1338
1339 /**
1340  * Return text from the clipboard.
1341  *
1342  * \note Caller needs to check for valid utf8 if this is a requirement.
1343  */
1344 char *WM_clipboard_text_get(bool selection, int *r_len)
1345 {
1346         return wm_clipboard_text_get_ex(selection, r_len, false);
1347 }
1348
1349 /**
1350  * Convenience function for pasting to areas of Blender which don't support newlines.
1351  */
1352 char *WM_clipboard_text_get_firstline(bool selection, int *r_len)
1353 {
1354         return wm_clipboard_text_get_ex(selection, r_len, true);
1355 }
1356
1357 void WM_clipboard_text_set(const char *buf, bool selection)
1358 {
1359         if (!G.background) {
1360 #ifdef _WIN32
1361                 /* do conversion from \n to \r\n on Windows */
1362                 const char *p;
1363                 char *p2, *newbuf;
1364                 int newlen = 0;
1365                 
1366                 for (p = buf; *p; p++) {
1367                         if (*p == '\n')
1368                                 newlen += 2;
1369                         else
1370                                 newlen++;
1371                 }
1372                 
1373                 newbuf = MEM_callocN(newlen + 1, "WM_clipboard_text_set");
1374         
1375                 for (p = buf, p2 = newbuf; *p; p++, p2++) {
1376                         if (*p == '\n') {
1377                                 *(p2++) = '\r'; *p2 = '\n';
1378                         }
1379                         else {
1380                                 *p2 = *p;
1381                         }
1382                 }
1383                 *p2 = '\0';
1384         
1385                 GHOST_putClipboard((GHOST_TInt8 *)newbuf, selection);
1386                 MEM_freeN(newbuf);
1387 #else
1388                 GHOST_putClipboard((GHOST_TInt8 *)buf, selection);
1389 #endif
1390         }
1391 }
1392
1393 /* ******************* progress bar **************** */
1394
1395 void WM_progress_set(wmWindow *win, float progress)
1396 {
1397         GHOST_SetProgressBar(win->ghostwin, progress);
1398 }
1399
1400 void WM_progress_clear(wmWindow *win)
1401 {
1402         GHOST_EndProgressBar(win->ghostwin);
1403 }
1404
1405 /* ************************************ */
1406
1407 void wm_window_get_position(wmWindow *win, int *r_pos_x, int *r_pos_y)
1408 {
1409         *r_pos_x = win->posx;
1410         *r_pos_y = win->posy;
1411 }
1412
1413 void wm_window_set_size(wmWindow *win, int width, int height) 
1414 {
1415         GHOST_SetClientSize(win->ghostwin, width, height);
1416 }
1417
1418 void wm_window_lower(wmWindow *win) 
1419 {
1420         GHOST_SetWindowOrder(win->ghostwin, GHOST_kWindowOrderBottom);
1421 }
1422
1423 void wm_window_raise(wmWindow *win) 
1424 {
1425         GHOST_SetWindowOrder(win->ghostwin, GHOST_kWindowOrderTop);
1426 }
1427
1428 void wm_window_swap_buffers(wmWindow *win)
1429 {
1430         
1431 #ifdef WIN32
1432         glDisable(GL_SCISSOR_TEST);
1433         GHOST_SwapWindowBuffers(win->ghostwin);
1434         glEnable(GL_SCISSOR_TEST);
1435 #else
1436         GHOST_SwapWindowBuffers(win->ghostwin);
1437 #endif
1438 }
1439
1440 void wm_window_set_swap_interval (wmWindow *win, int interval)
1441 {
1442         GHOST_SetSwapInterval(win->ghostwin, interval);
1443 }
1444
1445 bool wm_window_get_swap_interval(wmWindow *win, int *intervalOut)
1446 {
1447         return GHOST_GetSwapInterval(win->ghostwin, intervalOut);
1448 }
1449
1450
1451 /* ******************* exported api ***************** */
1452
1453
1454 /* called whem no ghost system was initialized */
1455 void WM_init_state_size_set(int stax, int stay, int sizx, int sizy)
1456 {
1457         wm_init_state.start_x = stax; /* left hand pos */
1458         wm_init_state.start_y = stay; /* bottom pos */
1459         wm_init_state.size_x = sizx < 640 ? 640 : sizx;
1460         wm_init_state.size_y = sizy < 480 ? 480 : sizy;
1461         wm_init_state.override_flag |= WIN_OVERRIDE_GEOM;
1462 }
1463
1464 /* for borderless and border windows set from command-line */
1465 void WM_init_state_fullscreen_set(void)
1466 {
1467         wm_init_state.windowstate = GHOST_kWindowStateFullScreen;
1468         wm_init_state.override_flag |= WIN_OVERRIDE_WINSTATE;
1469 }
1470
1471 void WM_init_state_normal_set(void)
1472 {
1473         wm_init_state.windowstate = GHOST_kWindowStateNormal;
1474         wm_init_state.override_flag |= WIN_OVERRIDE_WINSTATE;
1475 }
1476
1477 void WM_init_native_pixels(bool do_it)
1478 {
1479         wm_init_state.native_pixels = do_it;
1480 }
1481
1482 /* This function requires access to the GHOST_SystemHandle (g_system) */
1483 void WM_cursor_warp(wmWindow *win, int x, int y)
1484 {
1485         if (win && win->ghostwin) {
1486                 float f = GHOST_GetNativePixelSize(win->ghostwin);
1487                 int oldx = x, oldy = y;
1488
1489                 x = x / f;
1490                 y = y / f;
1491                 y = win->sizey - y - 1;
1492
1493                 GHOST_ClientToScreen(win->ghostwin, x, y, &x, &y);
1494                 GHOST_SetCursorPosition(g_system, x, y);
1495
1496                 win->eventstate->prevx = oldx;
1497                 win->eventstate->prevy = oldy;
1498
1499                 win->eventstate->x = oldx;
1500                 win->eventstate->y = oldy;
1501         }
1502 }
1503
1504 /**
1505  * Get the cursor pressure, in most cases you'll want to use wmTabletData from the event
1506  */
1507 float WM_cursor_pressure(const struct wmWindow *win)
1508 {
1509         const GHOST_TabletData *td = GHOST_GetTabletData(win->ghostwin);
1510         /* if there's tablet data from an active tablet device then add it */
1511         if ((td != NULL) && td->Active != GHOST_kTabletModeNone) {
1512                 return td->Pressure;
1513         }
1514         else {
1515                 return -1.0f;
1516         }
1517 }
1518
1519 /* support for native pixel size */
1520 /* mac retina opens window in size X, but it has up to 2 x more pixels */
1521 int WM_window_pixels_x(wmWindow *win)
1522 {
1523         float f = GHOST_GetNativePixelSize(win->ghostwin);
1524         
1525         return (int)(f * (float)win->sizex);
1526 }
1527
1528 int WM_window_pixels_y(wmWindow *win)
1529 {
1530         float f = GHOST_GetNativePixelSize(win->ghostwin);
1531         
1532         return (int)(f * (float)win->sizey);
1533         
1534 }
1535
1536 bool WM_window_is_fullscreen(wmWindow *win)
1537 {
1538         return win->windowstate == GHOST_kWindowStateFullScreen;
1539 }
1540
1541
1542 #ifdef WITH_INPUT_IME
1543 /* note: keep in mind wm_window_IME_begin is also used to reposition the IME window */
1544 void wm_window_IME_begin(wmWindow *win, int x, int y, int w, int h, bool complete)
1545 {
1546         BLI_assert(win);
1547
1548         GHOST_BeginIME(win->ghostwin, x, win->sizey - y, w, h, complete);
1549 }
1550
1551 void wm_window_IME_end(wmWindow *win)
1552 {
1553         BLI_assert(win && win->ime_data);
1554
1555         GHOST_EndIME(win->ghostwin);
1556         win->ime_data = NULL;
1557 }
1558 #endif  /* WITH_INPUT_IME */