1
0
mirror of https://github.com/mpv-player/mpv synced 2025-02-01 20:52:05 +00:00

vo_opengl, x11: implement icc-profile-auto

This queries the _ICC_PROFILE property on the root window. It also tries
to reload the ICC when it changes, or if the mpv window changes the
monitor. (If multiple monitors are covered, mpv will randomly select one
of them.)

The official spec is a dead link on freedesktop.org, so don't blame me
for any bugs.

Note that this assumes that Xinerama screen numbers match the way mpv
enumerates the xrandr monitors. Although there is some chance that this
matches, it most likely doesn't, and we actually have to do complicated
things to map the screen numbers. If it turns out that this is required,
I will fix it as soon as someone with a suitable setup for testing the
fix reports it.
This commit is contained in:
wm4 2015-01-26 02:18:47 +01:00
parent 73d5e396fe
commit df3e6b549c
3 changed files with 37 additions and 5 deletions

View File

@ -523,7 +523,7 @@ Available video output drivers are:
Automatically select the ICC display profile currently specified by
the display settings of the operating system.
NOTE: Only implemented on OS X with Cocoa.
NOTE: Only implemented on OS X and X11
``icc-cache=<file>``
Store and load the 3D LUT created from the ICC profile in this file.

View File

@ -148,7 +148,7 @@ static void *x11_get_property(struct vo_x11_state *x11, Window w, Atom property,
*out_nitems = 0;
if (!w)
return NULL;
long max_len = 64 * 1024; // static maximum limit
long max_len = 128 * 1024 * 1024; // static maximum limit
Atom ret_type = 0;
int ret_format = 0;
unsigned long ret_nitems = 0;
@ -970,6 +970,8 @@ int vo_x11_check_events(struct vo *vo)
}
} else if (Event.xproperty.atom == XA(x11, _NET_WM_STATE)) {
x11->pending_vo_events |= VO_EVENT_WIN_STATE;
} else if (Event.xproperty.atom == x11->icc_profile_property) {
x11->pending_vo_events |= VO_EVENT_ICC_PROFILE_PATH_CHANGED;
}
break;
default:
@ -1541,8 +1543,10 @@ static void vo_x11_update_geometry(struct vo *vo)
x11->winrc = (struct mp_rect){x, y, x + w, y + h};
double fps = 1000.0;
for (int n = 0; n < x11->num_displays; n++) {
if (rc_overlaps(x11->displays[n].rc, x11->winrc))
fps = MPMIN(fps, x11->displays[n].fps);
struct xrandr_display *disp = &x11->displays[n];
disp->overlaps = rc_overlaps(disp->rc, x11->winrc);
if (disp->overlaps)
fps = MPMIN(fps, disp->fps);
}
double fallback = x11->num_displays > 0 ? x11->displays[0].fps : 0;
fps = fps < 1000.0 ? fps : fallback;
@ -1550,7 +1554,7 @@ static void vo_x11_update_geometry(struct vo *vo)
MP_VERBOSE(x11, "Current display FPS: %f\n", fps);
x11->current_display_fps = fps;
// might have changed displays
x11->pending_vo_events |= VO_EVENT_WIN_STATE;
x11->pending_vo_events |= VO_EVENT_WIN_STATE | VO_EVENT_ICC_PROFILE_PATH_CHANGED;
}
static void vo_x11_fullscreen(struct vo *vo)
@ -1684,6 +1688,31 @@ int vo_x11_control(struct vo *vo, int *events, int request, void *arg)
*(char ***)arg = names;
return VO_TRUE;
}
case VOCTRL_GET_ICC_PROFILE: {
int screen = 0; // xinerama screen number
for (int n = 0; n < x11->num_displays; n++) {
struct xrandr_display *disp = &x11->displays[n];
if (disp->overlaps) {
screen = n;
break;
}
}
char prop[80];
snprintf(prop, sizeof(prop), "_ICC_PROFILE");
if (screen > 0)
mp_snprintf_cat(prop, sizeof(prop), "_%d", screen);
x11->icc_profile_property = XAs(x11, prop);
int len;
void *icc = x11_get_property(x11, x11->rootwin, x11->icc_profile_property,
XA_CARDINAL, 8, &len);
if (!icc)
return VO_FALSE;
*(bstr *)arg = bstrdup(NULL, (bstr){icc, len});
XFree(icc);
// Watch x11->icc_profile_property
XSelectInput(x11->display, x11->rootwin, PropertyChangeMask);
return VO_TRUE;
}
case VOCTRL_SET_CURSOR_VISIBILITY:
vo_set_cursor_hidden(vo, !(*(bool *)arg));
return VO_TRUE;

View File

@ -35,6 +35,7 @@ struct xrandr_display {
struct mp_rect rc;
double fps;
char *name;
bool overlaps;
};
struct vo_x11_state {
@ -110,6 +111,8 @@ struct vo_x11_state {
/* dragging the window */
bool win_drag_button1_down;
Atom icc_profile_property;
};
int vo_x11_init(struct vo *vo);