Merge branch 'master' into menu-accelerators

This commit is contained in:
Alex Chernika 2026-05-08 00:20:57 +02:00
commit 634a3464bd
No known key found for this signature in database
GPG key ID: 6029FAD8ABFB076A
12 changed files with 321 additions and 69 deletions

18
NEWS.md
View file

@ -314,7 +314,7 @@ Note to package maintainers: This release requires wayland version >=1.22.90
and get keyboard focus so that they can be operated with the keyboard. and get keyboard focus so that they can be operated with the keyboard.
An example use-case is the xfce4-panel applications-menu being opened by An example use-case is the xfce4-panel applications-menu being opened by
the command xfce4-popup-applicationsmenu. [#3165] @johanmalm the command xfce4-popup-applicationsmenu. [#3165] @johanmalm
- On popup destory, return focus to whoever had it before the popop [#3165] - On popup destroy, return focus to whoever had it before the popop [#3165]
@johanmalm @tokyo4j @johanmalm @tokyo4j
- Unshade window if selected from client-list-combined-menu [#3345] @Amodio - Unshade window if selected from client-list-combined-menu [#3345] @Amodio
- Show non-dialog child windows in window-switcher [#3339] @tokyo4j - Show non-dialog child windows in window-switcher [#3339] @tokyo4j
@ -409,7 +409,7 @@ A big thank you to all involved in this release.
client surface. Fixes a regression in 885919f. @tokyo4j [#3211] client surface. Fixes a regression in 885919f. @tokyo4j [#3211]
- Set all foreign-toplevel initial states correctly. This is not believed to fix - Set all foreign-toplevel initial states correctly. This is not believed to fix
any particular user-issue, but just feels safer. @jlindgren90 [#3217] any particular user-issue, but just feels safer. @jlindgren90 [#3217]
- Update layer-shell client top layer visiblity on unmap instead of destroy - Update layer-shell client top layer visibility on unmap instead of destroy
because it is possible for fullscreen xwayland windows to be unmapped without because it is possible for fullscreen xwayland windows to be unmapped without
being destroyed, and in this case the top layer visibility needs to be updated being destroyed, and in this case the top layer visibility needs to be updated
to unhide other layer-shell clients like panels. @jlindgren90 [#3199] to unhide other layer-shell clients like panels. @jlindgren90 [#3199]
@ -421,7 +421,7 @@ A big thank you to all involved in this release.
@elviosak [#3146] [#3168] @elviosak [#3146] [#3168]
- Work around client-side rounding issues at right/bottom pixel. This fixes an - Work around client-side rounding issues at right/bottom pixel. This fixes an
issue with some clients (notably Qt ones) where cursor coordinates in the issue with some clients (notably Qt ones) where cursor coordinates in the
rightmost or bottom fixel are incorrectly rounded up putting them outside the rightmost or bottom pixel are incorrectly rounded up putting them outside the
surface bounds. The issue has been particularly noticeable with layer-shell surface bounds. The issue has been particularly noticeable with layer-shell
clients like lxqt-panel. @jlindgren90 [#3157] [#2379] [#3099] clients like lxqt-panel. @jlindgren90 [#3157] [#2379] [#3099]
Note: This also avoids a similar server-side rounding issue with some Note: This also avoids a similar server-side rounding issue with some
@ -638,7 +638,7 @@ window.*.title.bg.colorTo.splitTo:
window rule to enable this. @Consolatis @tokyo4j [#2840] window rule to enable this. @Consolatis @tokyo4j [#2840]
- Add config option `<core><primarySelection>`. This enables autoscroll - Add config option `<core><primarySelection>`. This enables autoscroll
(middle-click to scroll up/down) in Chromium and electron based clients (middle-click to scroll up/down) in Chromium and electron based clients
without inadvertantly pasting the primary clipboard. @johanmalm [#2832] without inadvertently pasting the primary clipboard. @johanmalm [#2832]
- Bump `xdg_shell` version from 3 to 6 @tokyo4j [#2814] - Bump `xdg_shell` version from 3 to 6 @tokyo4j [#2814]
- Bump `wl_compositor` version from 5 to 6 @tokyo4j [#2812] - Bump `wl_compositor` version from 5 to 6 @tokyo4j [#2812]
- Support tablet tool mouse buttons @jp7677 [#2778] - Support tablet tool mouse buttons @jp7677 [#2778]
@ -715,7 +715,7 @@ window.*.title.bg.colorTo.splitTo:
agnostic on choice of launcher. agnostic on choice of launcher.
- `A-<arrow>` for `MoveToEdge` because `Alt-` keybinds should be for clients - `A-<arrow>` for `MoveToEdge` because `Alt-` keybinds should be for clients
to use and this one results in frequent user complaints because it prevents to use and this one results in frequent user complaints because it prevents
some common usage patterns like alt-left/right in web browers. some common usage patterns like alt-left/right in web browsers.
- Change default titlebar menu button from a dot to an arrow @johanmalm [#2844] - Change default titlebar menu button from a dot to an arrow @johanmalm [#2844]
- When `dragLock` is set to `yes`, the drag no longer expires after a short - When `dragLock` is set to `yes`, the drag no longer expires after a short
delay (known as `Sticky` mode) as recommended by libinput [#2803]. The timeout delay (known as `Sticky` mode) as recommended by libinput [#2803]. The timeout
@ -887,7 +887,7 @@ Notes to package maintainers:
closing a popup did not move the pointer focus to the main toplevel until the closing a popup did not move the pointer focus to the main toplevel until the
cursor was moved. [#2443] cursor was moved. [#2443]
- Improve algorithm for menu placement with xdg-positioner [#2408] - Improve algorithm for menu placement with xdg-positioner [#2408]
- Do not forward IME key-release without correspinding key-press to avoid stuck - Do not forward IME key-release without corresponding key-press to avoid stuck
keys [#2437] keys [#2437]
### Changed ### Changed
@ -1347,7 +1347,7 @@ joint effort by @spl237 and @Consolatis.
- Respect `menu.overlap.x` when using pipemenus. [#1940] - Respect `menu.overlap.x` when using pipemenus. [#1940]
- Do not try to restore windows to very small width/height on unmaximize. - Do not try to restore windows to very small width/height on unmaximize.
This fixes a bug with Thonny (Python IDE made with Tk). [#1938] This fixes a bug with Thonny (Python IDE made with Tk). [#1938]
- Conditially set squared server-side decoration (SSD) corners when a view is - Conditionally set squared server-side decoration (SSD) corners when a view is
tiled. Written-by: @jp7677 [#1926] tiled. Written-by: @jp7677 [#1926]
- Remember initial direction when starting window-cycling with `PreviousView`. - Remember initial direction when starting window-cycling with `PreviousView`.
Also make the toggling of direction when shift is pressed relative to the Also make the toggling of direction when shift is pressed relative to the
@ -1371,7 +1371,7 @@ joint effort by @spl237 and @Consolatis.
Chromium and Steam. [#1861] Chromium and Steam. [#1861]
- Session-lock: fix flashing & update cursor shape. [#1858] - Session-lock: fix flashing & update cursor shape. [#1858]
- Remove tearing-controller listeners on destroy. [#1853] - Remove tearing-controller listeners on destroy. [#1853]
- Handle invalid `ForEach` and `If` action cofigs. [#1838] - Handle invalid `ForEach` and `If` action configs. [#1838]
- Delay startup of applications until event loop is ready. This avoids race - Delay startup of applications until event loop is ready. This avoids race
conditions when using autostart scripts that trigger a labwc SIGHUP. [#1588] conditions when using autostart scripts that trigger a labwc SIGHUP. [#1588]
- With `SendToDesktop` action follow=no option, ensure the topmost window is - With `SendToDesktop` action follow=no option, ensure the topmost window is
@ -1405,7 +1405,7 @@ contributions from others as noted in the log.
### Added ### Added
- Add `<menu><ignoreButtonReleasePeriod>` to prevent clicks with small movements - Add `<menu><ignoreButtonReleasePeriod>` to prevent clicks with small movements
from inadvertantly closing a menu or selecting a menu item. This is the from inadvertently closing a menu or selecting a menu item. This is the
equivalent of `<menu><hideDelay>` on Openbox. [#1760] equivalent of `<menu><hideDelay>` on Openbox. [#1760]
- Support drop-shadows (disabled by default) for windows using server-side - Support drop-shadows (disabled by default) for windows using server-side
decorations. Written-by: @cillian64 decorations. Written-by: @cillian64

View file

@ -175,6 +175,7 @@ this is for compatibility with Openbox.
<adaptiveSync>no</adaptiveSync> <adaptiveSync>no</adaptiveSync>
<allowTearing>no</allowTearing> <allowTearing>no</allowTearing>
<autoEnableOutputs>yes</autoEnableOutputs> <autoEnableOutputs>yes</autoEnableOutputs>
<hdr>no</hdr>
<reuseOutputMode>no</reuseOutputMode> <reuseOutputMode>no</reuseOutputMode>
<xwaylandPersistence>no</xwaylandPersistence> <xwaylandPersistence>no</xwaylandPersistence>
<primarySelection>yes</primarySelection> <primarySelection>yes</primarySelection>
@ -240,6 +241,11 @@ this is for compatibility with Openbox.
'pkill kanshi ; wlopm --off \*' resume 'kanshi & wlopm --on \*' 'pkill kanshi ; wlopm --off \*' resume 'kanshi & wlopm --on \*'
``` ```
*<core><hdr>* [yes|no]
Automatically enable HDR support on outputs when configuring them,
where supported by the particular output device and display. Default
is no.
*<core><reuseOutputMode>* [yes|no] *<core><reuseOutputMode>* [yes|no]
Try to re-use the existing output mode (resolution / refresh rate). Try to re-use the existing output mode (resolution / refresh rate).
This may prevent unnecessary screenblank delays when starting labwc This may prevent unnecessary screenblank delays when starting labwc

View file

@ -13,6 +13,7 @@
<adaptiveSync>no</adaptiveSync> <adaptiveSync>no</adaptiveSync>
<allowTearing>no</allowTearing> <allowTearing>no</allowTearing>
<autoEnableOutputs>yes</autoEnableOutputs> <autoEnableOutputs>yes</autoEnableOutputs>
<hdr>no</hdr>
<reuseOutputMode>no</reuseOutputMode> <reuseOutputMode>no</reuseOutputMode>
<xwaylandPersistence>no</xwaylandPersistence> <xwaylandPersistence>no</xwaylandPersistence>
<primarySelection>yes</primarySelection> <primarySelection>yes</primarySelection>

View file

@ -62,7 +62,11 @@
#define BOUNDED_INT(a) ((a) < INT_MAX && (a) > INT_MIN) #define BOUNDED_INT(a) ((a) < INT_MAX && (a) > INT_MIN)
#endif #endif
#define LAB_WLR_VERSION_AT_LEAST(major, minor, micro) \ #define _LAB_CALC_WLR_VERSION_NUM(major, minor, micro) (((major) << 16) | ((minor) << 8) | (micro))
(WLR_VERSION_NUM >= (((major) << 16) | ((minor) << 8) | (micro)))
#define LAB_WLR_VERSION_AT_LEAST(major, minor, micro) ( \
server.wlr_version >= _LAB_CALC_WLR_VERSION_NUM(major, minor, micro))
#define LAB_WLR_VERSION_LOWER(major, minor, micro) (!LAB_WLR_VERSION_AT_LEAST(major, minor, micro))
#endif /* LABWC_MACROS_H */ #endif /* LABWC_MACROS_H */

View file

@ -36,6 +36,12 @@ enum tearing_mode {
LAB_TEARING_FULLSCREEN_FORCED, LAB_TEARING_FULLSCREEN_FORCED,
}; };
enum render_bit_depth {
LAB_RENDER_BIT_DEPTH_DEFAULT = 0,
LAB_RENDER_BIT_DEPTH_8,
LAB_RENDER_BIT_DEPTH_10,
};
enum tiling_events_mode { enum tiling_events_mode {
LAB_TILING_EVENTS_NEVER = 0, LAB_TILING_EVENTS_NEVER = 0,
LAB_TILING_EVENTS_REGION = 1 << 0, LAB_TILING_EVENTS_REGION = 1 << 0,
@ -74,6 +80,7 @@ struct rcxml {
int gap; int gap;
enum adaptive_sync_mode adaptive_sync; enum adaptive_sync_mode adaptive_sync;
enum tearing_mode allow_tearing; enum tearing_mode allow_tearing;
enum render_bit_depth target_render_depth;
bool auto_enable_outputs; bool auto_enable_outputs;
bool reuse_output_mode; bool reuse_output_mode;
uint32_t allowed_interfaces; uint32_t allowed_interfaces;

View file

@ -148,6 +148,8 @@ struct seat {
}; };
struct server { struct server {
uint32_t wlr_version;
struct wl_display *wl_display; struct wl_display *wl_display;
struct wl_event_loop *wl_event_loop; /* Can be used for timer events */ struct wl_event_loop *wl_event_loop; /* Can be used for timer events */

View file

@ -71,6 +71,9 @@ struct wlr_box output_usable_area_in_layout_coords(struct output *output);
void handle_output_power_manager_set_mode(struct wl_listener *listener, void handle_output_power_manager_set_mode(struct wl_listener *listener,
void *data); void *data);
void output_enable_adaptive_sync(struct output *output, bool enabled); void output_enable_adaptive_sync(struct output *output, bool enabled);
void output_enable_hdr(struct output *output, struct wlr_output_state *os,
bool enabled, bool silent);
void output_state_setup_hdr(struct output *output, bool silent);
/** /**
* Notifies whether a fullscreen view is displayed on the given output. * Notifies whether a fullscreen view is displayed on the given output.

View file

@ -1080,6 +1080,16 @@ set_tearing_mode(const char *str, enum tearing_mode *variable)
} }
} }
static void
set_hdr_mode(const char *str, enum render_bit_depth *variable)
{
if (parse_bool(str, -1) == 1) {
*variable = LAB_RENDER_BIT_DEPTH_10;
} else {
*variable = LAB_RENDER_BIT_DEPTH_8;
}
}
/* Returns true if the node's children should also be traversed */ /* Returns true if the node's children should also be traversed */
static bool static bool
entry(xmlNode *node, char *nodename, char *content) entry(xmlNode *node, char *nodename, char *content)
@ -1144,6 +1154,8 @@ entry(xmlNode *node, char *nodename, char *content)
set_adaptive_sync_mode(content, &rc.adaptive_sync); set_adaptive_sync_mode(content, &rc.adaptive_sync);
} else if (!strcasecmp(nodename, "allowTearing.core")) { } else if (!strcasecmp(nodename, "allowTearing.core")) {
set_tearing_mode(content, &rc.allow_tearing); set_tearing_mode(content, &rc.allow_tearing);
} else if (!strcasecmp(nodename, "Hdr.core")) {
set_hdr_mode(content, &rc.target_render_depth);
} else if (!strcasecmp(nodename, "autoEnableOutputs.core")) { } else if (!strcasecmp(nodename, "autoEnableOutputs.core")) {
set_bool(content, &rc.auto_enable_outputs); set_bool(content, &rc.auto_enable_outputs);
} else if (!strcasecmp(nodename, "reuseOutputMode.core")) { } else if (!strcasecmp(nodename, "reuseOutputMode.core")) {
@ -1518,6 +1530,7 @@ rcxml_init(void)
rc.gap = 0; rc.gap = 0;
rc.adaptive_sync = LAB_ADAPTIVE_SYNC_DISABLED; rc.adaptive_sync = LAB_ADAPTIVE_SYNC_DISABLED;
rc.allow_tearing = LAB_TEARING_DISABLED; rc.allow_tearing = LAB_TEARING_DISABLED;
rc.target_render_depth = LAB_RENDER_BIT_DEPTH_DEFAULT;
rc.auto_enable_outputs = true; rc.auto_enable_outputs = true;
rc.reuse_output_mode = false; rc.reuse_output_mode = false;
rc.allowed_interfaces = UINT32_MAX; rc.allowed_interfaces = UINT32_MAX;

View file

@ -9,6 +9,7 @@
#include "common/mem.h" #include "common/mem.h"
#include "common/scene-helpers.h" #include "common/scene-helpers.h"
#include "config/rcxml.h" #include "config/rcxml.h"
#include "config/types.h"
#include "labwc.h" #include "labwc.h"
#include "node.h" #include "node.h"
#include "output.h" #include "output.h"
@ -322,6 +323,27 @@ handle_osd_tree_destroy(struct wl_listener *listener, void *data)
free(osd_output); free(osd_output);
} }
static enum lab_view_criteria
get_view_criteria(struct cycle_filter *filter)
{
enum lab_view_criteria criteria =
LAB_VIEW_CRITERIA_NO_SKIP_WINDOW_SWITCHER
| LAB_VIEW_CRITERIA_NO_DIALOG;
if (filter->workspace == CYCLE_WORKSPACE_CURRENT) {
criteria |= LAB_VIEW_CRITERIA_CURRENT_WORKSPACE;
}
return criteria;
}
static const char *
get_cycle_app_id(struct cycle_filter *filter)
{
if (filter->app_id == CYCLE_APP_ID_CURRENT && server.active_view) {
return server.active_view->app_id;
}
return NULL;
}
static struct wl_list *prev(struct wl_list *elm) { return elm->prev; } static struct wl_list *prev(struct wl_list *elm) { return elm->prev; }
static struct wl_list *next(struct wl_list *elm) { return elm->next; } static struct wl_list *next(struct wl_list *elm) { return elm->next; }
@ -331,17 +353,10 @@ cycle_immediate(enum lab_cycle_dir direction, struct cycle_filter filter)
if (wl_list_empty(&server.views)) { if (wl_list_empty(&server.views)) {
return; return;
} }
enum lab_view_criteria criteria =
LAB_VIEW_CRITERIA_NO_SKIP_WINDOW_SWITCHER enum lab_view_criteria criteria = get_view_criteria(&filter);
| LAB_VIEW_CRITERIA_NO_DIALOG;
if (filter.workspace == CYCLE_WORKSPACE_CURRENT) {
criteria |= LAB_VIEW_CRITERIA_CURRENT_WORKSPACE;
}
uint64_t cycle_outputs = get_outputs_by_filter(filter.output); uint64_t cycle_outputs = get_outputs_by_filter(filter.output);
const char *cycle_app_id = NULL; const char *cycle_app_id = get_cycle_app_id(&filter);
if (filter.app_id == CYCLE_APP_ID_CURRENT && server.active_view) {
cycle_app_id = server.active_view->app_id;
}
struct wl_list *head = &server.views; struct wl_list *head = &server.views;
struct wl_list *(*iter)(struct wl_list *list); struct wl_list *(*iter)(struct wl_list *list);
@ -381,20 +396,9 @@ cycle_immediate(enum lab_cycle_dir direction, struct cycle_filter filter)
static bool static bool
init_cycle(struct cycle_filter filter) init_cycle(struct cycle_filter filter)
{ {
enum lab_view_criteria criteria = enum lab_view_criteria criteria = get_view_criteria(&filter);
LAB_VIEW_CRITERIA_NO_SKIP_WINDOW_SWITCHER uint64_t cycle_outputs = get_outputs_by_filter(filter.output);
| LAB_VIEW_CRITERIA_NO_DIALOG; const char *cycle_app_id = get_cycle_app_id(&filter);
if (filter.workspace == CYCLE_WORKSPACE_CURRENT) {
criteria |= LAB_VIEW_CRITERIA_CURRENT_WORKSPACE;
}
uint64_t cycle_outputs =
get_outputs_by_filter(filter.output);
const char *cycle_app_id = NULL;
if (filter.app_id == CYCLE_APP_ID_CURRENT && server.active_view) {
cycle_app_id = server.active_view->app_id;
}
struct view *view; struct view *view;
for_each_view(view, &server.views, criteria) { for_each_view(view, &server.views, criteria) {

View file

@ -4,8 +4,10 @@
#include <pango/pangocairo.h> #include <pango/pangocairo.h>
#include <signal.h> #include <signal.h>
#include <unistd.h> #include <unistd.h>
#include <wlr/version.h>
#include "common/fd-util.h" #include "common/fd-util.h"
#include "common/font.h" #include "common/font.h"
#include "common/macros.h"
#include "common/spawn.h" #include "common/spawn.h"
#include "config/rcxml.h" #include "config/rcxml.h"
#include "config/session.h" #include "config/session.h"
@ -65,12 +67,15 @@ static void
print_version(void) print_version(void)
{ {
#define FEATURE_ENABLED(feature) (HAVE_##feature ? "+" : "-") #define FEATURE_ENABLED(feature) (HAVE_##feature ? "+" : "-")
printf("labwc %s (%sxwayland %snls %srsvg %slibsfdo)\n", printf("labwc %s (%sxwayland %snls %srsvg %slibsfdo) running on wlroots %d.%d.%d\n",
LABWC_VERSION, LABWC_VERSION,
FEATURE_ENABLED(XWAYLAND), FEATURE_ENABLED(XWAYLAND),
FEATURE_ENABLED(NLS), FEATURE_ENABLED(NLS),
FEATURE_ENABLED(RSVG), FEATURE_ENABLED(RSVG),
FEATURE_ENABLED(LIBSFDO) FEATURE_ENABLED(LIBSFDO),
wlr_version_get_major(),
wlr_version_get_minor(),
wlr_version_get_micro()
); );
#undef FEATURE_ENABLED #undef FEATURE_ENABLED
} }
@ -164,6 +169,12 @@ main(int argc, char *argv[])
char *primary_client = NULL; char *primary_client = NULL;
enum wlr_log_importance verbosity = WLR_ERROR; enum wlr_log_importance verbosity = WLR_ERROR;
server.wlr_version = _LAB_CALC_WLR_VERSION_NUM(
wlr_version_get_major(),
wlr_version_get_minor(),
wlr_version_get_micro()
);
int c; int c;
while (1) { while (1) {
int index = 0; int index = 0;

View file

@ -24,6 +24,7 @@ output_state_init(struct output *output)
backup_config, output->wlr_output); backup_config, output->wlr_output);
wlr_output_head_v1_state_apply(&backup_head->state, &output->pending); wlr_output_head_v1_state_apply(&backup_head->state, &output->pending);
wlr_output_configuration_v1_destroy(backup_config); wlr_output_configuration_v1_destroy(backup_config);
} }

View file

@ -9,6 +9,7 @@
#define _POSIX_C_SOURCE 200809L #define _POSIX_C_SOURCE 200809L
#include "output.h" #include "output.h"
#include <assert.h> #include <assert.h>
#include <drm_fourcc.h>
#include <strings.h> #include <strings.h>
#include <wlr/backend/wayland.h> #include <wlr/backend/wayland.h>
#include <wlr/config.h> #include <wlr/config.h>
@ -51,6 +52,150 @@
#include <wlr/backend/session.h> #include <wlr/backend/session.h>
#endif #endif
static uint32_t output_formats_8bit[] = {
/* 32 bpp RGB with 8 bit component width */
DRM_FORMAT_XRGB8888,
DRM_FORMAT_XBGR8888,
DRM_FORMAT_RGBX8888,
DRM_FORMAT_BGRX8888,
DRM_FORMAT_ARGB8888,
DRM_FORMAT_ABGR8888,
DRM_FORMAT_RGBA8888,
DRM_FORMAT_BGRA8888,
/* 24 bpp RGB */
DRM_FORMAT_RGB888,
DRM_FORMAT_BGR888,
};
uint32_t output_formats_10bit[] = {
/* 32 bpp RGB with 10 bit component width */
DRM_FORMAT_XRGB2101010,
DRM_FORMAT_XBGR2101010,
DRM_FORMAT_RGBX1010102,
DRM_FORMAT_BGRX1010102,
DRM_FORMAT_ARGB2101010,
DRM_FORMAT_ABGR2101010,
DRM_FORMAT_RGBA1010102,
DRM_FORMAT_BGRA1010102,
};
static bool
output_set_render_format(struct output *output, uint32_t candidates[], size_t count)
{
for (size_t i = 0; i < count; i++) {
wlr_output_state_set_render_format(&output->pending, candidates[i]);
if (wlr_output_test_state(output->wlr_output, &output->pending)) {
return true;
}
}
return false;
}
static bool
output_format_in_candidates(uint32_t render_format, uint32_t candidates[], size_t count)
{
for (size_t i = 0; i < count; i++) {
if (candidates[i] == render_format) {
return true;
}
}
return false;
}
static enum render_bit_depth
bit_depth_from_format(uint32_t render_format)
{
if (output_format_in_candidates(render_format, output_formats_10bit,
ARRAY_SIZE(output_formats_10bit))) {
return LAB_RENDER_BIT_DEPTH_10;
} else if (output_format_in_candidates(render_format, output_formats_8bit,
ARRAY_SIZE(output_formats_8bit))) {
return LAB_RENDER_BIT_DEPTH_8;
}
return LAB_RENDER_BIT_DEPTH_DEFAULT;
}
static enum render_bit_depth
get_config_render_bit_depth(void)
{
return rc.target_render_depth;
}
static bool
output_supports_hdr(const struct wlr_output *output, const char **unsupported_reason_ptr)
{
const char *unsupported_reason = NULL;
if (!(output->supported_primaries & WLR_COLOR_NAMED_PRIMARIES_BT2020)) {
unsupported_reason = "BT2020 primaries not supported by output";
} else if (!(output->supported_transfer_functions &
WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ)) {
unsupported_reason = "PQ transfer function not supported by output";
} else if (!server.renderer->features.output_color_transform) {
unsupported_reason = "renderer doesn't support output color transforms";
}
if (unsupported_reason_ptr) {
*unsupported_reason_ptr = unsupported_reason;
}
return !unsupported_reason;
}
void
output_state_setup_hdr(struct output *output, bool silent)
{
uint32_t render_format = output->wlr_output->render_format;
const char *unsupported_reason = NULL;
bool hdr_supported = output_supports_hdr(output->wlr_output,
&unsupported_reason);
bool hdr_succeeded = false;
enum render_bit_depth render_bit_depth = get_config_render_bit_depth();
if (render_bit_depth == LAB_RENDER_BIT_DEPTH_DEFAULT) {
render_bit_depth = bit_depth_from_format(render_format);
}
if (!hdr_supported && render_bit_depth == LAB_RENDER_BIT_DEPTH_10) {
if (!silent) {
wlr_log(WLR_INFO, "Cannot enable HDR on output %s: %s",
output->wlr_output->name, unsupported_reason);
}
render_bit_depth = LAB_RENDER_BIT_DEPTH_8;
}
if (render_bit_depth == LAB_RENDER_BIT_DEPTH_10 &&
bit_depth_from_format(render_format) == render_bit_depth) {
/* 10-bit was set successfully before, try to save some
* tests by reusing the format
*/
hdr_succeeded = true;
} else if (render_bit_depth == LAB_RENDER_BIT_DEPTH_10) {
hdr_succeeded = output_set_render_format(output, output_formats_10bit,
ARRAY_SIZE(output_formats_10bit));
if (!hdr_succeeded) {
if (!silent) {
wlr_log(WLR_INFO, "No 10 bit color formats"
" supported, HDR disabled.");
}
if (!output_set_render_format(output, output_formats_8bit,
ARRAY_SIZE(output_formats_8bit))) {
if (!silent) {
wlr_log(WLR_ERROR, "No 8 bit color formats"
" supported either!");
}
}
}
} else {
if (!output_set_render_format(output, output_formats_8bit,
ARRAY_SIZE(output_formats_8bit)) && !silent) {
wlr_log(WLR_ERROR, "No 8 bit color formats supported!");
}
}
output_enable_hdr(output, &output->pending, hdr_succeeded, silent);
}
bool bool
output_get_tearing_allowance(struct output *output) output_get_tearing_allowance(struct output *output)
{ {
@ -371,10 +516,7 @@ configure_new_output(struct output *output)
output_enable_adaptive_sync(output, true); output_enable_adaptive_sync(output, true);
} }
output_state_commit(output); output_state_setup_hdr(output, false);
wlr_output_effective_resolution(wlr_output,
&output->usable_area.width, &output->usable_area.height);
/* /*
* Wait until wlr_output_layout_add_auto() returns before * Wait until wlr_output_layout_add_auto() returns before
@ -384,6 +526,19 @@ configure_new_output(struct output *output)
server.pending_output_layout_change++; server.pending_output_layout_change++;
add_output_to_layout(output); add_output_to_layout(output);
server.pending_output_layout_change--; server.pending_output_layout_change--;
/*
* Commit the output this way instead, HDR needs a buffer, and
* this commit must be called after the output is added to the
* layout above.
*/
lab_wlr_scene_output_commit(output->scene_output, &output->pending);
/*
* Collect the effective resolution after the final commit.
*/
wlr_output_effective_resolution(wlr_output,
&output->usable_area.width, &output->usable_area.height);
} }
static uint64_t static uint64_t
@ -653,6 +808,7 @@ output_config_apply(struct wlr_output_configuration_v1 *config)
wlr_output_state_set_transform(os, head->state.transform); wlr_output_state_set_transform(os, head->state.transform);
output_enable_adaptive_sync(output, output_enable_adaptive_sync(output,
head->state.adaptive_sync_enabled); head->state.adaptive_sync_enabled);
output_state_setup_hdr(output, false);
} }
if (!output_state_commit(output)) { if (!output_state_commit(output)) {
/* /*
@ -666,6 +822,19 @@ output_config_apply(struct wlr_output_configuration_v1 *config)
break; break;
} }
if (output_enabled) {
/*
* The above commit was likely made without an image
* buffer attached. This will break applying HDR color
* transformation, since image descriptions must be
* committed with a buffer attached. Queue the HDR mode
* again if output is enabled, but make it silent,
* since it would have emitted messages already when
* called above.
*/
output_state_setup_hdr(output, true);
}
/* /*
* Add or remove output from layout only if the commit went * Add or remove output from layout only if the commit went
* through. Note that at startup, the output may have already * through. Note that at startup, the output may have already
@ -1136,3 +1305,34 @@ output_set_has_fullscreen_view(struct output *output, bool has_fullscreen_view)
output_enable_adaptive_sync(output, has_fullscreen_view); output_enable_adaptive_sync(output, has_fullscreen_view);
output_state_commit(output); output_state_commit(output);
} }
void
output_enable_hdr(struct output *output, struct wlr_output_state *os,
bool enabled, bool silent)
{
if (enabled && !output_supports_hdr(output->wlr_output, NULL)) {
enabled = false;
}
if (!enabled) {
if (output->wlr_output->supported_primaries != 0 ||
output->wlr_output->supported_transfer_functions != 0) {
if (!silent) {
wlr_log(WLR_DEBUG, "Disabling HDR on output %s",
output->wlr_output->name);
}
wlr_output_state_set_image_description(os, NULL);
}
return;
}
if (!silent) {
wlr_log(WLR_DEBUG, "Enabling HDR on output %s",
output->wlr_output->name);
}
const struct wlr_output_image_description image_desc = {
.primaries = WLR_COLOR_NAMED_PRIMARIES_BT2020,
.transfer_function = WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ,
};
wlr_output_state_set_image_description(os, &image_desc);
}