Merge pull request #1095 from agx/output-add-mode
Allow to add additional modes to outputs
This commit is contained in:
commit
be54278207
|
@ -566,6 +566,33 @@ error_conn:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool wlr_drm_connector_add_mode(struct wlr_output *output,
|
||||||
|
const drmModeModeInfo *modeinfo) {
|
||||||
|
struct wlr_drm_connector *conn = (struct wlr_drm_connector *)output;
|
||||||
|
|
||||||
|
assert(modeinfo);
|
||||||
|
if (modeinfo->type != DRM_MODE_TYPE_USERDEF) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_drm_mode *mode = calloc(1, sizeof(*mode));
|
||||||
|
if (!mode) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
memcpy(&mode->drm_mode, modeinfo, sizeof(*modeinfo));
|
||||||
|
|
||||||
|
mode->wlr_mode.width = mode->drm_mode.hdisplay;
|
||||||
|
mode->wlr_mode.height = mode->drm_mode.vdisplay;
|
||||||
|
mode->wlr_mode.refresh = mode->drm_mode.vrefresh;
|
||||||
|
|
||||||
|
wlr_log(L_INFO, "Registered custom mode "
|
||||||
|
"%"PRId32"x%"PRId32"@%"PRId32,
|
||||||
|
mode->wlr_mode.width, mode->wlr_mode.height,
|
||||||
|
mode->wlr_mode.refresh);
|
||||||
|
wl_list_insert(&conn->output.modes, &mode->wlr_mode.link);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static void drm_connector_transform(struct wlr_output *output,
|
static void drm_connector_transform(struct wlr_output *output,
|
||||||
enum wl_output_transform transform) {
|
enum wl_output_transform transform) {
|
||||||
output->transform = transform;
|
output->transform = transform;
|
||||||
|
|
|
@ -143,5 +143,9 @@ void restore_drm_outputs(struct wlr_drm_backend *drm);
|
||||||
void scan_drm_connectors(struct wlr_drm_backend *state);
|
void scan_drm_connectors(struct wlr_drm_backend *state);
|
||||||
int handle_drm_event(int fd, uint32_t mask, void *data);
|
int handle_drm_event(int fd, uint32_t mask, void *data);
|
||||||
void enable_drm_connector(struct wlr_output *output, bool enable);
|
void enable_drm_connector(struct wlr_output *output, bool enable);
|
||||||
|
/**
|
||||||
|
* Add mode to the list of available modes
|
||||||
|
*/
|
||||||
|
bool wlr_drm_connector_add_mode(struct wlr_output *output, const drmModeModeInfo *mode);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,11 +1,17 @@
|
||||||
#ifndef ROOTSTON_CONFIG_H
|
#ifndef ROOTSTON_CONFIG_H
|
||||||
#define ROOTSTON_CONFIG_H
|
#define ROOTSTON_CONFIG_H
|
||||||
|
|
||||||
|
#include <xf86drmMode.h>
|
||||||
#include <wlr/types/wlr_input_device.h>
|
#include <wlr/types/wlr_input_device.h>
|
||||||
#include <wlr/types/wlr_output_layout.h>
|
#include <wlr/types/wlr_output_layout.h>
|
||||||
|
|
||||||
#define ROOTS_CONFIG_DEFAULT_SEAT_NAME "seat0"
|
#define ROOTS_CONFIG_DEFAULT_SEAT_NAME "seat0"
|
||||||
|
|
||||||
|
struct roots_output_mode_config {
|
||||||
|
drmModeModeInfo info;
|
||||||
|
struct wl_list link;
|
||||||
|
};
|
||||||
|
|
||||||
struct roots_output_config {
|
struct roots_output_config {
|
||||||
char *name;
|
char *name;
|
||||||
bool enable;
|
bool enable;
|
||||||
|
@ -17,6 +23,7 @@ struct roots_output_config {
|
||||||
int width, height;
|
int width, height;
|
||||||
float refresh_rate;
|
float refresh_rate;
|
||||||
} mode;
|
} mode;
|
||||||
|
struct wl_list modes;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct roots_device_config {
|
struct roots_device_config {
|
||||||
|
|
|
@ -116,6 +116,51 @@ static uint32_t parse_modifier(const char *symname) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool parse_modeline(const char *s, drmModeModeInfo *mode) {
|
||||||
|
char hsync[16];
|
||||||
|
char vsync[16];
|
||||||
|
float fclock;
|
||||||
|
|
||||||
|
mode->type = DRM_MODE_TYPE_USERDEF;
|
||||||
|
|
||||||
|
if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
|
||||||
|
&fclock,
|
||||||
|
&mode->hdisplay,
|
||||||
|
&mode->hsync_start,
|
||||||
|
&mode->hsync_end,
|
||||||
|
&mode->htotal,
|
||||||
|
&mode->vdisplay,
|
||||||
|
&mode->vsync_start,
|
||||||
|
&mode->vsync_end,
|
||||||
|
&mode->vtotal, hsync, vsync) != 11) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mode->clock = fclock * 1000;
|
||||||
|
mode->vrefresh = mode->clock * 1000.0 * 1000.0
|
||||||
|
/ mode->htotal / mode->vtotal;
|
||||||
|
if (strcasecmp(hsync, "+hsync") == 0) {
|
||||||
|
mode->flags |= DRM_MODE_FLAG_PHSYNC;
|
||||||
|
} else if (strcasecmp(hsync, "-hsync") == 0) {
|
||||||
|
mode->flags |= DRM_MODE_FLAG_NHSYNC;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcasecmp(vsync, "+vsync") == 0) {
|
||||||
|
mode->flags |= DRM_MODE_FLAG_PVSYNC;
|
||||||
|
} else if (strcasecmp(vsync, "-vsync") == 0) {
|
||||||
|
mode->flags |= DRM_MODE_FLAG_NVSYNC;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(mode->name, sizeof(mode->name), "%dx%d@%d",
|
||||||
|
mode->hdisplay, mode->vdisplay, mode->vrefresh / 1000);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void add_binding_config(struct wl_list *bindings, const char* combination,
|
void add_binding_config(struct wl_list *bindings, const char* combination,
|
||||||
const char* command) {
|
const char* command) {
|
||||||
struct roots_binding_config *bc =
|
struct roots_binding_config *bc =
|
||||||
|
@ -269,6 +314,7 @@ static int config_ini_handler(void *user, const char *section, const char *name,
|
||||||
oc->transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
oc->transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||||
oc->scale = 1;
|
oc->scale = 1;
|
||||||
oc->enable = true;
|
oc->enable = true;
|
||||||
|
wl_list_init(&oc->modes);
|
||||||
wl_list_insert(&config->outputs, &oc->link);
|
wl_list_insert(&config->outputs, &oc->link);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -322,6 +368,15 @@ static int config_ini_handler(void *user, const char *section, const char *name,
|
||||||
wlr_log(L_DEBUG, "Configured output %s with mode %dx%d@%f",
|
wlr_log(L_DEBUG, "Configured output %s with mode %dx%d@%f",
|
||||||
oc->name, oc->mode.width, oc->mode.height,
|
oc->name, oc->mode.width, oc->mode.height,
|
||||||
oc->mode.refresh_rate);
|
oc->mode.refresh_rate);
|
||||||
|
} else if (strcmp(name, "modeline") == 0) {
|
||||||
|
struct roots_output_mode_config *mode = calloc(1, sizeof(*mode));
|
||||||
|
|
||||||
|
if (parse_modeline(value, &mode->info)) {
|
||||||
|
wl_list_insert(&oc->modes, &mode->link);
|
||||||
|
} else {
|
||||||
|
free(mode);
|
||||||
|
wlr_log(L_ERROR, "Invalid modeline: %s", value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (strncmp(cursor_prefix, section, strlen(cursor_prefix)) == 0) {
|
} else if (strncmp(cursor_prefix, section, strlen(cursor_prefix)) == 0) {
|
||||||
const char *seat_name = section + strlen(cursor_prefix);
|
const char *seat_name = section + strlen(cursor_prefix);
|
||||||
|
@ -459,6 +514,10 @@ struct roots_config *roots_config_create_from_args(int argc, char *argv[]) {
|
||||||
void roots_config_destroy(struct roots_config *config) {
|
void roots_config_destroy(struct roots_config *config) {
|
||||||
struct roots_output_config *oc, *otmp = NULL;
|
struct roots_output_config *oc, *otmp = NULL;
|
||||||
wl_list_for_each_safe(oc, otmp, &config->outputs, link) {
|
wl_list_for_each_safe(oc, otmp, &config->outputs, link) {
|
||||||
|
struct roots_output_mode_config *omc, *omctmp = NULL;
|
||||||
|
wl_list_for_each_safe(omc, omctmp, &oc->modes, link) {
|
||||||
|
free(omc);
|
||||||
|
}
|
||||||
free(oc->name);
|
free(oc->name);
|
||||||
free(oc);
|
free(oc);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "rootston/layers.h"
|
#include "rootston/layers.h"
|
||||||
#include "rootston/output.h"
|
#include "rootston/output.h"
|
||||||
#include "rootston/server.h"
|
#include "rootston/server.h"
|
||||||
|
#include "backend/drm/drm.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rotate a child's position relative to a parent. The parent size is (pw, ph),
|
* Rotate a child's position relative to a parent. The parent size is (pw, ph),
|
||||||
|
@ -821,7 +822,7 @@ void handle_new_output(struct wl_listener *listener, void *data) {
|
||||||
wlr_output->model, wlr_output->serial, wlr_output->phys_width,
|
wlr_output->model, wlr_output->serial, wlr_output->phys_width,
|
||||||
wlr_output->phys_height);
|
wlr_output->phys_height);
|
||||||
|
|
||||||
if (wl_list_length(&wlr_output->modes) > 0) {
|
if (!wl_list_empty(&wlr_output->modes)) {
|
||||||
struct wlr_output_mode *mode =
|
struct wlr_output_mode *mode =
|
||||||
wl_container_of((&wlr_output->modes)->prev, mode, link);
|
wl_container_of((&wlr_output->modes)->prev, mode, link);
|
||||||
wlr_output_set_mode(wlr_output, mode);
|
wlr_output_set_mode(wlr_output, mode);
|
||||||
|
@ -857,6 +858,17 @@ void handle_new_output(struct wl_listener *listener, void *data) {
|
||||||
roots_config_get_output(config, wlr_output);
|
roots_config_get_output(config, wlr_output);
|
||||||
if (output_config) {
|
if (output_config) {
|
||||||
if (output_config->enable) {
|
if (output_config->enable) {
|
||||||
|
struct roots_output_mode_config *mode_config;
|
||||||
|
|
||||||
|
if (wlr_output_is_drm(wlr_output)) {
|
||||||
|
wl_list_for_each(mode_config, &output_config->modes, link) {
|
||||||
|
wlr_drm_connector_add_mode(wlr_output, &mode_config->info);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!wl_list_empty(&output_config->modes)) {
|
||||||
|
wlr_log(L_ERROR, "Can only add modes for DRM backend");
|
||||||
|
}
|
||||||
|
}
|
||||||
if (output_config->mode.width) {
|
if (output_config->mode.width) {
|
||||||
set_mode(wlr_output, output_config);
|
set_mode(wlr_output, output_config);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,13 @@ y = 0
|
||||||
# and rotate by specified angle
|
# and rotate by specified angle
|
||||||
rotate = 90
|
rotate = 90
|
||||||
|
|
||||||
|
# Additional video mode to add
|
||||||
|
# Format is generated by cvt and is documented in x.org.conf(5)
|
||||||
|
modeline = 87.25 720 776 848 976 1440 1443 1453 1493 -hsync +vsync
|
||||||
|
modeline = 65.13 768 816 896 1024 1024 1025 1028 1060 -HSync +VSync
|
||||||
|
# Select one of the above modes
|
||||||
|
mode = 768x1024
|
||||||
|
|
||||||
[cursor]
|
[cursor]
|
||||||
# Restrict cursor movements to single output
|
# Restrict cursor movements to single output
|
||||||
map-to-output = VGA-1
|
map-to-output = VGA-1
|
||||||
|
|
Loading…
Reference in New Issue