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