Skip to content

Commit

Permalink
Add support for manually setting subpixel hinting on outputs.
Browse files Browse the repository at this point in the history
Many laptop screens report unknown subpixel order. Allow users to manually set subpixel hinting to work around this.

Addresses swaywm#3163
  • Loading branch information
ggreer committed Mar 11, 2019
1 parent 076257a commit db939f7
Show file tree
Hide file tree
Showing 14 changed files with 102 additions and 5 deletions.
21 changes: 21 additions & 0 deletions common/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <wayland-server-protocol.h>
#include "log.h"
#include "util.h"

Expand Down Expand Up @@ -54,3 +55,23 @@ float parse_float(const char *value) {
}
return flt;
}


const char *sway_wl_output_subpixel_to_string(enum wl_output_subpixel subpixel) {
switch (subpixel) {
case WL_OUTPUT_SUBPIXEL_UNKNOWN:
return "unknown";
case WL_OUTPUT_SUBPIXEL_NONE:
return "none";
case WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB:
return "rgb";
case WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR:
return "bgr";
case WL_OUTPUT_SUBPIXEL_VERTICAL_RGB:
return "vrgb";
case WL_OUTPUT_SUBPIXEL_VERTICAL_BGR:
return "vbgr";
}
sway_assert(false, "Unknown value for wl_output_subpixel.");
return NULL;
}
1 change: 1 addition & 0 deletions include/sway/commands.h
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ sway_cmd output_cmd_enable;
sway_cmd output_cmd_mode;
sway_cmd output_cmd_position;
sway_cmd output_cmd_scale;
sway_cmd output_cmd_subpixel;
sway_cmd output_cmd_transform;

sway_cmd seat_cmd_attach;
Expand Down
1 change: 1 addition & 0 deletions include/sway/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ struct output_config {
int x, y;
float scale;
int32_t transform;
enum wl_output_subpixel subpixel;

char *background;
char *background_option;
Expand Down
1 change: 1 addition & 0 deletions include/sway/output.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ struct sway_output {

int lx, ly; // layout coords
int width, height; // transformed buffer size
enum wl_output_subpixel detected_subpixel;

bool enabled, configured;
list_t *workspaces;
Expand Down
3 changes: 3 additions & 0 deletions include/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <stdint.h>
#include <stdbool.h>
#include <wayland-server-protocol.h>

/**
* Wrap i into the range [0, max[
Expand All @@ -29,4 +30,6 @@ bool parse_boolean(const char *boolean, bool current);
*/
float parse_float(const char *value);

const char *sway_wl_output_subpixel_to_string(enum wl_output_subpixel subpixel);

#endif
1 change: 1 addition & 0 deletions sway/commands/output.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ static struct cmd_handler output_handlers[] = {
{ "res", output_cmd_mode },
{ "resolution", output_cmd_mode },
{ "scale", output_cmd_scale },
{ "subpixel", output_cmd_subpixel },
{ "transform", output_cmd_transform },
};

Expand Down
36 changes: 36 additions & 0 deletions sway/commands/output/subpixel.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#include <string.h>
#include "log.h"
#include "sway/commands.h"
#include "sway/config.h"
#include "sway/output.h"

struct cmd_results *output_cmd_subpixel(int argc, char **argv) {
if (!config->handler_context.output_config) {
return cmd_results_new(CMD_FAILURE, "Missing output config");
}
if (!argc) {
return cmd_results_new(CMD_INVALID, "Missing subpixel argument.");
}
enum wl_output_subpixel subpixel;

if (strcmp(*argv, "rgb") == 0) {
subpixel = WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
} else if (strcmp(*argv, "bgr") == 0) {
subpixel = WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
} else if (strcmp(*argv, "vrgb") == 0) {
subpixel = WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
} else if (strcmp(*argv, "vbgr") == 0) {
subpixel = WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
} else if (strcmp(*argv, "none") == 0) {
subpixel = WL_OUTPUT_SUBPIXEL_NONE;
} else {
return cmd_results_new(CMD_INVALID, "Invalid output subpixel.");
}

struct output_config *oc = config->handler_context.output_config;
config->handler_context.leftovers.argc = argc - 1;
config->handler_context.leftovers.argv = argv + 1;

oc->subpixel = subpixel;
return NULL;
}
23 changes: 19 additions & 4 deletions sway/config/output.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@
#include <unistd.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_output.h>
#include "log.h"
#include "sway/config.h"
#include "sway/output.h"
#include "sway/tree/root.h"
#include "log.h"
#include "util.h"

int output_name_cmp(const void *item, const void *data) {
const struct output_config *output = item;
Expand Down Expand Up @@ -43,6 +44,7 @@ struct output_config *new_output_config(const char *name) {
oc->x = oc->y = -1;
oc->scale = -1;
oc->transform = -1;
oc->subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN;
return oc;
}

Expand All @@ -65,6 +67,9 @@ void merge_output_config(struct output_config *dst, struct output_config *src) {
if (src->scale != -1) {
dst->scale = src->scale;
}
if (src->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN) {
dst->subpixel = src->subpixel;
}
if (src->refresh_rate != -1) {
dst->refresh_rate = src->refresh_rate;
}
Expand Down Expand Up @@ -130,10 +135,10 @@ struct output_config *store_output_config(struct output_config *oc) {
}

sway_log(SWAY_DEBUG, "Config stored for output %s (enabled: %d) (%dx%d@%fHz "
"position %d,%d scale %f transform %d) (bg %s %s) (dpms %d)",
"position %d,%d scale %f subpixel %s transform %d) (bg %s %s) (dpms %d)",
oc->name, oc->enabled, oc->width, oc->height, oc->refresh_rate,
oc->x, oc->y, oc->scale, oc->transform, oc->background,
oc->background_option, oc->dpms_state);
oc->x, oc->y, oc->scale, sway_wl_output_subpixel_to_string(oc->subpixel),
oc->transform, oc->background, oc->background_option, oc->dpms_state);

return oc;
}
Expand Down Expand Up @@ -306,6 +311,14 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) {
sway_log(SWAY_DEBUG, "Set %s scale to %f", oc->name, oc->scale);
wlr_output_set_scale(wlr_output, oc->scale);
}

if (oc && (oc->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN || config->reloading)) {
sway_log(SWAY_DEBUG, "Set %s subpixel to %s", oc->name,
sway_wl_output_subpixel_to_string(oc->subpixel));
wlr_output_set_subpixel(wlr_output, oc->subpixel);
output_damage_whole(output);
}

if (oc && oc->transform >= 0) {
sway_log(SWAY_DEBUG, "Set %s transform to %d", oc->name, oc->transform);
wlr_output_set_transform(wlr_output, oc->transform);
Expand Down Expand Up @@ -367,6 +380,8 @@ static void default_output_config(struct output_config *oc,
}
oc->x = oc->y = -1;
oc->scale = 1;
struct sway_output *output = wlr_output->data;
oc->subpixel = output->detected_subpixel;
oc->transform = WL_OUTPUT_TRANSFORM_NORMAL;
oc->dpms_state = DPMS_ON;
}
Expand Down
2 changes: 2 additions & 0 deletions sway/ipc-server.c
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,8 @@ void ipc_client_handle_command(struct ipc_client *client) {
json_object_object_add(output_json, "focused",
json_object_new_boolean(focused));

const char *subpixel = sway_wl_output_subpixel_to_string(output->wlr_output->subpixel);
json_object_object_add(output_json, "subpixel_hinting", json_object_new_string(subpixel));
json_object_array_add(outputs, output_json);
}
struct sway_output *output;
Expand Down
1 change: 1 addition & 0 deletions sway/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ sway_sources = files(
'commands/output/mode.c',
'commands/output/position.c',
'commands/output/scale.c',
'commands/output/subpixel.c',
'commands/output/transform.c',

'tree/arrange.c',
Expand Down
4 changes: 4 additions & 0 deletions sway/sway-ipc.7.scd
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,9 @@ following properties:
|- scale
: float
: The scale currently in use on the output or _-1_ for disabled outputs
|- subpixel_hinting
: string
: The subpixel hinting current in use on the output. This can be _rgb_, _bgr_, _vrgb_, _vbgr_, or _none_
|- transform
: string
: The transform currently in use for the output. This can be _normal_, _90_,
Expand Down Expand Up @@ -242,6 +245,7 @@ following properties:
"active": true,
"primary": false,
"scale": 1.0,
"subpixel_hinting": "rgb",
"transform": "normal",
"current_workspace": "1",
"modes": [
Expand Down
7 changes: 7 additions & 0 deletions sway/sway-output.5.scd
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,13 @@ must be separated by one space. For example:
applications to taste. HiDPI isn't supported with Xwayland clients (windows
will blur).

*output* <name> subpixel rgb|bgr|vrgb|vbgr|none
Manually sets the subpixel hinting for the specified output. This value is
usually auto-detected, but some displays may misreport their subpixel
geometry. Using the correct subpixel hinting allows for sharper text.
Incorrect values will result in blurrier text. When changing this via
*swaymsg*, some applications may need to be restarted to use the new value.

*output* <name> background|bg <file> <mode> [<fallback_color>]
Sets the wallpaper for the given output to the specified file, using the
given scaling mode (one of "stretch", "fill", "fit", "center", "tile"). If
Expand Down
1 change: 1 addition & 0 deletions sway/tree/output.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ struct sway_output *output_create(struct wlr_output *wlr_output) {
node_init(&output->node, N_OUTPUT, output);
output->wlr_output = wlr_output;
wlr_output->data = output;
output->detected_subpixel = wlr_output->subpixel;

wl_signal_init(&output->events.destroy);

Expand Down
5 changes: 4 additions & 1 deletion swaymsg/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -186,11 +186,12 @@ static void pretty_print_output(json_object *o) {
json_object_object_get_ex(o, "focused", &focused);
json_object_object_get_ex(o, "active", &active);
json_object_object_get_ex(o, "current_workspace", &ws);
json_object *make, *model, *serial, *scale, *transform;
json_object *make, *model, *serial, *scale, *subpixel, *transform;
json_object_object_get_ex(o, "make", &make);
json_object_object_get_ex(o, "model", &model);
json_object_object_get_ex(o, "serial", &serial);
json_object_object_get_ex(o, "scale", &scale);
json_object_object_get_ex(o, "subpixel_hinting", &subpixel);
json_object_object_get_ex(o, "transform", &transform);
json_object *x, *y;
json_object_object_get_ex(rect, "x", &x);
Expand All @@ -209,6 +210,7 @@ static void pretty_print_output(json_object *o) {
" Current mode: %dx%d @ %f Hz\n"
" Position: %d,%d\n"
" Scale factor: %f\n"
" Subpixel hinting: %s\n"
" Transform: %s\n"
" Workspace: %s\n",
json_object_get_string(name),
Expand All @@ -221,6 +223,7 @@ static void pretty_print_output(json_object *o) {
(float)json_object_get_int(refresh) / 1000,
json_object_get_int(x), json_object_get_int(y),
json_object_get_double(scale),
json_object_get_string(subpixel),
json_object_get_string(transform),
json_object_get_string(ws)
);
Expand Down

0 comments on commit db939f7

Please sign in to comment.