mirror of
https://codeberg.org/dwl/dwl-patches.git
synced 2025-10-26 09:44:21 +00:00
Patch refactor, updated readme.
This commit is contained in:
parent
15ed11dd2e
commit
fa433ca6e3
@ -1,7 +1,102 @@
|
||||
### Description
|
||||
Dynamic tiling layout desingned for ultrawide monitors. It provides a focus-driven, mouse- and keyboard-friendly tiling layout that grants you granular control over how clients are placed and resized. It combines both the layout and client management under one patch.
|
||||
|
||||
More detailed description on my [github](https://github.com/julmajustus/dwl-patches).
|
||||
# btrtile — A Focus-Driven Tiling Layout
|
||||
|
||||
It provides a focus-driven, mouse- and keyboard-friendly tiling layout that grants you granular control over how clients are placed and resized.
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
# Why btrtile
|
||||
|
||||
While dwl’s patches folder is full of different layouts, I couldn't find suitable layout that would work well with my workflow and single ultrawide monitor setup. btrtile aims to solve that by introducing a layout strategy that splits clients according to user focus and pointer position.
|
||||
|
||||
---
|
||||
|
||||
# Features
|
||||
|
||||
- **Combined Tiling and Management**
|
||||
Combines tiling layout and management of clients under one patchset.
|
||||
|
||||
- **Focus-Driven Splits**
|
||||
When you add a new client, btrtile checks where your pointer is relative to the focused client’s geometry.
|
||||
- If the pointer is on the left half (for a horizontally large client), the new client spawns on the left side, and vice versa.
|
||||
- By default, new splits are 50/50.
|
||||
|
||||
- **Adaptive Splitting**
|
||||
- If the area to be split is wider than its height, btrtile does a horizontal split.
|
||||
- Otherwise, it does a vertical split.
|
||||
|
||||
- **Keyboard and Mouse Driven**
|
||||
- Supports keyboard-based commands for quick ratio adjustments and client swapping.
|
||||
- Mouse-based resizing and moving are integrated for more intuitive manipulation.
|
||||
|
||||
---
|
||||
|
||||
# How It Works
|
||||
|
||||
btrtile organizes clients using a binary tree data structure that represents splits either vertically or horizontally.
|
||||
|
||||
When a new client appears:
|
||||
1. **Focused Client Detection**
|
||||
btrtile checks your pointer location to find which client (if any) you’re interacting with.
|
||||
2. **Split Creation**
|
||||
- If there’s a focused client, btrtile creates a split node around it, placing the new client on the side where your pointer is.
|
||||
|
||||
3. **Ratio Management**
|
||||
Each split node has a `split_ratio` (defaulting to 0.5). This ratio defines how much space is allocated to each child node. You can adjust this ratio using keyboard or mouse actions.
|
||||
|
||||
---
|
||||
|
||||
# What It Doesn’t Handle
|
||||
|
||||
- **Multi-Tag client Management**
|
||||
btrtile intentionally reverts clients to a single tag if they span multiple tags. This prevents potential inconsistencies or duplicate entries in its per-tag client tree.
|
||||
- If you attempt to place a single client on multiple tags while using the btrtile layout, btrtile will enforce a single-tag assignment to maintain stability.
|
||||
|
||||
- **Suckless philosophy**
|
||||
- Yea, it's a bloat. I tried to hide the suck inside a single file as much I could. While this approach is not ideal, it's how it's at least for now.
|
||||
|
||||
---
|
||||
|
||||
# Configuring btrtile
|
||||
|
||||
btrtile adds couple variables to config.h to fine tune the mouse resizing of tiled clients.
|
||||
|
||||
1. **resize_factor**
|
||||
- A multiplier to transfer pointer movement to client weight ratio. Depends heavily on mouse sensivity.
|
||||
Defaults to 0.0002f.
|
||||
|
||||
2. **resize_interval_ms**
|
||||
- A time based resize call limiter. Depends on framerate and screen refresh rate.
|
||||
Defaults to 16ms. (~60 resize updates per second)
|
||||
|
||||
Fine tune these values to find the best values for your setup, smoother resizing can significally increase cpu overhead.
|
||||
If mouse resizing feels sluggish, you can try compiling dwl with more aggressive optimization flags like -O2/-O3.
|
||||
|
||||
---
|
||||
|
||||
# Patch recommendations
|
||||
|
||||
1. **Patches that I use with my btrtile**
|
||||
|
||||
- [focusdir](https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/focusdir)
|
||||
Great patch to move focus between clients.
|
||||
|
||||
- [rotatetags](https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/rotatetags)
|
||||
Good patch to rotate the view or shift clients between tags.
|
||||
|
||||
- [warpcursor](https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/warpcursor)
|
||||
Moves cursor location to focused client.
|
||||
|
||||
- [pertag](https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/pertag)
|
||||
Allows each tag to have individual layout setups.
|
||||
|
||||
- [gaps](https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/gaps)
|
||||
Add gaps between clients.
|
||||
|
||||
---
|
||||
|
||||
### Download
|
||||
- [0.7](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/btrtile/btrtile-v0.7.patch)
|
||||
|
||||
@ -1,21 +1,21 @@
|
||||
From cdeedfa24d7f2fbc4a916d953e7a389fd24a281c Mon Sep 17 00:00:00 2001
|
||||
From 6d60b3cd6eb4d08f8566e80141071bd33d231c59 Mon Sep 17 00:00:00 2001
|
||||
From: julmajustus <julmajustus@tutanota.com>
|
||||
Date: Mon, 23 Dec 2024 20:27:50 +0200
|
||||
Subject: [PATCH] Btrtile layout with gapps
|
||||
Date: Wed, 1 Jan 2025 19:08:45 +0200
|
||||
Subject: [PATCH] btrtile-gapps init
|
||||
|
||||
---
|
||||
btrtile.c | 669 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
btrtile.c | 679 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
config.def.h | 12 +
|
||||
dwl.c | 206 +++++++++++++---
|
||||
3 files changed, 849 insertions(+), 38 deletions(-)
|
||||
dwl.c | 177 ++++++++++++--
|
||||
3 files changed, 841 insertions(+), 27 deletions(-)
|
||||
create mode 100644 btrtile.c
|
||||
|
||||
diff --git a/btrtile.c b/btrtile.c
|
||||
new file mode 100644
|
||||
index 0000000..12ccd20
|
||||
index 0000000..dea8a8c
|
||||
--- /dev/null
|
||||
+++ b/btrtile.c
|
||||
@@ -0,0 +1,669 @@
|
||||
@@ -0,0 +1,679 @@
|
||||
+/* ************************************************************************** */
|
||||
+/* */
|
||||
+/* ::: :::::::: */
|
||||
@ -24,7 +24,7 @@ index 0000000..12ccd20
|
||||
+/* By: jmakkone <jmakkone@student.hive.fi> +#+ +:+ +#+ */
|
||||
+/* +#+#+#+#+#+ +#+ */
|
||||
+/* Created: 2024/12/15 00:26:07 by jmakkone #+# #+# */
|
||||
+/* Updated: 2024/12/23 20:26:09 by jmakkone ### ########.fr */
|
||||
+/* Updated: 2025/01/01 17:26:52 by jmakkone ### ########.fr */
|
||||
+/* */
|
||||
+/* ************************************************************************** */
|
||||
+
|
||||
@ -50,35 +50,37 @@ index 0000000..12ccd20
|
||||
+
|
||||
+static void add_client_to_tiled_list(Client *c, struct wl_list *tiled_clients);
|
||||
+static void apply_layout(Monitor *m, LayoutNode *node,
|
||||
+ struct wlr_box area, unsigned int is_root);
|
||||
+ struct wlr_box area, unsigned int is_root);
|
||||
+static void btrtile(Monitor *m);
|
||||
+static LayoutNode *create_client_node(Client *c);
|
||||
+static LayoutNode *create_split_node(unsigned int split_vertically,
|
||||
+ LayoutNode *left, LayoutNode *right);
|
||||
+static LayoutNode *create_split_node(unsigned int split_vertically,
|
||||
+ LayoutNode *left, LayoutNode *right);
|
||||
+static void destroy_node_tree(LayoutNode *node);
|
||||
+static void destroy_tree_layout(Monitor *m);
|
||||
+static LayoutNode *find_client_node(LayoutNode *node, Client *c);
|
||||
+static LayoutNode *find_split_node(LayoutNode *root, LayoutNode *child);
|
||||
+static LayoutNode *find_suitable_split_node(LayoutNode *client_node, unsigned int need_vertical);
|
||||
+static LayoutNode *find_closest_client_node(LayoutNode *split_node,enum Direction dir,
|
||||
+ int current_x, int current_y, LayoutNode **closest, int *closest_dist);
|
||||
+static LayoutNode *find_suitable_split_node(LayoutNode *client_node,
|
||||
+ unsigned int need_vertical);
|
||||
+static LayoutNode *find_closest_client_node(LayoutNode *split_node,
|
||||
+ enum Direction dir, int current_x,
|
||||
+ int current_y, LayoutNode **closest,
|
||||
+ int *closest_dist);
|
||||
+static unsigned int get_client_center(LayoutNode *node, CoordType type);
|
||||
+static unsigned int get_current_tag(Monitor *m);
|
||||
+static void init_tree_layout(Monitor *m);
|
||||
+static void insert_client(Monitor *m, Client *focused, Client *new_client,
|
||||
+ LayoutNode **root, struct wl_list *tiled_clients);
|
||||
+ LayoutNode **root, struct wl_list *tiled_clients);
|
||||
+static unsigned int is_client_tiled(Client *c, struct wl_list *tiled_clients);
|
||||
+static LayoutNode *remove_client_node(LayoutNode *node, Client *c);
|
||||
+static void remove_client(Monitor *m, Client *c,
|
||||
+ LayoutNode **root, struct wl_list *tiled_clients);
|
||||
+static void remove_client(Monitor *m, Client *c,
|
||||
+ LayoutNode **root, struct wl_list *tiled_clients);
|
||||
+static void setratio_h(const Arg *arg);
|
||||
+static void setratio_v(const Arg *arg);
|
||||
+static void swapclients(const Arg *arg);
|
||||
+
|
||||
+static int resizing_from_mouse = 0;
|
||||
+static double resize_init_x, resize_init_y;
|
||||
+static double resize_last_update_x, resize_last_update_y;
|
||||
+static unsigned int arrange_counter = 0;
|
||||
+static uint32_t last_resize_time = 0;
|
||||
+
|
||||
+void
|
||||
+add_client_to_tiled_list(Client *c, struct wl_list *tiled_clients)
|
||||
@ -89,7 +91,7 @@ index 0000000..12ccd20
|
||||
+
|
||||
+void
|
||||
+apply_layout(Monitor *m, LayoutNode *node,
|
||||
+ struct wlr_box area, unsigned int is_root)
|
||||
+ struct wlr_box area, unsigned int is_root)
|
||||
+{
|
||||
+ float ratio;
|
||||
+ int mid;
|
||||
@ -122,9 +124,9 @@ index 0000000..12ccd20
|
||||
+
|
||||
+ if (node->split_vertically) {
|
||||
+ mid = (int)(area.width * ratio);
|
||||
+ left_area = (struct wlr_box){ area.x, area.y, mid, area.height };
|
||||
+ left_area = (struct wlr_box){ area.x, area.y, mid, area.height};
|
||||
+ right_area = (struct wlr_box){ area.x + mid, area.y,
|
||||
+ area.width - mid, area.height };
|
||||
+ area.width - mid, area.height};
|
||||
+
|
||||
+ if (e) {
|
||||
+ left_area.width -= gappx / 2;
|
||||
@ -134,7 +136,7 @@ index 0000000..12ccd20
|
||||
+ } else {
|
||||
+ mid = (int)(area.height * ratio);
|
||||
+ left_area = (struct wlr_box){ area.x, area.y, area.width, mid };
|
||||
+ right_area = (struct wlr_box){ area.x, area.y + mid,
|
||||
+ right_area = (struct wlr_box){ area.x, area.y + mid,
|
||||
+ area.width, area.height - mid };
|
||||
+
|
||||
+ if (e) {
|
||||
@ -167,9 +169,9 @@ index 0000000..12ccd20
|
||||
+ if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen) {
|
||||
+ n++;
|
||||
+ if (!focused_client &&
|
||||
+ cursor->x >= c->old_geom.x
|
||||
+ cursor->x >= c->old_geom.x
|
||||
+ && cursor->x < c->old_geom.x + c->old_geom.width
|
||||
+ && cursor->y >= c->old_geom.y
|
||||
+ && cursor->y >= c->old_geom.y
|
||||
+ && cursor->y < c->old_geom.y + c->old_geom.height) {
|
||||
+ focused_client = c;
|
||||
+ }
|
||||
@ -200,10 +202,11 @@ index 0000000..12ccd20
|
||||
+ wl_list_for_each_reverse(c, &clients, link) {
|
||||
+ if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen) {
|
||||
+ found = 0;
|
||||
+ /* If client has multiple tags set, we might create infinite
|
||||
+ * point to self loops by adding the same client to multiple tiled_clients
|
||||
+ * lists, so hacky way to prevent that is to revert clients active tags to
|
||||
+ * current active tag if multiple tags are selected. */
|
||||
+ /* If client has multiple tags set, we might create infinite
|
||||
+ * point to self loops by adding the same client to multiple
|
||||
+ * tiled_clients lists, so hacky way to prevent that is to revert
|
||||
+ * clients active tags to current active tag if multiple
|
||||
+ * tags are selected. */
|
||||
+ if (c->tags != 1u << curtag)
|
||||
+ c->tags = 1u << curtag;
|
||||
+ wl_list_for_each(cc, tiled_clients, link_tiled) {
|
||||
@ -219,10 +222,11 @@ index 0000000..12ccd20
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* Compare the current list of clients to the previous one and remove clients
|
||||
+ * that no longer exist on the current tag.
|
||||
+ * Aka handles cases where user moves clients to other tags. When client is closed
|
||||
+ * or killed we manage the list and tree clean up in destroynotify */
|
||||
+ /* Compare the current list of clients to the previous one and remove
|
||||
+ * clients that no longer exist on the current tag.
|
||||
+ * This handles cases where user moves clients to other tags.
|
||||
+ * When client is closed or killed we manage the list and tree clean up in
|
||||
+ * destroynotify */
|
||||
+ wl_list_for_each_safe(cc, tmp, tiled_clients, link_tiled) {
|
||||
+ found = 0;
|
||||
+ wl_list_for_each(cur, ¤t_clients, link_temp) {
|
||||
@ -260,8 +264,8 @@ index 0000000..12ccd20
|
||||
+}
|
||||
+
|
||||
+LayoutNode *
|
||||
+create_split_node(unsigned int split_vertically,
|
||||
+ LayoutNode *left, LayoutNode *right)
|
||||
+create_split_node(unsigned int split_vertically,
|
||||
+ LayoutNode *left, LayoutNode *right)
|
||||
+{
|
||||
+ LayoutNode *node = calloc(1, sizeof(LayoutNode));
|
||||
+
|
||||
@ -283,7 +287,8 @@ index 0000000..12ccd20
|
||||
+{
|
||||
+ Client *cc;
|
||||
+ wl_list_for_each(cc, tiled_clients, link_tiled) {
|
||||
+ if (cc == c) return 1;
|
||||
+ if (cc == c)
|
||||
+ return 1;
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
@ -345,14 +350,15 @@ index 0000000..12ccd20
|
||||
+ curtag = get_current_tag(selmon);
|
||||
+ /* If we're starting from a client_node, go up one level first */
|
||||
+ if (node->is_client_node) {
|
||||
+ node = node->split_node ? node->split_node :
|
||||
+ node = node->split_node ? node->split_node :
|
||||
+ find_split_node(selmon->tree_layout->root[curtag], node);
|
||||
+ }
|
||||
+
|
||||
+ /* Climb the tree until we find a node that is not client_node and
|
||||
+ /* Climb the tree until we find a node that is not client_node and
|
||||
+ * match needed orientation. */
|
||||
+ while (node && (node->is_client_node || node->split_vertically != need_vertical)) {
|
||||
+ node = node->split_node ? node->split_node :
|
||||
+ while (node && (node->is_client_node ||
|
||||
+ node->split_vertically != need_vertical)) {
|
||||
+ node = node->split_node ? node->split_node :
|
||||
+ find_split_node(selmon->tree_layout->root[curtag], node);
|
||||
+ }
|
||||
+
|
||||
@ -360,7 +366,9 @@ index 0000000..12ccd20
|
||||
+}
|
||||
+
|
||||
+LayoutNode *
|
||||
+find_closest_client_node(LayoutNode *split_node, enum Direction dir, int current_x, int current_y, LayoutNode **closest, int *closest_dist)
|
||||
+find_closest_client_node(LayoutNode *split_node, enum Direction dir,
|
||||
+ int current_x, int current_y, LayoutNode **closest,
|
||||
+ int *closest_dist)
|
||||
+{
|
||||
+ int client_center_x, client_center_y, dist, is_candidate;
|
||||
+ if (!split_node)
|
||||
@ -408,8 +416,10 @@ index 0000000..12ccd20
|
||||
+ }
|
||||
+
|
||||
+ /* Recursively search in left and right split_nodes */
|
||||
+ find_closest_client_node(split_node->left, dir, current_x, current_y, closest, closest_dist);
|
||||
+ find_closest_client_node(split_node->right, dir, current_x, current_y, closest, closest_dist);
|
||||
+ find_closest_client_node(split_node->left, dir, current_x, current_y,
|
||||
+ closest, closest_dist);
|
||||
+ find_closest_client_node(split_node->right, dir, current_x, current_y,
|
||||
+ closest, closest_dist);
|
||||
+
|
||||
+ return *closest;
|
||||
+}
|
||||
@ -443,7 +453,7 @@ index 0000000..12ccd20
|
||||
+ if (active & (1u << i))
|
||||
+ return i;
|
||||
+ }
|
||||
+ return 0;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
@ -466,64 +476,59 @@ index 0000000..12ccd20
|
||||
+ LayoutNode *old_root, *client_node, *old_client_node, *new_client_node;
|
||||
+ unsigned int wider;
|
||||
+
|
||||
+ if (*root == NULL) {
|
||||
+ /* If there is no root node, inserted client must be the first one.
|
||||
+ * If there's no focused client or client node cannot be found for the
|
||||
+ * focused client we treat them as root node.*/
|
||||
+ if (!*root) {
|
||||
+ *root = create_client_node(new_client);
|
||||
+ add_client_to_tiled_list(new_client, tiled_clients);
|
||||
+ return;
|
||||
+ }
|
||||
+ if (!focused) {
|
||||
+ } else if (!focused || !(client_node = find_client_node(*root, focused))) {
|
||||
+ old_root = *root;
|
||||
+ *root = create_split_node(1, old_root, create_client_node(new_client));
|
||||
+ add_client_to_tiled_list(new_client, tiled_clients);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ client_node = find_client_node(*root, focused);
|
||||
+ if (!client_node) {
|
||||
+ /*Focused client not found in the tree, insert as root*/
|
||||
+ old_root = *root;
|
||||
+ *root = create_split_node(1, old_root, create_client_node(new_client));
|
||||
+ add_client_to_tiled_list(new_client, tiled_clients);
|
||||
+ return;
|
||||
+ }
|
||||
+ mid_x = focused->old_geom.x + focused->old_geom.width / 2;
|
||||
+ mid_y = focused->old_geom.y + focused->old_geom.height / 2;
|
||||
+ old_client_node = create_client_node(client_node->client);
|
||||
+ new_client_node = create_client_node(new_client);
|
||||
+
|
||||
+ wider = focused->old_geom.width >= focused->old_geom.height;
|
||||
+ if (wider) {
|
||||
+ /* Vertical split */
|
||||
+ client_node->is_client_node = 0;
|
||||
+ client_node->split_vertically = 1;
|
||||
+ if (cursor->x < mid_x) {
|
||||
+ client_node->left = new_client_node;
|
||||
+ client_node->right = old_client_node;
|
||||
+ } else {
|
||||
+ client_node->left = old_client_node;
|
||||
+ client_node->right = new_client_node;
|
||||
+ }
|
||||
+ } else {
|
||||
+ /* Horizontal split */
|
||||
+ client_node->is_client_node = 0;
|
||||
+ client_node->split_vertically = 0;
|
||||
+ if (cursor->y < mid_y) {
|
||||
+ client_node->left = new_client_node;
|
||||
+ client_node->right = old_client_node;
|
||||
+ /* We check the cursor location on splittable area and choose
|
||||
+ * the new client's position. On horizontal splits left node represent
|
||||
+ * the upper node and vice versa.*/
|
||||
+ mid_x = focused->old_geom.x + focused->old_geom.width / 2;
|
||||
+ mid_y = focused->old_geom.y + focused->old_geom.height / 2;
|
||||
+ old_client_node = create_client_node(client_node->client);
|
||||
+ new_client_node = create_client_node(new_client);
|
||||
+
|
||||
+ wider = focused->old_geom.width >= focused->old_geom.height;
|
||||
+ if (wider) {
|
||||
+ /* Vertical split */
|
||||
+ client_node->split_vertically = 1;
|
||||
+ if (cursor->x < mid_x) {
|
||||
+ client_node->left = new_client_node;
|
||||
+ client_node->right = old_client_node;
|
||||
+ } else {
|
||||
+ client_node->left = old_client_node;
|
||||
+ client_node->right = new_client_node;
|
||||
+ }
|
||||
+ } else {
|
||||
+ client_node->left = old_client_node;
|
||||
+ client_node->right = new_client_node;
|
||||
+ /* Horizontal split */
|
||||
+ client_node->split_vertically = 0;
|
||||
+ if (cursor->y < mid_y) {
|
||||
+ client_node->left = new_client_node;
|
||||
+ client_node->right = old_client_node;
|
||||
+ } else {
|
||||
+ client_node->left = old_client_node;
|
||||
+ client_node->right = new_client_node;
|
||||
+ }
|
||||
+ }
|
||||
+ /* The old client node becomes the splitnode for the old and new client
|
||||
+ * nodes.*/
|
||||
+ client_node->is_client_node = 0;
|
||||
+ client_node->client = NULL;
|
||||
+ add_client_to_tiled_list(new_client, tiled_clients);
|
||||
+ }
|
||||
+ client_node->client = NULL;
|
||||
+ add_client_to_tiled_list(new_client, tiled_clients);
|
||||
+}
|
||||
+
|
||||
+LayoutNode *
|
||||
+remove_client_node(LayoutNode *node, Client *c)
|
||||
+{
|
||||
+ LayoutNode *tmp;
|
||||
+
|
||||
+ if (!node)
|
||||
+ return NULL;
|
||||
+ if (node->is_client_node) {
|
||||
@ -539,8 +544,8 @@ index 0000000..12ccd20
|
||||
+ node->left = remove_client_node(node->left, c);
|
||||
+ node->right = remove_client_node(node->right, c);
|
||||
+
|
||||
+ /* If one of the child node is NULL after removal and the other is not,
|
||||
+ * we "lift" the other child up to replace this split node. */
|
||||
+ /* If one of the client node is NULL after removal and the other is not,
|
||||
+ * we "lift" the other client node up to replace this split node. */
|
||||
+ if (!node->left && node->right) {
|
||||
+ tmp = node->right;
|
||||
+
|
||||
@ -569,7 +574,8 @@ index 0000000..12ccd20
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+remove_client(Monitor *m, Client *c, LayoutNode **root, struct wl_list *tiled_clients)
|
||||
+remove_client(Monitor *m, Client *c, LayoutNode **root,
|
||||
+ struct wl_list *tiled_clients)
|
||||
+{
|
||||
+ Client *cc, *tmp;
|
||||
+
|
||||
@ -608,7 +614,8 @@ index 0000000..12ccd20
|
||||
+ new_ratio = 0.95f;
|
||||
+
|
||||
+ node->split_ratio = new_ratio;
|
||||
+ /* Skip the resize if done by mouse, we call arrange from motionotify */
|
||||
+ /* Skip the arrange if done resizing by mouse,
|
||||
+ * we call arrange from motionotify */
|
||||
+ if (!resizing_from_mouse) {
|
||||
+ arrange(selmon);
|
||||
+ }
|
||||
@ -638,7 +645,8 @@ index 0000000..12ccd20
|
||||
+ if (new_ratio > 0.95f) new_ratio = 0.95f;
|
||||
+
|
||||
+ node->split_ratio = new_ratio;
|
||||
+ /* Skip the resize if done by mouse, we call arrange from motionotify */
|
||||
+ /* Skip the arrange if done resizing by mouse,
|
||||
+ * we call arrange from motionotify */
|
||||
+ if (!resizing_from_mouse) {
|
||||
+ arrange(selmon);
|
||||
+ }
|
||||
@ -650,7 +658,7 @@ index 0000000..12ccd20
|
||||
+ Client *tmp, *sel = focustop(selmon);
|
||||
+ enum Direction dir = (enum Direction)arg->i;
|
||||
+ LayoutNode *client_node, *target = NULL, *split_node = NULL;
|
||||
+ unsigned int current_x, current_y, curtag = get_current_tag(selmon);
|
||||
+ unsigned int current_x, current_y, curtag = get_current_tag(selmon);
|
||||
+ int closest_dist = INT_MAX;
|
||||
+
|
||||
+ if (!arg || !sel || !selmon->lt[selmon->sellt]->arrange)
|
||||
@ -663,8 +671,8 @@ index 0000000..12ccd20
|
||||
+ current_x = get_client_center(client_node, COORD_X);
|
||||
+ current_y = get_client_center(client_node, COORD_Y);
|
||||
+
|
||||
+ /* For up/down swaps, restrict search within the current horizontal split node
|
||||
+ * if no suitable horizontal split node is found, default to vertical */
|
||||
+ /* For up/down swaps, restrict search within the current horizontal split
|
||||
+ * node if no suitable horizontal split node is found, default to vertical */
|
||||
+ if (dir == DIR_UP || dir == DIR_DOWN) {
|
||||
+ split_node = find_suitable_split_node(client_node, 0);
|
||||
+ if (!split_node) {
|
||||
@ -674,8 +682,10 @@ index 0000000..12ccd20
|
||||
+ split_node = selmon->tree_layout->root[curtag];
|
||||
+ }
|
||||
+
|
||||
+ /* Find the closest client node in the specified direction and swap the clients */
|
||||
+ find_closest_client_node(split_node, dir, current_x, current_y, &target, &closest_dist);
|
||||
+ /* Find the closest client node in the specified direction and swap
|
||||
+ * the clients */
|
||||
+ find_closest_client_node(split_node, dir, current_x, current_y,
|
||||
+ &target, &closest_dist);
|
||||
+
|
||||
+ if (target && target->is_client_node && target->client) {
|
||||
+ tmp = client_node->client;
|
||||
@ -686,17 +696,15 @@ index 0000000..12ccd20
|
||||
+ }
|
||||
+}
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 22d2171..c7924cb 100644
|
||||
index 22d2171..92f3ad6 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -11,9 +11,12 @@ static const float rootcolor[] = COLOR(0x222222ff);
|
||||
static const float bordercolor[] = COLOR(0x444444ff);
|
||||
static const float focuscolor[] = COLOR(0x005577ff);
|
||||
@@ -13,7 +13,10 @@ static const float focuscolor[] = COLOR(0x005577ff);
|
||||
static const float urgentcolor[] = COLOR(0xff0000ff);
|
||||
+static const unsigned int ARRANGE_RATE = 3; /* Call rate limiter for client rearrange when resizing with mouse */
|
||||
+static const unsigned int resize_threshold = 5; /* Pixel threshold for mouse resizing, smaller threshold for smoother updates */
|
||||
/* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */
|
||||
static const float fullscreen_bg[] = {0.1f, 0.1f, 0.1f, 1.0f}; /* You can also use glsl colors */
|
||||
+static const float resize_factor = 0.0002f; /* Resize multiplier for mouse resizing, depends on mouse sensivity. */
|
||||
+static const uint32_t resize_interval_ms = 16; /* Resize interval depends on framerate and screen refresh rate. */
|
||||
|
||||
+enum Direction { DIR_LEFT, DIR_RIGHT, DIR_UP, DIR_DOWN };
|
||||
/* tagging - TAGCOUNT must be no greater than 31 */
|
||||
@ -710,10 +718,10 @@ index 22d2171..c7924cb 100644
|
||||
{ "[]=", tile },
|
||||
{ "><>", NULL }, /* no layout function means floating behavior */
|
||||
{ "[M]", monocle },
|
||||
@@ -127,6 +131,14 @@ static const Key keys[] = {
|
||||
/* modifier key function argument */
|
||||
{ MODKEY, XKB_KEY_p, spawn, {.v = menucmd} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} },
|
||||
@@ -148,6 +152,14 @@ static const Key keys[] = {
|
||||
{ MODKEY, XKB_KEY_period, focusmon, {.i = WLR_DIRECTION_RIGHT} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_less, tagmon, {.i = WLR_DIRECTION_LEFT} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_greater, tagmon, {.i = WLR_DIRECTION_RIGHT} },
|
||||
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Up, swapclients, {.i = DIR_UP} },
|
||||
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Down, swapclients, {.i = DIR_DOWN} },
|
||||
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Right, swapclients, {.i = DIR_RIGHT} },
|
||||
@ -722,11 +730,11 @@ index 22d2171..c7924cb 100644
|
||||
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_Left, setratio_h, {.f = -0.025f} },
|
||||
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_Up, setratio_v, {.f = -0.025f} },
|
||||
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_Down, setratio_v, {.f = +0.025f} },
|
||||
{ MODKEY, XKB_KEY_j, focusstack, {.i = +1} },
|
||||
{ MODKEY, XKB_KEY_k, focusstack, {.i = -1} },
|
||||
{ MODKEY, XKB_KEY_i, incnmaster, {.i = +1} },
|
||||
TAGKEYS( XKB_KEY_1, XKB_KEY_exclam, 0),
|
||||
TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1),
|
||||
TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2),
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index a2711f6..e9cb17b 100644
|
||||
index def2562..604a9a4 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -1,6 +1,7 @@
|
||||
@ -784,14 +792,14 @@ index a2711f6..e9cb17b 100644
|
||||
static void spawn(const Arg *arg);
|
||||
static void startdrag(struct wl_listener *listener, void *data);
|
||||
static void tag(const Arg *arg);
|
||||
@@ -432,6 +442,7 @@ static xcb_atom_t netatom[NetLast];
|
||||
@@ -431,6 +441,7 @@ static xcb_atom_t netatom[NetLast];
|
||||
|
||||
/* attempt to encapsulate suck into one file */
|
||||
#include "client.h"
|
||||
|
||||
+#include "btrtile.c"
|
||||
|
||||
/* function implementations */
|
||||
void
|
||||
applybounds(Client *c, struct wlr_box *bbox)
|
||||
@@ -600,10 +611,17 @@ buttonpress(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct wlr_pointer_button_event *event = data;
|
||||
@ -812,70 +820,58 @@ index a2711f6..e9cb17b 100644
|
||||
wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
|
||||
|
||||
switch (event->state) {
|
||||
@@ -631,18 +649,52 @@ buttonpress(struct wl_listener *listener, void *data)
|
||||
case WL_POINTER_BUTTON_STATE_RELEASED:
|
||||
@@ -632,15 +650,49 @@ buttonpress(struct wl_listener *listener, void *data)
|
||||
/* If you released any buttons, we exit interactive move/resize mode. */
|
||||
/* TODO should reset to the pointer focus's current setcursor */
|
||||
- if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) {
|
||||
- wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
|
||||
- cursor_mode = CurNormal;
|
||||
+ if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) {
|
||||
+ c = grabc;
|
||||
+ if (c && c->was_tiled && !strcmp(selmon->ltsymbol, "|w|")) {
|
||||
if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) {
|
||||
+ c = grabc;
|
||||
+ if (c && c->was_tiled && !strcmp(selmon->ltsymbol, "|w|")) {
|
||||
+ /* Check if more than one tag is active, if so we escape */
|
||||
+ if (active_tags && (active_tags & (active_tags - 1)))
|
||||
+ break;
|
||||
+ if (cursor_mode == CurMove && c->isfloating) {
|
||||
+ target = NULL;
|
||||
+ surface = NULL;
|
||||
+ xytonode(cursor->x, cursor->y, &surface, &target, NULL, &sx, &sy);
|
||||
+ if (cursor_mode == CurMove && c->isfloating) {
|
||||
+ target = NULL;
|
||||
+ surface = NULL;
|
||||
+ xytonode(cursor->x, cursor->y, &surface, &target, NULL, &sx, &sy);
|
||||
+
|
||||
+ if (target && !target->isfloating && !target->isfullscreen) {
|
||||
+ insert_client(selmon, target, c, root, tiled_clients);
|
||||
+ } else {
|
||||
+ if (!root) {
|
||||
+ *root = create_client_node(c);
|
||||
+ add_client_to_tiled_list(c, tiled_clients);
|
||||
+ } else {
|
||||
+ old_root = *root;
|
||||
+ *root = create_split_node(1, old_root, create_client_node(c));
|
||||
+ add_client_to_tiled_list(c, tiled_clients);
|
||||
+ }
|
||||
+ }
|
||||
+ if (target && !target->isfloating && !target->isfullscreen) {
|
||||
+ insert_client(selmon, target, c, root, tiled_clients);
|
||||
+ } else {
|
||||
+ if (!root) {
|
||||
+ *root = create_client_node(c);
|
||||
+ add_client_to_tiled_list(c, tiled_clients);
|
||||
+ } else {
|
||||
+ old_root = *root;
|
||||
+ *root = create_split_node(1, old_root, create_client_node(c));
|
||||
+ add_client_to_tiled_list(c, tiled_clients);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ setfloating(c, 0);
|
||||
+ arrange(selmon);
|
||||
+ setfloating(c, 0);
|
||||
+ arrange(selmon);
|
||||
+
|
||||
+ } else if (cursor_mode == CurResize && !c->isfloating) {
|
||||
+ resizing_from_mouse = 0;
|
||||
+ }
|
||||
+ } else {
|
||||
+ if (cursor_mode == CurResize && resizing_from_mouse)
|
||||
+ resizing_from_mouse = 0;
|
||||
+ }
|
||||
+ } else if (cursor_mode == CurResize && !c->isfloating) {
|
||||
+ resizing_from_mouse = 0;
|
||||
+ }
|
||||
+ } else {
|
||||
+ if (cursor_mode == CurResize && resizing_from_mouse)
|
||||
+ resizing_from_mouse = 0;
|
||||
+ }
|
||||
+ /* Default behaviour */
|
||||
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
|
||||
+ cursor_mode = CurNormal;
|
||||
wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
|
||||
cursor_mode = CurNormal;
|
||||
/* Drop the window off on its new monitor */
|
||||
- selmon = xytomon(cursor->x, cursor->y);
|
||||
- setmon(grabc, selmon, 0);
|
||||
- return;
|
||||
selmon = xytomon(cursor->x, cursor->y);
|
||||
setmon(grabc, selmon, 0);
|
||||
+ grabc = NULL;
|
||||
return;
|
||||
- } else {
|
||||
- cursor_mode = CurNormal;
|
||||
- }
|
||||
- break;
|
||||
- }
|
||||
+ selmon = xytomon(cursor->x, cursor->y);
|
||||
+ setmon(grabc, selmon, 0);
|
||||
+ grabc = NULL;
|
||||
+ return;
|
||||
+ }
|
||||
+ cursor_mode = CurNormal;
|
||||
+ break;
|
||||
+ }
|
||||
}
|
||||
+ cursor_mode = CurNormal;
|
||||
break;
|
||||
}
|
||||
/* If the event wasn't handled by the compositor, notify the client with
|
||||
* pointer focus that a button press has occurred */
|
||||
wlr_seat_pointer_notify_button(seat,
|
||||
@@ -720,6 +772,9 @@ cleanupmon(struct wl_listener *listener, void *data)
|
||||
wlr_output_layout_remove(output_layout, m->wlr_output);
|
||||
wlr_scene_output_destroy(m->scene_output);
|
||||
@ -886,15 +882,15 @@ index a2711f6..e9cb17b 100644
|
||||
closemon(m);
|
||||
wlr_scene_node_destroy(&m->fullscreen_bg->node);
|
||||
free(m);
|
||||
@@ -1025,6 +1080,7 @@ createmon(struct wl_listener *listener, void *data)
|
||||
@@ -1026,6 +1081,7 @@ createmon(struct wl_listener *listener, void *data)
|
||||
|
||||
wl_list_insert(&mons, &m->link);
|
||||
printstatus();
|
||||
|
||||
+ init_tree_layout(m);
|
||||
|
||||
/* The xdg-protocol specifies:
|
||||
*
|
||||
* If the fullscreened surface is not opaque, the compositor must make
|
||||
@@ -1263,6 +1319,15 @@ destroynotify(struct wl_listener *listener, void *data)
|
||||
@@ -1265,6 +1321,15 @@ destroynotify(struct wl_listener *listener, void *data)
|
||||
wl_list_remove(&c->destroy.link);
|
||||
wl_list_remove(&c->set_title.link);
|
||||
wl_list_remove(&c->fullscreen.link);
|
||||
@ -910,26 +906,25 @@ index a2711f6..e9cb17b 100644
|
||||
#ifdef XWAYLAND
|
||||
if (c->type != XDGShell) {
|
||||
wl_list_remove(&c->activate.link);
|
||||
@@ -1809,7 +1874,9 @@ void
|
||||
@@ -1811,7 +1876,8 @@ void
|
||||
motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double dy,
|
||||
double dx_unaccel, double dy_unaccel)
|
||||
{
|
||||
- double sx = 0, sy = 0, sx_confined, sy_confined;
|
||||
+ int tiled = 0;
|
||||
+ float factor;
|
||||
+ double sx = 0, sy = 0, sx_confined, sy_confined, dx_total, dy_total;
|
||||
Client *c = NULL, *w = NULL;
|
||||
LayerSurface *l = NULL;
|
||||
struct wlr_surface *surface = NULL;
|
||||
@@ -1863,18 +1930,60 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d
|
||||
@@ -1865,18 +1931,56 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d
|
||||
/* Update drag icon's position */
|
||||
wlr_scene_node_set_position(&drag_icon->node, (int)round(cursor->x), (int)round(cursor->y));
|
||||
|
||||
- /* If we are currently grabbing the mouse, handle and return */
|
||||
+ /* Skip if internal call or already resizing */
|
||||
+ if (time == 0 && resizing_from_mouse)
|
||||
+ goto focus;
|
||||
+
|
||||
/* If we are currently grabbing the mouse, handle and return */
|
||||
+ tiled = grabc && !grabc->isfloating && !grabc->isfullscreen;
|
||||
if (cursor_mode == CurMove) {
|
||||
/* Move the grabbed client to the new position. */
|
||||
@ -953,21 +948,18 @@ index a2711f6..e9cb17b 100644
|
||||
+ dx_total = cursor->x - resize_last_update_x;
|
||||
+ dy_total = cursor->y - resize_last_update_y;
|
||||
+
|
||||
+ if (fabs(dx_total) > resize_threshold || fabs(dy_total) > resize_threshold) {
|
||||
+ if (time - last_resize_time >= resize_interval_ms) {
|
||||
+ Arg a = {0};
|
||||
+ factor = 0.0002f;
|
||||
+ if (fabs(dx_total) > fabs(dy_total)) {
|
||||
+ a.f = (float)(dx_total * factor);
|
||||
+ a.f = (float)(dx_total * resize_factor);
|
||||
+ setratio_h(&a);
|
||||
+ } else {
|
||||
+ a.f = (float)(dy_total * factor);
|
||||
+ a.f = (float)(dy_total * resize_factor);
|
||||
+ setratio_v(&a);
|
||||
+ }
|
||||
+ /* Limit arrange rate to reduce recursion calls */
|
||||
+ if (++arrange_counter >= ARRANGE_RATE) {
|
||||
+ arrange(selmon);
|
||||
+ arrange_counter = 0;
|
||||
+ }
|
||||
+ arrange(selmon);
|
||||
+
|
||||
+ last_resize_time = time;
|
||||
+ resize_last_update_x = cursor->x;
|
||||
+ resize_last_update_y = cursor->y;
|
||||
+ }
|
||||
@ -988,7 +980,7 @@ index a2711f6..e9cb17b 100644
|
||||
/* If there's no client surface under the cursor, set the cursor image to a
|
||||
* default. This is what makes the cursor image appear when you move it
|
||||
* off of a client or over its border. */
|
||||
@@ -1908,23 +2017,44 @@ moveresize(const Arg *arg)
|
||||
@@ -1910,22 +2014,41 @@ moveresize(const Arg *arg)
|
||||
if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen)
|
||||
return;
|
||||
|
||||
@ -1004,52 +996,46 @@ index a2711f6..e9cb17b 100644
|
||||
- /* Doesn't work for X11 output - the next absolute motion event
|
||||
- * returns the cursor to where it started */
|
||||
- wlr_cursor_warp_closest(cursor, NULL,
|
||||
- grabc->geom.x + grabc->geom.width,
|
||||
- grabc->geom.y + grabc->geom.height);
|
||||
+ cursor_mode = arg->ui;
|
||||
+ grabc->was_tiled = (!grabc->isfloating && !grabc->isfullscreen);
|
||||
+
|
||||
+ if (grabc->was_tiled) {
|
||||
+ switch (cursor_mode) {
|
||||
+ case CurMove:
|
||||
+ setfloating(grabc, 1);
|
||||
+ grabcx = (int)round(cursor->x) - grabc->geom.x;
|
||||
+ grabcy = (int)round(cursor->y) - grabc->geom.y;
|
||||
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "fleur");
|
||||
+ break;
|
||||
+ case CurResize:
|
||||
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize");
|
||||
+ resize_last_update_x = cursor->x;
|
||||
+ resize_last_update_y = cursor->y;
|
||||
+ resizing_from_mouse = 1;
|
||||
+ break;
|
||||
+ }
|
||||
+ } else {
|
||||
+ /* Default floating logic */
|
||||
+ /* Float the window and tell motionnotify to grab it */
|
||||
+ setfloating(grabc, 1);
|
||||
+ switch (cursor_mode) {
|
||||
+ case CurMove:
|
||||
+ grabcx = (int)round(cursor->x) - grabc->geom.x;
|
||||
+ grabcy = (int)round(cursor->y) - grabc->geom.y;
|
||||
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "fleur");
|
||||
+ break;
|
||||
+ case CurResize:
|
||||
+ wlr_cursor_warp_closest(cursor, NULL,
|
||||
grabc->geom.x + grabc->geom.width,
|
||||
grabc->geom.y + grabc->geom.height);
|
||||
- wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize");
|
||||
- break;
|
||||
- }
|
||||
+ cursor_mode = arg->ui;
|
||||
+ grabc->was_tiled = (!grabc->isfloating && !grabc->isfullscreen);
|
||||
+
|
||||
+ if (grabc->was_tiled) {
|
||||
+ switch (cursor_mode) {
|
||||
+ case CurMove:
|
||||
+ setfloating(grabc, 1);
|
||||
+ grabcx = (int)round(cursor->x) - grabc->geom.x;
|
||||
+ grabcy = (int)round(cursor->y) - grabc->geom.y;
|
||||
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "fleur");
|
||||
+ break;
|
||||
+ case CurResize:
|
||||
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize");
|
||||
+ resize_init_x = cursor->x;
|
||||
+ resize_init_y = cursor->y;
|
||||
+ resize_last_update_x = resize_init_x;
|
||||
+ resize_last_update_y = resize_init_y;
|
||||
+ resizing_from_mouse = 1;
|
||||
+ break;
|
||||
+ }
|
||||
+ } else {
|
||||
+ /* Default floating logic */
|
||||
+ /* Float the window and tell motionnotify to grab it */
|
||||
+ setfloating(grabc, 1);
|
||||
+ switch (cursor_mode) {
|
||||
+ case CurMove:
|
||||
+ grabcx = (int)round(cursor->x) - grabc->geom.x;
|
||||
+ grabcy = (int)round(cursor->y) - grabc->geom.y;
|
||||
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "fleur");
|
||||
+ break;
|
||||
+ case CurResize:
|
||||
+ wlr_cursor_warp_closest(cursor, NULL,
|
||||
+ grabc->geom.x + grabc->geom.width,
|
||||
+ grabc->geom.y + grabc->geom.height);
|
||||
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize");
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize");
|
||||
+ break;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
--
|
||||
2.45.2
|
||||
|
||||
|
||||
@ -1,21 +1,21 @@
|
||||
From 2a2d5dd776834879005f1dbcb5c2cc8aaab90125 Mon Sep 17 00:00:00 2001
|
||||
From 2b7e152bd39432cd82738a29a8815cf9264f02d8 Mon Sep 17 00:00:00 2001
|
||||
From: julmajustus <julmajustus@tutanota.com>
|
||||
Date: Mon, 23 Dec 2024 20:24:21 +0200
|
||||
Subject: [PATCH] Btrtile layout
|
||||
Date: Wed, 1 Jan 2025 19:06:03 +0200
|
||||
Subject: [PATCH] btrtile init
|
||||
|
||||
---
|
||||
btrtile.c | 649 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
btrtile.c | 659 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
config.def.h | 12 +
|
||||
dwl.c | 206 +++++++++++++---
|
||||
3 files changed, 829 insertions(+), 38 deletions(-)
|
||||
dwl.c | 177 +++++++++++---
|
||||
3 files changed, 821 insertions(+), 27 deletions(-)
|
||||
create mode 100644 btrtile.c
|
||||
|
||||
diff --git a/btrtile.c b/btrtile.c
|
||||
new file mode 100644
|
||||
index 0000000..955b374
|
||||
index 0000000..7fb0716
|
||||
--- /dev/null
|
||||
+++ b/btrtile.c
|
||||
@@ -0,0 +1,649 @@
|
||||
@@ -0,0 +1,659 @@
|
||||
+/* ************************************************************************** */
|
||||
+/* */
|
||||
+/* ::: :::::::: */
|
||||
@ -24,7 +24,7 @@ index 0000000..955b374
|
||||
+/* By: jmakkone <jmakkone@student.hive.fi> +#+ +:+ +#+ */
|
||||
+/* +#+#+#+#+#+ +#+ */
|
||||
+/* Created: 2024/12/15 00:26:07 by jmakkone #+# #+# */
|
||||
+/* Updated: 2024/12/23 20:23:05 by jmakkone ### ########.fr */
|
||||
+/* Updated: 2025/01/01 18:40:14 by jmakkone ### ########.fr */
|
||||
+/* */
|
||||
+/* ************************************************************************** */
|
||||
+
|
||||
@ -50,35 +50,37 @@ index 0000000..955b374
|
||||
+
|
||||
+static void add_client_to_tiled_list(Client *c, struct wl_list *tiled_clients);
|
||||
+static void apply_layout(Monitor *m, LayoutNode *node,
|
||||
+ struct wlr_box area, unsigned int is_root);
|
||||
+ struct wlr_box area, unsigned int is_root);
|
||||
+static void btrtile(Monitor *m);
|
||||
+static LayoutNode *create_client_node(Client *c);
|
||||
+static LayoutNode *create_split_node(unsigned int split_vertically,
|
||||
+ LayoutNode *left, LayoutNode *right);
|
||||
+static LayoutNode *create_split_node(unsigned int split_vertically,
|
||||
+ LayoutNode *left, LayoutNode *right);
|
||||
+static void destroy_node_tree(LayoutNode *node);
|
||||
+static void destroy_tree_layout(Monitor *m);
|
||||
+static LayoutNode *find_client_node(LayoutNode *node, Client *c);
|
||||
+static LayoutNode *find_split_node(LayoutNode *root, LayoutNode *child);
|
||||
+static LayoutNode *find_suitable_split_node(LayoutNode *client_node, unsigned int need_vertical);
|
||||
+static LayoutNode *find_closest_client_node(LayoutNode *split_node,enum Direction dir,
|
||||
+ int current_x, int current_y, LayoutNode **closest, int *closest_dist);
|
||||
+static LayoutNode *find_suitable_split_node(LayoutNode *client_node,
|
||||
+ unsigned int need_vertical);
|
||||
+static LayoutNode *find_closest_client_node(LayoutNode *split_node,
|
||||
+ enum Direction dir, int current_x,
|
||||
+ int current_y, LayoutNode **closest,
|
||||
+ int *closest_dist);
|
||||
+static unsigned int get_client_center(LayoutNode *node, CoordType type);
|
||||
+static unsigned int get_current_tag(Monitor *m);
|
||||
+static void init_tree_layout(Monitor *m);
|
||||
+static void insert_client(Monitor *m, Client *focused, Client *new_client,
|
||||
+ LayoutNode **root, struct wl_list *tiled_clients);
|
||||
+ LayoutNode **root, struct wl_list *tiled_clients);
|
||||
+static unsigned int is_client_tiled(Client *c, struct wl_list *tiled_clients);
|
||||
+static LayoutNode *remove_client_node(LayoutNode *node, Client *c);
|
||||
+static void remove_client(Monitor *m, Client *c,
|
||||
+ LayoutNode **root, struct wl_list *tiled_clients);
|
||||
+static void remove_client(Monitor *m, Client *c,
|
||||
+ LayoutNode **root, struct wl_list *tiled_clients);
|
||||
+static void setratio_h(const Arg *arg);
|
||||
+static void setratio_v(const Arg *arg);
|
||||
+static void swapclients(const Arg *arg);
|
||||
+
|
||||
+static int resizing_from_mouse = 0;
|
||||
+static double resize_init_x, resize_init_y;
|
||||
+static double resize_last_update_x, resize_last_update_y;
|
||||
+static unsigned int arrange_counter = 0;
|
||||
+static uint32_t last_resize_time = 0;
|
||||
+
|
||||
+void
|
||||
+add_client_to_tiled_list(Client *c, struct wl_list *tiled_clients)
|
||||
@ -89,7 +91,7 @@ index 0000000..955b374
|
||||
+
|
||||
+void
|
||||
+apply_layout(Monitor *m, LayoutNode *node,
|
||||
+ struct wlr_box area, unsigned int is_root)
|
||||
+ struct wlr_box area, unsigned int is_root)
|
||||
+{
|
||||
+ float ratio;
|
||||
+ int mid;
|
||||
@ -114,13 +116,13 @@ index 0000000..955b374
|
||||
+
|
||||
+ if (node->split_vertically) {
|
||||
+ mid = (int)(area.width * ratio);
|
||||
+ left_area = (struct wlr_box){ area.x, area.y, mid, area.height };
|
||||
+ left_area = (struct wlr_box){ area.x, area.y, mid, area.height};
|
||||
+ right_area = (struct wlr_box){ area.x + mid, area.y,
|
||||
+ area.width - mid, area.height };
|
||||
+ area.width - mid, area.height};
|
||||
+ } else {
|
||||
+ mid = (int)(area.height * ratio);
|
||||
+ left_area = (struct wlr_box){ area.x, area.y, area.width, mid };
|
||||
+ right_area = (struct wlr_box){ area.x, area.y + mid,
|
||||
+ right_area = (struct wlr_box){ area.x, area.y + mid,
|
||||
+ area.width, area.height - mid };
|
||||
+ }
|
||||
+
|
||||
@ -147,9 +149,9 @@ index 0000000..955b374
|
||||
+ if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen) {
|
||||
+ n++;
|
||||
+ if (!focused_client &&
|
||||
+ cursor->x >= c->old_geom.x
|
||||
+ cursor->x >= c->old_geom.x
|
||||
+ && cursor->x < c->old_geom.x + c->old_geom.width
|
||||
+ && cursor->y >= c->old_geom.y
|
||||
+ && cursor->y >= c->old_geom.y
|
||||
+ && cursor->y < c->old_geom.y + c->old_geom.height) {
|
||||
+ focused_client = c;
|
||||
+ }
|
||||
@ -180,10 +182,11 @@ index 0000000..955b374
|
||||
+ wl_list_for_each_reverse(c, &clients, link) {
|
||||
+ if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen) {
|
||||
+ found = 0;
|
||||
+ /* If client has multiple tags set, we might create infinite
|
||||
+ * point to self loops by adding the same client to multiple tiled_clients
|
||||
+ * lists, so hacky way to prevent that is to revert clients active tags to
|
||||
+ * current active tag if multiple tags are selected. */
|
||||
+ /* If client has multiple tags set, we might create infinite
|
||||
+ * point to self loops by adding the same client to multiple
|
||||
+ * tiled_clients lists, so hacky way to prevent that is to revert
|
||||
+ * clients active tags to current active tag if multiple
|
||||
+ * tags are selected. */
|
||||
+ if (c->tags != 1u << curtag)
|
||||
+ c->tags = 1u << curtag;
|
||||
+ wl_list_for_each(cc, tiled_clients, link_tiled) {
|
||||
@ -199,10 +202,11 @@ index 0000000..955b374
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* Compare the current list of clients to the previous one and remove clients
|
||||
+ * that no longer exist on the current tag.
|
||||
+ * Aka handles cases where user moves clients to other tags. When client is closed
|
||||
+ * or killed we manage the list and tree clean up in destroynotify */
|
||||
+ /* Compare the current list of clients to the previous one and remove
|
||||
+ * clients that no longer exist on the current tag.
|
||||
+ * This handles cases where user moves clients to other tags.
|
||||
+ * When client is closed or killed we manage the list and tree clean up in
|
||||
+ * destroynotify */
|
||||
+ wl_list_for_each_safe(cc, tmp, tiled_clients, link_tiled) {
|
||||
+ found = 0;
|
||||
+ wl_list_for_each(cur, ¤t_clients, link_temp) {
|
||||
@ -240,8 +244,8 @@ index 0000000..955b374
|
||||
+}
|
||||
+
|
||||
+LayoutNode *
|
||||
+create_split_node(unsigned int split_vertically,
|
||||
+ LayoutNode *left, LayoutNode *right)
|
||||
+create_split_node(unsigned int split_vertically,
|
||||
+ LayoutNode *left, LayoutNode *right)
|
||||
+{
|
||||
+ LayoutNode *node = calloc(1, sizeof(LayoutNode));
|
||||
+
|
||||
@ -263,7 +267,8 @@ index 0000000..955b374
|
||||
+{
|
||||
+ Client *cc;
|
||||
+ wl_list_for_each(cc, tiled_clients, link_tiled) {
|
||||
+ if (cc == c) return 1;
|
||||
+ if (cc == c)
|
||||
+ return 1;
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
@ -325,14 +330,15 @@ index 0000000..955b374
|
||||
+ curtag = get_current_tag(selmon);
|
||||
+ /* If we're starting from a client_node, go up one level first */
|
||||
+ if (node->is_client_node) {
|
||||
+ node = node->split_node ? node->split_node :
|
||||
+ node = node->split_node ? node->split_node :
|
||||
+ find_split_node(selmon->tree_layout->root[curtag], node);
|
||||
+ }
|
||||
+
|
||||
+ /* Climb the tree until we find a node that is not client_node and
|
||||
+ /* Climb the tree until we find a node that is not client_node and
|
||||
+ * match needed orientation. */
|
||||
+ while (node && (node->is_client_node || node->split_vertically != need_vertical)) {
|
||||
+ node = node->split_node ? node->split_node :
|
||||
+ while (node && (node->is_client_node ||
|
||||
+ node->split_vertically != need_vertical)) {
|
||||
+ node = node->split_node ? node->split_node :
|
||||
+ find_split_node(selmon->tree_layout->root[curtag], node);
|
||||
+ }
|
||||
+
|
||||
@ -340,7 +346,9 @@ index 0000000..955b374
|
||||
+}
|
||||
+
|
||||
+LayoutNode *
|
||||
+find_closest_client_node(LayoutNode *split_node, enum Direction dir, int current_x, int current_y, LayoutNode **closest, int *closest_dist)
|
||||
+find_closest_client_node(LayoutNode *split_node, enum Direction dir,
|
||||
+ int current_x, int current_y, LayoutNode **closest,
|
||||
+ int *closest_dist)
|
||||
+{
|
||||
+ int client_center_x, client_center_y, dist, is_candidate;
|
||||
+ if (!split_node)
|
||||
@ -388,8 +396,10 @@ index 0000000..955b374
|
||||
+ }
|
||||
+
|
||||
+ /* Recursively search in left and right split_nodes */
|
||||
+ find_closest_client_node(split_node->left, dir, current_x, current_y, closest, closest_dist);
|
||||
+ find_closest_client_node(split_node->right, dir, current_x, current_y, closest, closest_dist);
|
||||
+ find_closest_client_node(split_node->left, dir, current_x, current_y,
|
||||
+ closest, closest_dist);
|
||||
+ find_closest_client_node(split_node->right, dir, current_x, current_y,
|
||||
+ closest, closest_dist);
|
||||
+
|
||||
+ return *closest;
|
||||
+}
|
||||
@ -423,7 +433,7 @@ index 0000000..955b374
|
||||
+ if (active & (1u << i))
|
||||
+ return i;
|
||||
+ }
|
||||
+ return 0;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
@ -446,64 +456,59 @@ index 0000000..955b374
|
||||
+ LayoutNode *old_root, *client_node, *old_client_node, *new_client_node;
|
||||
+ unsigned int wider;
|
||||
+
|
||||
+ if (*root == NULL) {
|
||||
+ /* If there is no root node, inserted client must be the first one.
|
||||
+ * If there's no focused client or client node cannot be found for the
|
||||
+ * focused client we treat them as root node.*/
|
||||
+ if (!*root) {
|
||||
+ *root = create_client_node(new_client);
|
||||
+ add_client_to_tiled_list(new_client, tiled_clients);
|
||||
+ return;
|
||||
+ }
|
||||
+ if (!focused) {
|
||||
+ } else if (!focused || !(client_node = find_client_node(*root, focused))) {
|
||||
+ old_root = *root;
|
||||
+ *root = create_split_node(1, old_root, create_client_node(new_client));
|
||||
+ add_client_to_tiled_list(new_client, tiled_clients);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ client_node = find_client_node(*root, focused);
|
||||
+ if (!client_node) {
|
||||
+ /*Focused client not found in the tree, insert as root*/
|
||||
+ old_root = *root;
|
||||
+ *root = create_split_node(1, old_root, create_client_node(new_client));
|
||||
+ add_client_to_tiled_list(new_client, tiled_clients);
|
||||
+ return;
|
||||
+ }
|
||||
+ mid_x = focused->old_geom.x + focused->old_geom.width / 2;
|
||||
+ mid_y = focused->old_geom.y + focused->old_geom.height / 2;
|
||||
+ old_client_node = create_client_node(client_node->client);
|
||||
+ new_client_node = create_client_node(new_client);
|
||||
+
|
||||
+ wider = focused->old_geom.width >= focused->old_geom.height;
|
||||
+ if (wider) {
|
||||
+ /* Vertical split */
|
||||
+ client_node->is_client_node = 0;
|
||||
+ client_node->split_vertically = 1;
|
||||
+ if (cursor->x < mid_x) {
|
||||
+ client_node->left = new_client_node;
|
||||
+ client_node->right = old_client_node;
|
||||
+ } else {
|
||||
+ client_node->left = old_client_node;
|
||||
+ client_node->right = new_client_node;
|
||||
+ }
|
||||
+ } else {
|
||||
+ /* Horizontal split */
|
||||
+ client_node->is_client_node = 0;
|
||||
+ client_node->split_vertically = 0;
|
||||
+ if (cursor->y < mid_y) {
|
||||
+ client_node->left = new_client_node;
|
||||
+ client_node->right = old_client_node;
|
||||
+ /* We check the cursor location on splittable area and choose
|
||||
+ * the new client's position. On horizontal splits left node represent
|
||||
+ * the upper node and vice versa.*/
|
||||
+ mid_x = focused->old_geom.x + focused->old_geom.width / 2;
|
||||
+ mid_y = focused->old_geom.y + focused->old_geom.height / 2;
|
||||
+ old_client_node = create_client_node(client_node->client);
|
||||
+ new_client_node = create_client_node(new_client);
|
||||
+
|
||||
+ wider = focused->old_geom.width >= focused->old_geom.height;
|
||||
+ if (wider) {
|
||||
+ /* Vertical split */
|
||||
+ client_node->split_vertically = 1;
|
||||
+ if (cursor->x < mid_x) {
|
||||
+ client_node->left = new_client_node;
|
||||
+ client_node->right = old_client_node;
|
||||
+ } else {
|
||||
+ client_node->left = old_client_node;
|
||||
+ client_node->right = new_client_node;
|
||||
+ }
|
||||
+ } else {
|
||||
+ client_node->left = old_client_node;
|
||||
+ client_node->right = new_client_node;
|
||||
+ /* Horizontal split */
|
||||
+ client_node->split_vertically = 0;
|
||||
+ if (cursor->y < mid_y) {
|
||||
+ client_node->left = new_client_node;
|
||||
+ client_node->right = old_client_node;
|
||||
+ } else {
|
||||
+ client_node->left = old_client_node;
|
||||
+ client_node->right = new_client_node;
|
||||
+ }
|
||||
+ }
|
||||
+ /* The old client node becomes the splitnode for the old and new client
|
||||
+ * nodes.*/
|
||||
+ client_node->is_client_node = 0;
|
||||
+ client_node->client = NULL;
|
||||
+ add_client_to_tiled_list(new_client, tiled_clients);
|
||||
+ }
|
||||
+ client_node->client = NULL;
|
||||
+ add_client_to_tiled_list(new_client, tiled_clients);
|
||||
+}
|
||||
+
|
||||
+LayoutNode *
|
||||
+remove_client_node(LayoutNode *node, Client *c)
|
||||
+{
|
||||
+ LayoutNode *tmp;
|
||||
+
|
||||
+ if (!node)
|
||||
+ return NULL;
|
||||
+ if (node->is_client_node) {
|
||||
@ -519,8 +524,8 @@ index 0000000..955b374
|
||||
+ node->left = remove_client_node(node->left, c);
|
||||
+ node->right = remove_client_node(node->right, c);
|
||||
+
|
||||
+ /* If one of the child node is NULL after removal and the other is not,
|
||||
+ * we "lift" the other child up to replace this split node. */
|
||||
+ /* If one of the client node is NULL after removal and the other is not,
|
||||
+ * we "lift" the other client node up to replace this split node. */
|
||||
+ if (!node->left && node->right) {
|
||||
+ tmp = node->right;
|
||||
+
|
||||
@ -549,7 +554,8 @@ index 0000000..955b374
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+remove_client(Monitor *m, Client *c, LayoutNode **root, struct wl_list *tiled_clients)
|
||||
+remove_client(Monitor *m, Client *c, LayoutNode **root,
|
||||
+ struct wl_list *tiled_clients)
|
||||
+{
|
||||
+ Client *cc, *tmp;
|
||||
+
|
||||
@ -588,7 +594,8 @@ index 0000000..955b374
|
||||
+ new_ratio = 0.95f;
|
||||
+
|
||||
+ node->split_ratio = new_ratio;
|
||||
+ /* Skip the resize if done by mouse, we call arrange from motionotify */
|
||||
+ /* Skip the arrange if done resizing by mouse,
|
||||
+ * we call arrange from motionotify */
|
||||
+ if (!resizing_from_mouse) {
|
||||
+ arrange(selmon);
|
||||
+ }
|
||||
@ -618,7 +625,8 @@ index 0000000..955b374
|
||||
+ if (new_ratio > 0.95f) new_ratio = 0.95f;
|
||||
+
|
||||
+ node->split_ratio = new_ratio;
|
||||
+ /* Skip the resize if done by mouse, we call arrange from motionotify */
|
||||
+ /* Skip the arrange if done resizing by mouse,
|
||||
+ * we call arrange from motionotify */
|
||||
+ if (!resizing_from_mouse) {
|
||||
+ arrange(selmon);
|
||||
+ }
|
||||
@ -630,7 +638,7 @@ index 0000000..955b374
|
||||
+ Client *tmp, *sel = focustop(selmon);
|
||||
+ enum Direction dir = (enum Direction)arg->i;
|
||||
+ LayoutNode *client_node, *target = NULL, *split_node = NULL;
|
||||
+ unsigned int current_x, current_y, curtag = get_current_tag(selmon);
|
||||
+ unsigned int current_x, current_y, curtag = get_current_tag(selmon);
|
||||
+ int closest_dist = INT_MAX;
|
||||
+
|
||||
+ if (!arg || !sel || !selmon->lt[selmon->sellt]->arrange)
|
||||
@ -643,8 +651,8 @@ index 0000000..955b374
|
||||
+ current_x = get_client_center(client_node, COORD_X);
|
||||
+ current_y = get_client_center(client_node, COORD_Y);
|
||||
+
|
||||
+ /* For up/down swaps, restrict search within the current horizontal split node
|
||||
+ * if no suitable horizontal split node is found, default to vertical */
|
||||
+ /* For up/down swaps, restrict search within the current horizontal split
|
||||
+ * node if no suitable horizontal split node is found, default to vertical */
|
||||
+ if (dir == DIR_UP || dir == DIR_DOWN) {
|
||||
+ split_node = find_suitable_split_node(client_node, 0);
|
||||
+ if (!split_node) {
|
||||
@ -654,8 +662,10 @@ index 0000000..955b374
|
||||
+ split_node = selmon->tree_layout->root[curtag];
|
||||
+ }
|
||||
+
|
||||
+ /* Find the closest client node in the specified direction and swap the clients */
|
||||
+ find_closest_client_node(split_node, dir, current_x, current_y, &target, &closest_dist);
|
||||
+ /* Find the closest client node in the specified direction and swap
|
||||
+ * the clients */
|
||||
+ find_closest_client_node(split_node, dir, current_x, current_y,
|
||||
+ &target, &closest_dist);
|
||||
+
|
||||
+ if (target && target->is_client_node && target->client) {
|
||||
+ tmp = client_node->client;
|
||||
@ -666,17 +676,15 @@ index 0000000..955b374
|
||||
+ }
|
||||
+}
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 22d2171..c7924cb 100644
|
||||
index 22d2171..92f3ad6 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -11,9 +11,12 @@ static const float rootcolor[] = COLOR(0x222222ff);
|
||||
static const float bordercolor[] = COLOR(0x444444ff);
|
||||
static const float focuscolor[] = COLOR(0x005577ff);
|
||||
@@ -13,7 +13,10 @@ static const float focuscolor[] = COLOR(0x005577ff);
|
||||
static const float urgentcolor[] = COLOR(0xff0000ff);
|
||||
+static const unsigned int ARRANGE_RATE = 3; /* Call rate limiter for client rearrange when resizing with mouse */
|
||||
+static const unsigned int resize_threshold = 5; /* Pixel threshold for mouse resizing, smaller threshold for smoother updates */
|
||||
/* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */
|
||||
static const float fullscreen_bg[] = {0.1f, 0.1f, 0.1f, 1.0f}; /* You can also use glsl colors */
|
||||
+static const float resize_factor = 0.0002f; /* Resize multiplier for mouse resizing, depends on mouse sensivity. */
|
||||
+static const uint32_t resize_interval_ms = 16; /* Resize interval depends on framerate and screen refresh rate. */
|
||||
|
||||
+enum Direction { DIR_LEFT, DIR_RIGHT, DIR_UP, DIR_DOWN };
|
||||
/* tagging - TAGCOUNT must be no greater than 31 */
|
||||
@ -690,10 +698,10 @@ index 22d2171..c7924cb 100644
|
||||
{ "[]=", tile },
|
||||
{ "><>", NULL }, /* no layout function means floating behavior */
|
||||
{ "[M]", monocle },
|
||||
@@ -127,6 +131,14 @@ static const Key keys[] = {
|
||||
/* modifier key function argument */
|
||||
{ MODKEY, XKB_KEY_p, spawn, {.v = menucmd} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} },
|
||||
@@ -148,6 +152,14 @@ static const Key keys[] = {
|
||||
{ MODKEY, XKB_KEY_period, focusmon, {.i = WLR_DIRECTION_RIGHT} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_less, tagmon, {.i = WLR_DIRECTION_LEFT} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_greater, tagmon, {.i = WLR_DIRECTION_RIGHT} },
|
||||
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Up, swapclients, {.i = DIR_UP} },
|
||||
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Down, swapclients, {.i = DIR_DOWN} },
|
||||
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Right, swapclients, {.i = DIR_RIGHT} },
|
||||
@ -702,11 +710,11 @@ index 22d2171..c7924cb 100644
|
||||
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_Left, setratio_h, {.f = -0.025f} },
|
||||
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_Up, setratio_v, {.f = -0.025f} },
|
||||
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_Down, setratio_v, {.f = +0.025f} },
|
||||
{ MODKEY, XKB_KEY_j, focusstack, {.i = +1} },
|
||||
{ MODKEY, XKB_KEY_k, focusstack, {.i = -1} },
|
||||
{ MODKEY, XKB_KEY_i, incnmaster, {.i = +1} },
|
||||
TAGKEYS( XKB_KEY_1, XKB_KEY_exclam, 0),
|
||||
TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1),
|
||||
TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2),
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index a2711f6..e9cb17b 100644
|
||||
index def2562..604a9a4 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -1,6 +1,7 @@
|
||||
@ -764,14 +772,14 @@ index a2711f6..e9cb17b 100644
|
||||
static void spawn(const Arg *arg);
|
||||
static void startdrag(struct wl_listener *listener, void *data);
|
||||
static void tag(const Arg *arg);
|
||||
@@ -432,6 +442,7 @@ static xcb_atom_t netatom[NetLast];
|
||||
@@ -431,6 +441,7 @@ static xcb_atom_t netatom[NetLast];
|
||||
|
||||
/* attempt to encapsulate suck into one file */
|
||||
#include "client.h"
|
||||
|
||||
+#include "btrtile.c"
|
||||
|
||||
/* function implementations */
|
||||
void
|
||||
applybounds(Client *c, struct wlr_box *bbox)
|
||||
@@ -600,10 +611,17 @@ buttonpress(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct wlr_pointer_button_event *event = data;
|
||||
@ -792,70 +800,58 @@ index a2711f6..e9cb17b 100644
|
||||
wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
|
||||
|
||||
switch (event->state) {
|
||||
@@ -631,18 +649,52 @@ buttonpress(struct wl_listener *listener, void *data)
|
||||
case WL_POINTER_BUTTON_STATE_RELEASED:
|
||||
@@ -632,15 +650,49 @@ buttonpress(struct wl_listener *listener, void *data)
|
||||
/* If you released any buttons, we exit interactive move/resize mode. */
|
||||
/* TODO should reset to the pointer focus's current setcursor */
|
||||
- if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) {
|
||||
- wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
|
||||
- cursor_mode = CurNormal;
|
||||
+ if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) {
|
||||
+ c = grabc;
|
||||
+ if (c && c->was_tiled && !strcmp(selmon->ltsymbol, "|w|")) {
|
||||
if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) {
|
||||
+ c = grabc;
|
||||
+ if (c && c->was_tiled && !strcmp(selmon->ltsymbol, "|w|")) {
|
||||
+ /* Check if more than one tag is active, if so we escape */
|
||||
+ if (active_tags && (active_tags & (active_tags - 1)))
|
||||
+ break;
|
||||
+ if (cursor_mode == CurMove && c->isfloating) {
|
||||
+ target = NULL;
|
||||
+ surface = NULL;
|
||||
+ xytonode(cursor->x, cursor->y, &surface, &target, NULL, &sx, &sy);
|
||||
+ if (cursor_mode == CurMove && c->isfloating) {
|
||||
+ target = NULL;
|
||||
+ surface = NULL;
|
||||
+ xytonode(cursor->x, cursor->y, &surface, &target, NULL, &sx, &sy);
|
||||
+
|
||||
+ if (target && !target->isfloating && !target->isfullscreen) {
|
||||
+ insert_client(selmon, target, c, root, tiled_clients);
|
||||
+ } else {
|
||||
+ if (!root) {
|
||||
+ *root = create_client_node(c);
|
||||
+ add_client_to_tiled_list(c, tiled_clients);
|
||||
+ } else {
|
||||
+ old_root = *root;
|
||||
+ *root = create_split_node(1, old_root, create_client_node(c));
|
||||
+ add_client_to_tiled_list(c, tiled_clients);
|
||||
+ }
|
||||
+ }
|
||||
+ if (target && !target->isfloating && !target->isfullscreen) {
|
||||
+ insert_client(selmon, target, c, root, tiled_clients);
|
||||
+ } else {
|
||||
+ if (!root) {
|
||||
+ *root = create_client_node(c);
|
||||
+ add_client_to_tiled_list(c, tiled_clients);
|
||||
+ } else {
|
||||
+ old_root = *root;
|
||||
+ *root = create_split_node(1, old_root, create_client_node(c));
|
||||
+ add_client_to_tiled_list(c, tiled_clients);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ setfloating(c, 0);
|
||||
+ arrange(selmon);
|
||||
+ setfloating(c, 0);
|
||||
+ arrange(selmon);
|
||||
+
|
||||
+ } else if (cursor_mode == CurResize && !c->isfloating) {
|
||||
+ resizing_from_mouse = 0;
|
||||
+ }
|
||||
+ } else {
|
||||
+ if (cursor_mode == CurResize && resizing_from_mouse)
|
||||
+ resizing_from_mouse = 0;
|
||||
+ }
|
||||
+ } else if (cursor_mode == CurResize && !c->isfloating) {
|
||||
+ resizing_from_mouse = 0;
|
||||
+ }
|
||||
+ } else {
|
||||
+ if (cursor_mode == CurResize && resizing_from_mouse)
|
||||
+ resizing_from_mouse = 0;
|
||||
+ }
|
||||
+ /* Default behaviour */
|
||||
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
|
||||
+ cursor_mode = CurNormal;
|
||||
wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
|
||||
cursor_mode = CurNormal;
|
||||
/* Drop the window off on its new monitor */
|
||||
- selmon = xytomon(cursor->x, cursor->y);
|
||||
- setmon(grabc, selmon, 0);
|
||||
- return;
|
||||
selmon = xytomon(cursor->x, cursor->y);
|
||||
setmon(grabc, selmon, 0);
|
||||
+ grabc = NULL;
|
||||
return;
|
||||
- } else {
|
||||
- cursor_mode = CurNormal;
|
||||
- }
|
||||
- break;
|
||||
- }
|
||||
+ selmon = xytomon(cursor->x, cursor->y);
|
||||
+ setmon(grabc, selmon, 0);
|
||||
+ grabc = NULL;
|
||||
+ return;
|
||||
+ }
|
||||
+ cursor_mode = CurNormal;
|
||||
+ break;
|
||||
+ }
|
||||
}
|
||||
+ cursor_mode = CurNormal;
|
||||
break;
|
||||
}
|
||||
/* If the event wasn't handled by the compositor, notify the client with
|
||||
* pointer focus that a button press has occurred */
|
||||
wlr_seat_pointer_notify_button(seat,
|
||||
@@ -720,6 +772,9 @@ cleanupmon(struct wl_listener *listener, void *data)
|
||||
wlr_output_layout_remove(output_layout, m->wlr_output);
|
||||
wlr_scene_output_destroy(m->scene_output);
|
||||
@ -866,15 +862,15 @@ index a2711f6..e9cb17b 100644
|
||||
closemon(m);
|
||||
wlr_scene_node_destroy(&m->fullscreen_bg->node);
|
||||
free(m);
|
||||
@@ -1025,6 +1080,7 @@ createmon(struct wl_listener *listener, void *data)
|
||||
@@ -1026,6 +1081,7 @@ createmon(struct wl_listener *listener, void *data)
|
||||
|
||||
wl_list_insert(&mons, &m->link);
|
||||
printstatus();
|
||||
|
||||
+ init_tree_layout(m);
|
||||
|
||||
/* The xdg-protocol specifies:
|
||||
*
|
||||
* If the fullscreened surface is not opaque, the compositor must make
|
||||
@@ -1263,6 +1319,15 @@ destroynotify(struct wl_listener *listener, void *data)
|
||||
@@ -1265,6 +1321,15 @@ destroynotify(struct wl_listener *listener, void *data)
|
||||
wl_list_remove(&c->destroy.link);
|
||||
wl_list_remove(&c->set_title.link);
|
||||
wl_list_remove(&c->fullscreen.link);
|
||||
@ -890,26 +886,25 @@ index a2711f6..e9cb17b 100644
|
||||
#ifdef XWAYLAND
|
||||
if (c->type != XDGShell) {
|
||||
wl_list_remove(&c->activate.link);
|
||||
@@ -1809,7 +1874,9 @@ void
|
||||
@@ -1811,7 +1876,8 @@ void
|
||||
motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double dy,
|
||||
double dx_unaccel, double dy_unaccel)
|
||||
{
|
||||
- double sx = 0, sy = 0, sx_confined, sy_confined;
|
||||
+ int tiled = 0;
|
||||
+ float factor;
|
||||
+ double sx = 0, sy = 0, sx_confined, sy_confined, dx_total, dy_total;
|
||||
Client *c = NULL, *w = NULL;
|
||||
LayerSurface *l = NULL;
|
||||
struct wlr_surface *surface = NULL;
|
||||
@@ -1863,18 +1930,60 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d
|
||||
@@ -1865,18 +1931,56 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d
|
||||
/* Update drag icon's position */
|
||||
wlr_scene_node_set_position(&drag_icon->node, (int)round(cursor->x), (int)round(cursor->y));
|
||||
|
||||
- /* If we are currently grabbing the mouse, handle and return */
|
||||
+ /* Skip if internal call or already resizing */
|
||||
+ if (time == 0 && resizing_from_mouse)
|
||||
+ goto focus;
|
||||
+
|
||||
/* If we are currently grabbing the mouse, handle and return */
|
||||
+ tiled = grabc && !grabc->isfloating && !grabc->isfullscreen;
|
||||
if (cursor_mode == CurMove) {
|
||||
/* Move the grabbed client to the new position. */
|
||||
@ -933,21 +928,18 @@ index a2711f6..e9cb17b 100644
|
||||
+ dx_total = cursor->x - resize_last_update_x;
|
||||
+ dy_total = cursor->y - resize_last_update_y;
|
||||
+
|
||||
+ if (fabs(dx_total) > resize_threshold || fabs(dy_total) > resize_threshold) {
|
||||
+ if (time - last_resize_time >= resize_interval_ms) {
|
||||
+ Arg a = {0};
|
||||
+ factor = 0.0002f;
|
||||
+ if (fabs(dx_total) > fabs(dy_total)) {
|
||||
+ a.f = (float)(dx_total * factor);
|
||||
+ a.f = (float)(dx_total * resize_factor);
|
||||
+ setratio_h(&a);
|
||||
+ } else {
|
||||
+ a.f = (float)(dy_total * factor);
|
||||
+ a.f = (float)(dy_total * resize_factor);
|
||||
+ setratio_v(&a);
|
||||
+ }
|
||||
+ /* Limit arrange rate to reduce recursion calls */
|
||||
+ if (++arrange_counter >= ARRANGE_RATE) {
|
||||
+ arrange(selmon);
|
||||
+ arrange_counter = 0;
|
||||
+ }
|
||||
+ arrange(selmon);
|
||||
+
|
||||
+ last_resize_time = time;
|
||||
+ resize_last_update_x = cursor->x;
|
||||
+ resize_last_update_y = cursor->y;
|
||||
+ }
|
||||
@ -968,7 +960,7 @@ index a2711f6..e9cb17b 100644
|
||||
/* If there's no client surface under the cursor, set the cursor image to a
|
||||
* default. This is what makes the cursor image appear when you move it
|
||||
* off of a client or over its border. */
|
||||
@@ -1908,23 +2017,44 @@ moveresize(const Arg *arg)
|
||||
@@ -1910,22 +2014,41 @@ moveresize(const Arg *arg)
|
||||
if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen)
|
||||
return;
|
||||
|
||||
@ -984,52 +976,46 @@ index a2711f6..e9cb17b 100644
|
||||
- /* Doesn't work for X11 output - the next absolute motion event
|
||||
- * returns the cursor to where it started */
|
||||
- wlr_cursor_warp_closest(cursor, NULL,
|
||||
- grabc->geom.x + grabc->geom.width,
|
||||
- grabc->geom.y + grabc->geom.height);
|
||||
+ cursor_mode = arg->ui;
|
||||
+ grabc->was_tiled = (!grabc->isfloating && !grabc->isfullscreen);
|
||||
+
|
||||
+ if (grabc->was_tiled) {
|
||||
+ switch (cursor_mode) {
|
||||
+ case CurMove:
|
||||
+ setfloating(grabc, 1);
|
||||
+ grabcx = (int)round(cursor->x) - grabc->geom.x;
|
||||
+ grabcy = (int)round(cursor->y) - grabc->geom.y;
|
||||
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "fleur");
|
||||
+ break;
|
||||
+ case CurResize:
|
||||
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize");
|
||||
+ resize_last_update_x = cursor->x;
|
||||
+ resize_last_update_y = cursor->y;
|
||||
+ resizing_from_mouse = 1;
|
||||
+ break;
|
||||
+ }
|
||||
+ } else {
|
||||
+ /* Default floating logic */
|
||||
+ /* Float the window and tell motionnotify to grab it */
|
||||
+ setfloating(grabc, 1);
|
||||
+ switch (cursor_mode) {
|
||||
+ case CurMove:
|
||||
+ grabcx = (int)round(cursor->x) - grabc->geom.x;
|
||||
+ grabcy = (int)round(cursor->y) - grabc->geom.y;
|
||||
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "fleur");
|
||||
+ break;
|
||||
+ case CurResize:
|
||||
+ wlr_cursor_warp_closest(cursor, NULL,
|
||||
grabc->geom.x + grabc->geom.width,
|
||||
grabc->geom.y + grabc->geom.height);
|
||||
- wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize");
|
||||
- break;
|
||||
- }
|
||||
+ cursor_mode = arg->ui;
|
||||
+ grabc->was_tiled = (!grabc->isfloating && !grabc->isfullscreen);
|
||||
+
|
||||
+ if (grabc->was_tiled) {
|
||||
+ switch (cursor_mode) {
|
||||
+ case CurMove:
|
||||
+ setfloating(grabc, 1);
|
||||
+ grabcx = (int)round(cursor->x) - grabc->geom.x;
|
||||
+ grabcy = (int)round(cursor->y) - grabc->geom.y;
|
||||
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "fleur");
|
||||
+ break;
|
||||
+ case CurResize:
|
||||
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize");
|
||||
+ resize_init_x = cursor->x;
|
||||
+ resize_init_y = cursor->y;
|
||||
+ resize_last_update_x = resize_init_x;
|
||||
+ resize_last_update_y = resize_init_y;
|
||||
+ resizing_from_mouse = 1;
|
||||
+ break;
|
||||
+ }
|
||||
+ } else {
|
||||
+ /* Default floating logic */
|
||||
+ /* Float the window and tell motionnotify to grab it */
|
||||
+ setfloating(grabc, 1);
|
||||
+ switch (cursor_mode) {
|
||||
+ case CurMove:
|
||||
+ grabcx = (int)round(cursor->x) - grabc->geom.x;
|
||||
+ grabcy = (int)round(cursor->y) - grabc->geom.y;
|
||||
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "fleur");
|
||||
+ break;
|
||||
+ case CurResize:
|
||||
+ wlr_cursor_warp_closest(cursor, NULL,
|
||||
+ grabc->geom.x + grabc->geom.width,
|
||||
+ grabc->geom.y + grabc->geom.height);
|
||||
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize");
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize");
|
||||
+ break;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
--
|
||||
2.45.2
|
||||
|
||||
|
||||
BIN
patches/btrtile/demos/btrtiledemo.gif
Normal file
BIN
patches/btrtile/demos/btrtiledemo.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 MiB |
Loading…
x
Reference in New Issue
Block a user