diff options
Diffstat (limited to 'video/out/x11_common.c')
-rw-r--r-- | video/out/x11_common.c | 203 |
1 files changed, 133 insertions, 70 deletions
diff --git a/video/out/x11_common.c b/video/out/x11_common.c index b4605bf..fa2f2ba 100644 --- a/video/out/x11_common.c +++ b/video/out/x11_common.c @@ -29,6 +29,7 @@ #include <X11/Xlib.h> #include <X11/Xutil.h> #include <X11/Xatom.h> +#include <X11/Xresource.h> #include <X11/keysym.h> #include <X11/XKBlib.h> #include <X11/XF86keysym.h> @@ -98,7 +99,9 @@ #define MWM_FUNC_MAXIMIZE (1L << 4) #define MWM_FUNC_CLOSE (1L << 5) -#define MWM_DECOR_ALL (1L << 0) +// Equals to all MWM_DECOR_* OR'd together. +#define MWM_DECOR_ALL 126 +#define MWM_DECOR_TITLE (1L << 3) typedef struct { @@ -603,6 +606,70 @@ static void vo_x11_get_bounding_monitors(struct vo_x11_state *x11, long b[4]) } } +// Get the dpi scale of the x11 screen. Almost no GUI programs use this value +// nowadays, and it has inconsistent behavior for different drivers. +// (it returns the physical display DPI for proprietary NVIDIA driver only, +// but essentially a user-set prefrence value everywhere else) +static void vo_x11_get_x11_screen_dpi_scale(struct vo_x11_state *x11) +{ + int w_mm = DisplayWidthMM(x11->display, x11->screen); + int h_mm = DisplayHeightMM(x11->display, x11->screen); + double dpi_x = x11->ws_width * 25.4 / w_mm; + double dpi_y = x11->ws_height * 25.4 / h_mm; + double base_dpi = 96; + if (isfinite(dpi_x) && isfinite(dpi_y)) { + int s_x = lrint(MPCLAMP(2 * dpi_x / base_dpi, 0, 20)); + int s_y = lrint(MPCLAMP(2 * dpi_y / base_dpi, 0, 20)); + if (s_x == s_y && s_x > 2 && s_x < 20) { + x11->dpi_scale = s_x / 2.0; + MP_VERBOSE(x11, "Using X11 screen DPI scale: %g", x11->dpi_scale); + } + } +} + +// Get the dpi scale from the Xft.dpi resource. In practice, this value is much more +// commonly used by GUI programs for scaling compared to the x11 screen dpi. +// This is always a preference value so it's also more consistent. +static bool vo_x11_get_xft_dpi_scale(struct vo_x11_state *x11) +{ + XrmInitialize(); + char *resman = XResourceManagerString(x11->display); + if (!resman) + return false; + + XrmDatabase db = XrmGetStringDatabase(resman); + if (!db) + return false; + + XrmValue ret; + char *type; + double base_dpi = 96; + bool success = false; + if (XrmGetResource(db, "Xft.dpi", "String", &type, &ret) == True && + ret.addr && !strcmp("String", type)) + { + char *end; + long value = strtol(ret.addr, &end, 10); + if (*ret.addr && *end == '\0') { + int s = lrint(MPCLAMP(2 * value / base_dpi, 0, 20)); + if (s > 2 && s < 20) { + x11->dpi_scale = s / 2.0; + MP_VERBOSE(x11, "Using Xft.dpi scale: %g", x11->dpi_scale); + success = true; + } + } + } + XrmDestroyDatabase(db); + return success; +} + +static void vo_x11_get_dpi_scale(struct vo_x11_state *x11) +{ + if (!vo_x11_get_xft_dpi_scale(x11)) + vo_x11_get_x11_screen_dpi_scale(x11); + x11->pending_vo_events |= VO_EVENT_DPI; +} + bool vo_x11_init(struct vo *vo) { char *dispName; @@ -667,21 +734,7 @@ bool vo_x11_init(struct vo *vo) x11->ws_width, x11->ws_height, dispName, x11->display_is_local ? "local" : "remote"); - int w_mm = DisplayWidthMM(x11->display, x11->screen); - int h_mm = DisplayHeightMM(x11->display, x11->screen); - double dpi_x = x11->ws_width * 25.4 / w_mm; - double dpi_y = x11->ws_height * 25.4 / h_mm; - double base_dpi = 96; - if (isfinite(dpi_x) && isfinite(dpi_y) && x11->opts->hidpi_window_scale) { - int s_x = lrint(MPCLAMP(dpi_x / base_dpi, 0, 10)); - int s_y = lrint(MPCLAMP(dpi_y / base_dpi, 0, 10)); - if (s_x == s_y && s_x > 1 && s_x < 10) { - x11->dpi_scale = s_x; - MP_VERBOSE(x11, "Assuming DPI scale %d for prescaling. This can " - "be disabled with --hidpi-window-scale=no.\n", - x11->dpi_scale); - } - } + vo_x11_get_dpi_scale(x11); x11->wm_type = vo_wm_detect(vo); @@ -754,7 +807,8 @@ static const struct mp_keymap keymap[] = { {XF86XK_HomePage, MP_KEY_HOMEPAGE}, {XF86XK_WWW, MP_KEY_WWW}, {XF86XK_Mail, MP_KEY_MAIL}, {XF86XK_Favorites, MP_KEY_FAVORITES}, {XF86XK_Search, MP_KEY_SEARCH}, {XF86XK_Sleep, MP_KEY_SLEEP}, - {XF86XK_Back, MP_KEY_BACK}, {XF86XK_Tools, MP_KEY_TOOLS}, + {XF86XK_Back, MP_KEY_GO_BACK}, {XF86XK_Forward, MP_KEY_GO_FORWARD}, + {XF86XK_Tools, MP_KEY_TOOLS}, {XF86XK_ZoomIn, MP_KEY_ZOOMIN}, {XF86XK_ZoomOut, MP_KEY_ZOOMOUT}, {0, 0} @@ -783,7 +837,7 @@ static int vo_x11_lookupkey(int key) return mpkey; } -static void vo_x11_decoration(struct vo *vo, bool d) +static void vo_x11_decoration(struct vo *vo, bool decorations, bool title_bar) { struct vo_x11_state *x11 = vo->x11; @@ -794,8 +848,9 @@ static void vo_x11_decoration(struct vo *vo, bool d) MotifWmHints mhints = {0}; bool got = x11_get_property_copy(x11, x11->window, motif_hints, motif_hints, 32, &mhints, sizeof(mhints)); - // hints weren't set, and decorations requested -> assume WM displays them - if (!got && d) + // If hints weren't set, and decorations and title bar requested, + // assume WM displays them. + if (!got && decorations && title_bar) return; if (!got) { mhints.flags = MWM_HINTS_FUNCTIONS; @@ -803,7 +858,8 @@ static void vo_x11_decoration(struct vo *vo, bool d) MWM_FUNC_MAXIMIZE | MWM_FUNC_RESIZE; } mhints.flags |= MWM_HINTS_DECORATIONS; - mhints.decorations = d ? MWM_DECOR_ALL : 0; + mhints.decorations = decorations ? MWM_DECOR_ALL : 0; + mhints.decorations &= ~(!title_bar ? MWM_DECOR_TITLE : 0); XChangeProperty(x11->display, x11->window, motif_hints, motif_hints, 32, PropModeReplace, (unsigned char *) &mhints, 5); } @@ -1105,11 +1161,6 @@ static void vo_x11_check_net_wm_state_change(struct vo *vo) XFree(elems); } - if (opts->window_maximized && !is_maximized && x11->geometry_change) { - x11->geometry_change = false; - vo_x11_config_vo_window(vo); - } - opts->window_minimized = is_minimized; x11->hidden = is_minimized; m_config_cache_write_opt(x11->opts_cache, &opts->window_minimized); @@ -1163,7 +1214,28 @@ static void release_all_keys(struct vo *vo) if (x11->no_autorepeat) mp_input_put_key(x11->input_ctx, MP_INPUT_RELEASE_ALL); - x11->win_drag_button1_down = false; +} + +static void vo_x11_begin_dragging(struct vo *vo) +{ + struct vo_x11_state *x11 = vo->x11; + XEvent Event = x11->last_button_event; + if (Event.type == ButtonPress && !x11->fs && + !mp_input_test_dragging(x11->input_ctx, Event.xmotion.x, + Event.xmotion.y)) + { + mp_input_put_key(x11->input_ctx, MP_INPUT_RELEASE_ALL); + XUngrabPointer(x11->display, CurrentTime); + + long params[5] = { + Event.xmotion.x_root, Event.xmotion.y_root, + 8, // _NET_WM_MOVERESIZE_MOVE + Event.xbutton.button, + 1, // source indication: normal + }; + x11_send_ewmh_msg(x11, "_NET_WM_MOVERESIZE", params); + x11->last_button_event = (XEvent){0}; + } } void vo_x11_check_events(struct vo *vo) @@ -1176,6 +1248,8 @@ void vo_x11_check_events(struct vo *vo) while (XPending(display)) { XNextEvent(display, &Event); + if (XFilterEvent(&Event, x11->window)) + continue; MP_TRACE(x11, "XEvent: %d\n", Event.type); switch (Event.type) { case Expose: @@ -1232,30 +1306,12 @@ void vo_x11_check_events(struct vo *vo) release_all_keys(vo); break; case MotionNotify: - if (x11->win_drag_button1_down && !x11->fs && - !mp_input_test_dragging(x11->input_ctx, Event.xmotion.x, - Event.xmotion.y)) - { - mp_input_put_key(x11->input_ctx, MP_INPUT_RELEASE_ALL); - XUngrabPointer(x11->display, CurrentTime); - - long params[5] = { - Event.xmotion.x_root, Event.xmotion.y_root, - 8, // _NET_WM_MOVERESIZE_MOVE - 1, // button 1 - 1, // source indication: normal - }; - x11_send_ewmh_msg(x11, "_NET_WM_MOVERESIZE", params); - } else { - mp_input_set_mouse_pos(x11->input_ctx, Event.xmotion.x, - Event.xmotion.y); - } - x11->win_drag_button1_down = false; + mp_input_set_mouse_pos(x11->input_ctx, Event.xmotion.x, + Event.xmotion.y); break; case LeaveNotify: if (Event.xcrossing.mode != NotifyNormal) break; - x11->win_drag_button1_down = false; mp_input_put_key(x11->input_ctx, MP_KEY_MOUSE_LEAVE); break; case EnterNotify: @@ -1266,22 +1322,20 @@ void vo_x11_check_events(struct vo *vo) case ButtonPress: if (Event.xbutton.button - 1 >= MP_KEY_MOUSE_BTN_COUNT) break; - if (Event.xbutton.button == 1) - x11->win_drag_button1_down = true; mp_input_put_key(x11->input_ctx, (MP_MBTN_BASE + Event.xbutton.button - 1) | get_mods(Event.xbutton.state) | MP_KEY_STATE_DOWN); long msg[4] = {XEMBED_REQUEST_FOCUS}; vo_x11_xembed_send_message(x11, msg); + x11->last_button_event = Event; break; case ButtonRelease: if (Event.xbutton.button - 1 >= MP_KEY_MOUSE_BTN_COUNT) break; - if (Event.xbutton.button == 1) - x11->win_drag_button1_down = false; mp_input_put_key(x11->input_ctx, (MP_MBTN_BASE + Event.xbutton.button - 1) | get_mods(Event.xbutton.state) | MP_KEY_STATE_UP); + x11->last_button_event = Event; break; case MapNotify: x11->window_hidden = false; @@ -1343,6 +1397,7 @@ void vo_x11_check_events(struct vo *vo) } if (Event.type == x11->xrandr_event) { xrandr_read(x11); + vo_x11_get_dpi_scale(x11); vo_x11_update_geometry(vo); } break; @@ -1372,8 +1427,7 @@ static void vo_x11_sizehint(struct vo *vo, struct mp_rect rc, bool override_pos) override_pos; // for fullscreen and such XSizeHints *hint = XAllocSizeHints(); - if (!hint) - return; // OOM + MP_HANDLE_OOM(hint); hint->flags |= PSize | (force_pos ? PPosition : 0); hint->x = rc.x0; @@ -1579,7 +1633,7 @@ static void vo_x11_create_window(struct vo *vo, XVisualInfo *vis, if (x11->xim) { x11->xic = XCreateIC(x11->xim, - XNInputStyle, XIMPreeditNone | XIMStatusNone, + XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow, x11->window, XNFocusWindow, x11->window, NULL); @@ -1601,7 +1655,7 @@ static void vo_x11_map_window(struct vo *vo, struct mp_rect rc) struct vo_x11_state *x11 = vo->x11; vo_x11_move_resize(vo, true, true, rc); - vo_x11_decoration(vo, x11->opts->border); + vo_x11_decoration(vo, x11->opts->border, x11->opts->title_bar); if (x11->opts->fullscreen && (x11->wm_type & vo_wm_FULLSCREEN)) { Atom state = XA(x11, _NET_WM_STATE_FULLSCREEN); @@ -1667,12 +1721,12 @@ static void vo_x11_map_window(struct vo *vo, struct mp_rect rc) vo_x11_xembed_update(x11, XEMBED_MAPPED); } -static void vo_x11_highlevel_resize(struct vo *vo, struct mp_rect rc) +static void vo_x11_highlevel_resize(struct vo *vo, struct mp_rect rc, bool force) { struct vo_x11_state *x11 = vo->x11; struct mp_vo_opts *opts = x11->opts; - bool reset_pos = opts->force_window_position; + bool reset_pos = opts->force_window_position || force; if (reset_pos) { x11->nofsrc = rc; } else { @@ -1742,10 +1796,6 @@ void vo_x11_config_vo_window(struct vo *vo) assert(x11->window); - // Don't attempt to change autofit/geometry on maximized windows. - if (x11->geometry_change && opts->window_maximized) - return; - vo_x11_update_screeninfo(vo); struct vo_win_geometry geo; @@ -1761,15 +1811,19 @@ void vo_x11_config_vo_window(struct vo *vo) bool reset_size = (x11->old_dw != RC_W(rc) || x11->old_dh != RC_H(rc)) && (opts->auto_window_resize || x11->geometry_change); + reset_size |= (x11->old_x != rc.x0 || x11->old_y != rc.y0) && + (x11->geometry_change); x11->old_dw = RC_W(rc); x11->old_dh = RC_H(rc); + x11->old_x = rc.x0; + x11->old_y = rc.y0; if (x11->window_hidden) { x11->nofsrc = rc; vo_x11_map_window(vo, rc); } else if (reset_size) { - vo_x11_highlevel_resize(vo, rc); + vo_x11_highlevel_resize(vo, rc, x11->geometry_change); } x11->geometry_change = false; @@ -1922,7 +1976,7 @@ static void vo_x11_fullscreen(struct vo *vo) rc = x11->screenrc; } - vo_x11_decoration(vo, opts->border && !x11->fs); + vo_x11_decoration(vo, opts->border && !x11->fs, opts->title_bar); vo_x11_sizehint(vo, rc, true); XMoveResizeWindow(x11->display, x11->window, rc.x0, rc.y0, @@ -2020,8 +2074,8 @@ int vo_x11_control(struct vo *vo, int *events, int request, void *arg) vo_x11_fullscreen(vo); if (opt == &opts->ontop) vo_x11_setlayer(vo, opts->ontop); - if (opt == &opts->border) - vo_x11_decoration(vo, opts->border); + if (opt == &opts->border || opt == &opts->title_bar) + vo_x11_decoration(vo, opts->border, opts->title_bar); if (opt == &opts->all_workspaces) vo_x11_sticky(vo, opts->all_workspaces); if (opt == &opts->window_minimized) @@ -2035,6 +2089,12 @@ int vo_x11_control(struct vo *vo, int *events, int request, void *arg) if (opt == &opts->geometry || opt == &opts->autofit || opt == &opts->autofit_smaller || opt == &opts->autofit_larger) { + if (opts->window_maximized && !opts->fullscreen) { + x11->opts->window_maximized = false; + m_config_cache_write_opt(x11->opts_cache, + &x11->opts->window_maximized); + vo_x11_maximize(vo); + } vo_x11_set_geometry(vo); } } @@ -2044,16 +2104,16 @@ int vo_x11_control(struct vo *vo, int *events, int request, void *arg) int *s = arg; if (!x11->window || x11->parent) return VO_FALSE; - s[0] = (x11->fs ? RC_W(x11->nofsrc) : RC_W(x11->winrc)) / x11->dpi_scale; - s[1] = (x11->fs ? RC_H(x11->nofsrc) : RC_H(x11->winrc)) / x11->dpi_scale; + s[0] = x11->fs ? RC_W(x11->nofsrc) : RC_W(x11->winrc); + s[1] = x11->fs ? RC_H(x11->nofsrc) : RC_H(x11->winrc); return VO_TRUE; } case VOCTRL_SET_UNFS_WINDOW_SIZE: { int *s = arg; if (!x11->window || x11->parent) return VO_FALSE; - int w = s[0] * x11->dpi_scale; - int h = s[1] * x11->dpi_scale; + int w = s[0]; + int h = s[1]; struct mp_rect rc = x11->winrc; rc.x1 = rc.x0 + w; rc.y1 = rc.y0 + h; @@ -2063,7 +2123,7 @@ int vo_x11_control(struct vo *vo, int *events, int request, void *arg) &x11->opts->window_maximized); vo_x11_maximize(vo); } - vo_x11_highlevel_resize(vo, rc); + vo_x11_highlevel_resize(vo, rc, false); if (!x11->fs) { // guess new window size, instead of waiting for X x11->winrc.x1 = x11->winrc.x0 + w; x11->winrc.y1 = x11->winrc.y0 + h; @@ -2151,6 +2211,9 @@ int vo_x11_control(struct vo *vo, int *events, int request, void *arg) case VOCTRL_GET_HIDPI_SCALE: *(double *)arg = x11->dpi_scale; return VO_TRUE; + case VOCTRL_BEGIN_DRAGGING: + vo_x11_begin_dragging(vo); + return VO_TRUE; } return VO_NOTIMPL; } |