Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/windowmanager/intern/wm_window.c')
-rw-r--r--source/blender/windowmanager/intern/wm_window.c282
1 files changed, 238 insertions, 44 deletions
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index 2d43c47679d..06bd60e8692 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -70,6 +70,7 @@
#include "ED_fileselect.h"
#include "UI_interface.h"
+#include "UI_resources.h"
#include "PIL_time.h"
@@ -77,6 +78,7 @@
#include "GPU_extensions.h"
#include "GPU_init_exit.h"
#include "GPU_glew.h"
+#include "BLF_api.h"
/* for assert */
#ifndef NDEBUG
@@ -294,11 +296,158 @@ wmWindow *wm_window_copy_test(bContext *C, wmWindow *win_src)
}
}
+
+/* -------------------------------------------------------------------- */
+/** \name Quit Confirmation Dialog
+ * \{ */
+
+/** Cancel quitting and close the dialog */
+static void wm_block_confirm_quit_cancel(bContext *C, void *arg_block, void *UNUSED(arg))
+{
+ wmWindow *win = CTX_wm_window(C);
+ UI_popup_block_close(C, win, arg_block);
+}
+
+/** Discard the file changes and quit */
+static void wm_block_confirm_quit_discard(bContext *C, void *arg_block, void *UNUSED(arg))
+{
+ wmWindow *win = CTX_wm_window(C);
+ UI_popup_block_close(C, win, arg_block);
+ WM_exit(C);
+}
+
+/* Save changes and quit */
+static void wm_block_confirm_quit_save(bContext *C, void *arg_block, void *UNUSED(arg))
+{
+ PointerRNA props_ptr;
+ wmWindow *win = CTX_wm_window(C);
+
+ UI_popup_block_close(C, win, arg_block);
+
+ wmOperatorType *ot = WM_operatortype_find("WM_OT_save_mainfile", false);
+
+ WM_operator_properties_create_ptr(&props_ptr, ot);
+ RNA_boolean_set(&props_ptr, "exit", true);
+ /* No need for second confirmation popup. */
+ RNA_boolean_set(&props_ptr, "check_existing", false);
+ WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr);
+ WM_operator_properties_free(&props_ptr);
+}
+
+
+/* Build the confirm dialog UI */
+static uiBlock *block_create_confirm_quit(struct bContext *C, struct ARegion *ar, void *UNUSED(arg1))
+{
+
+ uiStyle *style = UI_style_get();
+ uiBlock *block = UI_block_begin(C, ar, "confirm_quit_popup", UI_EMBOSS);
+
+ UI_block_flag_enable(block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_LOOP | UI_BLOCK_NO_WIN_CLIP | UI_BLOCK_NUMSELECT);
+ UI_block_emboss_set(block, UI_EMBOSS);
+
+ uiLayout *layout = UI_block_layout(
+ block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 10, 2, U.widget_unit * 24, U.widget_unit * 6, 0, style);
+
+ /* Text and some vertical space */
+ {
+ char *message;
+ if (G.main->name[0] == '\0') {
+ message = BLI_strdup(IFACE_("This file has not been saved yet. Save before closing?"));
+ }
+ else {
+ const char *basename = BLI_path_basename(G.main->name);
+ message = BLI_sprintfN(IFACE_("Save changes to \"%s\" before closing?"), basename);
+ }
+ uiItemL(layout, message, ICON_ERROR);
+ MEM_freeN(message);
+ }
+
+ uiItemS(layout);
+ uiItemS(layout);
+
+
+ /* Buttons */
+ uiBut *but;
+
+ uiLayout *split = uiLayoutSplit(layout, 0.0f, true);
+
+ uiLayout *col = uiLayoutColumn(split, false);
+
+ but = uiDefIconTextBut(
+ block, UI_BTYPE_BUT, 0, ICON_SCREEN_BACK, IFACE_("Cancel"), 0, 0, 0, UI_UNIT_Y,
+ NULL, 0, 0, 0, 0, TIP_("Do not quit"));
+ UI_but_func_set(but, wm_block_confirm_quit_cancel, block, NULL);
+
+ /* empty space between buttons */
+ col = uiLayoutColumn(split, false);
+ uiItemS(col);
+
+ col = uiLayoutColumn(split, 1);
+ but = uiDefIconTextBut(
+ block, UI_BTYPE_BUT, 0, ICON_CANCEL, IFACE_("Discard Changes"), 0, 0, 50, UI_UNIT_Y,
+ NULL, 0, 0, 0, 0, TIP_("Discard changes and quit"));
+ UI_but_func_set(but, wm_block_confirm_quit_discard, block, NULL);
+
+ col = uiLayoutColumn(split, 1);
+ but = uiDefIconTextBut(
+ block, UI_BTYPE_BUT, 0, ICON_FILE_TICK, IFACE_("Save & Quit"), 0, 0, 50, UI_UNIT_Y,
+ NULL, 0, 0, 0, 0, TIP_("Save and quit"));
+ UI_but_func_set(but, wm_block_confirm_quit_save, block, NULL);
+
+ UI_block_bounds_set_centered(block, 10);
+
+ return block;
+}
+
+
+/**
+ * Call the confirm dialog on quitting. It's displayed in the context window so
+ * caller should set it as desired.
+ */
+static void wm_confirm_quit(bContext *C)
+{
+ wmWindow *win = CTX_wm_window(C);
+
+ if (GHOST_SupportsNativeDialogs() == 0) {
+ UI_popup_block_invoke(C, block_create_confirm_quit, NULL);
+ }
+ else if (GHOST_confirmQuit(win->ghostwin)) {
+ wm_exit_schedule_delayed(C);
+ }
+}
+
+/**
+ * Call the quit confirmation prompt or exit directly if needed. The use can
+ * still cancel via the confirmation popup. Also, this may not quit Blender
+ * immediately, but rather schedule the closing.
+ *
+ * \param win The window to show the confirmation popup/window in.
+ */
+void wm_quit_with_optional_confirmation_prompt(bContext *C, wmWindow *win)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win_ctx = CTX_wm_window(C);
+
+ /* The popup will be displayed in the context window which may not be set
+ * here (this function gets called outside of normal event handling loop). */
+ CTX_wm_window_set(C, win);
+
+ if ((U.uiflag & USER_QUIT_PROMPT) && !wm->file_saved && !G.background) {
+ wm_confirm_quit(C);
+ }
+ else {
+ wm_exit_schedule_delayed(C);
+ }
+
+ CTX_wm_window_set(C, win_ctx);
+}
+
+/** \} */
+
/* this is event from ghost, or exit-blender op */
void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win)
{
wmWindow *tmpwin;
- bool do_exit = false;
/* first check if we have to quit (there are non-temp remaining windows) */
for (tmpwin = wm->windows.first; tmpwin; tmpwin = tmpwin->next) {
@@ -308,21 +457,11 @@ void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win)
break;
}
- if (tmpwin == NULL)
- do_exit = 1;
-
- if ((U.uiflag & USER_QUIT_PROMPT) && !wm->file_saved) {
- if (do_exit) {
- if (!GHOST_confirmQuit(win->ghostwin))
- return;
- }
- }
-
- /* let WM_exit do all freeing, for correct quit.blend save */
- if (do_exit) {
- WM_exit(C);
+ if (tmpwin == NULL) {
+ wm_quit_with_optional_confirmation_prompt(C, win);
}
else {
+ /* We're just closing a window */
bScreen *screen = win->screen;
BLI_remlink(&wm->windows, win);
@@ -374,14 +513,49 @@ void wm_window_title(wmWindowManager *wm, wmWindow *win)
}
}
-static float wm_window_get_virtual_pixelsize(void)
+void WM_window_set_dpi(wmWindow *win)
{
- return ((U.virtual_pixel == VIRTUAL_PIXEL_NATIVE) ? 1.0f : 2.0f);
-}
+ float auto_dpi = GHOST_GetDPIHint(win->ghostwin);
-float wm_window_pixelsize(wmWindow *win)
-{
- return (GHOST_GetNativePixelSize(win->ghostwin) * wm_window_get_virtual_pixelsize());
+ /* Clamp auto DPI to 96, since our font/interface drawing does not work well
+ * with lower sizes. The main case we are interested in supporting is higher
+ * DPI. If a smaller UI is desired it is still possible to adjust UI scale. */
+ auto_dpi = max_ff(auto_dpi, 96.0f);
+
+ /* Lazily init UI scale size, preserving backwards compatibility by
+ * computing UI scale from ratio of previous DPI and auto DPI */
+ if (U.ui_scale == 0) {
+ int virtual_pixel = (U.virtual_pixel == VIRTUAL_PIXEL_NATIVE) ? 1 : 2;
+
+ if (U.dpi == 0) {
+ U.ui_scale = virtual_pixel;
+ }
+ else {
+ U.ui_scale = (virtual_pixel * U.dpi * 96.0f) / (auto_dpi * 72.0f);
+ }
+
+ CLAMP(U.ui_scale, 0.25f, 4.0f);
+ }
+
+ /* Blender's UI drawing assumes DPI 72 as a good default following macOS
+ * while Windows and Linux use DPI 96. GHOST assumes a default 96 so we
+ * remap the DPI to Blender's convention. */
+ auto_dpi *= GHOST_GetNativePixelSize(win->ghostwin);
+ int dpi = auto_dpi * U.ui_scale * (72.0 / 96.0f);
+
+ /* Automatically set larger pixel size for high DPI. */
+ int pixelsize = max_ii(1, (int)(dpi / 64));
+ /* User adjustment for pixel size. */
+ pixelsize = max_ii(1, pixelsize + U.ui_line_width);
+
+ /* Set user preferences globals for drawing, and for forward compatibility. */
+ U.pixelsize = pixelsize;
+ U.dpi = dpi / pixelsize;
+ U.virtual_pixel = (pixelsize == 1) ? VIRTUAL_PIXEL_NATIVE : VIRTUAL_PIXEL_DOUBLE;
+ U.widget_unit = (U.pixelsize * U.dpi * 20 + 36) / 72;
+
+ /* update font drawing */
+ BLF_default_dpi(U.pixelsize * U.dpi);
}
/* belongs to below */
@@ -412,12 +586,7 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm
ghostwin = GHOST_CreateWindow(g_system, title,
win->posx, posy, win->sizex, win->sizey,
-#ifdef __APPLE__
- /* we agreed to not set any fullscreen or iconized state on startup */
- GHOST_kWindowStateNormal,
-#else
(GHOST_TWindowState)win->windowstate,
-#endif
GHOST_kDrawingContextTypeOpenGL,
glSettings);
@@ -441,8 +610,12 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm
/* store actual window size in blender window */
bounds = GHOST_GetClientBounds(win->ghostwin);
- win->sizex = GHOST_GetWidthRectangle(bounds);
- win->sizey = GHOST_GetHeightRectangle(bounds);
+
+ /* win32: gives undefined window size when minimized */
+ if (GHOST_GetWindowState(win->ghostwin) != GHOST_kWindowStateMinimized) {
+ win->sizex = GHOST_GetWidthRectangle(bounds);
+ win->sizey = GHOST_GetHeightRectangle(bounds);
+ }
GHOST_DisposeRectangle(bounds);
#ifndef __APPLE__
@@ -456,10 +629,8 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm
glClear(GL_COLOR_BUFFER_BIT);
}
- /* displays with larger native pixels, like Macbook. Used to scale dpi with */
/* needed here, because it's used before it reads userdef */
- U.pixelsize = wm_window_pixelsize(win);
- BKE_blender_userdef_refresh();
+ WM_window_set_dpi(win);
wm_window_swap_buffers(win);
@@ -472,7 +643,7 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm
}
/**
- * Initialize #wmWindows without ghostwin, open these and clear.
+ * Initialize #wmWindow without ghostwin, open these and clear.
*
* window size is read from window, if 0 it uses prefsize
* called in #WM_check, also inits stuff after file read.
@@ -618,15 +789,27 @@ wmWindow *WM_window_open(bContext *C, const rcti *rect)
* \param type: WM_WINDOW_RENDER, WM_WINDOW_USERPREFS...
* \return the window or NULL.
*/
-wmWindow *WM_window_open_temp(bContext *C, const rcti *rect_init, int type)
+wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, int type)
{
wmWindow *win_prev = CTX_wm_window(C);
wmWindow *win;
ScrArea *sa;
Scene *scene = CTX_data_scene(C);
const char *title;
- rcti rect = *rect_init;
- const short px_virtual = (short)wm_window_get_virtual_pixelsize();
+
+ /* convert to native OS window coordinates */
+ const float native_pixel_size = GHOST_GetNativePixelSize(win_prev->ghostwin);
+ x /= native_pixel_size;
+ y /= native_pixel_size;
+ sizex /= native_pixel_size;
+ sizey /= native_pixel_size;
+
+ /* calculate postition */
+ rcti rect;
+ rect.xmin = x + win_prev->posx - sizex / 2;
+ rect.ymin = y + win_prev->posy - sizey / 2;
+ rect.xmax = rect.xmin + sizex;
+ rect.ymax = rect.ymin + sizey;
/* changes rect to fit within desktop */
wm_window_check_position(&rect);
@@ -644,9 +827,8 @@ wmWindow *WM_window_open_temp(bContext *C, const rcti *rect_init, int type)
win->posy = rect.ymin;
}
- /* multiply with virtual pixelsize, ghost handles native one (e.g. for retina) */
- win->sizex = BLI_rcti_size_x(&rect) * px_virtual;
- win->sizey = BLI_rcti_size_y(&rect) * px_virtual;
+ win->sizex = BLI_rcti_size_x(&rect);
+ win->sizey = BLI_rcti_size_y(&rect);
if (win->ghostwin) {
wm_window_set_size(win, win->sizex, win->sizey);
@@ -835,8 +1017,7 @@ void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win)
GHOST_ActivateWindowDrawingContext(win->ghostwin);
/* this can change per window */
- U.pixelsize = wm_window_pixelsize(win);
- BKE_blender_userdef_refresh();
+ WM_window_set_dpi(win);
}
}
@@ -1035,6 +1216,8 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
if (type == GHOST_kEventWindowSize) {
WM_jobs_stop(wm, win->screen, NULL);
}
+
+ WM_window_set_dpi(win);
/* win32: gives undefined window size when minimized */
if (state != GHOST_kWindowStateMinimized) {
@@ -1118,7 +1301,18 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
}
break;
}
-
+
+ case GHOST_kEventWindowDPIHintChanged:
+ {
+ WM_window_set_dpi(win);
+ /* font's are stored at each DPI level, without this we can easy load 100's of fonts */
+ BLF_cache_clear();
+
+ WM_main_add_notifier(NC_WINDOW, NULL); /* full redraw */
+ WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL); /* refresh region sizes */
+ break;
+ }
+
case GHOST_kEventOpenMainFile:
{
PointerRNA props_ptr;
@@ -1199,11 +1393,9 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
{
// only update if the actual pixel size changes
float prev_pixelsize = U.pixelsize;
- U.pixelsize = wm_window_pixelsize(win);
+ WM_window_set_dpi(win);
if (U.pixelsize != prev_pixelsize) {
- BKE_blender_userdef_refresh();
-
// close all popups since they are positioned with the pixel
// size baked in and it's difficult to correct them
wmWindow *oldWindow = CTX_wm_window(C);
@@ -1407,6 +1599,7 @@ wmTimer *WM_event_add_timer_notifier(wmWindowManager *wm, wmWindow *win, unsigne
wt->timestep = timestep;
wt->win = win;
wt->customdata = SET_UINT_IN_POINTER(type);
+ wt->flags |= WM_TIMER_NO_FREE_CUSTOM_DATA;
BLI_addtail(&wm->timers, wt);
@@ -1428,8 +1621,9 @@ void WM_event_remove_timer(wmWindowManager *wm, wmWindow *UNUSED(win), wmTimer *
wm->reports.reporttimer = NULL;
BLI_remlink(&wm->timers, wt);
- if (wt->customdata)
+ if (wt->customdata != NULL && (wt->flags & WM_TIMER_NO_FREE_CUSTOM_DATA) == 0) {
MEM_freeN(wt->customdata);
+ }
MEM_freeN(wt);
/* there might be events in queue with this timer as customdata */