From 7a44b542b8ec8c1c03f7db81eb96c20105c83ffb Mon Sep 17 00:00:00 2001
From: Brian Ashworth <bosrsf04@gmail.com>
Date: Wed, 6 Mar 2019 00:33:10 -0500
Subject: [PATCH] ipc: change {,deco_}rect to match i3

This fixes the `deco_rect` and `rect` properties in the IPC responses
to match i3's behavior.

`deco_rect` should be relative to the parent node, not the current
node. This also takes tabbed and stacked decorations into account and
will calculate `deco_rect` for all containers since tabbed and stacked
child containers will have decorations.

`rect` should exclude the window decorations.
---
 sway/ipc-json.c     | 51 +++++++++++++++++++++++++++++++++++++--------
 sway/sway-ipc.7.scd |  5 +++--
 2 files changed, 45 insertions(+), 11 deletions(-)

diff --git a/sway/ipc-json.c b/sway/ipc-json.c
index 125df3877..c008f241f 100644
--- a/sway/ipc-json.c
+++ b/sway/ipc-json.c
@@ -350,6 +350,38 @@ static void ipc_json_describe_workspace(struct sway_workspace *workspace,
 	json_object_object_add(object, "floating_nodes", floating_array);
 }
 
+static void get_deco_rect(struct sway_container *c, struct wlr_box *deco_rect) {
+	enum sway_container_layout parent_layout = container_parent_layout(c);
+	if (parent_layout != L_TABBED && parent_layout != L_STACKED &&
+			c->current.border != B_NORMAL) {
+		deco_rect->x = deco_rect->y = deco_rect->width = deco_rect->height = 0;
+		return;
+	}
+
+	if (c->parent) {
+		deco_rect->x = c->x - c->parent->x;
+		deco_rect->y = c->y - c->parent->y;
+	} else {
+		deco_rect->x = c->x - c->workspace->x;
+		deco_rect->y = c->y - c->workspace->y;
+	}
+	deco_rect->width = c->width;
+	deco_rect->height = container_titlebar_height();
+
+	if (parent_layout == L_TABBED) {
+		deco_rect->width = c->parent
+			? c->parent->width / c->parent->children->length
+			: c->workspace->width / c->workspace->tiling->length;
+		deco_rect->x += deco_rect->width * container_sibling_index(c);
+	} else if (container_parent_layout(c) == L_STACKED) {
+		if (!c->view) {
+			size_t siblings = container_get_siblings(c)->length;
+			deco_rect->y -= deco_rect->height * siblings;
+		}
+		deco_rect->y += deco_rect->height * container_sibling_index(c);
+	}
+}
+
 static void ipc_json_describe_view(struct sway_container *c, json_object *object) {
 	json_object_object_add(object, "pid", json_object_new_int(c->view->pid));
 
@@ -377,15 +409,6 @@ static void ipc_json_describe_view(struct sway_container *c, json_object *object
 
 	json_object_object_add(object, "window_rect", ipc_json_create_rect(&window_box));
 
-	struct wlr_box deco_box = {0, 0, 0, 0};
-
-	if (c->current.border == B_NORMAL) {
-		deco_box.width = c->width;
-		deco_box.height = c->content_y - c->y;
-	}
-
-	json_object_object_add(object, "deco_rect", ipc_json_create_rect(&deco_box));
-
 	struct wlr_box geometry = {0, 0, c->view->natural_width, c->view->natural_height};
 	json_object_object_add(object, "geometry", ipc_json_create_rect(&geometry));
 
@@ -465,6 +488,10 @@ static void ipc_json_describe_container(struct sway_container *c, json_object *o
 			json_object_new_int(c->current.border_thickness));
 	json_object_object_add(object, "floating_nodes", json_object_new_array());
 
+	struct wlr_box deco_box = {0, 0, 0, 0};
+	get_deco_rect(c, &deco_box);
+	json_object_object_add(object, "deco_rect", ipc_json_create_rect(&deco_box));
+
 	if (c->view) {
 		ipc_json_describe_view(c, object);
 	}
@@ -505,6 +532,12 @@ json_object *ipc_json_describe_node(struct sway_node *node) {
 
 	struct wlr_box box;
 	node_get_box(node, &box);
+	if (node->type == N_CONTAINER) {
+		struct wlr_box deco_rect = {0, 0, 0, 0};
+		get_deco_rect(node->sway_container, &deco_rect);
+		box.y += deco_rect.height;
+		box.height -= deco_rect.height;
+	}
 
 	json_object *focus = json_object_new_array();
 	struct focus_inactive_data data = {
diff --git a/sway/sway-ipc.7.scd b/sway/sway-ipc.7.scd
index d598a54fd..6b4004536 100644
--- a/sway/sway-ipc.7.scd
+++ b/sway/sway-ipc.7.scd
@@ -314,14 +314,15 @@ node and will have the following properties:
    and other special nodes such as the scratchpad
 |- rect
 :  object
-:  The absolute geometry of the node
+:  The absolute geometry of the node. The window decorations are excluded from
+   this, but borders are included.
 |- window_rect
 :  object
 :  The geometry of the contents inside the node. The window decorations are
    excluded from this calculation, but borders are included.
 |- deco_rect
 :  object
-:  The geometry of the decorations inside the node
+:  The geometry of the decorations for the node relative to the parent node
 |- geometry
 :  object
 :  The natural geometry of the contents if it were to size itself