diff --git a/include/sway/commands.h b/include/sway/commands.h index 4a2f8c20d..b00e1c257 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -110,6 +110,7 @@ sway_cmd cmd_client_unfocused; sway_cmd cmd_client_urgent; sway_cmd cmd_client_placeholder; sway_cmd cmd_client_background; +sway_cmd cmd_color; sway_cmd cmd_commands; sway_cmd cmd_create_output; sway_cmd cmd_default_border; @@ -269,6 +270,7 @@ sway_cmd input_cmd_xkb_variant; sway_cmd output_cmd_adaptive_sync; sway_cmd output_cmd_background; +sway_cmd output_cmd_color; sway_cmd output_cmd_disable; sway_cmd output_cmd_dpms; sway_cmd output_cmd_enable; diff --git a/include/sway/config.h b/include/sway/config.h index 5ad240d34..512a7275e 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -6,6 +6,7 @@ #include #include #include +#include #include #include "../include/config.h" #include "list.h" @@ -253,6 +254,7 @@ struct output_config { char *background_option; char *background_fallback; enum config_dpms dpms_state; + struct wlr_color_config *color; }; /** diff --git a/include/sway/output.h b/include/sway/output.h index cabb4b557..64dac52e2 100644 --- a/include/sway/output.h +++ b/include/sway/output.h @@ -5,6 +5,7 @@ #include #include #include +#include #include "config.h" #include "sway/tree/node.h" #include "sway/tree/view.h" diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index fd028131c..179690363 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include "list.h" #include "sway/tree/node.h" diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index b495fdf93..e8f94c029 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h @@ -119,6 +119,7 @@ struct sway_view { struct wl_listener surface_new_subsurface; int max_render_time; // In milliseconds + struct wlr_color_config *color; enum seat_config_shortcuts_inhibit shortcuts_inhibit; }; diff --git a/sway/commands.c b/sway/commands.c index f20a8baa8..1003d88d0 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -54,6 +54,7 @@ static struct cmd_handler handlers[] = { { "client.placeholder", cmd_client_noop }, { "client.unfocused", cmd_client_unfocused }, { "client.urgent", cmd_client_urgent }, + { "color", cmd_color }, { "default_border", cmd_default_border }, { "default_floating_border", cmd_default_floating_border }, { "exec", cmd_exec }, diff --git a/sway/commands/color.c b/sway/commands/color.c new file mode 100644 index 000000000..ad6cecded --- /dev/null +++ b/sway/commands/color.c @@ -0,0 +1,41 @@ + +#include +#include +#include "log.h" +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/tree/container.h" +#include "sway/tree/view.h" + +struct cmd_results *cmd_color(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "color", EXPECTED_AT_LEAST, 2))) { + return error; + } + + struct sway_container *container = config->handler_context.container; + if (!container || !container->view) { + return cmd_results_new(CMD_INVALID, "Only views can have color profiles"); + } + struct sway_view *view = container->view; + + wlr_color_config_free(view->color); + view->color = NULL; + + if (strcasecmp(argv[0], "profile") == 0) { + if(strlen(argv[1]) != 0) { + view->color = wlr_color_config_load(argv[1]); + if(! view->color) { + config_add_swaynag_warning("error loading color profile '%s'", argv[1]); + } + } + argc -= 2; argv += 2; + } else { + return cmd_results_new(CMD_INVALID, "Invalid view color config."); + } + + config->handler_context.leftovers.argc = argc; + config->handler_context.leftovers.argv = argv; + return cmd_results_new(CMD_SUCCESS, NULL); +} + diff --git a/sway/commands/output.c b/sway/commands/output.c index 5186a2ba1..7f0790531 100644 --- a/sway/commands/output.c +++ b/sway/commands/output.c @@ -10,6 +10,7 @@ static struct cmd_handler output_handlers[] = { { "adaptive_sync", output_cmd_adaptive_sync }, { "background", output_cmd_background }, { "bg", output_cmd_background }, + { "color", output_cmd_color }, { "disable", output_cmd_disable }, { "dpms", output_cmd_dpms }, { "enable", output_cmd_enable }, diff --git a/sway/commands/output/color.c b/sway/commands/output/color.c new file mode 100644 index 000000000..5bb3dc6cc --- /dev/null +++ b/sway/commands/output/color.c @@ -0,0 +1,37 @@ + +#include +#include +#include "log.h" +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/output.h" + +struct cmd_results *output_cmd_color(int argc, char **argv) { + if (!config->handler_context.output_config) { + return cmd_results_new(CMD_FAILURE, "Missing output config"); + } + + if (argc < 2) { + return cmd_results_new(CMD_INVALID, "Missing color profile argument."); + } + + struct output_config *oc = config->handler_context.output_config; + wlr_color_config_free(oc->color); + oc->color = NULL; + + if (strcasecmp(argv[0], "profile") == 0) { + if(strlen(argv[1]) != 0) { + oc->color = wlr_color_config_load(argv[1]); + if(! oc->color) { + config_add_swaynag_warning("error loading color profile '%s'", argv[1]); + } + } + argc -= 2; argv += 2; + } else { + return cmd_results_new(CMD_INVALID, "Invalid output color config."); + } + + config->handler_context.leftovers.argc = argc; + config->handler_context.leftovers.argv = argv; + return NULL; +} diff --git a/sway/config/output.c b/sway/config/output.c index 68aafbe1c..2c083cb87 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -123,6 +123,10 @@ void merge_output_config(struct output_config *dst, struct output_config *src) { if (src->dpms_state != 0) { dst->dpms_state = src->dpms_state; } + if (src->color) { + wlr_color_config_free(dst->color); + dst->color = wlr_color_config_copy(src->color); + } } static void merge_wildcard_on_all(struct output_config *wildcard) { @@ -478,6 +482,12 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) { output->max_render_time = oc->max_render_time; } + if(oc) { + struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend); + wlr_color_config_free(renderer->color); + renderer->color = wlr_color_config_copy(oc->color); + } + // Reconfigure all devices, since input config may have been applied before // this output came online, and some config items (like map_to_output) are // dependent on an output being present. @@ -661,6 +671,7 @@ void free_output_config(struct output_config *oc) { free(oc->name); free(oc->background); free(oc->background_option); + wlr_color_config_free(oc->color); free(oc); } diff --git a/sway/desktop/render.c b/sway/desktop/render.c index d3d927c83..92903fc6c 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -261,6 +261,10 @@ static void render_view_toplevels(struct sway_view *view, output->lx - view->geometry.x; double oy = view->container->surface_y - output->ly - view->geometry.y; + + // override color config for surface + view->surface->color = view->color; + output_surface_for_each_surface(output, view->surface, ox, oy, render_surface_iterator, &data); } diff --git a/sway/ipc-json.c b/sway/ipc-json.c index 70b81ad1d..4daaaa472 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c @@ -308,6 +308,11 @@ static void ipc_json_describe_output(struct sway_output *output, } json_object_object_add(object, "max_render_time", json_object_new_int(output->max_render_time)); + + struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend); + if(renderer->color) { + json_object_object_add(object, "icc_profile", json_object_new_string(renderer->color->icc_profile_path)); + } } json_object *ipc_json_describe_disabled_output(struct sway_output *output) { @@ -506,6 +511,10 @@ static void ipc_json_describe_view(struct sway_container *c, json_object *object json_object_object_add(object, "geometry", ipc_json_create_rect(&geometry)); json_object_object_add(object, "max_render_time", json_object_new_int(c->view->max_render_time)); + + json_object_object_add(object, "icc_profile", c->view->color + ? json_object_new_string(c->view->color->icc_profile_path) + : NULL); json_object_object_add(object, "shell", json_object_new_string(view_get_shell(c->view))); diff --git a/sway/meson.build b/sway/meson.build index 0db458362..9345b6d9f 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -44,6 +44,7 @@ sway_sources = files( 'commands/bind.c', 'commands/border.c', 'commands/client.c', + 'commands/color.c', 'commands/create_output.c', 'commands/default_border.c', 'commands/default_floating_border.c', @@ -179,6 +180,7 @@ sway_sources = files( 'commands/output/adaptive_sync.c', 'commands/output/background.c', + 'commands/output/color.c', 'commands/output/disable.c', 'commands/output/dpms.c', 'commands/output/enable.c', diff --git a/sway/tree/view.c b/sway/tree/view.c index ac3147953..fd88f4228 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -62,6 +62,7 @@ void view_destroy(struct sway_view *view) { list_free(view->executed_criteria); free(view->title_format); + wlr_color_config_free(view->color); if (view->impl->destroy) { view->impl->destroy(view); diff --git a/swaymsg/main.c b/swaymsg/main.c index 38976f9c2..2af65a021 100644 --- a/swaymsg/main.c +++ b/swaymsg/main.c @@ -190,7 +190,7 @@ static void pretty_print_output(json_object *o) { json_object_object_get_ex(o, "active", &active); json_object_object_get_ex(o, "current_workspace", &ws); json_object *make, *model, *serial, *scale, *scale_filter, *subpixel, - *transform, *max_render_time, *adaptive_sync_status; + *transform, *max_render_time, *adaptive_sync_status, *icc_profile; json_object_object_get_ex(o, "make", &make); json_object_object_get_ex(o, "model", &model); json_object_object_get_ex(o, "serial", &serial); @@ -200,6 +200,7 @@ static void pretty_print_output(json_object *o) { json_object_object_get_ex(o, "transform", &transform); json_object_object_get_ex(o, "max_render_time", &max_render_time); json_object_object_get_ex(o, "adaptive_sync_status", &adaptive_sync_status); + json_object_object_get_ex(o, "icc_profile", &icc_profile); json_object *x, *y; json_object_object_get_ex(rect, "x", &x); json_object_object_get_ex(rect, "y", &y); @@ -243,6 +244,8 @@ static void pretty_print_output(json_object *o) { printf(" Adaptive sync: %s\n", json_object_get_string(adaptive_sync_status)); + printf(" ICC Profile: %s\n", + json_object_get_string(icc_profile)); } else { printf( "Output %s '%s %s %s' (inactive)\n",