From fc9398a42e1dfc15bbb8490c049981034abb4926 Mon Sep 17 00:00:00 2001
From: Tony Crisci <tony@dubstepdish.com>
Date: Tue, 3 Apr 2018 00:47:45 -0400
Subject: Implement opacity command

---
 sway/commands.c         |  1 +
 sway/commands/opacity.c | 39 +++++++++++++++++++++++++++++++++++++++
 sway/desktop/output.c   | 34 ++++++++++++++++++----------------
 sway/meson.build        |  1 +
 sway/sway.5.txt         |  4 ++++
 sway/tree/container.c   |  2 ++
 6 files changed, 65 insertions(+), 16 deletions(-)
 create mode 100644 sway/commands/opacity.c

(limited to 'sway')

diff --git a/sway/commands.c b/sway/commands.c
index 8156a08e..2786a879 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -163,6 +163,7 @@ static struct cmd_handler command_handlers[] = {
 	{ "kill", cmd_kill },
 	{ "layout", cmd_layout },
 	{ "move", cmd_move },
+	{ "opacity", cmd_opacity },
 	{ "reload", cmd_reload },
 	{ "split", cmd_split },
 	{ "splith", cmd_splith },
diff --git a/sway/commands/opacity.c b/sway/commands/opacity.c
new file mode 100644
index 00000000..b8cd1f09
--- /dev/null
+++ b/sway/commands/opacity.c
@@ -0,0 +1,39 @@
+#include <assert.h>
+#include <stdlib.h>
+#include "sway/commands.h"
+#include "sway/tree/view.h"
+#include "log.h"
+
+static bool parse_opacity(const char *opacity, float *val) {
+	char *err;
+	*val = strtof(opacity, &err);
+	if (*val < 0 || *val > 1 || *err) {
+		return false;
+	}
+	return true;
+}
+
+struct cmd_results *cmd_opacity(int argc, char **argv) {
+	struct cmd_results *error = NULL;
+	if ((error = checkarg(argc, "layout", EXPECTED_EQUAL_TO, 1))) {
+		return error;
+	}
+
+	struct sway_container *con =
+		config->handler_context.current_container;
+
+	float opacity = 0.0f;
+
+	if (!parse_opacity(argv[0], &opacity)) {
+		return cmd_results_new(CMD_INVALID, "opacity <value>",
+				"Invalid value (expected 0..1): %s", argv[0]);
+	}
+
+	con->alpha = opacity;
+
+	if (con->type == C_VIEW) {
+		view_damage_whole(con->sway_view);
+	}
+
+	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
diff --git a/sway/desktop/output.c b/sway/desktop/output.c
index 8a4fb4a2..6cf5da48 100644
--- a/sway/desktop/output.c
+++ b/sway/desktop/output.c
@@ -75,7 +75,7 @@ static bool surface_intersect_output(struct wlr_surface *surface,
 
 static void render_surface(struct wlr_surface *surface,
 		struct wlr_output *wlr_output, struct timespec *when,
-		double ox, double oy, float rotation) {
+		double ox, double oy, float rotation, float alpha) {
 	struct wlr_renderer *renderer =
 		wlr_backend_get_renderer(wlr_output->backend);
 
@@ -95,8 +95,8 @@ static void render_surface(struct wlr_surface *surface,
 		wlr_matrix_project_box(matrix, &box, transform, rotation,
 			wlr_output->transform_matrix);
 
-		// TODO: configurable alpha
-		wlr_render_texture_with_matrix(renderer, surface->texture, matrix, 1.0f);
+		wlr_render_texture_with_matrix(renderer, surface->texture,
+			matrix, alpha);
 
 		wlr_surface_send_frame_done(surface, when);
 	}
@@ -110,13 +110,13 @@ static void render_surface(struct wlr_surface *surface,
 			surface->current->width, surface->current->height, rotation);
 
 		render_surface(subsurface->surface, wlr_output, when,
-			ox + sx, oy + sy, rotation);
+			ox + sx, oy + sy, rotation, alpha);
 	}
 }
 
 static void render_xdg_v6_popups(struct wlr_xdg_surface_v6 *surface,
 		struct wlr_output *wlr_output, struct timespec *when, double base_x,
-		double base_y, float rotation) {
+		double base_y, float rotation, float alpha) {
 	double width = surface->surface->current->width;
 	double height = surface->surface->current->height;
 
@@ -136,19 +136,19 @@ static void render_xdg_v6_popups(struct wlr_xdg_surface_v6 *surface,
 			width, height, rotation);
 
 		render_surface(popup->surface, wlr_output, when,
-			base_x + popup_sx, base_y + popup_sy, rotation);
+			base_x + popup_sx, base_y + popup_sy, rotation, alpha);
 		render_xdg_v6_popups(popup, wlr_output, when,
-			base_x + popup_sx, base_y + popup_sy, rotation);
+			base_x + popup_sx, base_y + popup_sy, rotation, alpha);
 	}
 }
 
 static void render_wl_shell_surface(struct wlr_wl_shell_surface *surface,
 		struct wlr_output *wlr_output, struct timespec *when,
-		double lx, double ly, float rotation,
+		double lx, double ly, float rotation, float alpha,
 		bool is_child) {
 	if (is_child || surface->state != WLR_WL_SHELL_SURFACE_STATE_POPUP) {
 		render_surface(surface->surface, wlr_output, when,
-			lx, ly, rotation);
+			lx, ly, rotation, alpha);
 
 		double width = surface->surface->current->width;
 		double height = surface->surface->current->height;
@@ -164,7 +164,7 @@ static void render_wl_shell_surface(struct wlr_wl_shell_surface *surface,
 				width, height, rotation);
 
 			render_wl_shell_surface(popup, wlr_output, when,
-				lx + popup_x, ly + popup_y, rotation, true);
+				lx + popup_x, ly + popup_y, rotation, alpha, true);
 		}
 	}
 }
@@ -181,6 +181,7 @@ static void render_view(struct sway_container *view, void *data) {
 	struct wlr_output *wlr_output = output->wlr_output;
 	struct sway_view *sway_view = view->sway_view;
 	struct wlr_surface *surface = sway_view->surface;
+	float alpha = sway_view->swayc->alpha;
 
 	if (!surface) {
 		return;
@@ -191,17 +192,18 @@ static void render_view(struct sway_container *view, void *data) {
 		int window_offset_x = view->sway_view->wlr_xdg_surface_v6->geometry.x;
 		int window_offset_y = view->sway_view->wlr_xdg_surface_v6->geometry.y;
 		render_surface(surface, wlr_output, when,
-			view->x - window_offset_x, view->y - window_offset_y, 0);
+			view->x - window_offset_x, view->y - window_offset_y, 0, alpha);
 		render_xdg_v6_popups(sway_view->wlr_xdg_surface_v6, wlr_output,
-			when, view->x - window_offset_x, view->y - window_offset_y, 0);
+			when, view->x - window_offset_x, view->y - window_offset_y, 0, alpha);
 		break;
 	}
 	case SWAY_WL_SHELL_VIEW:
 		render_wl_shell_surface(sway_view->wlr_wl_shell_surface, wlr_output,
-			when, view->x, view->y, 0, false);
+			when, view->x, view->y, 0, alpha, false);
 		break;
 	case SWAY_XWAYLAND_VIEW:
-		render_surface(surface, wlr_output, when, view->x, view->y, 0);
+		render_surface(surface, wlr_output, when, view->x, view->y,
+			0, alpha);
 		break;
 	default:
 		break;
@@ -214,7 +216,7 @@ static void render_layer(struct sway_output *output, struct timespec *when,
 	wl_list_for_each(sway_layer, layer, link) {
 		struct wlr_layer_surface *layer = sway_layer->layer_surface;
 		render_surface(layer->surface, output->wlr_output, when,
-				sway_layer->geo.x, sway_layer->geo.y, 0);
+				sway_layer->geo.x, sway_layer->geo.y, 0, 1.0f);
 		wlr_surface_send_frame_done(layer->surface, when);
 	}
 }
@@ -288,7 +290,7 @@ static void render_output(struct sway_output *output, struct timespec *when,
 		}
 
 		render_surface(xsurface->surface, wlr_output, &output->last_frame,
-			view_box.x - output_box->x, view_box.y - output_box->y, 0);
+			view_box.x - output_box->x, view_box.y - output_box->y, 0, 1.0f);
 	}
 
 	// TODO: Consider revising this when fullscreen windows are supported
diff --git a/sway/meson.build b/sway/meson.build
index 91aab0a0..f210c195 100644
--- a/sway/meson.build
+++ b/sway/meson.build
@@ -15,6 +15,7 @@ sway_sources = files(
 	'commands/focus.c',
 	'commands/focus_follows_mouse.c',
 	'commands/kill.c',
+	'commands/opacity.c',
 	'commands/include.c',
 	'commands/input.c',
 	'commands/layout.c',
diff --git a/sway/sway.5.txt b/sway/sway.5.txt
index 900e499a..59c3295a 100644
--- a/sway/sway.5.txt
+++ b/sway/sway.5.txt
@@ -413,6 +413,10 @@ The default colors are:
 	However, any mark that starts with an underscore will not be drawn even if the
 	option is on. The default option is _on_.
 
+**opacity** <value>::
+	Set the opacity of the window between 0 (completely transparent) and 1
+	(completely opaque).
+
 **unmark** <identifier>::
 	**Unmark** will remove _identifier_ from the list of current marks on a window. If
 	no _identifier_ is specified, then **unmark** will remove all marks.
diff --git a/sway/tree/container.c b/sway/tree/container.c
index 753f333c..3be08645 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -72,6 +72,8 @@ struct sway_container *container_create(enum sway_container_type type) {
 	c->layout = L_NONE;
 	c->workspace_layout = L_NONE;
 	c->type = type;
+	c->alpha = 1.0f;
+
 	if (type != C_VIEW) {
 		c->children = create_list();
 	}
-- 
cgit v1.2.3