Merge branch 'master' into blender2.8
[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 #include "DNA_workspace_types.h"
42
43 #include "MEM_guardedalloc.h"
44
45 #include "GHOST_C-api.h"
46
47 #include "BLI_math.h"
48 #include "BLI_blenlib.h"
49 #include "BLI_utildefines.h"
50
51 #include "BLT_translation.h"
52
53 #include "BKE_blender.h"
54 #include "BKE_context.h"
55 #include "BKE_icons.h"
56 #include "BKE_library.h"
57 #include "BKE_global.h"
58 #include "BKE_main.h"
59 #include "BKE_screen.h"
60 #include "BKE_workspace.h"
61
62 #include "RNA_access.h"
63 #include "RNA_define.h"
64 #include "RNA_enum_types.h"
65
66 #include "WM_api.h"
67 #include "WM_types.h"
68 #include "wm.h"
69 #include "wm_draw.h"
70 #include "wm_window.h"
71 #include "wm_event_system.h"
72
73 #include "ED_scene.h"
74 #include "ED_screen.h"
75 #include "ED_fileselect.h"
76
77 #include "UI_interface.h"
78 #include "UI_interface_icons.h"
79
80 #include "PIL_time.h"
81
82 #include "GPU_batch.h"
83 #include "GPU_draw.h"
84 #include "GPU_extensions.h"
85 #include "GPU_init_exit.h"
86 #include "GPU_immediate.h"
87 #include "BLF_api.h"
88
89 #include "UI_resources.h"
90
91 #include "../../../intern/gawain/gawain/gwn_context.h"
92
93 /* for assert */
94 #ifndef NDEBUG
95 #  include "BLI_threads.h"
96 #endif
97
98 /* the global to talk to ghost */
99 static GHOST_SystemHandle g_system = NULL;
100
101 typedef enum WinOverrideFlag {
102         WIN_OVERRIDE_GEOM     = (1 << 0),
103         WIN_OVERRIDE_WINSTATE = (1 << 1)
104 } WinOverrideFlag;
105
106 /* set by commandline */
107 static struct WMInitStruct {
108         /* window geometry */
109         int size_x, size_y;
110         int start_x, start_y;
111
112         int windowstate;
113         WinOverrideFlag override_flag;
114         
115         bool native_pixels;
116 } wm_init_state = {0, 0, 0, 0, GHOST_kWindowStateNormal, 0, true};
117
118 /* ******** win open & close ************ */
119
120 /* XXX this one should correctly check for apple top header...
121  * done for Cocoa : returns window contents (and not frame) max size*/
122 void wm_get_screensize(int *r_width, int *r_height)
123 {
124         unsigned int uiwidth;
125         unsigned int uiheight;
126         
127         GHOST_GetMainDisplayDimensions(g_system, &uiwidth, &uiheight);
128         *r_width = uiwidth;
129         *r_height = uiheight;
130 }
131
132 /* size of all screens (desktop), useful since the mouse is bound by this */
133 void wm_get_desktopsize(int *r_width, int *r_height)
134 {
135         unsigned int uiwidth;
136         unsigned int uiheight;
137
138         GHOST_GetAllDisplayDimensions(g_system, &uiwidth, &uiheight);
139         *r_width = uiwidth;
140         *r_height = uiheight;
141 }
142
143 /* keeps offset and size within monitor bounds */
144 /* XXX solve dual screen... */
145 static void wm_window_check_position(rcti *rect)
146 {
147         int width, height, d;
148         
149         wm_get_screensize(&width, &height);
150         
151         if (rect->xmin < 0) {
152                 rect->xmax -= rect->xmin;
153                 rect->xmin  = 0;
154         }
155         if (rect->ymin < 0) {
156                 rect->ymax -= rect->ymin;
157                 rect->ymin  = 0;
158         }
159         if (rect->xmax > width) {
160                 d = rect->xmax - width;
161                 rect->xmax -= d;
162                 rect->xmin -= d;
163         }
164         if (rect->ymax > height) {
165                 d = rect->ymax - height;
166                 rect->ymax -= d;
167                 rect->ymin -= d;
168         }
169         
170         if (rect->xmin < 0) rect->xmin = 0;
171         if (rect->ymin < 0) rect->ymin = 0;
172 }
173
174
175 static void wm_ghostwindow_destroy(wmWindowManager *wm, wmWindow *win)
176 {
177         if (win->ghostwin) {
178                 /* We need this window's opengl context active to discard it. */
179                 GHOST_ActivateWindowDrawingContext(win->ghostwin);
180                 GWN_context_active_set(win->gwnctx);
181
182                 /* Delete local gawain objects.  */
183                 GWN_context_discard(win->gwnctx);
184
185                 GHOST_DisposeWindow(g_system, win->ghostwin);
186                 win->ghostwin = NULL;
187                 win->gwnctx = NULL;
188
189                 /* prevents non-drawable state of main windows (bugs #22967 and #25071, possibly #22477 too) */
190                 wm->windrawable = NULL;
191                 wm->winactive = NULL;
192         }
193 }
194
195 /* including window itself, C can be NULL. 
196  * ED_screen_exit should have been called */
197 void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win)
198 {
199         wmTimer *wt, *wtnext;
200         
201         /* update context */
202         if (C) {
203                 WM_event_remove_handlers(C, &win->handlers);
204                 WM_event_remove_handlers(C, &win->modalhandlers);
205
206                 if (CTX_wm_window(C) == win)
207                         CTX_wm_window_set(C, NULL);
208         }
209
210         /* end running jobs, a job end also removes its timer */
211         for (wt = wm->timers.first; wt; wt = wtnext) {
212                 wtnext = wt->next;
213                 if (wt->win == win && wt->event_type == TIMERJOBS)
214                         wm_jobs_timer_ended(wm, wt);
215         }
216         
217         /* timer removing, need to call this api function */
218         for (wt = wm->timers.first; wt; wt = wtnext) {
219                 wtnext = wt->next;
220                 if (wt->win == win)
221                         WM_event_remove_timer(wm, win, wt);
222         }
223
224         if (win->eventstate) MEM_freeN(win->eventstate);
225         
226         wm_event_free_all(win);
227
228         wm_draw_data_free(win);
229
230         wm_ghostwindow_destroy(wm, win);
231
232         BKE_workspace_instance_hook_free(G.main, win->workspace_hook);
233         MEM_freeN(win->stereo3d_format);
234
235         MEM_freeN(win);
236 }
237
238 static int find_free_winid(wmWindowManager *wm)
239 {
240         wmWindow *win;
241         int id = 1;
242         
243         for (win = wm->windows.first; win; win = win->next)
244                 if (id <= win->winid)
245                         id = win->winid + 1;
246         
247         return id;
248 }
249
250 /* don't change context itself */
251 wmWindow *wm_window_new(bContext *C)
252 {
253         Main *bmain = CTX_data_main(C);
254         wmWindowManager *wm = CTX_wm_manager(C);
255         wmWindow *win = MEM_callocN(sizeof(wmWindow), "window");
256
257         BLI_addtail(&wm->windows, win);
258         win->winid = find_free_winid(wm);
259
260         win->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Stereo 3D Format (window)");
261         win->workspace_hook = BKE_workspace_instance_hook_create(bmain);
262
263         return win;
264 }
265
266 /**
267  * A higher level version of copy that tests the new window can be added.
268  */
269 static wmWindow *wm_window_new_test(bContext *C)
270 {
271         wmWindow *win = wm_window_new(C);
272
273         WM_check(C);
274
275         if (win->ghostwin) {
276                 WM_event_add_notifier(C, NC_WINDOW | NA_ADDED, NULL);
277                 return win;
278         }
279         else {
280                 wmWindowManager *wm = CTX_wm_manager(C);
281                 wm_window_close(C, wm, win);
282                 return NULL;
283         }
284 }
285
286 /* part of wm_window.c api */
287 wmWindow *wm_window_copy(bContext *C, wmWindow *win_src, const bool duplicate_layout)
288 {
289         wmWindow *win_dst = wm_window_new(C);
290         WorkSpace *workspace = WM_window_get_active_workspace(win_src);
291         WorkSpaceLayout *layout_old = WM_window_get_active_layout(win_src);
292         Scene *scene = WM_window_get_active_scene(win_src);
293         WorkSpaceLayout *layout_new;
294
295         win_dst->posx = win_src->posx + 10;
296         win_dst->posy = win_src->posy;
297         win_dst->sizex = win_src->sizex;
298         win_dst->sizey = win_src->sizey;
299
300         win_dst->scene = scene;
301         WM_window_set_active_workspace(win_dst, workspace);
302         layout_new = duplicate_layout ? ED_workspace_layout_duplicate(workspace, layout_old, win_dst) : layout_old;
303         WM_window_set_active_layout(win_dst, workspace, layout_new);
304
305         win_dst->drawmethod = U.wmdrawmethod;
306
307         BLI_listbase_clear(&win_dst->drawdata);
308
309         *win_dst->stereo3d_format = *win_src->stereo3d_format;
310
311         return win_dst;
312 }
313
314 /**
315  * A higher level version of copy that tests the new window can be added.
316  * (called from the operator directly)
317  */
318 wmWindow *wm_window_copy_test(bContext *C, wmWindow *win_src, const bool duplicate_layout)
319 {
320         wmWindowManager *wm = CTX_wm_manager(C);
321         wmWindow *win_dst;
322
323         win_dst = wm_window_copy(C, win_src, duplicate_layout);
324
325         WM_check(C);
326
327         if (win_dst->ghostwin) {
328                 WM_event_add_notifier(C, NC_WINDOW | NA_ADDED, NULL);
329                 return win_dst;
330         }
331         else {
332                 wm_window_close(C, wm, win_dst);
333                 return NULL;
334         }
335 }
336
337
338 /* -------------------------------------------------------------------- */
339 /** \name Quit Confirmation Dialog
340  * \{ */
341
342 /** Cancel quitting and close the dialog */
343 static void wm_block_confirm_quit_cancel(bContext *C, void *arg_block, void *UNUSED(arg))
344 {
345         wmWindow *win = CTX_wm_window(C);
346         UI_popup_block_close(C, win, arg_block);
347 }
348
349 /** Discard the file changes and quit */
350 static void wm_block_confirm_quit_discard(bContext *C, void *arg_block, void *UNUSED(arg))
351 {
352         wmWindow *win = CTX_wm_window(C);
353         UI_popup_block_close(C, win, arg_block);
354         WM_exit(C);
355 }
356
357 /* Save changes and quit */
358 static void wm_block_confirm_quit_save(bContext *C, void *arg_block, void *UNUSED(arg))
359 {
360         PointerRNA props_ptr;
361         wmWindow *win = CTX_wm_window(C);
362
363         UI_popup_block_close(C, win, arg_block);
364
365         wmOperatorType *ot = WM_operatortype_find("WM_OT_save_mainfile", false);
366
367         WM_operator_properties_create_ptr(&props_ptr, ot);
368         RNA_boolean_set(&props_ptr, "exit", true);
369         /* No need for second confirmation popup. */
370         RNA_boolean_set(&props_ptr, "check_existing", false);
371         WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr);
372         WM_operator_properties_free(&props_ptr);
373 }
374
375
376 /* Build the confirm dialog UI */
377 static uiBlock *block_create_confirm_quit(struct bContext *C, struct ARegion *ar, void *UNUSED(arg1))
378 {
379
380         uiStyle *style = UI_style_get();
381         uiBlock *block = UI_block_begin(C, ar, "confirm_quit_popup", UI_EMBOSS);
382
383         UI_block_flag_enable(block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_LOOP | UI_BLOCK_NO_WIN_CLIP );
384         UI_block_emboss_set(block, UI_EMBOSS);
385
386         uiLayout *layout = UI_block_layout(
387                 block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 10, 2, U.pixelsize * 480, U.pixelsize * 110, 0, style);
388
389         /* Text and some vertical space */
390         {
391                 char *message;
392                 if (G.main->name[0] == '\0') {
393                         message = BLI_strdup(IFACE_("This file has not been saved yet. Save before closing?"));
394                 }
395                 else {
396                         const char *basename = BLI_path_basename(G.main->name);
397                         message = BLI_sprintfN(IFACE_("Save changes to \"%s\" before closing?"), basename);
398                 }
399                 uiItemL(layout, message, ICON_ERROR);
400                 MEM_freeN(message);
401         }
402
403         uiItemS(layout);
404         uiItemS(layout);
405
406
407         /* Buttons */
408         uiBut *but;
409
410         uiLayout *split = uiLayoutSplit(layout, 0.0f, true);
411
412         uiLayout *col = uiLayoutColumn(split, false);
413
414         but = uiDefIconTextBut(
415                 block, UI_BTYPE_BUT, 0, ICON_SCREEN_BACK, IFACE_("Cancel"), 0, 0, 0, UI_UNIT_Y,
416                 NULL, 0, 0, 0, 0, TIP_("Do not quit"));
417         UI_but_func_set(but, wm_block_confirm_quit_cancel, block, NULL);
418
419         /* empty space between buttons */
420         col = uiLayoutColumn(split, false);
421         uiItemS(col);
422
423         col = uiLayoutColumn(split, 1);
424         but = uiDefIconTextBut(
425                 block, UI_BTYPE_BUT, 0, ICON_CANCEL, IFACE_("Discard Changes"), 0, 0, 50, UI_UNIT_Y,
426                 NULL, 0, 0, 0, 0, TIP_("Discard changes and quit"));
427         UI_but_func_set(but, wm_block_confirm_quit_discard, block, NULL);
428
429         col = uiLayoutColumn(split, 1);
430         but = uiDefIconTextBut(
431                 block, UI_BTYPE_BUT, 0, ICON_FILE_TICK, IFACE_("Save & Quit"), 0, 0, 50, UI_UNIT_Y,
432                 NULL, 0, 0, 0, 0, TIP_("Save and quit"));
433         UI_but_func_set(but, wm_block_confirm_quit_save, block, NULL);
434
435         UI_block_bounds_set_centered(block, 10);
436
437         return block;
438 }
439
440
441 /** Call the confirm dialog on quitting. */
442 void wm_confirm_quit(bContext *C)
443 {
444         wmWindowManager *wm = CTX_wm_manager(C);
445
446         /* The popup needs to have a window set in context to show up since
447          * it's being called outside the normal operator event handling loop */
448         if (wm->winactive) {
449                 CTX_wm_window_set(C, wm->winactive);
450         }
451
452         UI_popup_block_invoke(C, block_create_confirm_quit, NULL);
453 }
454
455 /** \} */
456
457 /* this is event from ghost, or exit-blender op */
458 void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win)
459 {
460         wmWindow *tmpwin;
461         bool do_exit = false;
462         
463         /* first check if we have to quit (there are non-temp remaining windows) */
464         for (tmpwin = wm->windows.first; tmpwin; tmpwin = tmpwin->next) {
465                 if (tmpwin == win)
466                         continue;
467                 if (WM_window_is_temp_screen(tmpwin) == false)
468                         break;
469         }
470
471         if (tmpwin == NULL)
472                 do_exit = 1;
473
474         if ((U.uiflag & USER_QUIT_PROMPT) && !wm->file_saved && !G.background && do_exit) {
475                 /* We have unsaved changes and we're quitting */
476                 if(GHOST_SupportsNativeDialogs() == 0) {
477                         wm_confirm_quit(C);
478                 }
479                 else {
480                         if (!GHOST_confirmQuit(win->ghostwin))
481                                 return;
482                 }
483         }
484         else if (do_exit) {
485                 /* No changes but we're quitting */
486                 /* let WM_exit do all freeing, for correct quit.blend save */
487                 WM_exit(C);
488         }
489         else {
490                 bScreen *screen = WM_window_get_active_screen(win);
491                 WorkSpace *workspace = WM_window_get_active_workspace(win);
492                 WorkSpaceLayout *layout = BKE_workspace_active_layout_get(win->workspace_hook);
493
494                 BLI_remlink(&wm->windows, win);
495                 
496                 wm_draw_window_clear(win);
497                 
498                 CTX_wm_window_set(C, win);  /* needed by handlers */
499                 WM_event_remove_handlers(C, &win->handlers);
500                 WM_event_remove_handlers(C, &win->modalhandlers);
501
502                 /* for regular use this will _never_ be NULL,
503                  * however we may be freeing an improperly initialized window. */
504                 if (screen) {
505                         ED_screen_exit(C, win, screen);
506                 }
507
508                 if (tmpwin) {
509                         gpu_batch_presets_reset();
510                         immDeactivate();
511                 }
512
513                 wm_window_free(C, wm, win);
514
515                 /* keep imediatemode active before the next `wm_window_make_drawable` call */
516                 if (tmpwin) {
517                         GHOST_ActivateWindowDrawingContext(tmpwin->ghostwin);
518                         GWN_context_active_set(tmpwin->gwnctx);
519                         immActivate();
520                 }
521
522                 /* if temp screen, delete it after window free (it stops jobs that can access it) */
523                 if (screen && screen->temp) {
524                         Main *bmain = CTX_data_main(C);
525
526                         BLI_assert(BKE_workspace_layout_screen_get(layout) == screen);
527                         BKE_workspace_layout_remove(bmain, workspace, layout);
528                 }
529         }
530 }
531
532 void wm_window_title(wmWindowManager *wm, wmWindow *win)
533 {
534         if (WM_window_is_temp_screen(win)) {
535                 /* nothing to do for 'temp' windows,
536                  * because WM_window_open_temp always sets window title  */
537         }
538         else if (win->ghostwin) {
539                 /* this is set to 1 if you don't have startup.blend open */
540                 if (G.save_over && G.main->name[0]) {
541                         char str[sizeof(G.main->name) + 24];
542                         BLI_snprintf(str, sizeof(str), "Blender%s [%s%s]", wm->file_saved ? "" : "*", G.main->name,
543                                      G.main->recovered ? " (Recovered)" : "");
544                         GHOST_SetTitle(win->ghostwin, str);
545                 }
546                 else
547                         GHOST_SetTitle(win->ghostwin, "Blender");
548
549                 /* Informs GHOST of unsaved changes, to set window modified visual indicator (MAC OS X)
550                  * and to give hint of unsaved changes for a user warning mechanism
551                  * in case of OS application terminate request (e.g. OS Shortcut Alt+F4, Cmd+Q, (...), or session end) */
552                 GHOST_SetWindowModifiedState(win->ghostwin, (GHOST_TUns8) !wm->file_saved);
553                 
554         }
555 }
556
557 void WM_window_set_dpi(wmWindow *win)
558 {
559         float auto_dpi = GHOST_GetDPIHint(win->ghostwin);
560
561         /* Clamp auto DPI to 96, since our font/interface drawing does not work well
562          * with lower sizes. The main case we are interested in supporting is higher
563          * DPI. If a smaller UI is desired it is still possible to adjust UI scale. */
564         auto_dpi = max_ff(auto_dpi, 96.0f);
565
566         /* Lazily init UI scale size, preserving backwards compatibility by
567          * computing UI scale from ratio of previous DPI and auto DPI */
568         if (U.ui_scale == 0) {
569                 int virtual_pixel = (U.virtual_pixel == VIRTUAL_PIXEL_NATIVE) ? 1 : 2;
570
571                 if (U.dpi == 0) {
572                         U.ui_scale = virtual_pixel;
573                 }
574                 else {
575                         U.ui_scale = (virtual_pixel * U.dpi * 96.0f) / (auto_dpi * 72.0f);
576                 }
577
578                 CLAMP(U.ui_scale, 0.25f, 4.0f);
579         }
580
581         /* Blender's UI drawing assumes DPI 72 as a good default following macOS
582          * while Windows and Linux use DPI 96. GHOST assumes a default 96 so we
583          * remap the DPI to Blender's convention. */
584         auto_dpi *= GHOST_GetNativePixelSize(win->ghostwin);
585         int dpi = auto_dpi * U.ui_scale * (72.0 / 96.0f);
586
587         /* Automatically set larger pixel size for high DPI. */
588         int pixelsize = max_ii(1, (int)(dpi / 64));
589         /* User adjustment for pixel size. */
590         pixelsize = max_ii(1, pixelsize + U.ui_line_width);
591
592         /* Set user preferences globals for drawing, and for forward compatibility. */
593         U.pixelsize = pixelsize;
594         U.dpi = dpi / pixelsize;
595         U.virtual_pixel = (pixelsize == 1) ? VIRTUAL_PIXEL_NATIVE : VIRTUAL_PIXEL_DOUBLE;
596         U.widget_unit = (U.pixelsize * U.dpi * 20 + 36) / 72;
597
598         /* update font drawing */
599         BLF_default_dpi(U.pixelsize * U.dpi);
600 }
601
602 /* belongs to below */
603 static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wmWindow *win)
604 {
605         GHOST_WindowHandle ghostwin;
606         GHOST_GLSettings glSettings = {0};
607         int scr_w, scr_h, posy;
608         
609         /* a new window is created when pageflip mode is required for a window */
610         if (win->stereo3d_format->display_mode == S3D_DISPLAY_PAGEFLIP)
611                 glSettings.flags |= GHOST_glStereoVisual;
612
613         if (G.debug & G_DEBUG_GPU) {
614                 glSettings.flags |= GHOST_glDebugContext;
615         }
616
617         wm_get_screensize(&scr_w, &scr_h);
618         posy = (scr_h - win->posy - win->sizey);
619         
620         ghostwin = GHOST_CreateWindow(g_system, title,
621                                       win->posx, posy, win->sizex, win->sizey,
622                                       (GHOST_TWindowState)win->windowstate,
623                                       GHOST_kDrawingContextTypeOpenGL,
624                                       glSettings);
625
626         if (ghostwin) {
627                 GHOST_RectangleHandle bounds;
628
629                 win->gwnctx = GWN_context_create();
630                 
631                 /* the new window has already been made drawable upon creation */
632                 wm->windrawable = win;
633
634                 /* needed so we can detect the graphics card below */
635                 GPU_init();
636                 
637                 win->ghostwin = ghostwin;
638                 GHOST_SetWindowUserData(ghostwin, win); /* pointer back */
639                 
640                 if (win->eventstate == NULL)
641                         win->eventstate = MEM_callocN(sizeof(wmEvent), "window event state");
642
643                 /* store actual window size in blender window */
644                 bounds = GHOST_GetClientBounds(win->ghostwin);
645
646                 /* win32: gives undefined window size when minimized */
647                 if (GHOST_GetWindowState(win->ghostwin) != GHOST_kWindowStateMinimized) {
648                         win->sizex = GHOST_GetWidthRectangle(bounds);
649                         win->sizey = GHOST_GetHeightRectangle(bounds);
650                 }
651                 GHOST_DisposeRectangle(bounds);
652                 
653 #ifndef __APPLE__
654                 /* set the state here, so minimized state comes up correct on windows */
655                 GHOST_SetWindowState(ghostwin, (GHOST_TWindowState)win->windowstate);
656 #endif
657                 /* until screens get drawn, make it nice gray */
658                 glClearColor(0.55, 0.55, 0.55, 0.0);
659                 /* Crash on OSS ATI: bugs.launchpad.net/ubuntu/+source/mesa/+bug/656100 */
660                 if (!GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE)) {
661                         glClear(GL_COLOR_BUFFER_BIT);
662                 }
663                 
664                 /* needed here, because it's used before it reads userdef */
665                 WM_window_set_dpi(win);
666                 
667                 wm_window_swap_buffers(win);
668                 
669                 //GHOST_SetWindowState(ghostwin, GHOST_kWindowStateModified);
670                 
671                 /* standard state vars for window */
672                 glEnable(GL_SCISSOR_TEST);
673                 GPU_state_init();
674         }
675 }
676
677 /**
678  * Initialize #wmWindow without ghostwin, open these and clear.
679  *
680  * window size is read from window, if 0 it uses prefsize
681  * called in #WM_check, also inits stuff after file read.
682  *
683  * \warning
684  * After running, 'win->ghostwin' can be NULL in rare cases
685  * (where OpenGL driver fails to create a context for eg).
686  * We could remove them with #wm_window_ghostwindows_remove_invalid
687  * but better not since caller may continue to use.
688  * Instead, caller needs to handle the error case and cleanup.
689  */
690 void wm_window_ghostwindows_ensure(wmWindowManager *wm)
691 {
692         wmKeyMap *keymap;
693         wmWindow *win;
694         
695         BLI_assert(G.background == false);
696
697         /* no commandline prefsize? then we set this.
698          * Note that these values will be used only
699          * when there is no startup.blend yet.
700          */
701         if (wm_init_state.size_x == 0) {
702                 wm_get_screensize(&wm_init_state.size_x, &wm_init_state.size_y);
703                 
704                 /* note!, this isnt quite correct, active screen maybe offset 1000s if PX,
705                  * we'd need a wm_get_screensize like function that gives offset,
706                  * in practice the window manager will likely move to the correct monitor */
707                 wm_init_state.start_x = 0;
708                 wm_init_state.start_y = 0;
709
710 #ifdef WITH_X11 /* X11 */
711                 /* X11, start maximized but use default sane size */
712                 wm_init_state.size_x = min_ii(wm_init_state.size_x, WM_WIN_INIT_SIZE_X);
713                 wm_init_state.size_y = min_ii(wm_init_state.size_y, WM_WIN_INIT_SIZE_Y);
714                 /* pad */
715                 wm_init_state.start_x = WM_WIN_INIT_PAD;
716                 wm_init_state.start_y = WM_WIN_INIT_PAD;
717                 wm_init_state.size_x -= WM_WIN_INIT_PAD * 2;
718                 wm_init_state.size_y -= WM_WIN_INIT_PAD * 2;
719 #endif
720         }
721         
722         for (win = wm->windows.first; win; win = win->next) {
723                 if (win->ghostwin == NULL) {
724                         if ((win->sizex == 0) || (wm_init_state.override_flag & WIN_OVERRIDE_GEOM)) {
725                                 win->posx = wm_init_state.start_x;
726                                 win->posy = wm_init_state.start_y;
727                                 win->sizex = wm_init_state.size_x;
728                                 win->sizey = wm_init_state.size_y;
729
730                                 win->windowstate = GHOST_kWindowStateNormal;
731                                 wm_init_state.override_flag &= ~WIN_OVERRIDE_GEOM;
732                         }
733
734                         if (wm_init_state.override_flag & WIN_OVERRIDE_WINSTATE) {
735                                 win->windowstate = wm_init_state.windowstate;
736                                 wm_init_state.override_flag &= ~WIN_OVERRIDE_WINSTATE;
737                         }
738
739                         /* without this, cursor restore may fail, T45456 */
740                         if (win->cursor == 0) {
741                                 win->cursor = CURSOR_STD;
742                         }
743
744                         wm_window_ghostwindow_add(wm, "Blender", win);
745                 }
746                 /* happens after fileread */
747                 if (win->eventstate == NULL)
748                         win->eventstate = MEM_callocN(sizeof(wmEvent), "window event state");
749
750                 /* add keymap handlers (1 handler for all keys in map!) */
751                 keymap = WM_keymap_find(wm->defaultconf, "Window", 0, 0);
752                 WM_event_add_keymap_handler(&win->handlers, keymap);
753                 
754                 keymap = WM_keymap_find(wm->defaultconf, "Screen", 0, 0);
755                 WM_event_add_keymap_handler(&win->handlers, keymap);
756
757                 keymap = WM_keymap_find(wm->defaultconf, "Screen Editing", 0, 0);
758                 WM_event_add_keymap_handler(&win->modalhandlers, keymap);
759                 
760                 /* add drop boxes */
761                 {
762                         ListBase *lb = WM_dropboxmap_find("Window", 0, 0);
763                         WM_event_add_dropbox_handler(&win->handlers, lb);
764                 }
765                 wm_window_title(wm, win);
766         }
767 }
768
769 /**
770  * Call after #wm_window_ghostwindows_ensure or #WM_check
771  * (after loading a new file) in the unlikely event a window couldn't be created.
772  */
773 void wm_window_ghostwindows_remove_invalid(bContext *C, wmWindowManager *wm)
774 {
775         wmWindow *win, *win_next;
776
777         BLI_assert(G.background == false);
778
779         for (win = wm->windows.first; win; win = win_next) {
780                 win_next = win->next;
781                 if (win->ghostwin == NULL) {
782                         wm_window_close(C, wm, win);
783                 }
784         }
785 }
786
787 /**
788  * new window, no screen yet, but we open ghostwindow for it,
789  * also gets the window level handlers
790  * \note area-rip calls this.
791  * \return the window or NULL.
792  */
793 wmWindow *WM_window_open(bContext *C, const rcti *rect)
794 {
795         wmWindow *win_prev = CTX_wm_window(C);
796         wmWindow *win = wm_window_new(C);
797         
798         win->posx = rect->xmin;
799         win->posy = rect->ymin;
800         win->sizex = BLI_rcti_size_x(rect);
801         win->sizey = BLI_rcti_size_y(rect);
802
803         win->drawmethod = U.wmdrawmethod;
804
805         WM_check(C);
806
807         if (win->ghostwin) {
808                 return win;
809         }
810         else {
811                 wm_window_close(C, CTX_wm_manager(C), win);
812                 CTX_wm_window_set(C, win_prev);
813                 return NULL;
814         }
815 }
816
817 /**
818  * Uses `screen->temp` tag to define what to do, currently it limits
819  * to only one "temp" window for render out, preferences, filewindow, etc...
820  *
821  * \param type: WM_WINDOW_RENDER, WM_WINDOW_USERPREFS...
822  * \return the window or NULL.
823  */
824 wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, int type)
825 {
826         Main *bmain = CTX_data_main(C);
827         wmWindow *win_prev = CTX_wm_window(C);
828         wmWindow *win;
829         bScreen *screen;
830         ScrArea *sa;
831         Scene *scene = CTX_data_scene(C);
832         const char *title;
833
834         /* convert to native OS window coordinates */
835         const float native_pixel_size = GHOST_GetNativePixelSize(win_prev->ghostwin);
836         x /= native_pixel_size;
837         y /= native_pixel_size;
838         sizex /= native_pixel_size;
839         sizey /= native_pixel_size;
840
841         /* calculate postition */
842         rcti rect;
843         rect.xmin = x + win_prev->posx - sizex / 2;
844         rect.ymin = y + win_prev->posy - sizey / 2;
845         rect.xmax = rect.xmin + sizex;
846         rect.ymax = rect.ymin + sizey;
847
848         /* changes rect to fit within desktop */
849         wm_window_check_position(&rect);
850         
851         /* test if we have a temp screen already */
852         for (win = CTX_wm_manager(C)->windows.first; win; win = win->next)
853                 if (WM_window_is_temp_screen(win))
854                         break;
855         
856         /* add new window? */
857         if (win == NULL) {
858                 win = wm_window_new(C);
859                 
860                 win->posx = rect.xmin;
861                 win->posy = rect.ymin;
862         }
863
864         screen = WM_window_get_active_screen(win);
865
866         win->sizex = BLI_rcti_size_x(&rect);
867         win->sizey = BLI_rcti_size_y(&rect);
868
869         if (win->ghostwin) {
870                 wm_window_set_size(win, win->sizex, win->sizey);
871                 wm_window_raise(win);
872         }
873
874         if (WM_window_get_active_workspace(win) == NULL) {
875                 WorkSpace *workspace = WM_window_get_active_workspace(win_prev);
876                 WM_window_set_active_workspace(win, workspace);
877         }
878
879         if (screen == NULL) {
880                 /* add new screen layout */
881                 WorkSpace *workspace = WM_window_get_active_workspace(win);
882                 WorkSpaceLayout *layout = ED_workspace_layout_add(workspace, win, "temp");
883
884                 screen = BKE_workspace_layout_screen_get(layout);
885                 WM_window_set_active_layout(win, workspace, layout);
886         }
887
888         if (win->scene == NULL) {
889                 win->scene = scene;
890         }
891         /* In case we reuse an already existing temp window (see win lookup above). */
892         else if (WM_window_get_active_scene(win) != scene) {
893                 WM_window_change_active_scene(bmain, C, win, scene);
894         }
895
896         screen->temp = 1;
897
898         /* make window active, and validate/resize */
899         CTX_wm_window_set(C, win);
900         WM_check(C);
901
902         /* It's possible `win->ghostwin == NULL`.
903          * instead of attempting to cleanup here (in a half finished state),
904          * finish setting up the screen, then free it at the end of the function,
905          * to avoid having to take into account a partially-created window.
906          */
907
908         /* ensure it shows the right spacetype editor */
909         sa = screen->areabase.first;
910         CTX_wm_area_set(C, sa);
911         
912         if (type == WM_WINDOW_RENDER) {
913                 ED_area_newspace(C, sa, SPACE_IMAGE, false);
914         }
915         else {
916                 ED_area_newspace(C, sa, SPACE_USERPREF, false);
917         }
918         
919         ED_screen_change(C, screen);
920         ED_screen_refresh(CTX_wm_manager(C), win); /* test scale */
921         
922         if (sa->spacetype == SPACE_IMAGE)
923                 title = IFACE_("Blender Render");
924         else if (ELEM(sa->spacetype, SPACE_OUTLINER, SPACE_USERPREF))
925                 title = IFACE_("Blender User Preferences");
926         else if (sa->spacetype == SPACE_FILE)
927                 title = IFACE_("Blender File View");
928         else
929                 title = "Blender";
930
931         if (win->ghostwin) {
932                 GHOST_SetTitle(win->ghostwin, title);
933                 return win;
934         }
935         else {
936                 /* very unlikely! but opening a new window can fail */
937                 wm_window_close(C, CTX_wm_manager(C), win);
938                 CTX_wm_window_set(C, win_prev);
939
940                 return NULL;
941         }
942 }
943
944
945 /* ****************** Operators ****************** */
946
947 int wm_window_close_exec(bContext *C, wmOperator *UNUSED(op))
948 {
949         wmWindowManager *wm = CTX_wm_manager(C);
950         wmWindow *win = CTX_wm_window(C);
951         wm_window_close(C, wm, win);
952         return OPERATOR_FINISHED;
953 }
954
955 static WorkSpaceLayout *wm_window_new_find_layout(wmOperator *op, WorkSpace *workspace)
956 {
957         ListBase *listbase = BKE_workspace_layouts_get(workspace);
958         const int layout_id = RNA_enum_get(op->ptr, "screen");
959         int i = 0;
960
961         for (WorkSpaceLayout *layout = listbase->first; layout; layout = layout->next) {
962                 if (i++ == layout_id) {
963                         return layout;
964                 }
965         }
966
967         BLI_assert(0);
968         return NULL;
969 }
970
971 /* new window operator callback */
972 int wm_window_new_exec(bContext *C, wmOperator *op)
973 {
974         wmWindow *win_src = CTX_wm_window(C);
975         WorkSpace *workspace = WM_window_get_active_workspace(win_src);
976         WorkSpaceLayout *layout_new = wm_window_new_find_layout(op, workspace);
977         bScreen *screen_new = BKE_workspace_layout_screen_get(layout_new);
978         wmWindow *win_dst;
979
980         if ((win_dst = wm_window_new_test(C))) {
981                 if (screen_new->winid) {
982                         /* layout/screen is already used, duplicate it */
983                         layout_new = ED_workspace_layout_duplicate(workspace, layout_new, win_dst);
984                         screen_new = BKE_workspace_layout_screen_get(layout_new);
985                 }
986                 /* New window with a different screen but same workspace */
987                 WM_window_set_active_workspace(win_dst, workspace);
988                 WM_window_set_active_screen(win_dst, workspace, screen_new);
989                 win_dst->scene = win_src->scene;
990                 screen_new->winid = win_dst->winid;
991                 CTX_wm_window_set(C, win_dst);
992                 ED_screen_refresh(CTX_wm_manager(C), win_dst);
993         }
994
995         return (win_dst != NULL) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
996 }
997
998 int wm_window_new_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
999 {
1000         wmWindow *win = CTX_wm_window(C);
1001         WorkSpace *workspace = WM_window_get_active_workspace(win);
1002         ListBase *listbase = BKE_workspace_layouts_get(workspace);
1003
1004         if (BLI_listbase_count_ex(listbase, 2) == 1) {
1005                 RNA_enum_set(op->ptr, "screen", 0);
1006                 return wm_window_new_exec(C, op);
1007         }
1008         else {
1009                 return WM_enum_search_invoke_previews(C, op, 6, 2);
1010         }
1011 }
1012
1013 const EnumPropertyItem *wm_window_new_screen_itemf(
1014         bContext *C, struct PointerRNA *UNUSED(ptr), struct PropertyRNA *UNUSED(prop), bool *r_free)
1015 {
1016         if (C == NULL) {
1017                 return DummyRNA_NULL_items;
1018         }
1019         wmWindow *win = CTX_wm_window(C);
1020         WorkSpace *workspace = WM_window_get_active_workspace(win);
1021         ListBase *listbase = BKE_workspace_layouts_get(workspace);
1022         EnumPropertyItem *item = NULL;
1023         EnumPropertyItem tmp = {0, "", 0, "", ""};
1024         int value = 0, totitem = 0;
1025         int count_act_screens = 0;
1026         /* XXX setting max number of windows to 20. We'd need support
1027          * for dynamic strings in EnumPropertyItem.name to avoid this. */
1028         static char active_screens[20][MAX_NAME + 12];
1029
1030         for (WorkSpaceLayout *layout = listbase->first; layout; layout = layout->next) {
1031                 bScreen *screen = BKE_workspace_layout_screen_get(layout);
1032                 const char *layout_name = BKE_workspace_layout_name_get(layout);
1033
1034                 if (screen->winid) {
1035                         BLI_snprintf(active_screens[count_act_screens], sizeof(*active_screens), "%s (Duplicate)", layout_name);
1036                         tmp.name = active_screens[count_act_screens++];
1037                 }
1038                 else {
1039                         tmp.name = layout_name;
1040                 }
1041
1042                 tmp.value = value;
1043                 tmp.identifier = layout_name;
1044                 UI_id_icon_render(C, CTX_data_scene(C), &screen->id, true, false);
1045                 tmp.icon = BKE_icon_id_ensure(&screen->id);
1046
1047                 RNA_enum_item_add(&item, &totitem, &tmp);
1048                 value++;
1049         }
1050
1051         RNA_enum_item_end(&item, &totitem);
1052         *r_free = true;
1053
1054         return item;
1055 }
1056
1057 /* fullscreen operator callback */
1058 int wm_window_fullscreen_toggle_exec(bContext *C, wmOperator *UNUSED(op))
1059 {
1060         wmWindow *window = CTX_wm_window(C);
1061         GHOST_TWindowState state;
1062
1063         if (G.background)
1064                 return OPERATOR_CANCELLED;
1065
1066         state = GHOST_GetWindowState(window->ghostwin);
1067         if (state != GHOST_kWindowStateFullScreen)
1068                 GHOST_SetWindowState(window->ghostwin, GHOST_kWindowStateFullScreen);
1069         else
1070                 GHOST_SetWindowState(window->ghostwin, GHOST_kWindowStateNormal);
1071
1072         return OPERATOR_FINISHED;
1073         
1074 }
1075
1076
1077 /* ************ events *************** */
1078
1079 void wm_cursor_position_from_ghost(wmWindow *win, int *x, int *y)
1080 {
1081         float fac = GHOST_GetNativePixelSize(win->ghostwin);
1082         
1083         GHOST_ScreenToClient(win->ghostwin, *x, *y, x, y);
1084         *x *= fac;
1085         
1086         *y = (win->sizey - 1) - *y;
1087         *y *= fac;
1088 }
1089
1090 void wm_cursor_position_to_ghost(wmWindow *win, int *x, int *y)
1091 {
1092         float fac = GHOST_GetNativePixelSize(win->ghostwin);
1093
1094         *x /= fac;
1095         *y /= fac;
1096         *y = win->sizey - *y - 1;
1097
1098         GHOST_ClientToScreen(win->ghostwin, *x, *y, x, y);
1099 }
1100
1101 void wm_get_cursor_position(wmWindow *win, int *x, int *y)
1102 {
1103         GHOST_GetCursorPosition(g_system, x, y);
1104         wm_cursor_position_from_ghost(win, x, y);
1105 }
1106
1107 typedef enum {
1108         SHIFT    = 's',
1109         CONTROL  = 'c',
1110         ALT      = 'a',
1111         OS       = 'C'
1112 } modifierKeyType;
1113
1114 /* check if specified modifier key type is pressed */
1115 static int query_qual(modifierKeyType qual) 
1116 {
1117         GHOST_TModifierKeyMask left, right;
1118         int val = 0;
1119         
1120         switch (qual) {
1121                 case SHIFT:
1122                         left = GHOST_kModifierKeyLeftShift;
1123                         right = GHOST_kModifierKeyRightShift;
1124                         break;
1125                 case CONTROL:
1126                         left = GHOST_kModifierKeyLeftControl;
1127                         right = GHOST_kModifierKeyRightControl;
1128                         break;
1129                 case OS:
1130                         left = right = GHOST_kModifierKeyOS;
1131                         break;
1132                 case ALT:
1133                 default:
1134                         left = GHOST_kModifierKeyLeftAlt;
1135                         right = GHOST_kModifierKeyRightAlt;
1136                         break;
1137         }
1138         
1139         GHOST_GetModifierKeyState(g_system, left, &val);
1140         if (!val)
1141                 GHOST_GetModifierKeyState(g_system, right, &val);
1142         
1143         return val;
1144 }
1145
1146 void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win) 
1147 {
1148         if (win != wm->windrawable && win->ghostwin) {
1149 //              win->lmbut = 0; /* keeps hanging when mousepressed while other window opened */
1150
1151                 wm->windrawable = win;
1152                 if (G.debug & G_DEBUG_EVENTS) {
1153                         printf("%s: set drawable %d\n", __func__, win->winid);
1154                 }
1155
1156                 gpu_batch_presets_reset();
1157                 immDeactivate();
1158                 GHOST_ActivateWindowDrawingContext(win->ghostwin);
1159                 GWN_context_active_set(win->gwnctx);
1160                 immActivate();
1161
1162                 /* this can change per window */
1163                 WM_window_set_dpi(win);
1164         }
1165 }
1166
1167 /* Reset active the current window opengl drawing context. */
1168 void wm_window_reset_drawable(void)
1169 {
1170         BLI_assert(BLI_thread_is_main());
1171         wmWindowManager *wm = G.main->wm.first;
1172
1173         if (wm == NULL)
1174                 return;
1175
1176         wmWindow *win = wm->windrawable;
1177
1178         if (win && win->ghostwin) {
1179                 gpu_batch_presets_reset();
1180                 immDeactivate();
1181                 GHOST_ActivateWindowDrawingContext(win->ghostwin);
1182                 GWN_context_active_set(win->gwnctx);
1183                 immActivate();
1184         }
1185 }
1186
1187 /* called by ghost, here we handle events for windows themselves or send to event system */
1188 /* mouse coordinate converversion happens here */
1189 static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr)
1190 {
1191         bContext *C = C_void_ptr;
1192         wmWindowManager *wm = CTX_wm_manager(C);
1193         GHOST_TEventType type = GHOST_GetEventType(evt);
1194         int time = GHOST_GetEventTime(evt);
1195         
1196         if (type == GHOST_kEventQuit) {
1197                 WM_exit(C);
1198         }
1199         else {
1200                 GHOST_WindowHandle ghostwin = GHOST_GetEventWindow(evt);
1201                 GHOST_TEventDataPtr data = GHOST_GetEventData(evt);
1202                 wmWindow *win;
1203                 
1204                 /* Ghost now can call this function for life resizes, but it should return if WM didn't initialize yet.
1205                  * Can happen on file read (especially full size window)  */
1206                 if ((wm->initialized & WM_WINDOW_IS_INITIALIZED) == 0) {
1207                         return 1;
1208                 }
1209                 if (!ghostwin) {
1210                         /* XXX - should be checked, why are we getting an event here, and */
1211                         /* what is it? */
1212                         puts("<!> event has no window");
1213                         return 1;
1214                 }
1215                 else if (!GHOST_ValidWindow(g_system, ghostwin)) {
1216                         /* XXX - should be checked, why are we getting an event here, and */
1217                         /* what is it? */
1218                         puts("<!> event has invalid window");
1219                         return 1;
1220                 }
1221                 else {
1222                         win = GHOST_GetWindowUserData(ghostwin);
1223                 }
1224                 
1225                 switch (type) {
1226                         case GHOST_kEventWindowDeactivate:
1227                                 wm_event_add_ghostevent(wm, win, type, time, data);
1228                                 win->active = 0; /* XXX */
1229                                 
1230                                 /* clear modifiers for inactive windows */
1231                                 win->eventstate->alt = 0;
1232                                 win->eventstate->ctrl = 0;
1233                                 win->eventstate->shift = 0;
1234                                 win->eventstate->oskey = 0;
1235                                 win->eventstate->keymodifier = 0;
1236
1237                                 break;
1238                         case GHOST_kEventWindowActivate: 
1239                         {
1240                                 GHOST_TEventKeyData kdata;
1241                                 wmEvent event;
1242                                 int wx, wy;
1243                                 const int keymodifier = ((query_qual(SHIFT)     ? KM_SHIFT : 0) |
1244                                                          (query_qual(CONTROL)   ? KM_CTRL  : 0) |
1245                                                          (query_qual(ALT)       ? KM_ALT   : 0) |
1246                                                          (query_qual(OS)        ? KM_OSKEY : 0));
1247
1248                                 /* Win23/GHOST modifier bug, see T40317 */
1249 #ifndef WIN32
1250 //#  define USE_WIN_ACTIVATE
1251 #endif
1252
1253                                 wm->winactive = win; /* no context change! c->wm->windrawable is drawable, or for area queues */
1254                                 
1255                                 win->active = 1;
1256 //                              window_handle(win, INPUTCHANGE, win->active);
1257                                 
1258                                 /* bad ghost support for modifier keys... so on activate we set the modifiers again */
1259
1260                                 /* TODO: This is not correct since a modifier may be held when a window is activated...
1261                                  * better solve this at ghost level. attempted fix r54450 but it caused bug [#34255]
1262                                  *
1263                                  * For now don't send GHOST_kEventKeyDown events, just set the 'eventstate'.
1264                                  */
1265                                 kdata.ascii = '\0';
1266                                 kdata.utf8_buf[0] = '\0';
1267
1268                                 if (win->eventstate->shift) {
1269                                         if ((keymodifier & KM_SHIFT) == 0) {
1270                                                 kdata.key = GHOST_kKeyLeftShift;
1271                                                 wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, time, &kdata);
1272                                         }
1273                                 }
1274 #ifdef USE_WIN_ACTIVATE
1275                                 else {
1276                                         if (keymodifier & KM_SHIFT) {
1277                                                 win->eventstate->shift = KM_MOD_FIRST;
1278                                         }
1279                                 }
1280 #endif
1281                                 if (win->eventstate->ctrl) {
1282                                         if ((keymodifier & KM_CTRL) == 0) {
1283                                                 kdata.key = GHOST_kKeyLeftControl;
1284                                                 wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, time, &kdata);
1285                                         }
1286                                 }
1287 #ifdef USE_WIN_ACTIVATE
1288                                 else {
1289                                         if (keymodifier & KM_CTRL) {
1290                                                 win->eventstate->ctrl = KM_MOD_FIRST;
1291                                         }
1292                                 }
1293 #endif
1294                                 if (win->eventstate->alt) {
1295                                         if ((keymodifier & KM_ALT) == 0) {
1296                                                 kdata.key = GHOST_kKeyLeftAlt;
1297                                                 wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, time, &kdata);
1298                                         }
1299                                 }
1300 #ifdef USE_WIN_ACTIVATE
1301                                 else {
1302                                         if (keymodifier & KM_ALT) {
1303                                                 win->eventstate->alt = KM_MOD_FIRST;
1304                                         }
1305                                 }
1306 #endif
1307                                 if (win->eventstate->oskey) {
1308                                         if ((keymodifier & KM_OSKEY) == 0) {
1309                                                 kdata.key = GHOST_kKeyOS;
1310                                                 wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, time, &kdata);
1311                                         }
1312                                 }
1313 #ifdef USE_WIN_ACTIVATE
1314                                 else {
1315                                         if (keymodifier & KM_OSKEY) {
1316                                                 win->eventstate->oskey = KM_MOD_FIRST;
1317                                         }
1318                                 }
1319 #endif
1320
1321 #undef USE_WIN_ACTIVATE
1322
1323
1324                                 /* keymodifier zero, it hangs on hotkeys that open windows otherwise */
1325                                 win->eventstate->keymodifier = 0;
1326                                 
1327                                 /* entering window, update mouse pos. but no event */
1328                                 wm_get_cursor_position(win,  &wx, &wy);
1329
1330                                 win->eventstate->x = wx;
1331                                 win->eventstate->y = wy;
1332                                 
1333                                 win->addmousemove = 1;   /* enables highlighted buttons */
1334                                 
1335                                 wm_window_make_drawable(wm, win);
1336
1337                                 /* window might be focused by mouse click in configuration of window manager
1338                                  * when focus is not following mouse
1339                                  * click could have been done on a button and depending on window manager settings
1340                                  * click would be passed to blender or not, but in any case button under cursor
1341                                  * should be activated, so at max next click on button without moving mouse
1342                                  * would trigger it's handle function
1343                                  * currently it seems to be common practice to generate new event for, but probably
1344                                  * we'll need utility function for this? (sergey)
1345                                  */
1346                                 wm_event_init_from_window(win, &event);
1347                                 event.type = MOUSEMOVE;
1348                                 event.prevx = event.x;
1349                                 event.prevy = event.y;
1350
1351                                 wm_event_add(win, &event);
1352
1353                                 break;
1354                         }
1355                         case GHOST_kEventWindowClose:
1356                         {
1357                                 wm_window_close(C, wm, win);
1358                                 break;
1359                         }
1360                         case GHOST_kEventWindowUpdate:
1361                         {
1362                                 if (G.debug & G_DEBUG_EVENTS) {
1363                                         printf("%s: ghost redraw %d\n", __func__, win->winid);
1364                                 }
1365                                 
1366                                 wm_window_make_drawable(wm, win);
1367                                 WM_event_add_notifier(C, NC_WINDOW, NULL);
1368
1369                                 break;
1370                         }
1371                         case GHOST_kEventWindowSize:
1372                         case GHOST_kEventWindowMove:
1373                         {
1374                                 GHOST_TWindowState state;
1375                                 state = GHOST_GetWindowState(win->ghostwin);
1376                                 win->windowstate = state;
1377
1378                                 /* stop screencast if resize */
1379                                 if (type == GHOST_kEventWindowSize) {
1380                                         WM_jobs_stop(wm, WM_window_get_active_screen(win), NULL);
1381                                 }
1382
1383                                 WM_window_set_dpi(win);
1384                                 
1385                                 /* win32: gives undefined window size when minimized */
1386                                 if (state != GHOST_kWindowStateMinimized) {
1387                                         GHOST_RectangleHandle client_rect;
1388                                         int l, t, r, b, scr_w, scr_h;
1389                                         int sizex, sizey, posx, posy;
1390                                         
1391                                         client_rect = GHOST_GetClientBounds(win->ghostwin);
1392                                         GHOST_GetRectangle(client_rect, &l, &t, &r, &b);
1393                                         
1394                                         GHOST_DisposeRectangle(client_rect);
1395                                         
1396                                         wm_get_desktopsize(&scr_w, &scr_h);
1397                                         sizex = r - l;
1398                                         sizey = b - t;
1399                                         posx = l;
1400                                         posy = scr_h - t - win->sizey;
1401
1402                                         /*
1403                                          * Ghost sometimes send size or move events when the window hasn't changed.
1404                                          * One case of this is using compiz on linux. To alleviate the problem
1405                                          * we ignore all such event here.
1406                                          * 
1407                                          * It might be good to eventually do that at Ghost level, but that is for 
1408                                          * another time.
1409                                          */
1410                                         if (win->sizex != sizex ||
1411                                             win->sizey != sizey ||
1412                                             win->posx != posx ||
1413                                             win->posy != posy)
1414                                         {
1415                                                 const bScreen *screen = WM_window_get_active_screen(win);
1416
1417                                                 win->sizex = sizex;
1418                                                 win->sizey = sizey;
1419                                                 win->posx = posx;
1420                                                 win->posy = posy;
1421
1422                                                 /* debug prints */
1423                                                 if (G.debug & G_DEBUG_EVENTS) {
1424                                                         const char *state_str;
1425                                                         state = GHOST_GetWindowState(win->ghostwin);
1426
1427                                                         if (state == GHOST_kWindowStateNormal) {
1428                                                                 state_str = "normal";
1429                                                         }
1430                                                         else if (state == GHOST_kWindowStateMinimized) {
1431                                                                 state_str = "minimized";
1432                                                         }
1433                                                         else if (state == GHOST_kWindowStateMaximized) {
1434                                                                 state_str = "maximized";
1435                                                         }
1436                                                         else if (state == GHOST_kWindowStateFullScreen) {
1437                                                                 state_str = "fullscreen";
1438                                                         }
1439                                                         else {
1440                                                                 state_str = "<unknown>";
1441                                                         }
1442
1443                                                         printf("%s: window %d state = %s\n", __func__, win->winid, state_str);
1444
1445                                                         if (type != GHOST_kEventWindowSize) {
1446                                                                 printf("win move event pos %d %d size %d %d\n",
1447                                                                        win->posx, win->posy, win->sizex, win->sizey);
1448                                                         }
1449                                                 }
1450                                         
1451                                                 wm_window_make_drawable(wm, win);
1452                                                 wm_draw_window_clear(win);
1453                                                 BKE_icon_changed(screen->id.icon_id);
1454                                                 WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
1455                                                 WM_event_add_notifier(C, NC_WINDOW | NA_EDITED, NULL);
1456                                                 
1457 #if defined(__APPLE__) || defined(WIN32)
1458                                                 /* OSX and Win32 don't return to the mainloop while resize */
1459                                                 wm_event_do_notifiers(C);
1460                                                 wm_draw_update(C);
1461
1462                                                 /* Warning! code above nulls 'C->wm.window', causing BGE to quit, see: T45699.
1463                                                  * Further, its easier to match behavior across platforms, so restore the window. */
1464                                                 CTX_wm_window_set(C, win);
1465 #endif
1466                                         }
1467                                 }
1468                                 break;
1469                         }
1470
1471                         case GHOST_kEventWindowDPIHintChanged:
1472                         {
1473                                 WM_window_set_dpi(win);
1474                                 /* font's are stored at each DPI level, without this we can easy load 100's of fonts */
1475                                 BLF_cache_clear();
1476
1477                                 WM_main_add_notifier(NC_WINDOW, NULL);      /* full redraw */
1478                                 WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL);    /* refresh region sizes */
1479                                 break;
1480                         }
1481
1482                         case GHOST_kEventOpenMainFile:
1483                         {
1484                                 PointerRNA props_ptr;
1485                                 wmWindow *oldWindow;
1486                                 const char *path = GHOST_GetEventData(evt);
1487                                 
1488                                 if (path) {
1489                                         wmOperatorType *ot = WM_operatortype_find("WM_OT_open_mainfile", false);
1490                                         /* operator needs a valid window in context, ensures
1491                                          * it is correctly set */
1492                                         oldWindow = CTX_wm_window(C);
1493                                         CTX_wm_window_set(C, win);
1494                                         
1495                                         WM_operator_properties_create_ptr(&props_ptr, ot);
1496                                         RNA_string_set(&props_ptr, "filepath", path);
1497                                         WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &props_ptr);
1498                                         WM_operator_properties_free(&props_ptr);
1499                                         
1500                                         CTX_wm_window_set(C, oldWindow);
1501                                 }
1502                                 break;
1503                         }
1504                         case GHOST_kEventDraggingDropDone:
1505                         {
1506                                 wmEvent event;
1507                                 GHOST_TEventDragnDropData *ddd = GHOST_GetEventData(evt);
1508                                 int wx, wy;
1509                                 
1510                                 /* entering window, update mouse pos */
1511                                 wm_get_cursor_position(win, &wx, &wy);
1512                                 win->eventstate->x = wx;
1513                                 win->eventstate->y = wy;
1514                                 
1515                                 wm_event_init_from_window(win, &event);  /* copy last state, like mouse coords */
1516                                 
1517                                 /* activate region */
1518                                 event.type = MOUSEMOVE;
1519                                 event.prevx = event.x;
1520                                 event.prevy = event.y;
1521                                 
1522                                 wm->winactive = win; /* no context change! c->wm->windrawable is drawable, or for area queues */
1523                                 win->active = 1;
1524                                 
1525                                 wm_event_add(win, &event);
1526                                 
1527                                 
1528                                 /* make blender drop event with custom data pointing to wm drags */
1529                                 event.type = EVT_DROP;
1530                                 event.val = KM_RELEASE;
1531                                 event.custom = EVT_DATA_DRAGDROP;
1532                                 event.customdata = &wm->drags;
1533                                 event.customdatafree = 1;
1534                                 
1535                                 wm_event_add(win, &event);
1536                                 
1537                                 /* printf("Drop detected\n"); */
1538                                 
1539                                 /* add drag data to wm for paths: */
1540                                 
1541                                 if (ddd->dataType == GHOST_kDragnDropTypeFilenames) {
1542                                         GHOST_TStringArray *stra = ddd->data;
1543                                         int a, icon;
1544                                         
1545                                         for (a = 0; a < stra->count; a++) {
1546                                                 printf("drop file %s\n", stra->strings[a]);
1547                                                 /* try to get icon type from extension */
1548                                                 icon = ED_file_extension_icon((char *)stra->strings[a]);
1549                                                 
1550                                                 WM_event_start_drag(C, icon, WM_DRAG_PATH, stra->strings[a], 0.0, WM_DRAG_NOP);
1551                                                 /* void poin should point to string, it makes a copy */
1552                                                 break; /* only one drop element supported now */
1553                                         }
1554                                 }
1555                                 
1556                                 break;
1557                         }
1558                         case GHOST_kEventNativeResolutionChange:
1559                         {
1560                                 // only update if the actual pixel size changes
1561                                 float prev_pixelsize = U.pixelsize;
1562                                 WM_window_set_dpi(win);
1563
1564                                 if (U.pixelsize != prev_pixelsize) {
1565                                         BKE_icon_changed(WM_window_get_active_screen(win)->id.icon_id);
1566
1567                                         // close all popups since they are positioned with the pixel
1568                                         // size baked in and it's difficult to correct them
1569                                         wmWindow *oldWindow = CTX_wm_window(C);
1570                                         CTX_wm_window_set(C, win);
1571                                         UI_popup_handlers_remove_all(C, &win->modalhandlers);
1572                                         CTX_wm_window_set(C, oldWindow);
1573
1574                                         wm_window_make_drawable(wm, win);
1575                                         wm_draw_window_clear(win);
1576
1577                                         WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
1578                                         WM_event_add_notifier(C, NC_WINDOW | NA_EDITED, NULL);
1579                                 }
1580
1581                                 break;
1582                         }
1583                         case GHOST_kEventTrackpad:
1584                         {
1585                                 GHOST_TEventTrackpadData *pd = data;
1586                                 
1587                                 wm_cursor_position_from_ghost(win, &pd->x, &pd->y);
1588                                 wm_event_add_ghostevent(wm, win, type, time, data);
1589                                 break;
1590                         }
1591                         case GHOST_kEventCursorMove:
1592                         {
1593                                 GHOST_TEventCursorData *cd = data;
1594                                 
1595                                 wm_cursor_position_from_ghost(win, &cd->x, &cd->y);
1596                                 wm_event_add_ghostevent(wm, win, type, time, data);
1597                                 break;
1598                         }
1599                         default:
1600                                 wm_event_add_ghostevent(wm, win, type, time, data);
1601                                 break;
1602                 }
1603
1604         }
1605         return 1;
1606 }
1607
1608
1609 /**
1610  * This timer system only gives maximum 1 timer event per redraw cycle,
1611  * to prevent queues to get overloaded.
1612  * Timer handlers should check for delta to decide if they just update, or follow real time.
1613  * Timer handlers can also set duration to match frames passed
1614  */
1615 static int wm_window_timer(const bContext *C)
1616 {
1617         wmWindowManager *wm = CTX_wm_manager(C);
1618         wmTimer *wt, *wtnext;
1619         wmWindow *win;
1620         double time = PIL_check_seconds_timer();
1621         int retval = 0;
1622         
1623         for (wt = wm->timers.first; wt; wt = wtnext) {
1624                 wtnext = wt->next; /* in case timer gets removed */
1625                 win = wt->win;
1626
1627                 if (wt->sleep == 0) {
1628                         if (time > wt->ntime) {
1629                                 wt->delta = time - wt->ltime;
1630                                 wt->duration += wt->delta;
1631                                 wt->ltime = time;
1632                                 wt->ntime = wt->stime + wt->timestep * ceil(wt->duration / wt->timestep);
1633
1634                                 if (wt->event_type == TIMERJOBS)
1635                                         wm_jobs_timer(C, wm, wt);
1636                                 else if (wt->event_type == TIMERAUTOSAVE)
1637                                         wm_autosave_timer(C, wm, wt);
1638                                 else if (wt->event_type == TIMERNOTIFIER)
1639                                         WM_main_add_notifier(GET_UINT_FROM_POINTER(wt->customdata), NULL);
1640                                 else if (win) {
1641                                         wmEvent event;
1642                                         wm_event_init_from_window(win, &event);
1643                                         
1644                                         event.type = wt->event_type;
1645                                         event.val = KM_NOTHING;
1646                                         event.keymodifier = 0;
1647                                         event.custom = EVT_DATA_TIMER;
1648                                         event.customdata = wt;
1649                                         wm_event_add(win, &event);
1650
1651                                         retval = 1;
1652                                 }
1653                         }
1654                 }
1655         }
1656         return retval;
1657 }
1658
1659 void wm_window_process_events(const bContext *C) 
1660 {
1661         int hasevent;
1662
1663         BLI_assert(BLI_thread_is_main());
1664
1665         hasevent = GHOST_ProcessEvents(g_system, 0); /* 0 is no wait */
1666
1667         if (hasevent)
1668                 GHOST_DispatchEvents(g_system);
1669         
1670         hasevent |= wm_window_timer(C);
1671
1672         /* no event, we sleep 5 milliseconds */
1673         if (hasevent == 0)
1674                 PIL_sleep_ms(5);
1675 }
1676
1677 void wm_window_process_events_nosleep(void) 
1678 {
1679         if (GHOST_ProcessEvents(g_system, 0))
1680                 GHOST_DispatchEvents(g_system);
1681 }
1682
1683 /* exported as handle callback to bke blender.c */
1684 void wm_window_testbreak(void)
1685 {
1686         static double ltime = 0;
1687         double curtime = PIL_check_seconds_timer();
1688
1689         BLI_assert(BLI_thread_is_main());
1690
1691         /* only check for breaks every 50 milliseconds
1692          * if we get called more often.
1693          */
1694         if ((curtime - ltime) > 0.05) {
1695                 int hasevent = GHOST_ProcessEvents(g_system, 0); /* 0 is no wait */
1696                 
1697                 if (hasevent)
1698                         GHOST_DispatchEvents(g_system);
1699                 
1700                 ltime = curtime;
1701         }
1702 }
1703
1704 /* **************** init ********************** */
1705
1706 void wm_ghost_init(bContext *C)
1707 {
1708         if (!g_system) {
1709                 GHOST_EventConsumerHandle consumer = GHOST_CreateEventConsumer(ghost_event_proc, C);
1710                 
1711                 g_system = GHOST_CreateSystem();
1712                 GHOST_AddEventConsumer(g_system, consumer);
1713                 
1714                 if (wm_init_state.native_pixels) {
1715                         GHOST_UseNativePixels();
1716                 }
1717         }
1718 }
1719
1720 void wm_ghost_exit(void)
1721 {
1722         if (g_system)
1723                 GHOST_DisposeSystem(g_system);
1724
1725         g_system = NULL;
1726 }
1727
1728 /* **************** timer ********************** */
1729
1730 /* to (de)activate running timers temporary */
1731 void WM_event_timer_sleep(wmWindowManager *wm, wmWindow *UNUSED(win), wmTimer *timer, bool do_sleep)
1732 {
1733         wmTimer *wt;
1734         
1735         for (wt = wm->timers.first; wt; wt = wt->next)
1736                 if (wt == timer)
1737                         break;
1738
1739         if (wt)
1740                 wt->sleep = do_sleep;
1741 }
1742
1743 wmTimer *WM_event_add_timer(wmWindowManager *wm, wmWindow *win, int event_type, double timestep)
1744 {
1745         wmTimer *wt = MEM_callocN(sizeof(wmTimer), "window timer");
1746
1747         wt->event_type = event_type;
1748         wt->ltime = PIL_check_seconds_timer();
1749         wt->ntime = wt->ltime + timestep;
1750         wt->stime = wt->ltime;
1751         wt->timestep = timestep;
1752         wt->win = win;
1753         
1754         BLI_addtail(&wm->timers, wt);
1755         
1756         return wt;
1757 }
1758
1759 wmTimer *WM_event_add_timer_notifier(wmWindowManager *wm, wmWindow *win, unsigned int type, double timestep)
1760 {
1761         wmTimer *wt = MEM_callocN(sizeof(wmTimer), "window timer");
1762
1763         wt->event_type = TIMERNOTIFIER;
1764         wt->ltime = PIL_check_seconds_timer();
1765         wt->ntime = wt->ltime + timestep;
1766         wt->stime = wt->ltime;
1767         wt->timestep = timestep;
1768         wt->win = win;
1769         wt->customdata = SET_UINT_IN_POINTER(type);
1770         wt->flags |= WM_TIMER_NO_FREE_CUSTOM_DATA;
1771
1772         BLI_addtail(&wm->timers, wt);
1773
1774         return wt;
1775 }
1776
1777 void WM_event_remove_timer(wmWindowManager *wm, wmWindow *UNUSED(win), wmTimer *timer)
1778 {
1779         wmTimer *wt;
1780         
1781         /* extra security check */
1782         for (wt = wm->timers.first; wt; wt = wt->next)
1783                 if (wt == timer)
1784                         break;
1785         if (wt) {
1786                 wmWindow *win;
1787                 
1788                 if (wm->reports.reporttimer == wt)
1789                         wm->reports.reporttimer = NULL;
1790                 
1791                 BLI_remlink(&wm->timers, wt);
1792                 if (wt->customdata != NULL && (wt->flags & WM_TIMER_NO_FREE_CUSTOM_DATA) == 0) {
1793                         MEM_freeN(wt->customdata);
1794                 }
1795                 MEM_freeN(wt);
1796                 
1797                 /* there might be events in queue with this timer as customdata */
1798                 for (win = wm->windows.first; win; win = win->next) {
1799                         wmEvent *event;
1800                         for (event = win->queue.first; event; event = event->next) {
1801                                 if (event->customdata == wt) {
1802                                         event->customdata = NULL;
1803                                         event->type = EVENT_NONE;       /* timer users customdata, dont want NULL == NULL */
1804                                 }
1805                         }
1806                 }
1807         }
1808 }
1809
1810 void WM_event_remove_timer_notifier(wmWindowManager *wm, wmWindow *win, wmTimer *timer)
1811 {
1812         timer->customdata = NULL;
1813         WM_event_remove_timer(wm, win, timer);
1814 }
1815
1816 /* ******************* clipboard **************** */
1817
1818 static char *wm_clipboard_text_get_ex(bool selection, int *r_len,
1819                                       bool firstline)
1820 {
1821         char *p, *p2, *buf, *newbuf;
1822
1823         if (G.background) {
1824                 *r_len = 0;
1825                 return NULL;
1826         }
1827
1828         buf = (char *)GHOST_getClipboard(selection);
1829         if (!buf) {
1830                 *r_len = 0;
1831                 return NULL;
1832         }
1833         
1834         /* always convert from \r\n to \n */
1835         p2 = newbuf = MEM_mallocN(strlen(buf) + 1, __func__);
1836
1837         if (firstline) {
1838                 /* will return an over-alloc'ed value in the case there are newlines */
1839                 for (p = buf; *p; p++) {
1840                         if ((*p != '\n') && (*p != '\r')) {
1841                                 *(p2++) = *p;
1842                         }
1843                         else {
1844                                 break;
1845                         }
1846                 }
1847         }
1848         else {
1849                 for (p = buf; *p; p++) {
1850                         if (*p != '\r') {
1851                                 *(p2++) = *p;
1852                         }
1853                 }
1854         }
1855
1856         *p2 = '\0';
1857
1858         free(buf); /* ghost uses regular malloc */
1859         
1860         *r_len = (p2 - newbuf);
1861
1862         return newbuf;
1863 }
1864
1865 /**
1866  * Return text from the clipboard.
1867  *
1868  * \note Caller needs to check for valid utf8 if this is a requirement.
1869  */
1870 char *WM_clipboard_text_get(bool selection, int *r_len)
1871 {
1872         return wm_clipboard_text_get_ex(selection, r_len, false);
1873 }
1874
1875 /**
1876  * Convenience function for pasting to areas of Blender which don't support newlines.
1877  */
1878 char *WM_clipboard_text_get_firstline(bool selection, int *r_len)
1879 {
1880         return wm_clipboard_text_get_ex(selection, r_len, true);
1881 }
1882
1883 void WM_clipboard_text_set(const char *buf, bool selection)
1884 {
1885         if (!G.background) {
1886 #ifdef _WIN32
1887                 /* do conversion from \n to \r\n on Windows */
1888                 const char *p;
1889                 char *p2, *newbuf;
1890                 int newlen = 0;
1891                 
1892                 for (p = buf; *p; p++) {
1893                         if (*p == '\n')
1894                                 newlen += 2;
1895                         else
1896                                 newlen++;
1897                 }
1898                 
1899                 newbuf = MEM_callocN(newlen + 1, "WM_clipboard_text_set");
1900         
1901                 for (p = buf, p2 = newbuf; *p; p++, p2++) {
1902                         if (*p == '\n') {
1903                                 *(p2++) = '\r'; *p2 = '\n';
1904                         }
1905                         else {
1906                                 *p2 = *p;
1907                         }
1908                 }
1909                 *p2 = '\0';
1910         
1911                 GHOST_putClipboard((GHOST_TInt8 *)newbuf, selection);
1912                 MEM_freeN(newbuf);
1913 #else
1914                 GHOST_putClipboard((GHOST_TInt8 *)buf, selection);
1915 #endif
1916         }
1917 }
1918
1919 /* ******************* progress bar **************** */
1920
1921 void WM_progress_set(wmWindow *win, float progress)
1922 {
1923         GHOST_SetProgressBar(win->ghostwin, progress);
1924 }
1925
1926 void WM_progress_clear(wmWindow *win)
1927 {
1928         GHOST_EndProgressBar(win->ghostwin);
1929 }
1930
1931 /* ************************************ */
1932
1933 void wm_window_get_position(wmWindow *win, int *r_pos_x, int *r_pos_y)
1934 {
1935         *r_pos_x = win->posx;
1936         *r_pos_y = win->posy;
1937 }
1938
1939 void wm_window_set_size(wmWindow *win, int width, int height) 
1940 {
1941         GHOST_SetClientSize(win->ghostwin, width, height);
1942 }
1943
1944 void wm_window_lower(wmWindow *win) 
1945 {
1946         GHOST_SetWindowOrder(win->ghostwin, GHOST_kWindowOrderBottom);
1947 }
1948
1949 void wm_window_raise(wmWindow *win) 
1950 {
1951         GHOST_SetWindowOrder(win->ghostwin, GHOST_kWindowOrderTop);
1952 }
1953
1954 void wm_window_swap_buffers(wmWindow *win)
1955 {
1956 #ifdef WIN32
1957         glDisable(GL_SCISSOR_TEST);
1958         GHOST_SwapWindowBuffers(win->ghostwin);
1959         glEnable(GL_SCISSOR_TEST);
1960 #else
1961         GHOST_SwapWindowBuffers(win->ghostwin);
1962 #endif
1963 }
1964
1965 void wm_window_set_swap_interval (wmWindow *win, int interval)
1966 {
1967         GHOST_SetSwapInterval(win->ghostwin, interval);
1968 }
1969
1970 bool wm_window_get_swap_interval(wmWindow *win, int *intervalOut)
1971 {
1972         return GHOST_GetSwapInterval(win->ghostwin, intervalOut);
1973 }
1974
1975
1976 /* ******************* exported api ***************** */
1977
1978
1979 /* called whem no ghost system was initialized */
1980 void WM_init_state_size_set(int stax, int stay, int sizx, int sizy)
1981 {
1982         wm_init_state.start_x = stax; /* left hand pos */
1983         wm_init_state.start_y = stay; /* bottom pos */
1984         wm_init_state.size_x = sizx < 640 ? 640 : sizx;
1985         wm_init_state.size_y = sizy < 480 ? 480 : sizy;
1986         wm_init_state.override_flag |= WIN_OVERRIDE_GEOM;
1987 }
1988
1989 /* for borderless and border windows set from command-line */
1990 void WM_init_state_fullscreen_set(void)
1991 {
1992         wm_init_state.windowstate = GHOST_kWindowStateFullScreen;
1993         wm_init_state.override_flag |= WIN_OVERRIDE_WINSTATE;
1994 }
1995
1996 void WM_init_state_normal_set(void)
1997 {
1998         wm_init_state.windowstate = GHOST_kWindowStateNormal;
1999         wm_init_state.override_flag |= WIN_OVERRIDE_WINSTATE;
2000 }
2001
2002 void WM_init_native_pixels(bool do_it)
2003 {
2004         wm_init_state.native_pixels = do_it;
2005 }
2006
2007 /* This function requires access to the GHOST_SystemHandle (g_system) */
2008 void WM_cursor_warp(wmWindow *win, int x, int y)
2009 {
2010         if (win && win->ghostwin) {
2011                 int oldx = x, oldy = y;
2012
2013                 wm_cursor_position_to_ghost(win, &x, &y);
2014                 GHOST_SetCursorPosition(g_system, x, y);
2015
2016                 win->eventstate->prevx = oldx;
2017                 win->eventstate->prevy = oldy;
2018
2019                 win->eventstate->x = oldx;
2020                 win->eventstate->y = oldy;
2021         }
2022 }
2023
2024 /**
2025  * Set x, y to values we can actually position the cursor to.
2026  */
2027 void WM_cursor_compatible_xy(wmWindow *win, int *x, int *y)
2028 {
2029         float f = GHOST_GetNativePixelSize(win->ghostwin);
2030         if (f != 1.0f) {
2031                 *x = (int)(*x / f) * f;
2032                 *y = (int)(*y / f) * f;
2033         }
2034 }
2035
2036 /**
2037  * Get the cursor pressure, in most cases you'll want to use wmTabletData from the event
2038  */
2039 float WM_cursor_pressure(const struct wmWindow *win)
2040 {
2041         const GHOST_TabletData *td = GHOST_GetTabletData(win->ghostwin);
2042         /* if there's tablet data from an active tablet device then add it */
2043         if ((td != NULL) && td->Active != GHOST_kTabletModeNone) {
2044                 return td->Pressure;
2045         }
2046         else {
2047                 return -1.0f;
2048         }
2049 }
2050
2051 /* support for native pixel size */
2052 /* mac retina opens window in size X, but it has up to 2 x more pixels */
2053 int WM_window_pixels_x(wmWindow *win)
2054 {
2055         float f = GHOST_GetNativePixelSize(win->ghostwin);
2056         
2057         return (int)(f * (float)win->sizex);
2058 }
2059
2060 int WM_window_pixels_y(wmWindow *win)
2061 {
2062         float f = GHOST_GetNativePixelSize(win->ghostwin);
2063         
2064         return (int)(f * (float)win->sizey);
2065         
2066 }
2067
2068 bool WM_window_is_fullscreen(wmWindow *win)
2069 {
2070         return win->windowstate == GHOST_kWindowStateFullScreen;
2071 }
2072
2073 /**
2074  * Some editor data may need to be synced with scene data (3D View camera and layers).
2075  * This function ensures data is synced for editors in visible workspaces and their visible layouts.
2076  */
2077 void WM_windows_scene_data_sync(const ListBase *win_lb, Scene *scene)
2078 {
2079         for (wmWindow *win = win_lb->first; win; win = win->next) {
2080                 if (WM_window_get_active_scene(win) == scene) {
2081                         ED_workspace_scene_data_sync(win->workspace_hook, scene);
2082                 }
2083         }
2084 }
2085
2086 Scene *WM_windows_scene_get_from_screen(const wmWindowManager *wm, const bScreen *screen)
2087 {
2088         for (wmWindow *win = wm->windows.first; win; win = win->next) {
2089                 if (WM_window_get_active_screen(win) == screen) {
2090                         return WM_window_get_active_scene(win);
2091                 }
2092         }
2093
2094         return NULL;
2095 }
2096
2097 WorkSpace *WM_windows_workspace_get_from_screen(const wmWindowManager *wm, const bScreen *screen)
2098 {
2099         for (wmWindow *win = wm->windows.first; win; win = win->next) {
2100                 if (WM_window_get_active_screen(win) == screen) {
2101                         return WM_window_get_active_workspace(win);
2102                 }
2103         }
2104         return NULL;
2105 }
2106
2107 eObjectMode WM_windows_object_mode_get(const struct wmWindowManager *wm)
2108 {
2109         eObjectMode object_mode = 0;
2110         for (wmWindow *win = wm->windows.first; win; win = win->next) {
2111                 const WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook);
2112                 if (workspace != NULL) {
2113                         object_mode |= workspace->object_mode;
2114                 }
2115         }
2116         return object_mode;
2117 }
2118
2119 Scene *WM_window_get_active_scene(const wmWindow *win)
2120 {
2121         return win->scene;
2122 }
2123
2124 /**
2125  * \warning Only call outside of area/region loops
2126  */
2127 void WM_window_change_active_scene(Main *bmain, bContext *C, wmWindow *win, Scene *scene_new)
2128 {
2129         const bScreen *screen = WM_window_get_active_screen(win);
2130         Scene *scene_old = win->scene;
2131
2132         ED_scene_change_update(bmain, C, win, screen, scene_old, scene_new);
2133 }
2134
2135 WorkSpace *WM_window_get_active_workspace(const wmWindow *win)
2136 {
2137         return BKE_workspace_active_get(win->workspace_hook);
2138 }
2139 void WM_window_set_active_workspace(wmWindow *win, WorkSpace *workspace)
2140 {
2141         BKE_workspace_active_set(win->workspace_hook, workspace);
2142 }
2143
2144 WorkSpaceLayout *WM_window_get_active_layout(const wmWindow *win)
2145 {
2146         const WorkSpace *workspace = WM_window_get_active_workspace(win);
2147         return (LIKELY(workspace != NULL) ? BKE_workspace_active_layout_get(win->workspace_hook) : NULL);
2148 }
2149 void WM_window_set_active_layout(wmWindow *win, WorkSpace *workspace, WorkSpaceLayout *layout)
2150 {
2151         BKE_workspace_hook_layout_for_workspace_set(win->workspace_hook, workspace, layout);
2152 }
2153
2154 /**
2155  * Get the active screen of the active workspace in \a win.
2156  */
2157 bScreen *WM_window_get_active_screen(const wmWindow *win)
2158 {
2159         const WorkSpace *workspace = WM_window_get_active_workspace(win);
2160         /* May be NULL in rare cases like closing Blender */
2161         return (LIKELY(workspace != NULL) ? BKE_workspace_active_screen_get(win->workspace_hook) : NULL);
2162 }
2163 void WM_window_set_active_screen(wmWindow *win, WorkSpace *workspace, bScreen *screen)
2164 {
2165         BKE_workspace_active_screen_set(win->workspace_hook, workspace, screen);
2166 }
2167
2168 bool WM_window_is_temp_screen(const wmWindow *win)
2169 {
2170         const bScreen *screen = WM_window_get_active_screen(win);
2171         return (screen && screen->temp != 0);
2172 }
2173
2174
2175 #ifdef WITH_INPUT_IME
2176 /* note: keep in mind wm_window_IME_begin is also used to reposition the IME window */
2177 void wm_window_IME_begin(wmWindow *win, int x, int y, int w, int h, bool complete)
2178 {
2179         BLI_assert(win);
2180
2181         GHOST_BeginIME(win->ghostwin, x, win->sizey - y, w, h, complete);
2182 }
2183
2184 void wm_window_IME_end(wmWindow *win)
2185 {
2186         BLI_assert(win && win->ime_data);
2187
2188         GHOST_EndIME(win->ghostwin);
2189         win->ime_data = NULL;
2190 }
2191 #endif  /* WITH_INPUT_IME */
2192
2193 /* ****** direct opengl context management ****** */
2194
2195 void *WM_opengl_context_create(void)
2196 {
2197         /* On Windows there is a problem creating contexts that share lists
2198          * from one context that is current in another thread.
2199          * So we should call this function only on the main thread.
2200          */
2201         BLI_assert(BLI_thread_is_main());
2202         return GHOST_CreateOpenGLContext(g_system);
2203 }
2204
2205 void WM_opengl_context_dispose(void *context)
2206 {
2207         GHOST_DisposeOpenGLContext(g_system, (GHOST_ContextHandle)context);
2208 }
2209
2210 void WM_opengl_context_activate(void *context)
2211 {
2212         GHOST_ActivateOpenGLContext((GHOST_ContextHandle)context);
2213 }
2214
2215 void WM_opengl_context_release(void *context)
2216 {
2217         GHOST_ReleaseOpenGLContext((GHOST_ContextHandle)context);
2218 }