*/
#define _POSIX_C_SOURCE 200809L
+#include <assert.h>
#include <strings.h>
#include <wlr/backend/drm.h>
#include <wlr/backend/headless.h>
+#include <wlr/backend/wayland.h>
#include <wlr/types/wlr_buffer.h>
#include <wlr/types/wlr_drm_lease_v1.h>
#include <wlr/types/wlr_output.h>
static bool
verify_output_config_v1(const struct wlr_output_configuration_v1 *config)
{
- /* TODO implement */
+ const char *err_msg = NULL;
+ struct wlr_output_configuration_head_v1 *head;
+ wl_list_for_each(head, &config->heads, link) {
+ if (!head->state.enabled) {
+ continue;
+ }
+
+ /* Handle custom modes */
+ if (!head->state.mode) {
+ int32_t refresh = head->state.custom_mode.refresh;
+
+ if (wlr_output_is_drm(head->state.output) && refresh == 0) {
+ /*
+ * wlroots has a bug which causes a divide by zero
+ * when setting the refresh rate to 0 on a DRM output.
+ * It is already fixed but not part of an official 0.17.x
+ * release. Even it would be we still need to carry the
+ * fix here to prevent older 0.17.x releases from crashing.
+ *
+ * https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/3791
+ */
+ err_msg = "DRM backend does not support a refresh rate of 0";
+ goto custom_mode_failed;
+ }
+
+ if (wlr_output_is_wl(head->state.output) && refresh != 0) {
+ /* Wayland backend does not support refresh rates */
+ err_msg = "Wayland backend refresh rate unsupported";
+ goto custom_mode_failed;
+ }
+ }
+
+ /*
+ * Ensure the new output state can be applied on
+ * its own and inform the client when it can not.
+ *
+ * Applying the changes may still fail later when
+ * getting mixed with wlr_output->pending which
+ * may contain further unrelated changes.
+ */
+ struct wlr_output_state output_state;
+ wlr_output_state_init(&output_state);
+ wlr_output_head_v1_state_apply(&head->state, &output_state);
+
+ if (!wlr_output_test_state(head->state.output, &output_state)) {
+ wlr_output_state_finish(&output_state);
+ return false;
+ }
+ wlr_output_state_finish(&output_state);
+ }
+
return true;
+
+custom_mode_failed:
+ assert(err_msg);
+ wlr_log(WLR_INFO, "%s (%s: %dx%d@%d)",
+ err_msg,
+ head->state.output->name,
+ head->state.custom_mode.width,
+ head->state.custom_mode.height,
+ head->state.custom_mode.refresh);
+ return false;
}
static void