mirror of
https://codeberg.org/dwl/dwl-patches.git
synced 2026-09-20 06:12:54 +00:00
Compare commits
5
Commits
005596c2e8
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
77bc50859c | ||
|
|
d5bbf841c2 | ||
|
|
0d41b75737 | ||
|
|
161586e355 | ||
|
|
f93e314dc5 |
+28
-49
@@ -1,6 +1,6 @@
|
|||||||
### Description
|
### Description
|
||||||
|
|
||||||
# btrtile — A Focus-Driven Tiling Layout
|
# 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.
|
It provides a focus-driven, mouse- and keyboard-friendly tiling layout that grants you granular control over how clients are placed and resized.
|
||||||
|
|
||||||
@@ -14,38 +14,34 @@ While dwl’s patches folder is full of different layouts, I couldn't find suita
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# Features
|
# How it works
|
||||||
|
|
||||||
- **Combined Tiling and Management**
|
Clients live in a binary tree, every split has a ratio (50/50 by default).
|
||||||
Combines tiling layout and management of clients under one patchset.
|
|
||||||
|
|
||||||
- **Focus-Driven Splits**
|
When a new client opens, it splits the client you last focused. The pointer decides which side it lands on: left half of the client puts it on the left, and so on. If the area is wider than it is tall the split is vertical, otherwise horizontal. When several clients open at once, each one splits the previous one, so you get a nice spiral instead of a pile in one corner.
|
||||||
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**
|
- **Mouse**
|
||||||
- If the area to be split is wider than its height, btrtile does a vertical split.
|
Drag a tiled client with `MODKEY` + left button to float it, drop it on another tiled client to place it next to it.
|
||||||
- Otherwise, it does a horizontal split.
|
`MODKEY` + right button resizes the divider next to the client you grabbed, it follows the pointer 1:1.
|
||||||
|
- **Keyboard**
|
||||||
|
`setratio_h` / `setratio_v` move a divider, `swapclients` swaps a client with its neighbour in a direction,
|
||||||
|
`togglesplit` flips the direction of the split you're in (and keeps it that way),
|
||||||
|
`swapsplit` mirrors the split.
|
||||||
|
|
||||||
- **Keyboard and Mouse Driven**
|
**config.h:**
|
||||||
- Supports keyboard-based commands for quick ratio adjustments and client swapping.
|
```c
|
||||||
- Mouse-based resizing and moving are integrated for more intuitive manipulation.
|
use_active_for_splits = 1; /* 1: split the last focused client, 0: the one under the pointer */
|
||||||
|
force_split = 0; /* 0: new client on the pointer's side, 1: always left/top, 2: always right/bottom */
|
||||||
|
preserve_split = 0; /* 1: splits keep their direction, 0: direction follows the shape of the area */
|
||||||
|
split_width_multiplier = 1.0f; /* split side by side when width >= height * this */
|
||||||
|
resize_interval_ms = 16; /* limits mouse resize updates, 16ms is ~60 per second */
|
||||||
|
```
|
||||||
|
|
||||||
---
|
`force_split = 2` gives you a predictable spiral if you don't want the pointer to matter.
|
||||||
|
`split_width_multiplier` is handy on wide monitors, where windows tend to stay wider than tall for a long time.
|
||||||
|
|
||||||
# How It Works
|
Smoother mouse resizing costs some cpu, so tune `resize_interval_ms` to your refresh rate.
|
||||||
|
If resizing feels sluggish, try compiling dwl with -O2/-O3.
|
||||||
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.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -56,23 +52,6 @@ When a new client appears:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# 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 sensitivity.
|
|
||||||
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
|
# Patch recommendations
|
||||||
|
|
||||||
1. **Patches that I use with my btrtile**
|
1. **Patches that I use with my btrtile**
|
||||||
@@ -95,11 +74,11 @@ If mouse resizing feels sluggish, you can try compiling dwl with more aggressive
|
|||||||
---
|
---
|
||||||
|
|
||||||
### Download
|
### Download
|
||||||
- [git branch](https://codeberg.org/julmajustus/dwl/src/branch/btrtile-dev)
|
- [git branch](https://codeberg.org/julmajustus/dwl/src/branch/btrtile-0.9)
|
||||||
- [0.8](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/btrtile/btrtile-v0.8.patch)
|
- [0.8](./btrtile-v0.8.patch)
|
||||||
- [0.8 WITH gaps](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/btrtile/btrtile-v0.8-gaps.patch)
|
- [0.8 WITH gaps](./btrtile-v0.8-gaps.patch)
|
||||||
- [wlroots-next](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/btrtile/btrtile-wlroots-next-d41ecb7.patch)
|
- [main-d16036e](./btrtile-d16036e.patch)
|
||||||
- [wlroots-next WITH gaps](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/btrtile/btrtile-wlroots-next-d41ecb7-gaps.patch)
|
- [main-d16036e WITH gaps](./btrtile-gaps-d16036e.patch)
|
||||||
|
|
||||||
### Authors
|
### Authors
|
||||||
- [julmajustus](https://codeberg.org/julmajustus)
|
- [julmajustus](https://codeberg.org/julmajustus)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,922 +0,0 @@
|
|||||||
From efb796ce92e7212aa392141705c7322fedc45dba Mon Sep 17 00:00:00 2001
|
|
||||||
From: julmajustus <julmajustus@tutanota.com>
|
|
||||||
Date: Mon, 22 Jun 2026 22:46:19 +0300
|
|
||||||
Subject: [PATCH] btrtile: bug fixes and readability improvement
|
|
||||||
|
|
||||||
- Removed client old_geom caching for simplicity fixes: https://codeberg.org/dwl/dwl-patches/issues/647
|
|
||||||
- Improved readability of the client sanitization loop inside btrtile function
|
|
||||||
- Removed fullscreened client's from the sanitization loop to retain simple_scratchpad: Spring update scratchpad V2
|
|
||||||
|
|
||||||
- Added support for multiple scratchpads their geometry
|
|
||||||
---
|
|
||||||
btrtile.c | 575 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
||||||
config.def.h | 12 ++
|
|
||||||
dwl.c | 151 +++++++++++---
|
|
||||||
3 files changed, 711 insertions(+), 27 deletions(-)
|
|
||||||
create mode 100644 btrtile.c
|
|
||||||
|
|
||||||
diff --git a/btrtile.c b/btrtile.c
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000..645b741
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/btrtile.c
|
|
||||||
@@ -0,0 +1,575 @@
|
|
||||||
+/* ************************************************************************** */
|
|
||||||
+/* @@@ @@@@@@@@ */
|
|
||||||
+/* @@@ @@@@@@@@@@ */
|
|
||||||
+/* @@! @@! @@@@ */
|
|
||||||
+/* !@! !@! @!@!@ */
|
|
||||||
+/* btrtile.c @!! @!@ @! !@! */
|
|
||||||
+/* !!! !@!!! !!! */
|
|
||||||
+/* By: julmajustus <julmajustus@tutanota.com> !!: !!:! !!! */
|
|
||||||
+/* ::! :!: !:! */
|
|
||||||
+/* Created: 2024/12/15 00:26:07 by julmajustus :: ::::::: :: */
|
|
||||||
+/* Updated: 2026/06/22 22:34:11 by julmajustus : : : : : : */
|
|
||||||
+/* */
|
|
||||||
+/* ************************************************************************** */
|
|
||||||
+
|
|
||||||
+typedef struct LayoutNode {
|
|
||||||
+ unsigned int is_client_node;
|
|
||||||
+ unsigned int is_split_vertically;
|
|
||||||
+ float split_ratio;
|
|
||||||
+ struct LayoutNode *left;
|
|
||||||
+ struct LayoutNode *right;
|
|
||||||
+ struct LayoutNode *split_node;
|
|
||||||
+ Client *client;
|
|
||||||
+} LayoutNode;
|
|
||||||
+
|
|
||||||
+static void apply_layout(Monitor *m, LayoutNode *node,
|
|
||||||
+ 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 is_split_vertically,
|
|
||||||
+ LayoutNode *left, LayoutNode *right);
|
|
||||||
+static void destroy_node(LayoutNode *node);
|
|
||||||
+static void destroy_tree(Monitor *m);
|
|
||||||
+static LayoutNode *find_client_node(LayoutNode *node, Client *c);
|
|
||||||
+static LayoutNode *find_suitable_split(Monitor *m, LayoutNode *start,
|
|
||||||
+ unsigned int need_vertical, int focused_on_left);
|
|
||||||
+static void init_tree(Monitor *m);
|
|
||||||
+static void insert_client(Monitor *m, Client *focused_client, Client *new_client);
|
|
||||||
+static LayoutNode *remove_client_node(LayoutNode *node, Client *c);
|
|
||||||
+static void remove_client(Monitor *m, Client *c);
|
|
||||||
+static void setratio_h(const Arg *arg);
|
|
||||||
+static void setratio_v(const Arg *arg);
|
|
||||||
+static void swapclients(const Arg *arg);
|
|
||||||
+static unsigned int visible_count(LayoutNode *node, Monitor *m);
|
|
||||||
+static Client *xytoclient(double x, double y);
|
|
||||||
+
|
|
||||||
+static double resize_last_update_x, resize_last_update_y;
|
|
||||||
+static uint32_t last_resize_time = 0;
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+apply_layout(Monitor *m, LayoutNode *node,
|
|
||||||
+ struct wlr_box area, unsigned int is_root)
|
|
||||||
+{
|
|
||||||
+ Client *c;
|
|
||||||
+ float ratio;
|
|
||||||
+ unsigned int left_count, right_count, mid, e = m->gaps;
|
|
||||||
+ struct wlr_box left_area, right_area;
|
|
||||||
+
|
|
||||||
+ if (!node)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ if (is_root && e) {
|
|
||||||
+ area.x += gappx;
|
|
||||||
+ area.y += gappx;
|
|
||||||
+ area.width -= 2 * gappx;
|
|
||||||
+ area.height -= 2 * gappx;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* If this node is a client node, check if it is visible. */
|
|
||||||
+ if (node->is_client_node) {
|
|
||||||
+ c = node->client;
|
|
||||||
+ if (!c || !VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
|
|
||||||
+ return;
|
|
||||||
+ resize(c, area, 0);
|
|
||||||
+ return;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* For a split node, we see how many visible children are on each side: */
|
|
||||||
+ left_count = visible_count(node->left, m);
|
|
||||||
+ right_count = visible_count(node->right, m);
|
|
||||||
+
|
|
||||||
+ if (left_count == 0 && right_count == 0) {
|
|
||||||
+ return;
|
|
||||||
+ } else if (left_count > 0 && right_count == 0) {
|
|
||||||
+ apply_layout(m, node->left, area, 0);
|
|
||||||
+ return;
|
|
||||||
+ } else if (left_count == 0 && right_count > 0) {
|
|
||||||
+ apply_layout(m, node->right, area, 0);
|
|
||||||
+ return;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* If we’re here, we have visible clients in both subtrees. */
|
|
||||||
+ ratio = node->split_ratio;
|
|
||||||
+ if (ratio < 0.05f)
|
|
||||||
+ ratio = 0.05f;
|
|
||||||
+ if (ratio > 0.95f)
|
|
||||||
+ ratio = 0.95f;
|
|
||||||
+
|
|
||||||
+ memset(&left_area, 0, sizeof(left_area));
|
|
||||||
+ memset(&right_area, 0, sizeof(right_area));
|
|
||||||
+
|
|
||||||
+ if (node->is_split_vertically) {
|
|
||||||
+ mid = (unsigned int)(area.width * ratio);
|
|
||||||
+ left_area.x = area.x;
|
|
||||||
+ left_area.y = area.y;
|
|
||||||
+ left_area.width = mid;
|
|
||||||
+ left_area.height = area.height;
|
|
||||||
+
|
|
||||||
+ right_area.x = area.x + mid;
|
|
||||||
+ right_area.y = area.y;
|
|
||||||
+ right_area.width = area.width - mid;
|
|
||||||
+ right_area.height = area.height;
|
|
||||||
+
|
|
||||||
+ if (e) {
|
|
||||||
+ left_area.width -= gappx / 2;
|
|
||||||
+ right_area.x += gappx / 2;
|
|
||||||
+ right_area.width -= gappx / 2;
|
|
||||||
+ }
|
|
||||||
+ } else {
|
|
||||||
+ /* horizontal split */
|
|
||||||
+ mid = (unsigned int)(area.height * ratio);
|
|
||||||
+ left_area.x = area.x;
|
|
||||||
+ left_area.y = area.y;
|
|
||||||
+ left_area.width = area.width;
|
|
||||||
+ left_area.height = mid;
|
|
||||||
+
|
|
||||||
+ right_area.x = area.x;
|
|
||||||
+ right_area.y = area.y + mid;
|
|
||||||
+ right_area.width = area.width;
|
|
||||||
+ right_area.height= area.height - mid;
|
|
||||||
+
|
|
||||||
+ if (e) {
|
|
||||||
+ left_area.height -= gappx / 2;
|
|
||||||
+ right_area.y += gappx / 2;
|
|
||||||
+ right_area.height -= gappx / 2;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ apply_layout(m, node->left, left_area, 0);
|
|
||||||
+ apply_layout(m, node->right, right_area, 0);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+btrtile(Monitor *m)
|
|
||||||
+{
|
|
||||||
+ Client *c, *focused = NULL;
|
|
||||||
+ int n = 0;
|
|
||||||
+ LayoutNode *found;
|
|
||||||
+ struct wlr_box full_area;
|
|
||||||
+
|
|
||||||
+ if (!m)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ /* Remove floating and moved clients */
|
|
||||||
+ wl_list_for_each(c, &clients, link) {
|
|
||||||
+ if (c->mon != m || c->isfloating)
|
|
||||||
+ remove_client(m, c);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* If no client is found under cursor, fallback to focustop(m) */
|
|
||||||
+ if (!(focused = xytoclient(cursor->x, cursor->y)))
|
|
||||||
+ focused = focustop(m);
|
|
||||||
+
|
|
||||||
+ /* Insert visible clients that are not part of the tree. */
|
|
||||||
+ wl_list_for_each(c, &clients, link) {
|
|
||||||
+ if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen && c->mon == m) {
|
|
||||||
+ found = find_client_node(m->root, c);
|
|
||||||
+ if (!found) {
|
|
||||||
+ insert_client(m, focused, c);
|
|
||||||
+ }
|
|
||||||
+ n++;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (n == 0)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ full_area = m->w;
|
|
||||||
+ apply_layout(m, m->root, full_area, 1);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+LayoutNode *
|
|
||||||
+create_client_node(Client *c)
|
|
||||||
+{
|
|
||||||
+ LayoutNode *node = calloc(1, sizeof(LayoutNode));
|
|
||||||
+
|
|
||||||
+ if (!node)
|
|
||||||
+ return NULL;
|
|
||||||
+ node->is_client_node = 1;
|
|
||||||
+ node->split_ratio = 0.5f;
|
|
||||||
+ node->client = c;
|
|
||||||
+ return node;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+LayoutNode *
|
|
||||||
+create_split_node(unsigned int is_split_vertically,
|
|
||||||
+ LayoutNode *left, LayoutNode *right)
|
|
||||||
+{
|
|
||||||
+ LayoutNode *node = calloc(1, sizeof(LayoutNode));
|
|
||||||
+
|
|
||||||
+ if (!node)
|
|
||||||
+ return NULL;
|
|
||||||
+ node->is_client_node = 0;
|
|
||||||
+ node->split_ratio = 0.5f;
|
|
||||||
+ node->is_split_vertically = is_split_vertically;
|
|
||||||
+ node->left = left;
|
|
||||||
+ node->right = right;
|
|
||||||
+ if (left)
|
|
||||||
+ left->split_node = node;
|
|
||||||
+ if (right)
|
|
||||||
+ right->split_node = node;
|
|
||||||
+ return node;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+destroy_node(LayoutNode *node)
|
|
||||||
+{
|
|
||||||
+ if (!node)
|
|
||||||
+ return;
|
|
||||||
+ if (!node->is_client_node) {
|
|
||||||
+ destroy_node(node->left);
|
|
||||||
+ destroy_node(node->right);
|
|
||||||
+ }
|
|
||||||
+ free(node);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+destroy_tree(Monitor *m)
|
|
||||||
+{
|
|
||||||
+ if (!m || !m->root)
|
|
||||||
+ return;
|
|
||||||
+ destroy_node(m->root);
|
|
||||||
+ m->root = NULL;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+LayoutNode *
|
|
||||||
+find_client_node(LayoutNode *node, Client *c)
|
|
||||||
+{
|
|
||||||
+ LayoutNode *res;
|
|
||||||
+
|
|
||||||
+ if (!node || !c)
|
|
||||||
+ return NULL;
|
|
||||||
+ if (node->is_client_node) {
|
|
||||||
+ return (node->client == c) ? node : NULL;
|
|
||||||
+ }
|
|
||||||
+ res = find_client_node(node->left, c);
|
|
||||||
+ return res ? res : find_client_node(node->right, c);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+LayoutNode *
|
|
||||||
+find_suitable_split(Monitor *m, LayoutNode *start_node,
|
|
||||||
+ unsigned int need_vertical, int focused_on_left)
|
|
||||||
+{
|
|
||||||
+ LayoutNode *n = start_node, *child = NULL;
|
|
||||||
+
|
|
||||||
+ if (!m)
|
|
||||||
+ return NULL;
|
|
||||||
+
|
|
||||||
+ if (n && n->is_client_node) {
|
|
||||||
+ child = n;
|
|
||||||
+ n = n->split_node;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ while (n) {
|
|
||||||
+ if (!n->is_client_node && n->is_split_vertically == need_vertical
|
|
||||||
+ && visible_count(n->left, m) > 0
|
|
||||||
+ && visible_count(n->right, m) > 0) {
|
|
||||||
+ if ((focused_on_left && n->left == child) ||
|
|
||||||
+ (!focused_on_left && n->right == child))
|
|
||||||
+ return n;
|
|
||||||
+ }
|
|
||||||
+ child = n;
|
|
||||||
+ n = n->split_node;
|
|
||||||
+ }
|
|
||||||
+ return NULL;
|
|
||||||
+}
|
|
||||||
+void
|
|
||||||
+init_tree(Monitor *m)
|
|
||||||
+{
|
|
||||||
+ if (m)
|
|
||||||
+ m->root = NULL;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+insert_client(Monitor *m, Client *focused_client, Client *new_client)
|
|
||||||
+{
|
|
||||||
+ Client *old_client;
|
|
||||||
+ LayoutNode **root = &m->root, *old_root,
|
|
||||||
+ *focused_node, *new_client_node, *old_client_node;
|
|
||||||
+ unsigned int wider, mid_x, mid_y;
|
|
||||||
+
|
|
||||||
+ /* If no root , new client becomes the root. */
|
|
||||||
+ if (!*root) {
|
|
||||||
+ *root = create_client_node(new_client);
|
|
||||||
+ return;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* Find the focused_client node,
|
|
||||||
+ * if not found split the root. */
|
|
||||||
+ focused_node = focused_client ?
|
|
||||||
+ find_client_node(*root, focused_client) : NULL;
|
|
||||||
+ if (!focused_node) {
|
|
||||||
+ old_root = *root;
|
|
||||||
+ new_client_node = create_client_node(new_client);
|
|
||||||
+ *root = create_split_node(1, old_root, new_client_node);
|
|
||||||
+ return;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* Turn focused node from a client node into a split node,
|
|
||||||
+ * and attach old_client + new_client. */
|
|
||||||
+ old_client = focused_node->client;
|
|
||||||
+ old_client_node = create_client_node(old_client);
|
|
||||||
+ new_client_node = create_client_node(new_client);
|
|
||||||
+
|
|
||||||
+ /* Decide split direction. */
|
|
||||||
+ wider = (focused_client->geom.width >= focused_client->geom.height);
|
|
||||||
+ focused_node->is_client_node = 0;
|
|
||||||
+ focused_node->client = NULL;
|
|
||||||
+ focused_node->is_split_vertically = (wider ? 1 : 0);
|
|
||||||
+
|
|
||||||
+ /* Pick new_client side depending on the cursor position. */
|
|
||||||
+ mid_x = focused_client->geom.x + focused_client->geom.width / 2;
|
|
||||||
+ mid_y = focused_client->geom.y + focused_client->geom.height / 2;
|
|
||||||
+
|
|
||||||
+ if (wider) {
|
|
||||||
+ /* vertical split => left vs right */
|
|
||||||
+ if (cursor->x <= mid_x) {
|
|
||||||
+ focused_node->left = new_client_node;
|
|
||||||
+ focused_node->right = old_client_node;
|
|
||||||
+ } else {
|
|
||||||
+ focused_node->left = old_client_node;
|
|
||||||
+ focused_node->right = new_client_node;
|
|
||||||
+ }
|
|
||||||
+ } else {
|
|
||||||
+ /* horizontal split => top vs bottom */
|
|
||||||
+ if (cursor->y <= mid_y) {
|
|
||||||
+ focused_node->left = new_client_node;
|
|
||||||
+ focused_node->right = old_client_node;
|
|
||||||
+ } else {
|
|
||||||
+ focused_node->left = old_client_node;
|
|
||||||
+ focused_node->right = new_client_node;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ old_client_node->split_node = focused_node;
|
|
||||||
+ new_client_node->split_node = focused_node;
|
|
||||||
+ focused_node->split_ratio = 0.5f;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+LayoutNode *
|
|
||||||
+remove_client_node(LayoutNode *node, Client *c)
|
|
||||||
+{
|
|
||||||
+ LayoutNode *tmp;
|
|
||||||
+ if (!node)
|
|
||||||
+ return NULL;
|
|
||||||
+ if (node->is_client_node) {
|
|
||||||
+ /* If this client_node is the client we're removing,
|
|
||||||
+ * return NULL to remove it */
|
|
||||||
+ if (node->client == c) {
|
|
||||||
+ free(node);
|
|
||||||
+ return NULL;
|
|
||||||
+ }
|
|
||||||
+ return node;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ node->left = remove_client_node(node->left, c);
|
|
||||||
+ node->right = remove_client_node(node->right, c);
|
|
||||||
+
|
|
||||||
+ /* 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;
|
|
||||||
+
|
|
||||||
+ /* Save pointer to split node */
|
|
||||||
+ if (tmp)
|
|
||||||
+ tmp->split_node = node->split_node;
|
|
||||||
+
|
|
||||||
+ free(node);
|
|
||||||
+ return tmp;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (!node->right && node->left) {
|
|
||||||
+ tmp = node->left;
|
|
||||||
+
|
|
||||||
+ /* Save pointer to split node */
|
|
||||||
+ if (tmp)
|
|
||||||
+ tmp->split_node = node->split_node;
|
|
||||||
+
|
|
||||||
+ free(node);
|
|
||||||
+ return tmp;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* If both children exist or both are NULL (empty tree),
|
|
||||||
+ * return node as is. */
|
|
||||||
+ return node;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+remove_client(Monitor *m, Client *c)
|
|
||||||
+{
|
|
||||||
+ if (!m->root || !c)
|
|
||||||
+ return;
|
|
||||||
+ m->root = remove_client_node(m->root, c);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+setratio(unsigned int need_vertical, const Arg *arg)
|
|
||||||
+{
|
|
||||||
+ Client *sel;
|
|
||||||
+ LayoutNode *client_node, *split_node;
|
|
||||||
+ float new_ratio;
|
|
||||||
+ int focused_on_left;
|
|
||||||
+
|
|
||||||
+ if (!selmon || !selmon->lt[selmon->sellt]->arrange)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ sel = focustop(selmon);
|
|
||||||
+ if (!sel)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ client_node = find_client_node(selmon->root, sel);
|
|
||||||
+ if (!client_node)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ focused_on_left = (arg->f >= 0.0f);
|
|
||||||
+
|
|
||||||
+ split_node = find_suitable_split(selmon, client_node, need_vertical, focused_on_left);
|
|
||||||
+
|
|
||||||
+ if (!split_node)
|
|
||||||
+ split_node = find_suitable_split(selmon, client_node, need_vertical, !focused_on_left);
|
|
||||||
+ if (!split_node)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ new_ratio = (arg->f != 0.0f) ? (split_node->split_ratio + arg->f) : 0.5f;
|
|
||||||
+ if (new_ratio < 0.05f)
|
|
||||||
+ new_ratio = 0.05f;
|
|
||||||
+ if (new_ratio > 0.95f)
|
|
||||||
+ new_ratio = 0.95f;
|
|
||||||
+ split_node->split_ratio = new_ratio;
|
|
||||||
+
|
|
||||||
+ apply_layout(selmon, selmon->root, selmon->w, 1);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+setratio_h(const Arg *arg)
|
|
||||||
+{
|
|
||||||
+ setratio(1, arg);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+setratio_v(const Arg *arg)
|
|
||||||
+{
|
|
||||||
+ setratio(0, arg);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void swapclients(const Arg *arg) {
|
|
||||||
+ Client *c, *tmp, *target = NULL, *sel = focustop(selmon);
|
|
||||||
+ LayoutNode *sel_node, *target_node;
|
|
||||||
+ int closest_dist = INT_MAX, dist, sel_center_x, sel_center_y,
|
|
||||||
+ cand_center_x, cand_center_y;
|
|
||||||
+
|
|
||||||
+ if (!sel || sel->isfullscreen ||
|
|
||||||
+ !selmon->root || !selmon->lt[selmon->sellt]->arrange)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+ /* Get the center coordinates of the selected client */
|
|
||||||
+ sel_center_x = sel->geom.x + sel->geom.width / 2;
|
|
||||||
+ sel_center_y = sel->geom.y + sel->geom.height / 2;
|
|
||||||
+
|
|
||||||
+ wl_list_for_each(c, &clients, link) {
|
|
||||||
+ if (!VISIBLEON(c, selmon) || c->isfloating || c->isfullscreen || c == sel)
|
|
||||||
+ continue;
|
|
||||||
+
|
|
||||||
+ /* Get the center of candidate client */
|
|
||||||
+ cand_center_x = c->geom.x + c->geom.width / 2;
|
|
||||||
+ cand_center_y = c->geom.y + c->geom.height / 2;
|
|
||||||
+
|
|
||||||
+ /* Check that the candidate lies in the requested direction. */
|
|
||||||
+ switch (arg->ui) {
|
|
||||||
+ case 0:
|
|
||||||
+ if (cand_center_x >= sel_center_x)
|
|
||||||
+ continue;
|
|
||||||
+ break;
|
|
||||||
+ case 1:
|
|
||||||
+ if (cand_center_x <= sel_center_x)
|
|
||||||
+ continue;
|
|
||||||
+ break;
|
|
||||||
+ case 2:
|
|
||||||
+ if (cand_center_y >= sel_center_y)
|
|
||||||
+ continue;
|
|
||||||
+ break;
|
|
||||||
+ case 3:
|
|
||||||
+ if (cand_center_y <= sel_center_y)
|
|
||||||
+ continue;
|
|
||||||
+ break;
|
|
||||||
+ default:
|
|
||||||
+ continue;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* Get distance between the centers */
|
|
||||||
+ dist = abs(sel_center_x - cand_center_x) + abs(sel_center_y - cand_center_y);
|
|
||||||
+ if (dist < closest_dist) {
|
|
||||||
+ closest_dist = dist;
|
|
||||||
+ target = c;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* If target is found, swap the two clients’ positions in the layout tree */
|
|
||||||
+ if (target) {
|
|
||||||
+ sel_node = find_client_node(selmon->root, sel);
|
|
||||||
+ target_node = find_client_node(selmon->root, target);
|
|
||||||
+ if (sel_node && target_node) {
|
|
||||||
+ tmp = sel_node->client;
|
|
||||||
+ sel_node->client = target_node->client;
|
|
||||||
+ target_node->client = tmp;
|
|
||||||
+ arrange(selmon);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+unsigned int
|
|
||||||
+visible_count(LayoutNode *node, Monitor *m)
|
|
||||||
+{
|
|
||||||
+ Client *c;
|
|
||||||
+
|
|
||||||
+ if (!node)
|
|
||||||
+ return 0;
|
|
||||||
+ /* Check if this client is visible. */
|
|
||||||
+ if (node->is_client_node) {
|
|
||||||
+ c = node->client;
|
|
||||||
+ if (c && VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen)
|
|
||||||
+ return 1;
|
|
||||||
+ return 0;
|
|
||||||
+ }
|
|
||||||
+ /* Else it’s a split node. */
|
|
||||||
+ return visible_count(node->left, m) + visible_count(node->right, m);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+Client *
|
|
||||||
+xytoclient(double x, double y) {
|
|
||||||
+ Monitor *m = xytomon(x, y);
|
|
||||||
+ Client *c, *closest = NULL;
|
|
||||||
+ double dist, mindist = INT_MAX, dx, dy;
|
|
||||||
+
|
|
||||||
+ wl_list_for_each_reverse(c, &clients, link) {
|
|
||||||
+ if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen &&
|
|
||||||
+ x >= c->geom.x && x <= (c->geom.x + c->geom.width) &&
|
|
||||||
+ y >= c->geom.y && y <= (c->geom.y + c->geom.height)){
|
|
||||||
+ return c;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* If no client was found at cursor position fallback to closest. */
|
|
||||||
+ wl_list_for_each_reverse(c, &clients, link) {
|
|
||||||
+ if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen) {
|
|
||||||
+ dx = 0, dy = 0;
|
|
||||||
+
|
|
||||||
+ if (x < c->geom.x)
|
|
||||||
+ dx = c->geom.x - x;
|
|
||||||
+ else if (x > (c->geom.x + c->geom.width))
|
|
||||||
+ dx = x - (c->geom.x + c->geom.width);
|
|
||||||
+
|
|
||||||
+ if (y < c->geom.y)
|
|
||||||
+ dy = c->geom.y - y;
|
|
||||||
+ else if (y > (c->geom.y + c->geom.height))
|
|
||||||
+ dy = y - (c->geom.y + c->geom.height);
|
|
||||||
+
|
|
||||||
+ dist = dx * dx + dy * dy;
|
|
||||||
+ if (dist < mindist) {
|
|
||||||
+ mindist = dist;
|
|
||||||
+ closest = c;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ return closest;
|
|
||||||
+}
|
|
||||||
diff --git a/config.def.h b/config.def.h
|
|
||||||
index 8a6eda0..bc04e3f 100644
|
|
||||||
--- a/config.def.h
|
|
||||||
+++ b/config.def.h
|
|
||||||
@@ -13,7 +13,10 @@ static const float focuscolor[] = COLOR(0x005577ff);
|
|
||||||
static const float urgentcolor[] = COLOR(0xff0000ff);
|
|
||||||
/* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */
|
|
||||||
static const float fullscreen_bg[] = {0.0f, 0.0f, 0.0f, 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 */
|
|
||||||
#define TAGCOUNT (9)
|
|
||||||
|
|
||||||
@@ -30,6 +33,7 @@ static const Rule rules[] = {
|
|
||||||
/* layout(s) */
|
|
||||||
static const Layout layouts[] = {
|
|
||||||
/* symbol arrange function */
|
|
||||||
+ { "|w|", btrtile },
|
|
||||||
{ "[]=", tile },
|
|
||||||
{ "><>", NULL }, /* no layout function means floating behavior */
|
|
||||||
{ "[M]", monocle },
|
|
||||||
@@ -144,6 +148,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} },
|
|
||||||
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Left, swapclients, {.i = DIR_LEFT} },
|
|
||||||
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_Right, setratio_h, {.f = +0.025f} },
|
|
||||||
+ { 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} },
|
|
||||||
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 8101ffa..7abf390 100644
|
|
||||||
--- a/dwl.c
|
|
||||||
+++ b/dwl.c
|
|
||||||
@@ -1,6 +1,7 @@
|
|
||||||
/*
|
|
||||||
* See LICENSE file for copyright and license details.
|
|
||||||
*/
|
|
||||||
+#include <limits.h>
|
|
||||||
#include <getopt.h>
|
|
||||||
#include <libinput.h>
|
|
||||||
#include <linux/input-event-codes.h>
|
|
||||||
@@ -104,6 +105,7 @@ typedef struct {
|
|
||||||
const Arg arg;
|
|
||||||
} Button;
|
|
||||||
|
|
||||||
+typedef struct LayoutNode LayoutNode;
|
|
||||||
typedef struct Monitor Monitor;
|
|
||||||
typedef struct {
|
|
||||||
/* Must keep this field first */
|
|
||||||
@@ -141,7 +143,7 @@ typedef struct {
|
|
||||||
#endif
|
|
||||||
unsigned int bw;
|
|
||||||
uint32_t tags;
|
|
||||||
- int isfloating, isurgent, isfullscreen;
|
|
||||||
+ int isfloating, isurgent, isfullscreen, was_tiled;
|
|
||||||
uint32_t resize; /* configure serial of a pending resize */
|
|
||||||
} Client;
|
|
||||||
|
|
||||||
@@ -209,6 +211,7 @@ struct Monitor {
|
|
||||||
int nmaster;
|
|
||||||
char ltsymbol[16];
|
|
||||||
int asleep;
|
|
||||||
+ LayoutNode *root;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
@@ -251,6 +254,7 @@ static void arrangelayer(Monitor *m, struct wl_list *list,
|
|
||||||
struct wlr_box *usable_area, int exclusive);
|
|
||||||
static void arrangelayers(Monitor *m);
|
|
||||||
static void axisnotify(struct wl_listener *listener, void *data);
|
|
||||||
+static void btrtile(Monitor *m);
|
|
||||||
static void buttonpress(struct wl_listener *listener, void *data);
|
|
||||||
static void chvt(const Arg *arg);
|
|
||||||
static void checkidleinhibitor(struct wlr_surface *exclude);
|
|
||||||
@@ -333,6 +337,9 @@ static void setmon(Client *c, Monitor *m, uint32_t newtags);
|
|
||||||
static void setpsel(struct wl_listener *listener, void *data);
|
|
||||||
static void setsel(struct wl_listener *listener, void *data);
|
|
||||||
static void setup(void);
|
|
||||||
+static void setratio_h(const Arg *arg);
|
|
||||||
+static void setratio_v(const Arg *arg);
|
|
||||||
+static void swapclients(const Arg *arg);
|
|
||||||
static void spawn(const Arg *arg);
|
|
||||||
static void startdrag(struct wl_listener *listener, void *data);
|
|
||||||
static void tag(const Arg *arg);
|
|
||||||
@@ -458,6 +465,7 @@ static struct wlr_xwayland *xwayland;
|
|
||||||
|
|
||||||
/* attempt to encapsulate suck into one file */
|
|
||||||
#include "client.h"
|
|
||||||
+#include "btrtile.c"
|
|
||||||
|
|
||||||
/* function implementations */
|
|
||||||
void
|
|
||||||
@@ -628,7 +636,7 @@ buttonpress(struct wl_listener *listener, void *data)
|
|
||||||
struct wlr_pointer_button_event *event = data;
|
|
||||||
struct wlr_keyboard *keyboard;
|
|
||||||
uint32_t mods;
|
|
||||||
- Client *c;
|
|
||||||
+ Client *c, *target = NULL;
|
|
||||||
const Button *b;
|
|
||||||
|
|
||||||
wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
|
|
||||||
@@ -649,7 +657,7 @@ buttonpress(struct wl_listener *listener, void *data)
|
|
||||||
mods = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0;
|
|
||||||
for (b = buttons; b < END(buttons); b++) {
|
|
||||||
if (CLEANMASK(mods) == CLEANMASK(b->mod) &&
|
|
||||||
- event->button == b->button && b->func) {
|
|
||||||
+ event->button == b->button && b->func) {
|
|
||||||
b->func(&b->arg);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
@@ -659,6 +667,21 @@ 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) {
|
|
||||||
+ c = grabc;
|
|
||||||
+ if (c && c->was_tiled && !strcmp(selmon->ltsymbol, "|w|")) {
|
|
||||||
+ if (cursor_mode == CurMove && c->isfloating) {
|
|
||||||
+ target = xytoclient(cursor->x, cursor->y);
|
|
||||||
+
|
|
||||||
+ if (target && !target->isfloating && !target->isfullscreen)
|
|
||||||
+ insert_client(selmon, target, c);
|
|
||||||
+ else
|
|
||||||
+ selmon->root = create_client_node(c);
|
|
||||||
+
|
|
||||||
+ setfloating(c, 0);
|
|
||||||
+ apply_layout(selmon, selmon->root, selmon->w, 1);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ /* Default behaviour */
|
|
||||||
wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
|
|
||||||
cursor_mode = CurNormal;
|
|
||||||
/* Drop the window off on its new monitor */
|
|
||||||
@@ -750,6 +773,7 @@ cleanupmon(struct wl_listener *listener, void *data)
|
|
||||||
wlr_output_layout_remove(output_layout, m->wlr_output);
|
|
||||||
wlr_scene_output_destroy(m->scene_output);
|
|
||||||
|
|
||||||
+ destroy_tree(m);
|
|
||||||
closemon(m);
|
|
||||||
wlr_scene_node_destroy(&m->fullscreen_bg->node);
|
|
||||||
free(m);
|
|
||||||
@@ -1094,6 +1118,7 @@ createmon(struct wl_listener *listener, void *data)
|
|
||||||
|
|
||||||
wl_list_insert(&mons, &m->link);
|
|
||||||
printstatus();
|
|
||||||
+ init_tree(m);
|
|
||||||
|
|
||||||
/* The xdg-protocol specifies:
|
|
||||||
*
|
|
||||||
@@ -1332,10 +1357,18 @@ void
|
|
||||||
destroynotify(struct wl_listener *listener, void *data)
|
|
||||||
{
|
|
||||||
/* Called when the xdg_toplevel is destroyed. */
|
|
||||||
+ Monitor *mon;
|
|
||||||
Client *c = wl_container_of(listener, c, destroy);
|
|
||||||
wl_list_remove(&c->destroy.link);
|
|
||||||
wl_list_remove(&c->set_title.link);
|
|
||||||
wl_list_remove(&c->fullscreen.link);
|
|
||||||
+ /* We check if the destroyed client was part of any tiled_list, to catch
|
|
||||||
+ * client removals even if they would not be currently managed by btrtile */
|
|
||||||
+ wl_list_for_each(mon, &mons, link) {
|
|
||||||
+ if (mon->root) {
|
|
||||||
+ remove_client(mon, c);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
#ifdef XWAYLAND
|
|
||||||
if (c->type != XDGShell) {
|
|
||||||
wl_list_remove(&c->activate.link);
|
|
||||||
@@ -1866,7 +1899,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;
|
|
||||||
+ 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;
|
|
||||||
@@ -1920,18 +1954,55 @@ 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 */
|
|
||||||
+ if (time == 0)
|
|
||||||
+ goto focus;
|
|
||||||
+
|
|
||||||
+ tiled = grabc && !grabc->isfloating && !grabc->isfullscreen;
|
|
||||||
if (cursor_mode == CurMove) {
|
|
||||||
/* Move the grabbed client to the new position. */
|
|
||||||
- resize(grabc, (struct wlr_box){.x = (int)round(cursor->x) - grabcx, .y = (int)round(cursor->y) - grabcy,
|
|
||||||
- .width = grabc->geom.width, .height = grabc->geom.height}, 1);
|
|
||||||
- return;
|
|
||||||
+ if (grabc && grabc->isfloating) {
|
|
||||||
+ resize(grabc, (struct wlr_box){
|
|
||||||
+ .x = (int)round(cursor->x) - grabcx,
|
|
||||||
+ .y = (int)round(cursor->y) - grabcy,
|
|
||||||
+ .width = grabc->geom.width,
|
|
||||||
+ .height = grabc->geom.height
|
|
||||||
+ }, 1);
|
|
||||||
+ return;
|
|
||||||
+ }
|
|
||||||
} else if (cursor_mode == CurResize) {
|
|
||||||
- resize(grabc, (struct wlr_box){.x = grabc->geom.x, .y = grabc->geom.y,
|
|
||||||
- .width = (int)round(cursor->x) - grabc->geom.x, .height = (int)round(cursor->y) - grabc->geom.y}, 1);
|
|
||||||
- return;
|
|
||||||
+ if (tiled) {
|
|
||||||
+ dx_total = cursor->x - resize_last_update_x;
|
|
||||||
+ dy_total = cursor->y - resize_last_update_y;
|
|
||||||
+
|
|
||||||
+ if (time - last_resize_time >= resize_interval_ms) {
|
|
||||||
+ Arg a = {0};
|
|
||||||
+ if (fabs(dx_total) > fabs(dy_total)) {
|
|
||||||
+ a.f = (float)(dx_total * resize_factor);
|
|
||||||
+ setratio_h(&a);
|
|
||||||
+ } else {
|
|
||||||
+ a.f = (float)(dy_total * resize_factor);
|
|
||||||
+ setratio_v(&a);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ last_resize_time = time;
|
|
||||||
+ resize_last_update_x = cursor->x;
|
|
||||||
+ resize_last_update_y = cursor->y;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ } else if (grabc && grabc->isfloating) {
|
|
||||||
+ /* Floating resize as original */
|
|
||||||
+ resize(grabc, (struct wlr_box){
|
|
||||||
+ .x = grabc->geom.x,
|
|
||||||
+ .y = grabc->geom.y,
|
|
||||||
+ .width = (int)round(cursor->x) - grabc->geom.x,
|
|
||||||
+ .height = (int)round(cursor->y) - grabc->geom.y
|
|
||||||
+ }, 1);
|
|
||||||
+ return;
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
|
|
||||||
+focus:
|
|
||||||
/* 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. */
|
|
||||||
@@ -1965,22 +2036,40 @@ moveresize(const Arg *arg)
|
|
||||||
if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen)
|
|
||||||
return;
|
|
||||||
|
|
||||||
- /* Float the window and tell motionnotify to grab it */
|
|
||||||
- setfloating(grabc, 1);
|
|
||||||
- switch (cursor_mode = arg->ui) {
|
|
||||||
- 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, "all-scroll");
|
|
||||||
- break;
|
|
||||||
- case CurResize:
|
|
||||||
- /* 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);
|
|
||||||
- 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_last_update_x = cursor->x;
|
|
||||||
+ resize_last_update_y = cursor->y;
|
|
||||||
+ 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;
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -2833,6 +2922,14 @@ unmapnotify(struct wl_listener *listener, void *data)
|
|
||||||
focusclient(focustop(selmon), 1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
+ /* btrtile remove clients for each monitor */
|
|
||||||
+ Monitor *mon;
|
|
||||||
+ wl_list_for_each(mon, &mons, link) {
|
|
||||||
+ if (mon->root) {
|
|
||||||
+ remove_client(mon, c);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
wl_list_remove(&c->link);
|
|
||||||
setmon(c, NULL, 0);
|
|
||||||
wl_list_remove(&c->flink);
|
|
||||||
--
|
|
||||||
2.53.0
|
|
||||||
|
|
||||||
@@ -1,900 +0,0 @@
|
|||||||
From 3500e732fc34aa849cd3babeff7d2545a0230fa9 Mon Sep 17 00:00:00 2001
|
|
||||||
From: julmajustus <julmajustus@tutanota.com>
|
|
||||||
Date: Mon, 22 Jun 2026 22:33:17 +0300
|
|
||||||
Subject: [PATCH] btrtile: bug fixes and readability improvement
|
|
||||||
|
|
||||||
- Removed client old_geom caching for simplicity fixes: https://codeberg.org/dwl/dwl-patches/issues/647
|
|
||||||
- Improved readability of the client sanitization loop inside btrtile function
|
|
||||||
- Removed fullscreened client's from the sanitization loop to retain their geometry
|
|
||||||
---
|
|
||||||
btrtile.c | 556 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
||||||
config.def.h | 12 ++
|
|
||||||
dwl.c | 151 +++++++++++---
|
|
||||||
3 files changed, 692 insertions(+), 27 deletions(-)
|
|
||||||
create mode 100644 btrtile.c
|
|
||||||
|
|
||||||
diff --git a/btrtile.c b/btrtile.c
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000..b4f6f43
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/btrtile.c
|
|
||||||
@@ -0,0 +1,556 @@
|
|
||||||
+/* ************************************************************************** */
|
|
||||||
+/* @@@ @@@@@@@@ */
|
|
||||||
+/* @@@ @@@@@@@@@@ */
|
|
||||||
+/* @@! @@! @@@@ */
|
|
||||||
+/* !@! !@! @!@!@ */
|
|
||||||
+/* btrtile.c @!! @!@ @! !@! */
|
|
||||||
+/* !!! !@!!! !!! */
|
|
||||||
+/* By: julmajustus <julmajustus@tutanota.com> !!: !!:! !!! */
|
|
||||||
+/* ::! :!: !:! */
|
|
||||||
+/* Created: 2024/12/15 00:26:07 by julmajustus :: ::::::: :: */
|
|
||||||
+/* Updated: 2026/06/22 22:30:19 by julmajustus : : : : : : */
|
|
||||||
+/* */
|
|
||||||
+/* ************************************************************************** */
|
|
||||||
+
|
|
||||||
+typedef struct LayoutNode {
|
|
||||||
+ unsigned int is_client_node;
|
|
||||||
+ unsigned int is_split_vertically;
|
|
||||||
+ float split_ratio;
|
|
||||||
+ struct LayoutNode *left;
|
|
||||||
+ struct LayoutNode *right;
|
|
||||||
+ struct LayoutNode *split_node;
|
|
||||||
+ Client *client;
|
|
||||||
+} LayoutNode;
|
|
||||||
+
|
|
||||||
+static void apply_layout(Monitor *m, LayoutNode *node,
|
|
||||||
+ 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 is_split_vertically,
|
|
||||||
+ LayoutNode *left, LayoutNode *right);
|
|
||||||
+static void destroy_node(LayoutNode *node);
|
|
||||||
+static void destroy_tree(Monitor *m);
|
|
||||||
+static LayoutNode *find_client_node(LayoutNode *node, Client *c);
|
|
||||||
+static LayoutNode *find_suitable_split(Monitor *m, LayoutNode *start,
|
|
||||||
+ unsigned int need_vertical, int focused_on_left);
|
|
||||||
+static void init_tree(Monitor *m);
|
|
||||||
+static void insert_client(Monitor *m, Client *focused_client, Client *new_client);
|
|
||||||
+static LayoutNode *remove_client_node(LayoutNode *node, Client *c);
|
|
||||||
+static void remove_client(Monitor *m, Client *c);
|
|
||||||
+static void setratio_h(const Arg *arg);
|
|
||||||
+static void setratio_v(const Arg *arg);
|
|
||||||
+static void swapclients(const Arg *arg);
|
|
||||||
+static unsigned int visible_count(LayoutNode *node, Monitor *m);
|
|
||||||
+static Client *xytoclient(double x, double y);
|
|
||||||
+
|
|
||||||
+static double resize_last_update_x, resize_last_update_y;
|
|
||||||
+static uint32_t last_resize_time = 0;
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+apply_layout(Monitor *m, LayoutNode *node,
|
|
||||||
+ struct wlr_box area, unsigned int is_root)
|
|
||||||
+{
|
|
||||||
+ Client *c;
|
|
||||||
+ float ratio;
|
|
||||||
+ unsigned int left_count, right_count, mid;
|
|
||||||
+ struct wlr_box left_area, right_area;
|
|
||||||
+
|
|
||||||
+ if (!node)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ /* If this node is a client node, check if it is visible. */
|
|
||||||
+ if (node->is_client_node) {
|
|
||||||
+ c = node->client;
|
|
||||||
+ if (!c || !VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
|
|
||||||
+ return;
|
|
||||||
+ resize(c, area, 0);
|
|
||||||
+ return;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* For a split node, we see how many visible children are on each side: */
|
|
||||||
+ left_count = visible_count(node->left, m);
|
|
||||||
+ right_count = visible_count(node->right, m);
|
|
||||||
+
|
|
||||||
+ if (left_count == 0 && right_count == 0) {
|
|
||||||
+ return;
|
|
||||||
+ } else if (left_count > 0 && right_count == 0) {
|
|
||||||
+ apply_layout(m, node->left, area, 0);
|
|
||||||
+ return;
|
|
||||||
+ } else if (left_count == 0 && right_count > 0) {
|
|
||||||
+ apply_layout(m, node->right, area, 0);
|
|
||||||
+ return;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* If we’re here, we have visible clients in both subtrees. */
|
|
||||||
+ ratio = node->split_ratio;
|
|
||||||
+ if (ratio < 0.05f)
|
|
||||||
+ ratio = 0.05f;
|
|
||||||
+ if (ratio > 0.95f)
|
|
||||||
+ ratio = 0.95f;
|
|
||||||
+
|
|
||||||
+ memset(&left_area, 0, sizeof(left_area));
|
|
||||||
+ memset(&right_area, 0, sizeof(right_area));
|
|
||||||
+
|
|
||||||
+ if (node->is_split_vertically) {
|
|
||||||
+ mid = (unsigned int)(area.width * ratio);
|
|
||||||
+ left_area.x = area.x;
|
|
||||||
+ left_area.y = area.y;
|
|
||||||
+ left_area.width = mid;
|
|
||||||
+ left_area.height = area.height;
|
|
||||||
+
|
|
||||||
+ right_area.x = area.x + mid;
|
|
||||||
+ right_area.y = area.y;
|
|
||||||
+ right_area.width = area.width - mid;
|
|
||||||
+ right_area.height = area.height;
|
|
||||||
+ } else {
|
|
||||||
+ /* horizontal split */
|
|
||||||
+ mid = (unsigned int)(area.height * ratio);
|
|
||||||
+ left_area.x = area.x;
|
|
||||||
+ left_area.y = area.y;
|
|
||||||
+ left_area.width = area.width;
|
|
||||||
+ left_area.height = mid;
|
|
||||||
+
|
|
||||||
+ right_area.x = area.x;
|
|
||||||
+ right_area.y = area.y + mid;
|
|
||||||
+ right_area.width = area.width;
|
|
||||||
+ right_area.height= area.height - mid;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ apply_layout(m, node->left, left_area, 0);
|
|
||||||
+ apply_layout(m, node->right, right_area, 0);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+btrtile(Monitor *m)
|
|
||||||
+{
|
|
||||||
+ Client *c, *focused = NULL;
|
|
||||||
+ int n = 0;
|
|
||||||
+ LayoutNode *found;
|
|
||||||
+ struct wlr_box full_area;
|
|
||||||
+
|
|
||||||
+ if (!m)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ /* Remove floating and moved clients */
|
|
||||||
+ wl_list_for_each(c, &clients, link) {
|
|
||||||
+ if (c->mon != m || c->isfloating)
|
|
||||||
+ remove_client(m, c);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* If no client is found under cursor, fallback to focustop(m) */
|
|
||||||
+ if (!(focused = xytoclient(cursor->x, cursor->y)))
|
|
||||||
+ focused = focustop(m);
|
|
||||||
+
|
|
||||||
+ /* Insert visible clients that are not part of the tree. */
|
|
||||||
+ wl_list_for_each(c, &clients, link) {
|
|
||||||
+ if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen && c->mon == m) {
|
|
||||||
+ found = find_client_node(m->root, c);
|
|
||||||
+ if (!found) {
|
|
||||||
+ insert_client(m, focused, c);
|
|
||||||
+ }
|
|
||||||
+ n++;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (n == 0)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ full_area = m->w;
|
|
||||||
+ apply_layout(m, m->root, full_area, 1);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+LayoutNode *
|
|
||||||
+create_client_node(Client *c)
|
|
||||||
+{
|
|
||||||
+ LayoutNode *node = calloc(1, sizeof(LayoutNode));
|
|
||||||
+
|
|
||||||
+ if (!node)
|
|
||||||
+ return NULL;
|
|
||||||
+ node->is_client_node = 1;
|
|
||||||
+ node->split_ratio = 0.5f;
|
|
||||||
+ node->client = c;
|
|
||||||
+ return node;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+LayoutNode *
|
|
||||||
+create_split_node(unsigned int is_split_vertically,
|
|
||||||
+ LayoutNode *left, LayoutNode *right)
|
|
||||||
+{
|
|
||||||
+ LayoutNode *node = calloc(1, sizeof(LayoutNode));
|
|
||||||
+
|
|
||||||
+ if (!node)
|
|
||||||
+ return NULL;
|
|
||||||
+ node->is_client_node = 0;
|
|
||||||
+ node->split_ratio = 0.5f;
|
|
||||||
+ node->is_split_vertically = is_split_vertically;
|
|
||||||
+ node->left = left;
|
|
||||||
+ node->right = right;
|
|
||||||
+ if (left)
|
|
||||||
+ left->split_node = node;
|
|
||||||
+ if (right)
|
|
||||||
+ right->split_node = node;
|
|
||||||
+ return node;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+destroy_node(LayoutNode *node)
|
|
||||||
+{
|
|
||||||
+ if (!node)
|
|
||||||
+ return;
|
|
||||||
+ if (!node->is_client_node) {
|
|
||||||
+ destroy_node(node->left);
|
|
||||||
+ destroy_node(node->right);
|
|
||||||
+ }
|
|
||||||
+ free(node);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+destroy_tree(Monitor *m)
|
|
||||||
+{
|
|
||||||
+ if (!m || !m->root)
|
|
||||||
+ return;
|
|
||||||
+ destroy_node(m->root);
|
|
||||||
+ m->root = NULL;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+LayoutNode *
|
|
||||||
+find_client_node(LayoutNode *node, Client *c)
|
|
||||||
+{
|
|
||||||
+ LayoutNode *res;
|
|
||||||
+
|
|
||||||
+ if (!node || !c)
|
|
||||||
+ return NULL;
|
|
||||||
+ if (node->is_client_node) {
|
|
||||||
+ return (node->client == c) ? node : NULL;
|
|
||||||
+ }
|
|
||||||
+ res = find_client_node(node->left, c);
|
|
||||||
+ return res ? res : find_client_node(node->right, c);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+LayoutNode *
|
|
||||||
+find_suitable_split(Monitor *m, LayoutNode *start_node,
|
|
||||||
+ unsigned int need_vertical, int focused_on_left)
|
|
||||||
+{
|
|
||||||
+ LayoutNode *n = start_node, *child = NULL;
|
|
||||||
+
|
|
||||||
+ if (!m)
|
|
||||||
+ return NULL;
|
|
||||||
+
|
|
||||||
+ if (n && n->is_client_node) {
|
|
||||||
+ child = n;
|
|
||||||
+ n = n->split_node;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ while (n) {
|
|
||||||
+ if (!n->is_client_node && n->is_split_vertically == need_vertical
|
|
||||||
+ && visible_count(n->left, m) > 0
|
|
||||||
+ && visible_count(n->right, m) > 0) {
|
|
||||||
+ if ((focused_on_left && n->left == child) ||
|
|
||||||
+ (!focused_on_left && n->right == child))
|
|
||||||
+ return n;
|
|
||||||
+ }
|
|
||||||
+ child = n;
|
|
||||||
+ n = n->split_node;
|
|
||||||
+ }
|
|
||||||
+ return NULL;
|
|
||||||
+}
|
|
||||||
+void
|
|
||||||
+init_tree(Monitor *m)
|
|
||||||
+{
|
|
||||||
+ if (m)
|
|
||||||
+ m->root = NULL;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+insert_client(Monitor *m, Client *focused_client, Client *new_client)
|
|
||||||
+{
|
|
||||||
+ Client *old_client;
|
|
||||||
+ LayoutNode **root = &m->root, *old_root,
|
|
||||||
+ *focused_node, *new_client_node, *old_client_node;
|
|
||||||
+ unsigned int wider, mid_x, mid_y;
|
|
||||||
+
|
|
||||||
+ /* If no root , new client becomes the root. */
|
|
||||||
+ if (!*root) {
|
|
||||||
+ *root = create_client_node(new_client);
|
|
||||||
+ return;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* Find the focused_client node,
|
|
||||||
+ * if not found split the root. */
|
|
||||||
+ focused_node = focused_client ?
|
|
||||||
+ find_client_node(*root, focused_client) : NULL;
|
|
||||||
+ if (!focused_node) {
|
|
||||||
+ old_root = *root;
|
|
||||||
+ new_client_node = create_client_node(new_client);
|
|
||||||
+ *root = create_split_node(1, old_root, new_client_node);
|
|
||||||
+ return;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* Turn focused node from a client node into a split node,
|
|
||||||
+ * and attach old_client + new_client. */
|
|
||||||
+ old_client = focused_node->client;
|
|
||||||
+ old_client_node = create_client_node(old_client);
|
|
||||||
+ new_client_node = create_client_node(new_client);
|
|
||||||
+
|
|
||||||
+ /* Decide split direction. */
|
|
||||||
+ wider = (focused_client->geom.width >= focused_client->geom.height);
|
|
||||||
+ focused_node->is_client_node = 0;
|
|
||||||
+ focused_node->client = NULL;
|
|
||||||
+ focused_node->is_split_vertically = (wider ? 1 : 0);
|
|
||||||
+
|
|
||||||
+ /* Pick new_client side depending on the cursor position. */
|
|
||||||
+ mid_x = focused_client->geom.x + focused_client->geom.width / 2;
|
|
||||||
+ mid_y = focused_client->geom.y + focused_client->geom.height / 2;
|
|
||||||
+
|
|
||||||
+ if (wider) {
|
|
||||||
+ /* vertical split => left vs right */
|
|
||||||
+ if (cursor->x <= mid_x) {
|
|
||||||
+ focused_node->left = new_client_node;
|
|
||||||
+ focused_node->right = old_client_node;
|
|
||||||
+ } else {
|
|
||||||
+ focused_node->left = old_client_node;
|
|
||||||
+ focused_node->right = new_client_node;
|
|
||||||
+ }
|
|
||||||
+ } else {
|
|
||||||
+ /* horizontal split => top vs bottom */
|
|
||||||
+ if (cursor->y <= mid_y) {
|
|
||||||
+ focused_node->left = new_client_node;
|
|
||||||
+ focused_node->right = old_client_node;
|
|
||||||
+ } else {
|
|
||||||
+ focused_node->left = old_client_node;
|
|
||||||
+ focused_node->right = new_client_node;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ old_client_node->split_node = focused_node;
|
|
||||||
+ new_client_node->split_node = focused_node;
|
|
||||||
+ focused_node->split_ratio = 0.5f;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+LayoutNode *
|
|
||||||
+remove_client_node(LayoutNode *node, Client *c)
|
|
||||||
+{
|
|
||||||
+ LayoutNode *tmp;
|
|
||||||
+ if (!node)
|
|
||||||
+ return NULL;
|
|
||||||
+ if (node->is_client_node) {
|
|
||||||
+ /* If this client_node is the client we're removing,
|
|
||||||
+ * return NULL to remove it */
|
|
||||||
+ if (node->client == c) {
|
|
||||||
+ free(node);
|
|
||||||
+ return NULL;
|
|
||||||
+ }
|
|
||||||
+ return node;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ node->left = remove_client_node(node->left, c);
|
|
||||||
+ node->right = remove_client_node(node->right, c);
|
|
||||||
+
|
|
||||||
+ /* 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;
|
|
||||||
+
|
|
||||||
+ /* Save pointer to split node */
|
|
||||||
+ if (tmp)
|
|
||||||
+ tmp->split_node = node->split_node;
|
|
||||||
+
|
|
||||||
+ free(node);
|
|
||||||
+ return tmp;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (!node->right && node->left) {
|
|
||||||
+ tmp = node->left;
|
|
||||||
+
|
|
||||||
+ /* Save pointer to split node */
|
|
||||||
+ if (tmp)
|
|
||||||
+ tmp->split_node = node->split_node;
|
|
||||||
+
|
|
||||||
+ free(node);
|
|
||||||
+ return tmp;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* If both children exist or both are NULL (empty tree),
|
|
||||||
+ * return node as is. */
|
|
||||||
+ return node;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+remove_client(Monitor *m, Client *c)
|
|
||||||
+{
|
|
||||||
+ if (!m->root || !c)
|
|
||||||
+ return;
|
|
||||||
+ m->root = remove_client_node(m->root, c);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+setratio(unsigned int need_vertical, const Arg *arg)
|
|
||||||
+{
|
|
||||||
+ Client *sel;
|
|
||||||
+ LayoutNode *client_node, *split_node;
|
|
||||||
+ float new_ratio;
|
|
||||||
+ int focused_on_left;
|
|
||||||
+
|
|
||||||
+ if (!selmon || !selmon->lt[selmon->sellt]->arrange)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ sel = focustop(selmon);
|
|
||||||
+ if (!sel)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ client_node = find_client_node(selmon->root, sel);
|
|
||||||
+ if (!client_node)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ focused_on_left = (arg->f >= 0.0f);
|
|
||||||
+
|
|
||||||
+ split_node = find_suitable_split(selmon, client_node, need_vertical, focused_on_left);
|
|
||||||
+
|
|
||||||
+ if (!split_node)
|
|
||||||
+ split_node = find_suitable_split(selmon, client_node, need_vertical, !focused_on_left);
|
|
||||||
+ if (!split_node)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ new_ratio = (arg->f != 0.0f) ? (split_node->split_ratio + arg->f) : 0.5f;
|
|
||||||
+ if (new_ratio < 0.05f)
|
|
||||||
+ new_ratio = 0.05f;
|
|
||||||
+ if (new_ratio > 0.95f)
|
|
||||||
+ new_ratio = 0.95f;
|
|
||||||
+ split_node->split_ratio = new_ratio;
|
|
||||||
+
|
|
||||||
+ apply_layout(selmon, selmon->root, selmon->w, 1);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+setratio_h(const Arg *arg)
|
|
||||||
+{
|
|
||||||
+ setratio(1, arg);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+setratio_v(const Arg *arg)
|
|
||||||
+{
|
|
||||||
+ setratio(0, arg);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void swapclients(const Arg *arg) {
|
|
||||||
+ Client *c, *tmp, *target = NULL, *sel = focustop(selmon);
|
|
||||||
+ LayoutNode *sel_node, *target_node;
|
|
||||||
+ int closest_dist = INT_MAX, dist, sel_center_x, sel_center_y,
|
|
||||||
+ cand_center_x, cand_center_y;
|
|
||||||
+
|
|
||||||
+ if (!sel || sel->isfullscreen ||
|
|
||||||
+ !selmon->root || !selmon->lt[selmon->sellt]->arrange)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+ /* Get the center coordinates of the selected client */
|
|
||||||
+ sel_center_x = sel->geom.x + sel->geom.width / 2;
|
|
||||||
+ sel_center_y = sel->geom.y + sel->geom.height / 2;
|
|
||||||
+
|
|
||||||
+ wl_list_for_each(c, &clients, link) {
|
|
||||||
+ if (!VISIBLEON(c, selmon) || c->isfloating || c->isfullscreen || c == sel)
|
|
||||||
+ continue;
|
|
||||||
+
|
|
||||||
+ /* Get the center of candidate client */
|
|
||||||
+ cand_center_x = c->geom.x + c->geom.width / 2;
|
|
||||||
+ cand_center_y = c->geom.y + c->geom.height / 2;
|
|
||||||
+
|
|
||||||
+ /* Check that the candidate lies in the requested direction. */
|
|
||||||
+ switch (arg->ui) {
|
|
||||||
+ case 0:
|
|
||||||
+ if (cand_center_x >= sel_center_x)
|
|
||||||
+ continue;
|
|
||||||
+ break;
|
|
||||||
+ case 1:
|
|
||||||
+ if (cand_center_x <= sel_center_x)
|
|
||||||
+ continue;
|
|
||||||
+ break;
|
|
||||||
+ case 2:
|
|
||||||
+ if (cand_center_y >= sel_center_y)
|
|
||||||
+ continue;
|
|
||||||
+ break;
|
|
||||||
+ case 3:
|
|
||||||
+ if (cand_center_y <= sel_center_y)
|
|
||||||
+ continue;
|
|
||||||
+ break;
|
|
||||||
+ default:
|
|
||||||
+ continue;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* Get distance between the centers */
|
|
||||||
+ dist = abs(sel_center_x - cand_center_x) + abs(sel_center_y - cand_center_y);
|
|
||||||
+ if (dist < closest_dist) {
|
|
||||||
+ closest_dist = dist;
|
|
||||||
+ target = c;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* If target is found, swap the two clients’ positions in the layout tree */
|
|
||||||
+ if (target) {
|
|
||||||
+ sel_node = find_client_node(selmon->root, sel);
|
|
||||||
+ target_node = find_client_node(selmon->root, target);
|
|
||||||
+ if (sel_node && target_node) {
|
|
||||||
+ tmp = sel_node->client;
|
|
||||||
+ sel_node->client = target_node->client;
|
|
||||||
+ target_node->client = tmp;
|
|
||||||
+ arrange(selmon);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+unsigned int
|
|
||||||
+visible_count(LayoutNode *node, Monitor *m)
|
|
||||||
+{
|
|
||||||
+ Client *c;
|
|
||||||
+
|
|
||||||
+ if (!node)
|
|
||||||
+ return 0;
|
|
||||||
+ /* Check if this client is visible. */
|
|
||||||
+ if (node->is_client_node) {
|
|
||||||
+ c = node->client;
|
|
||||||
+ if (c && VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen)
|
|
||||||
+ return 1;
|
|
||||||
+ return 0;
|
|
||||||
+ }
|
|
||||||
+ /* Else it’s a split node. */
|
|
||||||
+ return visible_count(node->left, m) + visible_count(node->right, m);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+Client *
|
|
||||||
+xytoclient(double x, double y) {
|
|
||||||
+ Monitor *m = xytomon(x, y);
|
|
||||||
+ Client *c, *closest = NULL;
|
|
||||||
+ double dist, mindist = INT_MAX, dx, dy;
|
|
||||||
+
|
|
||||||
+ wl_list_for_each_reverse(c, &clients, link) {
|
|
||||||
+ if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen &&
|
|
||||||
+ x >= c->geom.x && x <= (c->geom.x + c->geom.width) &&
|
|
||||||
+ y >= c->geom.y && y <= (c->geom.y + c->geom.height)){
|
|
||||||
+ return c;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* If no client was found at cursor position fallback to closest. */
|
|
||||||
+ wl_list_for_each_reverse(c, &clients, link) {
|
|
||||||
+ if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen) {
|
|
||||||
+ dx = 0, dy = 0;
|
|
||||||
+
|
|
||||||
+ if (x < c->geom.x)
|
|
||||||
+ dx = c->geom.x - x;
|
|
||||||
+ else if (x > (c->geom.x + c->geom.width))
|
|
||||||
+ dx = x - (c->geom.x + c->geom.width);
|
|
||||||
+
|
|
||||||
+ if (y < c->geom.y)
|
|
||||||
+ dy = c->geom.y - y;
|
|
||||||
+ else if (y > (c->geom.y + c->geom.height))
|
|
||||||
+ dy = y - (c->geom.y + c->geom.height);
|
|
||||||
+
|
|
||||||
+ dist = dx * dx + dy * dy;
|
|
||||||
+ if (dist < mindist) {
|
|
||||||
+ mindist = dist;
|
|
||||||
+ closest = c;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ return closest;
|
|
||||||
+}
|
|
||||||
diff --git a/config.def.h b/config.def.h
|
|
||||||
index 8a6eda0..bc04e3f 100644
|
|
||||||
--- a/config.def.h
|
|
||||||
+++ b/config.def.h
|
|
||||||
@@ -13,7 +13,10 @@ static const float focuscolor[] = COLOR(0x005577ff);
|
|
||||||
static const float urgentcolor[] = COLOR(0xff0000ff);
|
|
||||||
/* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */
|
|
||||||
static const float fullscreen_bg[] = {0.0f, 0.0f, 0.0f, 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 */
|
|
||||||
#define TAGCOUNT (9)
|
|
||||||
|
|
||||||
@@ -30,6 +33,7 @@ static const Rule rules[] = {
|
|
||||||
/* layout(s) */
|
|
||||||
static const Layout layouts[] = {
|
|
||||||
/* symbol arrange function */
|
|
||||||
+ { "|w|", btrtile },
|
|
||||||
{ "[]=", tile },
|
|
||||||
{ "><>", NULL }, /* no layout function means floating behavior */
|
|
||||||
{ "[M]", monocle },
|
|
||||||
@@ -144,6 +148,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} },
|
|
||||||
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Left, swapclients, {.i = DIR_LEFT} },
|
|
||||||
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_Right, setratio_h, {.f = +0.025f} },
|
|
||||||
+ { 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} },
|
|
||||||
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 8101ffa..31446ed 100644
|
|
||||||
--- a/dwl.c
|
|
||||||
+++ b/dwl.c
|
|
||||||
@@ -1,6 +1,7 @@
|
|
||||||
/*
|
|
||||||
* See LICENSE file for copyright and license details.
|
|
||||||
*/
|
|
||||||
+#include <limits.h>
|
|
||||||
#include <getopt.h>
|
|
||||||
#include <libinput.h>
|
|
||||||
#include <linux/input-event-codes.h>
|
|
||||||
@@ -104,6 +105,7 @@ typedef struct {
|
|
||||||
const Arg arg;
|
|
||||||
} Button;
|
|
||||||
|
|
||||||
+typedef struct LayoutNode LayoutNode;
|
|
||||||
typedef struct Monitor Monitor;
|
|
||||||
typedef struct {
|
|
||||||
/* Must keep this field first */
|
|
||||||
@@ -141,7 +143,7 @@ typedef struct {
|
|
||||||
#endif
|
|
||||||
unsigned int bw;
|
|
||||||
uint32_t tags;
|
|
||||||
- int isfloating, isurgent, isfullscreen;
|
|
||||||
+ int isfloating, isurgent, isfullscreen, was_tiled;
|
|
||||||
uint32_t resize; /* configure serial of a pending resize */
|
|
||||||
} Client;
|
|
||||||
|
|
||||||
@@ -209,6 +211,7 @@ struct Monitor {
|
|
||||||
int nmaster;
|
|
||||||
char ltsymbol[16];
|
|
||||||
int asleep;
|
|
||||||
+ LayoutNode *root;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
@@ -251,6 +254,7 @@ static void arrangelayer(Monitor *m, struct wl_list *list,
|
|
||||||
struct wlr_box *usable_area, int exclusive);
|
|
||||||
static void arrangelayers(Monitor *m);
|
|
||||||
static void axisnotify(struct wl_listener *listener, void *data);
|
|
||||||
+static void btrtile(Monitor *m);
|
|
||||||
static void buttonpress(struct wl_listener *listener, void *data);
|
|
||||||
static void chvt(const Arg *arg);
|
|
||||||
static void checkidleinhibitor(struct wlr_surface *exclude);
|
|
||||||
@@ -333,6 +337,9 @@ static void setmon(Client *c, Monitor *m, uint32_t newtags);
|
|
||||||
static void setpsel(struct wl_listener *listener, void *data);
|
|
||||||
static void setsel(struct wl_listener *listener, void *data);
|
|
||||||
static void setup(void);
|
|
||||||
+static void setratio_h(const Arg *arg);
|
|
||||||
+static void setratio_v(const Arg *arg);
|
|
||||||
+static void swapclients(const Arg *arg);
|
|
||||||
static void spawn(const Arg *arg);
|
|
||||||
static void startdrag(struct wl_listener *listener, void *data);
|
|
||||||
static void tag(const Arg *arg);
|
|
||||||
@@ -458,6 +465,7 @@ static struct wlr_xwayland *xwayland;
|
|
||||||
|
|
||||||
/* attempt to encapsulate suck into one file */
|
|
||||||
#include "client.h"
|
|
||||||
+#include "btrtile.c"
|
|
||||||
|
|
||||||
/* function implementations */
|
|
||||||
void
|
|
||||||
@@ -628,7 +636,7 @@ buttonpress(struct wl_listener *listener, void *data)
|
|
||||||
struct wlr_pointer_button_event *event = data;
|
|
||||||
struct wlr_keyboard *keyboard;
|
|
||||||
uint32_t mods;
|
|
||||||
- Client *c;
|
|
||||||
+ Client *c, *target = NULL;
|
|
||||||
const Button *b;
|
|
||||||
|
|
||||||
wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
|
|
||||||
@@ -649,7 +657,7 @@ buttonpress(struct wl_listener *listener, void *data)
|
|
||||||
mods = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0;
|
|
||||||
for (b = buttons; b < END(buttons); b++) {
|
|
||||||
if (CLEANMASK(mods) == CLEANMASK(b->mod) &&
|
|
||||||
- event->button == b->button && b->func) {
|
|
||||||
+ event->button == b->button && b->func) {
|
|
||||||
b->func(&b->arg);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
@@ -659,6 +667,21 @@ 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) {
|
|
||||||
+ c = grabc;
|
|
||||||
+ if (c && c->was_tiled && !strcmp(selmon->ltsymbol, "|w|")) {
|
|
||||||
+ if (cursor_mode == CurMove && c->isfloating) {
|
|
||||||
+ target = xytoclient(cursor->x, cursor->y);
|
|
||||||
+
|
|
||||||
+ if (target && !target->isfloating && !target->isfullscreen)
|
|
||||||
+ insert_client(selmon, target, c);
|
|
||||||
+ else
|
|
||||||
+ selmon->root = create_client_node(c);
|
|
||||||
+
|
|
||||||
+ setfloating(c, 0);
|
|
||||||
+ apply_layout(selmon, selmon->root, selmon->w, 1);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ /* Default behaviour */
|
|
||||||
wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
|
|
||||||
cursor_mode = CurNormal;
|
|
||||||
/* Drop the window off on its new monitor */
|
|
||||||
@@ -750,6 +773,7 @@ cleanupmon(struct wl_listener *listener, void *data)
|
|
||||||
wlr_output_layout_remove(output_layout, m->wlr_output);
|
|
||||||
wlr_scene_output_destroy(m->scene_output);
|
|
||||||
|
|
||||||
+ destroy_tree(m);
|
|
||||||
closemon(m);
|
|
||||||
wlr_scene_node_destroy(&m->fullscreen_bg->node);
|
|
||||||
free(m);
|
|
||||||
@@ -1094,6 +1118,7 @@ createmon(struct wl_listener *listener, void *data)
|
|
||||||
|
|
||||||
wl_list_insert(&mons, &m->link);
|
|
||||||
printstatus();
|
|
||||||
+ init_tree(m);
|
|
||||||
|
|
||||||
/* The xdg-protocol specifies:
|
|
||||||
*
|
|
||||||
@@ -1333,9 +1358,17 @@ destroynotify(struct wl_listener *listener, void *data)
|
|
||||||
{
|
|
||||||
/* Called when the xdg_toplevel is destroyed. */
|
|
||||||
Client *c = wl_container_of(listener, c, destroy);
|
|
||||||
+ Monitor *mon;
|
|
||||||
wl_list_remove(&c->destroy.link);
|
|
||||||
wl_list_remove(&c->set_title.link);
|
|
||||||
wl_list_remove(&c->fullscreen.link);
|
|
||||||
+ /* We check if the destroyed client was part of any tiled_list, to catch
|
|
||||||
+ * client removals even if they would not be currently managed by btrtile */
|
|
||||||
+ wl_list_for_each(mon, &mons, link) {
|
|
||||||
+ if (mon->root) {
|
|
||||||
+ remove_client(mon, c);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
#ifdef XWAYLAND
|
|
||||||
if (c->type != XDGShell) {
|
|
||||||
wl_list_remove(&c->activate.link);
|
|
||||||
@@ -1866,7 +1899,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;
|
|
||||||
+ 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;
|
|
||||||
@@ -1920,18 +1954,55 @@ 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 */
|
|
||||||
+ if (time == 0)
|
|
||||||
+ goto focus;
|
|
||||||
+
|
|
||||||
+ tiled = grabc && !grabc->isfloating && !grabc->isfullscreen;
|
|
||||||
if (cursor_mode == CurMove) {
|
|
||||||
/* Move the grabbed client to the new position. */
|
|
||||||
- resize(grabc, (struct wlr_box){.x = (int)round(cursor->x) - grabcx, .y = (int)round(cursor->y) - grabcy,
|
|
||||||
- .width = grabc->geom.width, .height = grabc->geom.height}, 1);
|
|
||||||
- return;
|
|
||||||
+ if (grabc && grabc->isfloating) {
|
|
||||||
+ resize(grabc, (struct wlr_box){
|
|
||||||
+ .x = (int)round(cursor->x) - grabcx,
|
|
||||||
+ .y = (int)round(cursor->y) - grabcy,
|
|
||||||
+ .width = grabc->geom.width,
|
|
||||||
+ .height = grabc->geom.height
|
|
||||||
+ }, 1);
|
|
||||||
+ return;
|
|
||||||
+ }
|
|
||||||
} else if (cursor_mode == CurResize) {
|
|
||||||
- resize(grabc, (struct wlr_box){.x = grabc->geom.x, .y = grabc->geom.y,
|
|
||||||
- .width = (int)round(cursor->x) - grabc->geom.x, .height = (int)round(cursor->y) - grabc->geom.y}, 1);
|
|
||||||
- return;
|
|
||||||
+ if (tiled) {
|
|
||||||
+ dx_total = cursor->x - resize_last_update_x;
|
|
||||||
+ dy_total = cursor->y - resize_last_update_y;
|
|
||||||
+
|
|
||||||
+ if (time - last_resize_time >= resize_interval_ms) {
|
|
||||||
+ Arg a = {0};
|
|
||||||
+ if (fabs(dx_total) > fabs(dy_total)) {
|
|
||||||
+ a.f = (float)(dx_total * resize_factor);
|
|
||||||
+ setratio_h(&a);
|
|
||||||
+ } else {
|
|
||||||
+ a.f = (float)(dy_total * resize_factor);
|
|
||||||
+ setratio_v(&a);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ last_resize_time = time;
|
|
||||||
+ resize_last_update_x = cursor->x;
|
|
||||||
+ resize_last_update_y = cursor->y;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ } else if (grabc && grabc->isfloating) {
|
|
||||||
+ /* Floating resize as original */
|
|
||||||
+ resize(grabc, (struct wlr_box){
|
|
||||||
+ .x = grabc->geom.x,
|
|
||||||
+ .y = grabc->geom.y,
|
|
||||||
+ .width = (int)round(cursor->x) - grabc->geom.x,
|
|
||||||
+ .height = (int)round(cursor->y) - grabc->geom.y
|
|
||||||
+ }, 1);
|
|
||||||
+ return;
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
|
|
||||||
+focus:
|
|
||||||
/* 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. */
|
|
||||||
@@ -1965,22 +2036,40 @@ moveresize(const Arg *arg)
|
|
||||||
if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen)
|
|
||||||
return;
|
|
||||||
|
|
||||||
- /* Float the window and tell motionnotify to grab it */
|
|
||||||
- setfloating(grabc, 1);
|
|
||||||
- switch (cursor_mode = arg->ui) {
|
|
||||||
- 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, "all-scroll");
|
|
||||||
- break;
|
|
||||||
- case CurResize:
|
|
||||||
- /* 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);
|
|
||||||
- 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_last_update_x = cursor->x;
|
|
||||||
+ resize_last_update_y = cursor->y;
|
|
||||||
+ 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;
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -2833,6 +2922,14 @@ unmapnotify(struct wl_listener *listener, void *data)
|
|
||||||
focusclient(focustop(selmon), 1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
+ /* btrtile remove clients for each monitor */
|
|
||||||
+ Monitor *mon;
|
|
||||||
+ wl_list_for_each(mon, &mons, link) {
|
|
||||||
+ if (mon->root) {
|
|
||||||
+ remove_client(mon, c);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
wl_list_remove(&c->link);
|
|
||||||
setmon(c, NULL, 0);
|
|
||||||
wl_list_remove(&c->flink);
|
|
||||||
--
|
|
||||||
2.53.0
|
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
### Description
|
### Description
|
||||||
|
|
||||||
# fullscreenadaptivesync — Enables adaptive sync/VRR when a client is fullscreen.
|
# fullscreenadaptivesync - Enables adaptive sync/VRR when a client is fullscreen.
|
||||||
|
|
||||||
Adds a function that automatically enables adaptive sync/VRR when a fullscreen client is detected, and disables it once the client exits fullscreen.
|
Adds a function that automatically enables adaptive sync/VRR when a fullscreen client is detected, and disables it once the client exits fullscreen.
|
||||||
|
|
||||||
@@ -22,9 +22,9 @@ Adds a function that automatically enables adaptive sync/VRR when a fullscreen c
|
|||||||
- Enabled by default.
|
- Enabled by default.
|
||||||
|
|
||||||
### Download
|
### Download
|
||||||
- [git branch](https://codeberg.org/julmajustus/dwl/src/branch/fullscreenadaptivesync-wlroots-next)
|
- [git branch](https://codeberg.org/julmajustus/dwl/src/branch/fullscreenadaptivesync-0.9)
|
||||||
- [0.8](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/fullscreenadaptivesync/fullscreenadaptivesync-v0.8.patch)
|
- [0.8](./fullscreenadaptivesync-v0.8.patch)
|
||||||
- [wlroots-next-d41ecb7](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/fullscreenadaptivesync/fullscreenadaptivesync-wlroots-next-d41ecb7.patch)
|
- [main-d16036e](./fullscreenadaptivesync-d16036e.patch)
|
||||||
|
|
||||||
### Authors
|
### Authors
|
||||||
- [julmajustus](https://codeberg.org/julmajustus)
|
- [julmajustus](https://codeberg.org/julmajustus)
|
||||||
|
|||||||
+20
-23
@@ -1,18 +1,15 @@
|
|||||||
From 5d475f7afe7ba7cee389a5c5ed4fa676b408fee5 Mon Sep 17 00:00:00 2001
|
From 860793b4ff7b03c0fe4be03f2086ae5f25876293 Mon Sep 17 00:00:00 2001
|
||||||
From: julmajustus <julmajustus@tutanota.com>
|
From: julmajustus <julmajustus@tutanota.com>
|
||||||
Date: Mon, 22 Jun 2026 23:02:25 +0300
|
Date: Sun, 20 Sep 2026 02:32:01 +0300
|
||||||
Subject: [PATCH] fullscreen_adaptive_sync: Minor bug fixes
|
Subject: [PATCH] fullscreenadaptivesync refactor for d16036e
|
||||||
|
|
||||||
- Fixed logic error inside unmapnotify
|
|
||||||
- Added no-op guards inside set_adaptive_sync
|
|
||||||
- Added extra check for the config commit success
|
|
||||||
---
|
---
|
||||||
config.def.h | 1 +
|
config.def.h | 1 +
|
||||||
dwl.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++---
|
dwl.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++---
|
||||||
2 files changed, 57 insertions(+), 3 deletions(-)
|
2 files changed, 57 insertions(+), 3 deletions(-)
|
||||||
|
|
||||||
diff --git a/config.def.h b/config.def.h
|
diff --git a/config.def.h b/config.def.h
|
||||||
index 8a6eda0..06b3153 100644
|
index 13c5322..262e3f3 100644
|
||||||
--- a/config.def.h
|
--- a/config.def.h
|
||||||
+++ b/config.def.h
|
+++ b/config.def.h
|
||||||
@@ -138,6 +138,7 @@ static const Key keys[] = {
|
@@ -138,6 +138,7 @@ static const Key keys[] = {
|
||||||
@@ -21,13 +18,13 @@ index 8a6eda0..06b3153 100644
|
|||||||
{ MODKEY, XKB_KEY_e, togglefullscreen, {0} },
|
{ MODKEY, XKB_KEY_e, togglefullscreen, {0} },
|
||||||
+ { MODKEY, XKB_KEY_F5, togglefullscreenadaptivesync, {0} },
|
+ { MODKEY, XKB_KEY_F5, togglefullscreenadaptivesync, {0} },
|
||||||
{ MODKEY, XKB_KEY_0, view, {.ui = ~0} },
|
{ MODKEY, XKB_KEY_0, view, {.ui = ~0} },
|
||||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_parenright, tag, {.ui = ~0} },
|
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_0, tag, {.ui = ~0} },
|
||||||
{ MODKEY, XKB_KEY_comma, focusmon, {.i = WLR_DIRECTION_LEFT} },
|
{ MODKEY, XKB_KEY_comma, focusmon, {.i = WLR_DIRECTION_LEFT} },
|
||||||
diff --git a/dwl.c b/dwl.c
|
diff --git a/dwl.c b/dwl.c
|
||||||
index 8101ffa..aabd882 100644
|
index 4cfd0fd..c3ab2ba 100644
|
||||||
--- a/dwl.c
|
--- a/dwl.c
|
||||||
+++ b/dwl.c
|
+++ b/dwl.c
|
||||||
@@ -323,6 +323,7 @@ static void requeststartdrag(struct wl_listener *listener, void *data);
|
@@ -340,6 +340,7 @@ static void requeststartdrag(struct wl_listener *listener, void *data);
|
||||||
static void requestmonstate(struct wl_listener *listener, void *data);
|
static void requestmonstate(struct wl_listener *listener, void *data);
|
||||||
static void resize(Client *c, struct wlr_box geo, int interact);
|
static void resize(Client *c, struct wlr_box geo, int interact);
|
||||||
static void run(char *startup_cmd);
|
static void run(char *startup_cmd);
|
||||||
@@ -35,7 +32,7 @@ index 8101ffa..aabd882 100644
|
|||||||
static void setcursor(struct wl_listener *listener, void *data);
|
static void setcursor(struct wl_listener *listener, void *data);
|
||||||
static void setcursorshape(struct wl_listener *listener, void *data);
|
static void setcursorshape(struct wl_listener *listener, void *data);
|
||||||
static void setfloating(Client *c, int floating);
|
static void setfloating(Client *c, int floating);
|
||||||
@@ -340,6 +341,7 @@ static void tagmon(const Arg *arg);
|
@@ -357,6 +358,7 @@ static void tagmon(const Arg *arg);
|
||||||
static void tile(Monitor *m);
|
static void tile(Monitor *m);
|
||||||
static void togglefloating(const Arg *arg);
|
static void togglefloating(const Arg *arg);
|
||||||
static void togglefullscreen(const Arg *arg);
|
static void togglefullscreen(const Arg *arg);
|
||||||
@@ -43,16 +40,16 @@ index 8101ffa..aabd882 100644
|
|||||||
static void toggletag(const Arg *arg);
|
static void toggletag(const Arg *arg);
|
||||||
static void toggleview(const Arg *arg);
|
static void toggleview(const Arg *arg);
|
||||||
static void unlocksession(struct wl_listener *listener, void *data);
|
static void unlocksession(struct wl_listener *listener, void *data);
|
||||||
@@ -440,6 +442,8 @@ static struct wl_listener request_start_drag = {.notify = requeststartdrag};
|
@@ -462,6 +464,8 @@ static struct wl_listener start_drag = {.notify = startdrag};
|
||||||
static struct wl_listener start_drag = {.notify = startdrag};
|
|
||||||
static struct wl_listener new_session_lock = {.notify = locksession};
|
static struct wl_listener new_session_lock = {.notify = locksession};
|
||||||
|
static struct wl_listener new_foreign_toplevel_capture_request = {.notify = capturerequest};
|
||||||
|
|
||||||
+static int fullscreen_adaptive_sync_enabled = 1;
|
+static int fullscreen_adaptive_sync_enabled = 1;
|
||||||
+
|
+
|
||||||
#ifdef XWAYLAND
|
#ifdef XWAYLAND
|
||||||
static void activatex11(struct wl_listener *listener, void *data);
|
static void activatex11(struct wl_listener *listener, void *data);
|
||||||
static void associatex11(struct wl_listener *listener, void *data);
|
static void associatex11(struct wl_listener *listener, void *data);
|
||||||
@@ -2300,6 +2304,43 @@ run(char *startup_cmd)
|
@@ -2453,6 +2457,43 @@ run(char *startup_cmd)
|
||||||
wl_display_run(dpy);
|
wl_display_run(dpy);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,7 +93,7 @@ index 8101ffa..aabd882 100644
|
|||||||
void
|
void
|
||||||
setcursor(struct wl_listener *listener, void *data)
|
setcursor(struct wl_listener *listener, void *data)
|
||||||
{
|
{
|
||||||
@@ -2363,10 +2404,12 @@ setfullscreen(Client *c, int fullscreen)
|
@@ -2516,10 +2557,12 @@ setfullscreen(Client *c, int fullscreen)
|
||||||
if (fullscreen) {
|
if (fullscreen) {
|
||||||
c->prev = c->geom;
|
c->prev = c->geom;
|
||||||
resize(c, c->mon->m, 0);
|
resize(c, c->mon->m, 0);
|
||||||
@@ -109,7 +106,7 @@ index 8101ffa..aabd882 100644
|
|||||||
}
|
}
|
||||||
arrange(c->mon);
|
arrange(c->mon);
|
||||||
printstatus();
|
printstatus();
|
||||||
@@ -2546,7 +2589,7 @@ setup(void)
|
@@ -2699,7 +2742,7 @@ setup(void)
|
||||||
output_layout = wlr_output_layout_create(dpy);
|
output_layout = wlr_output_layout_create(dpy);
|
||||||
wl_signal_add(&output_layout->events.change, &layout_change);
|
wl_signal_add(&output_layout->events.change, &layout_change);
|
||||||
|
|
||||||
@@ -118,7 +115,7 @@ index 8101ffa..aabd882 100644
|
|||||||
|
|
||||||
/* Configure a listener to be notified when new outputs are available on the
|
/* Configure a listener to be notified when new outputs are available on the
|
||||||
* backend. */
|
* backend. */
|
||||||
@@ -2636,8 +2679,8 @@ setup(void)
|
@@ -2795,8 +2838,8 @@ setup(void)
|
||||||
wl_signal_add(&virtual_keyboard_mgr->events.new_virtual_keyboard,
|
wl_signal_add(&virtual_keyboard_mgr->events.new_virtual_keyboard,
|
||||||
&new_virtual_keyboard);
|
&new_virtual_keyboard);
|
||||||
virtual_pointer_mgr = wlr_virtual_pointer_manager_v1_create(dpy);
|
virtual_pointer_mgr = wlr_virtual_pointer_manager_v1_create(dpy);
|
||||||
@@ -129,7 +126,7 @@ index 8101ffa..aabd882 100644
|
|||||||
|
|
||||||
seat = wlr_seat_create(dpy, "seat0");
|
seat = wlr_seat_create(dpy, "seat0");
|
||||||
wl_signal_add(&seat->events.request_set_cursor, &request_cursor);
|
wl_signal_add(&seat->events.request_set_cursor, &request_cursor);
|
||||||
@@ -2767,6 +2810,12 @@ togglefullscreen(const Arg *arg)
|
@@ -2930,6 +2973,12 @@ togglefullscreen(const Arg *arg)
|
||||||
setfullscreen(sel, !sel->isfullscreen);
|
setfullscreen(sel, !sel->isfullscreen);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,7 +139,7 @@ index 8101ffa..aabd882 100644
|
|||||||
void
|
void
|
||||||
toggletag(const Arg *arg)
|
toggletag(const Arg *arg)
|
||||||
{
|
{
|
||||||
@@ -2822,6 +2871,7 @@ unmapnotify(struct wl_listener *listener, void *data)
|
@@ -2985,6 +3034,7 @@ unmapnotify(struct wl_listener *listener, void *data)
|
||||||
{
|
{
|
||||||
/* Called when the surface is unmapped, and should no longer be shown. */
|
/* Called when the surface is unmapped, and should no longer be shown. */
|
||||||
Client *c = wl_container_of(listener, c, unmap);
|
Client *c = wl_container_of(listener, c, unmap);
|
||||||
@@ -150,7 +147,7 @@ index 8101ffa..aabd882 100644
|
|||||||
if (c == grabc) {
|
if (c == grabc) {
|
||||||
cursor_mode = CurNormal;
|
cursor_mode = CurNormal;
|
||||||
grabc = NULL;
|
grabc = NULL;
|
||||||
@@ -2837,6 +2887,9 @@ unmapnotify(struct wl_listener *listener, void *data)
|
@@ -3002,6 +3052,9 @@ unmapnotify(struct wl_listener *listener, void *data)
|
||||||
setmon(c, NULL, 0);
|
setmon(c, NULL, 0);
|
||||||
wl_list_remove(&c->flink);
|
wl_list_remove(&c->flink);
|
||||||
}
|
}
|
||||||
@@ -158,8 +155,8 @@ index 8101ffa..aabd882 100644
|
|||||||
+ if (c->isfullscreen)
|
+ if (c->isfullscreen)
|
||||||
+ set_adaptive_sync(lastmon, 0);
|
+ set_adaptive_sync(lastmon, 0);
|
||||||
|
|
||||||
wlr_scene_node_destroy(&c->scene->node);
|
if (c->foreign_toplevel_handle) {
|
||||||
printstatus();
|
wlr_ext_foreign_toplevel_handle_v1_destroy(c->foreign_toplevel_handle);
|
||||||
--
|
--
|
||||||
2.53.0
|
2.55.0
|
||||||
|
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
### Description
|
||||||
|
Largely based on [raphi](https://sr.ht/~raphi/)'s [somebar](https://sr.ht/~raphi/somebar/), this patch provides an ipc for wayland clients to get and set dwl state. The ipc is intended for status bars, but can also be scripted with tools like [dwlmsg](https://codeberg.org/julmajustus/dwlmsg).
|
||||||
|
|
||||||
|
Status information to stdout is currently disabled as dwl tends to freeze. For now, `dwlmsg -w` should act as a drop-in replacement.
|
||||||
|
|
||||||
|
Note to [pertag](../pertag/) users: apply [this](./ipcpertag.patch) for ipc tagsetting to work as expected
|
||||||
|
|
||||||
|
### Download
|
||||||
|
- [git branch](https://codeberg.org/julmajustus/dwl/src/branch/ipc-0.9)
|
||||||
|
- [main-d16036e](./ipc.patch)
|
||||||
|
|
||||||
|
### Authors
|
||||||
|
- [MadcowOG](https://github.com/MadcowOG)
|
||||||
|
- [fbushstone](https://github.com/fbushstone)
|
||||||
|
- [notchoc](https://codeberg.org/notchoc)
|
||||||
|
- [snuk](https://codeberg.org/snuk)
|
||||||
|
- [julmajustus](https://codeberg.org/julmajustus)
|
||||||
@@ -1,17 +1,17 @@
|
|||||||
From b65477621f0438b0ed6c405f74c9d15e8fb57e96 Mon Sep 17 00:00:00 2001
|
From e377ecd4c9f43282c8e795a1f3643c33cc5cabae Mon Sep 17 00:00:00 2001
|
||||||
From: choc <notchoc@disroot.org>
|
From: julmajustus <julmajustus@tutanota.com>
|
||||||
Date: Mon, 29 Jul 2024 21:26:06 +0800
|
Date: Sun, 20 Sep 2026 02:06:41 +0300
|
||||||
Subject: [PATCH] ipc: focus set_tag'd output
|
Subject: [PATCH] focus-tagset-output init
|
||||||
|
|
||||||
---
|
---
|
||||||
dwl.c | 1 +
|
dwl.c | 1 +
|
||||||
1 file changed, 1 insertion(+)
|
1 file changed, 1 insertion(+)
|
||||||
|
|
||||||
diff --git a/dwl.c b/dwl.c
|
diff --git a/dwl.c b/dwl.c
|
||||||
index 4a025f0..dcbb063 100644
|
index d24fcb3..6c52e78 100644
|
||||||
--- a/dwl.c
|
--- a/dwl.c
|
||||||
+++ b/dwl.c
|
+++ b/dwl.c
|
||||||
@@ -1533,6 +1533,7 @@ dwl_ipc_output_set_tags(struct wl_client *client, struct wl_resource *resource,
|
@@ -1707,6 +1707,7 @@ dwl_ipc_output_set_tags(struct wl_client *client, struct wl_resource *resource,
|
||||||
if (!ipc_output)
|
if (!ipc_output)
|
||||||
return;
|
return;
|
||||||
monitor = ipc_output->mon;
|
monitor = ipc_output->mon;
|
||||||
@@ -20,5 +20,5 @@ index 4a025f0..dcbb063 100644
|
|||||||
if (!newtags || newtags == monitor->tagset[monitor->seltags])
|
if (!newtags || newtags == monitor->tagset[monitor->seltags])
|
||||||
return;
|
return;
|
||||||
--
|
--
|
||||||
2.43.0
|
2.55.0
|
||||||
|
|
||||||
@@ -1,40 +1,33 @@
|
|||||||
From 6c6d655b68770ce82a24fde9b58c4d97b672553a Mon Sep 17 00:00:00 2001
|
From ef4e12f827e50bbbe4b1cb211cdf1f5420fc87bd Mon Sep 17 00:00:00 2001
|
||||||
From: choc <notchoc@proton.me>
|
From: julmajustus <julmajustus@tutanota.com>
|
||||||
Date: Mon, 23 Oct 2023 10:35:17 +0800
|
Date: Sun, 20 Sep 2026 02:01:46 +0300
|
||||||
Subject: [PATCH] implement dwl-ipc-unstable-v2
|
Subject: [PATCH] ipc init
|
||||||
https://codeberg.org/dwl/dwl-patches/wiki/ipc
|
|
||||||
|
|
||||||
---
|
---
|
||||||
Makefile | 14 +-
|
Makefile | 13 +-
|
||||||
config.def.h | 1 +
|
config.def.h | 1 +
|
||||||
dwl.c | 257 ++++++++++++++++++++++++++----
|
dwl.c | 266 ++++++++++++++++++++++++++----
|
||||||
protocols/dwl-ipc-unstable-v2.xml | 181 +++++++++++++++++++++
|
protocols/dwl-ipc-unstable-v2.xml | 191 +++++++++++++++++++++
|
||||||
4 files changed, 419 insertions(+), 34 deletions(-)
|
4 files changed, 437 insertions(+), 34 deletions(-)
|
||||||
create mode 100644 protocols/dwl-ipc-unstable-v2.xml
|
create mode 100644 protocols/dwl-ipc-unstable-v2.xml
|
||||||
|
|
||||||
diff --git a/Makefile b/Makefile
|
diff --git a/Makefile b/Makefile
|
||||||
index 8db7409..a79a080 100644
|
index 8304245..b71571f 100644
|
||||||
--- a/Makefile
|
--- a/Makefile
|
||||||
+++ b/Makefile
|
+++ b/Makefile
|
||||||
@@ -17,12 +17,14 @@ DWLCFLAGS = `$(PKG_CONFIG) --cflags $(PKGS)` $(WLR_INCS) $(DWLCPPFLAGS) $(DWLDEV
|
@@ -20,8 +20,9 @@ all: dwl
|
||||||
LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` $(WLR_LIBS) -lm $(LIBS)
|
dwl: dwl.c client.h config.h ime.h util.h config.mk cursor-shape-v1-protocol.h \
|
||||||
|
ext-image-copy-capture-v1-protocol.h \
|
||||||
all: dwl
|
|
||||||
-dwl: dwl.o util.o
|
|
||||||
- $(CC) dwl.o util.o $(DWLCFLAGS) $(LDFLAGS) $(LDLIBS) -o $@
|
|
||||||
+dwl: dwl.o util.o dwl-ipc-unstable-v2-protocol.o
|
|
||||||
+ $(CC) dwl.o util.o dwl-ipc-unstable-v2-protocol.o $(DWLCFLAGS) $(LDFLAGS) $(LDLIBS) -o $@
|
|
||||||
dwl.o: dwl.c client.h config.h config.mk cursor-shape-v1-protocol.h \
|
|
||||||
pointer-constraints-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.h \
|
pointer-constraints-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.h \
|
||||||
- wlr-output-power-management-unstable-v1-protocol.h xdg-shell-protocol.h
|
- wlr-output-power-management-unstable-v1-protocol.h xdg-shell-protocol.h
|
||||||
|
- $(CC) dwl.c $(DWLCFLAGS) $(LDFLAGS) $(LDLIBS) -o $@
|
||||||
+ wlr-output-power-management-unstable-v1-protocol.h xdg-shell-protocol.h \
|
+ wlr-output-power-management-unstable-v1-protocol.h xdg-shell-protocol.h \
|
||||||
+ dwl-ipc-unstable-v2-protocol.h
|
+ dwl-ipc-unstable-v2-protocol.h dwl-ipc-unstable-v2-protocol.c
|
||||||
util.o: util.c util.h
|
+ $(CC) dwl.c dwl-ipc-unstable-v2-protocol.c $(DWLCFLAGS) $(LDFLAGS) $(LDLIBS) -o $@
|
||||||
+dwl-ipc-unstable-v2-protocol.o: dwl-ipc-unstable-v2-protocol.c dwl-ipc-unstable-v2-protocol.h
|
|
||||||
|
|
||||||
# wayland-scanner is a tool which generates C headers and rigging for Wayland
|
# wayland-scanner is a tool which generates C headers and rigging for Wayland
|
||||||
# protocols, which are specified in XML. wlroots requires you to rig these up
|
# protocols, which are specified in XML. wlroots requires you to rig these up
|
||||||
@@ -45,6 +47,12 @@ wlr-output-power-management-unstable-v1-protocol.h:
|
@@ -47,11 +48,17 @@ wlr-output-power-management-unstable-v1-protocol.h:
|
||||||
xdg-shell-protocol.h:
|
xdg-shell-protocol.h:
|
||||||
$(WAYLAND_SCANNER) server-header \
|
$(WAYLAND_SCANNER) server-header \
|
||||||
$(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@
|
$(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@
|
||||||
@@ -47,11 +40,17 @@ index 8db7409..a79a080 100644
|
|||||||
|
|
||||||
config.h:
|
config.h:
|
||||||
cp config.def.h $@
|
cp config.def.h $@
|
||||||
|
clean:
|
||||||
|
- rm -f dwl *.o *-protocol.h
|
||||||
|
+ rm -f dwl *.o *-protocol.h *-protocol.c
|
||||||
|
|
||||||
|
dist: clean
|
||||||
|
mkdir -p dwl-$(VERSION)
|
||||||
diff --git a/config.def.h b/config.def.h
|
diff --git a/config.def.h b/config.def.h
|
||||||
index 22d2171..1593033 100644
|
index 13c5322..998c715 100644
|
||||||
--- a/config.def.h
|
--- a/config.def.h
|
||||||
+++ b/config.def.h
|
+++ b/config.def.h
|
||||||
@@ -127,6 +127,7 @@ static const Key keys[] = {
|
@@ -123,6 +123,7 @@ static const Key keys[] = {
|
||||||
/* modifier key function argument */
|
/* modifier key function argument */
|
||||||
{ MODKEY, XKB_KEY_p, spawn, {.v = menucmd} },
|
{ MODKEY, XKB_KEY_p, spawn, {.v = menucmd} },
|
||||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} },
|
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} },
|
||||||
@@ -60,19 +59,19 @@ index 22d2171..1593033 100644
|
|||||||
{ MODKEY, XKB_KEY_k, focusstack, {.i = -1} },
|
{ MODKEY, XKB_KEY_k, focusstack, {.i = -1} },
|
||||||
{ MODKEY, XKB_KEY_i, incnmaster, {.i = +1} },
|
{ MODKEY, XKB_KEY_i, incnmaster, {.i = +1} },
|
||||||
diff --git a/dwl.c b/dwl.c
|
diff --git a/dwl.c b/dwl.c
|
||||||
index 8a587d1..7a4949b 100644
|
index 4cfd0fd..d24fcb3 100644
|
||||||
--- a/dwl.c
|
--- a/dwl.c
|
||||||
+++ b/dwl.c
|
+++ b/dwl.c
|
||||||
@@ -68,6 +68,7 @@
|
@@ -76,6 +76,7 @@
|
||||||
#include <xcb/xcb_icccm.h>
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "xdg-shell-protocol.h"
|
||||||
+#include "dwl-ipc-unstable-v2-protocol.h"
|
+#include "dwl-ipc-unstable-v2-protocol.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
/* macros */
|
/* macros */
|
||||||
@@ -144,6 +145,12 @@ typedef struct {
|
@@ -161,6 +162,12 @@ typedef struct {
|
||||||
uint32_t resize; /* configure serial of a pending resize */
|
int isfloating, isurgent, isfullscreen;
|
||||||
} Client;
|
} Client;
|
||||||
|
|
||||||
+typedef struct {
|
+typedef struct {
|
||||||
@@ -84,7 +83,7 @@ index 8a587d1..7a4949b 100644
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t mod;
|
uint32_t mod;
|
||||||
xkb_keysym_t keysym;
|
xkb_keysym_t keysym;
|
||||||
@@ -189,6 +196,7 @@ typedef struct {
|
@@ -205,6 +212,7 @@ typedef struct {
|
||||||
|
|
||||||
struct Monitor {
|
struct Monitor {
|
||||||
struct wl_list link;
|
struct wl_list link;
|
||||||
@@ -92,8 +91,8 @@ index 8a587d1..7a4949b 100644
|
|||||||
struct wlr_output *wlr_output;
|
struct wlr_output *wlr_output;
|
||||||
struct wlr_scene_output *scene_output;
|
struct wlr_scene_output *scene_output;
|
||||||
struct wlr_scene_rect *fullscreen_bg; /* See createmon() for info */
|
struct wlr_scene_rect *fullscreen_bg; /* See createmon() for info */
|
||||||
@@ -286,6 +294,17 @@ static void destroysessionlock(struct wl_listener *listener, void *data);
|
@@ -303,6 +311,17 @@ static void destroypointerconstraint(struct wl_listener *listener, void *data);
|
||||||
static void destroysessionmgr(struct wl_listener *listener, void *data);
|
static void destroysessionlock(struct wl_listener *listener, void *data);
|
||||||
static void destroykeyboardgroup(struct wl_listener *listener, void *data);
|
static void destroykeyboardgroup(struct wl_listener *listener, void *data);
|
||||||
static Monitor *dirtomon(enum wlr_direction dir);
|
static Monitor *dirtomon(enum wlr_direction dir);
|
||||||
+static void dwl_ipc_manager_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id);
|
+static void dwl_ipc_manager_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id);
|
||||||
@@ -110,7 +109,7 @@ index 8a587d1..7a4949b 100644
|
|||||||
static void focusclient(Client *c, int lift);
|
static void focusclient(Client *c, int lift);
|
||||||
static void focusmon(const Arg *arg);
|
static void focusmon(const Arg *arg);
|
||||||
static void focusstack(const Arg *arg);
|
static void focusstack(const Arg *arg);
|
||||||
@@ -338,6 +357,7 @@ static void startdrag(struct wl_listener *listener, void *data);
|
@@ -355,6 +374,7 @@ static void startdrag(struct wl_listener *listener, void *data);
|
||||||
static void tag(const Arg *arg);
|
static void tag(const Arg *arg);
|
||||||
static void tagmon(const Arg *arg);
|
static void tagmon(const Arg *arg);
|
||||||
static void tile(Monitor *m);
|
static void tile(Monitor *m);
|
||||||
@@ -118,9 +117,9 @@ index 8a587d1..7a4949b 100644
|
|||||||
static void togglefloating(const Arg *arg);
|
static void togglefloating(const Arg *arg);
|
||||||
static void togglefullscreen(const Arg *arg);
|
static void togglefullscreen(const Arg *arg);
|
||||||
static void toggletag(const Arg *arg);
|
static void toggletag(const Arg *arg);
|
||||||
@@ -411,6 +431,9 @@ static struct wlr_box sgeom;
|
@@ -462,6 +482,9 @@ static struct wl_listener start_drag = {.notify = startdrag};
|
||||||
static struct wl_list mons;
|
static struct wl_listener new_session_lock = {.notify = locksession};
|
||||||
static Monitor *selmon;
|
static struct wl_listener new_foreign_toplevel_capture_request = {.notify = capturerequest};
|
||||||
|
|
||||||
+static struct zdwl_ipc_manager_v2_interface dwl_manager_implementation = {.release = dwl_ipc_manager_release, .get_output = dwl_ipc_manager_get_output};
|
+static struct zdwl_ipc_manager_v2_interface dwl_manager_implementation = {.release = dwl_ipc_manager_release, .get_output = dwl_ipc_manager_get_output};
|
||||||
+static struct zdwl_ipc_output_v2_interface dwl_output_implementation = {.release = dwl_ipc_output_release, .set_tags = dwl_ipc_output_set_tags, .set_layout = dwl_ipc_output_set_layout, .set_client_tags = dwl_ipc_output_set_client_tags};
|
+static struct zdwl_ipc_output_v2_interface dwl_output_implementation = {.release = dwl_ipc_output_release, .set_tags = dwl_ipc_output_set_tags, .set_layout = dwl_ipc_output_set_layout, .set_client_tags = dwl_ipc_output_set_client_tags};
|
||||||
@@ -128,7 +127,7 @@ index 8a587d1..7a4949b 100644
|
|||||||
#ifdef XWAYLAND
|
#ifdef XWAYLAND
|
||||||
static void activatex11(struct wl_listener *listener, void *data);
|
static void activatex11(struct wl_listener *listener, void *data);
|
||||||
static void associatex11(struct wl_listener *listener, void *data);
|
static void associatex11(struct wl_listener *listener, void *data);
|
||||||
@@ -703,6 +726,10 @@ cleanupmon(struct wl_listener *listener, void *data)
|
@@ -823,6 +846,10 @@ cleanupmon(struct wl_listener *listener, void *data)
|
||||||
LayerSurface *l, *tmp;
|
LayerSurface *l, *tmp;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
@@ -139,7 +138,7 @@ index 8a587d1..7a4949b 100644
|
|||||||
/* m->layers[i] are intentionally not unlinked */
|
/* m->layers[i] are intentionally not unlinked */
|
||||||
for (i = 0; i < LENGTH(m->layers); i++) {
|
for (i = 0; i < LENGTH(m->layers); i++) {
|
||||||
wl_list_for_each_safe(l, tmp, &m->layers[i], link)
|
wl_list_for_each_safe(l, tmp, &m->layers[i], link)
|
||||||
@@ -983,6 +1010,8 @@ createmon(struct wl_listener *listener, void *data)
|
@@ -1150,6 +1177,8 @@ createmon(struct wl_listener *listener, void *data)
|
||||||
m = wlr_output->data = ecalloc(1, sizeof(*m));
|
m = wlr_output->data = ecalloc(1, sizeof(*m));
|
||||||
m->wlr_output = wlr_output;
|
m->wlr_output = wlr_output;
|
||||||
|
|
||||||
@@ -148,7 +147,7 @@ index 8a587d1..7a4949b 100644
|
|||||||
for (i = 0; i < LENGTH(m->layers); i++)
|
for (i = 0; i < LENGTH(m->layers); i++)
|
||||||
wl_list_init(&m->layers[i]);
|
wl_list_init(&m->layers[i]);
|
||||||
|
|
||||||
@@ -1334,6 +1363,192 @@ dirtomon(enum wlr_direction dir)
|
@@ -1504,6 +1533,199 @@ dirtomon(enum wlr_direction dir)
|
||||||
return selmon;
|
return selmon;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,13 +217,13 @@ index 8a587d1..7a4949b 100644
|
|||||||
+{
|
+{
|
||||||
+ Monitor *monitor = ipc_output->mon;
|
+ Monitor *monitor = ipc_output->mon;
|
||||||
+ Client *c, *focused;
|
+ Client *c, *focused;
|
||||||
+ int tagmask, state, numclients, focused_client, tag;
|
+ int tagmask, state, numclients, is_focused_client, tag;
|
||||||
+ const char *title, *appid;
|
+ const char *title, *appid;
|
||||||
+ focused = focustop(monitor);
|
+ focused = focustop(monitor);
|
||||||
+ zdwl_ipc_output_v2_send_active(ipc_output->resource, monitor == selmon);
|
+ zdwl_ipc_output_v2_send_active(ipc_output->resource, monitor == selmon);
|
||||||
+
|
+
|
||||||
+ for (tag = 0 ; tag < TAGCOUNT; tag++) {
|
+ for (tag = 0 ; tag < TAGCOUNT; tag++) {
|
||||||
+ numclients = state = focused_client = 0;
|
+ numclients = state = is_focused_client = 0;
|
||||||
+ tagmask = 1 << tag;
|
+ tagmask = 1 << tag;
|
||||||
+ if ((tagmask & monitor->tagset[monitor->seltags]) != 0)
|
+ if ((tagmask & monitor->tagset[monitor->seltags]) != 0)
|
||||||
+ state |= ZDWL_IPC_OUTPUT_V2_TAG_STATE_ACTIVE;
|
+ state |= ZDWL_IPC_OUTPUT_V2_TAG_STATE_ACTIVE;
|
||||||
@@ -235,13 +234,13 @@ index 8a587d1..7a4949b 100644
|
|||||||
+ if (!(c->tags & tagmask))
|
+ if (!(c->tags & tagmask))
|
||||||
+ continue;
|
+ continue;
|
||||||
+ if (c == focused)
|
+ if (c == focused)
|
||||||
+ focused_client = 1;
|
+ is_focused_client = 1;
|
||||||
+ if (c->isurgent)
|
+ if (c->isurgent)
|
||||||
+ state |= ZDWL_IPC_OUTPUT_V2_TAG_STATE_URGENT;
|
+ state |= ZDWL_IPC_OUTPUT_V2_TAG_STATE_URGENT;
|
||||||
+
|
+
|
||||||
+ numclients++;
|
+ numclients++;
|
||||||
+ }
|
+ }
|
||||||
+ zdwl_ipc_output_v2_send_tag(ipc_output->resource, tag, state, numclients, focused_client);
|
+ zdwl_ipc_output_v2_send_tag(ipc_output->resource, tag, state, numclients, is_focused_client);
|
||||||
+ }
|
+ }
|
||||||
+ title = focused ? client_get_title(focused) : "";
|
+ title = focused ? client_get_title(focused) : "";
|
||||||
+ appid = focused ? client_get_appid(focused) : "";
|
+ appid = focused ? client_get_appid(focused) : "";
|
||||||
@@ -256,6 +255,13 @@ index 8a587d1..7a4949b 100644
|
|||||||
+ if (wl_resource_get_version(ipc_output->resource) >= ZDWL_IPC_OUTPUT_V2_FLOATING_SINCE_VERSION) {
|
+ if (wl_resource_get_version(ipc_output->resource) >= ZDWL_IPC_OUTPUT_V2_FLOATING_SINCE_VERSION) {
|
||||||
+ zdwl_ipc_output_v2_send_floating(ipc_output->resource, focused ? focused->isfloating : 0);
|
+ zdwl_ipc_output_v2_send_floating(ipc_output->resource, focused ? focused->isfloating : 0);
|
||||||
+ }
|
+ }
|
||||||
|
+ if (wl_resource_get_version(ipc_output->resource) >= ZDWL_IPC_OUTPUT_V2_FULLSCREEN_SINCE_VERSION) {
|
||||||
|
+ zdwl_ipc_output_v2_send_focused_geometry(ipc_output->resource,
|
||||||
|
+ focused ? focused->geom.x : 0,
|
||||||
|
+ focused ? focused->geom.y : 0,
|
||||||
|
+ focused ? focused->geom.width : 0,
|
||||||
|
+ focused ? focused->geom.height : 0);
|
||||||
|
+ }
|
||||||
+ zdwl_ipc_output_v2_send_frame(ipc_output->resource);
|
+ zdwl_ipc_output_v2_send_frame(ipc_output->resource);
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
@@ -341,13 +347,13 @@ index 8a587d1..7a4949b 100644
|
|||||||
void
|
void
|
||||||
focusclient(Client *c, int lift)
|
focusclient(Client *c, int lift)
|
||||||
{
|
{
|
||||||
@@ -2033,38 +2248,9 @@ void
|
@@ -2257,38 +2479,9 @@ void
|
||||||
printstatus(void)
|
printstatus(void)
|
||||||
{
|
{
|
||||||
Monitor *m = NULL;
|
Monitor *m = NULL;
|
||||||
- Client *c;
|
- Client *c;
|
||||||
- uint32_t occ, urg, sel;
|
- uint32_t occ, urg, sel;
|
||||||
|
-
|
||||||
- wl_list_for_each(m, &mons, link) {
|
- wl_list_for_each(m, &mons, link) {
|
||||||
- occ = urg = 0;
|
- occ = urg = 0;
|
||||||
- wl_list_for_each(c, &clients, link) {
|
- wl_list_for_each(c, &clients, link) {
|
||||||
@@ -370,7 +376,7 @@ index 8a587d1..7a4949b 100644
|
|||||||
- printf("%s floating \n", m->wlr_output->name);
|
- printf("%s floating \n", m->wlr_output->name);
|
||||||
- sel = 0;
|
- sel = 0;
|
||||||
- }
|
- }
|
||||||
-
|
|
||||||
- printf("%s selmon %u\n", m->wlr_output->name, m == selmon);
|
- printf("%s selmon %u\n", m->wlr_output->name, m == selmon);
|
||||||
- printf("%s tags %"PRIu32" %"PRIu32" %"PRIu32" %"PRIu32"\n",
|
- printf("%s tags %"PRIu32" %"PRIu32" %"PRIu32" %"PRIu32"\n",
|
||||||
- m->wlr_output->name, occ, m->tagset[m->seltags], sel, urg);
|
- m->wlr_output->name, occ, m->tagset[m->seltags], sel, urg);
|
||||||
@@ -382,16 +388,18 @@ index 8a587d1..7a4949b 100644
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -2584,6 +2770,8 @@ setup(void)
|
@@ -2816,6 +3009,10 @@ setup(void)
|
||||||
LISTEN_STATIC(&output_mgr->events.apply, outputmgrapply);
|
text_input_manager = wlr_text_input_manager_v3_create(dpy);
|
||||||
LISTEN_STATIC(&output_mgr->events.test, outputmgrtest);
|
input_method_relay = input_method_relay_create();
|
||||||
|
|
||||||
|
+ wl_global_create(dpy, &zdwl_ipc_manager_v2_interface, 2, NULL, dwl_ipc_manager_bind);
|
||||||
|
+
|
||||||
+ wl_global_create(dpy, &zdwl_ipc_manager_v2_interface, 2, NULL, dwl_ipc_manager_bind);
|
+ wl_global_create(dpy, &zdwl_ipc_manager_v2_interface, 2, NULL, dwl_ipc_manager_bind);
|
||||||
+
|
+
|
||||||
/* Make sure XWayland clients don't connect to the parent X server,
|
/* Make sure XWayland clients don't connect to the parent X server,
|
||||||
* e.g when running in the x11 backend or the wayland backend and the
|
* e.g when running in the x11 backend or the wayland backend and the
|
||||||
* compositor has Xwayland support */
|
* compositor has Xwayland support */
|
||||||
@@ -2681,6 +2869,13 @@ tile(Monitor *m)
|
@@ -2913,6 +3110,13 @@ tile(Monitor *m)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -407,10 +415,10 @@ index 8a587d1..7a4949b 100644
|
|||||||
{
|
{
|
||||||
diff --git a/protocols/dwl-ipc-unstable-v2.xml b/protocols/dwl-ipc-unstable-v2.xml
|
diff --git a/protocols/dwl-ipc-unstable-v2.xml b/protocols/dwl-ipc-unstable-v2.xml
|
||||||
new file mode 100644
|
new file mode 100644
|
||||||
index 0000000..0a6e7e5
|
index 0000000..07cc1c2
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/protocols/dwl-ipc-unstable-v2.xml
|
+++ b/protocols/dwl-ipc-unstable-v2.xml
|
||||||
@@ -0,0 +1,181 @@
|
@@ -0,0 +1,191 @@
|
||||||
+<?xml version="1.0" encoding="utf-8"?>
|
+<?xml version="1.0" encoding="utf-8"?>
|
||||||
+<!--
|
+<!--
|
||||||
+This is largely ripped from somebar's ipc patchset; just with some personal modifications.
|
+This is largely ripped from somebar's ipc patchset; just with some personal modifications.
|
||||||
@@ -437,7 +445,7 @@ index 0000000..0a6e7e5
|
|||||||
+ This interface is exposed as a global in wl_registry.
|
+ This interface is exposed as a global in wl_registry.
|
||||||
+
|
+
|
||||||
+ Clients can use this interface to get a dwl_ipc_output.
|
+ Clients can use this interface to get a dwl_ipc_output.
|
||||||
+ After binding the client will receive the dwl_ipc_manager.tags and dwl_ipc_manager.layout events.
|
+ After binding the client will recieve the dwl_ipc_manager.tags and dwl_ipc_manager.layout events.
|
||||||
+ The dwl_ipc_manager.tags and dwl_ipc_manager.layout events expose tags and layouts to the client.
|
+ The dwl_ipc_manager.tags and dwl_ipc_manager.layout events expose tags and layouts to the client.
|
||||||
+ </description>
|
+ </description>
|
||||||
+
|
+
|
||||||
@@ -459,7 +467,7 @@ index 0000000..0a6e7e5
|
|||||||
+ <event name="tags">
|
+ <event name="tags">
|
||||||
+ <description summary="Announces tag amount">
|
+ <description summary="Announces tag amount">
|
||||||
+ This event is sent after binding.
|
+ This event is sent after binding.
|
||||||
+ A roundtrip after binding guarantees the client received all tags.
|
+ A roundtrip after binding guarantees the client recieved all tags.
|
||||||
+ </description>
|
+ </description>
|
||||||
+ <arg name="amount" type="uint"/>
|
+ <arg name="amount" type="uint"/>
|
||||||
+ </event>
|
+ </event>
|
||||||
@@ -467,7 +475,7 @@ index 0000000..0a6e7e5
|
|||||||
+ <event name="layout">
|
+ <event name="layout">
|
||||||
+ <description summary="Announces a layout">
|
+ <description summary="Announces a layout">
|
||||||
+ This event is sent after binding.
|
+ This event is sent after binding.
|
||||||
+ A roundtrip after binding guarantees the client received all layouts.
|
+ A roundtrip after binding guarantees the client recieved all layouts.
|
||||||
+ </description>
|
+ </description>
|
||||||
+ <arg name="name" type="string"/>
|
+ <arg name="name" type="string"/>
|
||||||
+ </event>
|
+ </event>
|
||||||
@@ -573,7 +581,7 @@ index 0000000..0a6e7e5
|
|||||||
+
|
+
|
||||||
+ <request name="set_layout">
|
+ <request name="set_layout">
|
||||||
+ <description summary="Set the layout of this output"/>
|
+ <description summary="Set the layout of this output"/>
|
||||||
+ <arg name="index" type="uint" summary="index of a layout received by dwl_ipc_manager.layout"/>
|
+ <arg name="index" type="uint" summary="index of a layout recieved by dwl_ipc_manager.layout"/>
|
||||||
+ </request>
|
+ </request>
|
||||||
+
|
+
|
||||||
+ <!-- Version 2 -->
|
+ <!-- Version 2 -->
|
||||||
@@ -590,8 +598,18 @@ index 0000000..0a6e7e5
|
|||||||
+ </description>
|
+ </description>
|
||||||
+ <arg name="is_floating" type="uint" summary="If the selected client is floating. Nonzero is valid, zero invalid"/>
|
+ <arg name="is_floating" type="uint" summary="If the selected client is floating. Nonzero is valid, zero invalid"/>
|
||||||
+ </event>
|
+ </event>
|
||||||
|
+
|
||||||
|
+ <event name="focused_geometry" since="2">
|
||||||
|
+ <description summary="Send focused client geometry">
|
||||||
|
+ Sends the focused client's geometry (x, y, width, and height) to the client.
|
||||||
|
+ </description>
|
||||||
|
+ <arg name="x" type="int" summary="X coordinate of the focused client"/>
|
||||||
|
+ <arg name="y" type="int" summary="Y coordinate of the focused client"/>
|
||||||
|
+ <arg name="width" type="int" summary="Width of the focused client"/>
|
||||||
|
+ <arg name="height" type="int" summary="Height of the focused client"/>
|
||||||
|
+ </event>
|
||||||
+ </interface>
|
+ </interface>
|
||||||
+</protocol>
|
+</protocol>
|
||||||
--
|
--
|
||||||
2.43.0
|
2.55.0
|
||||||
|
|
||||||
@@ -1,17 +1,17 @@
|
|||||||
From c7d77ff4dec1da5a68b4da8aa42d4ed78dc41a00 Mon Sep 17 00:00:00 2001
|
From 90a2d3941de8842074157a7144c901eb316ba0e2 Mon Sep 17 00:00:00 2001
|
||||||
From: choc <notchoc@proton.me>
|
From: julmajustus <julmajustus@tutanota.com>
|
||||||
Date: Thu, 14 Mar 2024 11:18:37 +0800
|
Date: Sun, 20 Sep 2026 02:04:17 +0300
|
||||||
Subject: [PATCH] fix ipc to work with pertag
|
Subject: [PATCH] ipcpertag init
|
||||||
|
|
||||||
---
|
---
|
||||||
dwl.c | 50 +++++++++++++++++++++++++++++++++++---------------
|
dwl.c | 50 +++++++++++++++++++++++++++++++++++---------------
|
||||||
1 file changed, 35 insertions(+), 15 deletions(-)
|
1 file changed, 35 insertions(+), 15 deletions(-)
|
||||||
|
|
||||||
diff --git a/dwl.c b/dwl.c
|
diff --git a/dwl.c b/dwl.c
|
||||||
index a1a7809..d86e6e2 100644
|
index d24fcb3..b43843e 100644
|
||||||
--- a/dwl.c
|
--- a/dwl.c
|
||||||
+++ b/dwl.c
|
+++ b/dwl.c
|
||||||
@@ -1526,28 +1526,37 @@ void
|
@@ -1679,28 +1679,37 @@ void
|
||||||
dwl_ipc_output_set_layout(struct wl_client *client, struct wl_resource *resource, uint32_t index)
|
dwl_ipc_output_set_layout(struct wl_client *client, struct wl_resource *resource, uint32_t index)
|
||||||
{
|
{
|
||||||
DwlIpcOutput *ipc_output;
|
DwlIpcOutput *ipc_output;
|
||||||
@@ -57,7 +57,7 @@ index a1a7809..d86e6e2 100644
|
|||||||
unsigned int newtags = tagmask & TAGMASK;
|
unsigned int newtags = tagmask & TAGMASK;
|
||||||
|
|
||||||
ipc_output = wl_resource_get_user_data(resource);
|
ipc_output = wl_resource_get_user_data(resource);
|
||||||
@@ -1555,16 +1564,27 @@ dwl_ipc_output_set_tags(struct wl_client *client, struct wl_resource *resource,
|
@@ -1708,16 +1717,27 @@ dwl_ipc_output_set_tags(struct wl_client *client, struct wl_resource *resource,
|
||||||
return;
|
return;
|
||||||
monitor = ipc_output->mon;
|
monitor = ipc_output->mon;
|
||||||
|
|
||||||
@@ -93,5 +93,5 @@ index a1a7809..d86e6e2 100644
|
|||||||
|
|
||||||
void
|
void
|
||||||
--
|
--
|
||||||
2.43.0
|
2.55.0
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
### Description
|
### Description
|
||||||
|
|
||||||
# simple_scratchpad — A very simple scratchpad utility.
|
# simple_scratchpad - A very simple scratchpad utility.
|
||||||
|
|
||||||
Adds functions to add, toggle and remove clients to/from scratchpad client lists.
|
Adds functions to add, toggle and remove clients to/from scratchpad client lists.
|
||||||

|

|
||||||
@@ -21,9 +21,9 @@ Adds functions to add, toggle and remove clients to/from scratchpad client lists
|
|||||||
|
|
||||||
|
|
||||||
### Download
|
### Download
|
||||||
- [git branch](https://codeberg.org/julmajustus/dwl/src/branch/simple_scratchpad)
|
- [git branch](https://codeberg.org/julmajustus/dwl/src/branch/simple_scratchpad-0.9)
|
||||||
- [scratchpad-wlroots-next-d41ecb7.patch](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/simple_scratchpad/simple_scratchpad-wlroots-next-d41ecb7.patch)
|
- [main-d16036e](./simple_scratchpad-d16036e.patch)
|
||||||
- [scratchpad-v0.8.patch](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/simple_scratchpad/simple_scratchpad-v0.8.patch)
|
- [scratchpad-v0.8.patch](./simple_scratchpad-v0.8.patch)
|
||||||
|
|
||||||
### Authors
|
### Authors
|
||||||
- [julmajustus](https://codeberg.org/julmajustus)
|
- [julmajustus](https://codeberg.org/julmajustus)
|
||||||
|
|||||||
+54
-39
@@ -1,21 +1,35 @@
|
|||||||
From be4f7488eac6ea502e0e9d1cc5595e01d97cb345 Mon Sep 17 00:00:00 2001
|
From da5b4335fab5ca589ac6a9e569aa99aaa091eae9 Mon Sep 17 00:00:00 2001
|
||||||
From: julmajustus <julmajustus@tutanota.com>
|
From: julmajustus <julmajustus@tutanota.com>
|
||||||
Date: Thu, 21 May 2026 00:28:41 +0300
|
Date: Sun, 20 Sep 2026 02:23:44 +0300
|
||||||
Subject: [PATCH] simple_scratchpad: Spring update scratchpad V2
|
Subject: [PATCH] simple_scratchpad d16036e refactor
|
||||||
|
|
||||||
- Added support for multiple scratchpads
|
|
||||||
---
|
---
|
||||||
|
Makefile | 3 +-
|
||||||
config.def.h | 7 ++++
|
config.def.h | 7 ++++
|
||||||
dwl.c | 43 +++++++++++++++++++++--
|
dwl.c | 40 +++++++++++++++++++-
|
||||||
simple_scratchpad.c | 85 +++++++++++++++++++++++++++++++++++++++++++++
|
simple_scratchpad.h | 89 +++++++++++++++++++++++++++++++++++++++++++++
|
||||||
3 files changed, 133 insertions(+), 2 deletions(-)
|
4 files changed, 136 insertions(+), 3 deletions(-)
|
||||||
create mode 100644 simple_scratchpad.c
|
create mode 100644 simple_scratchpad.h
|
||||||
|
|
||||||
|
diff --git a/Makefile b/Makefile
|
||||||
|
index 8304245..4592dff 100644
|
||||||
|
--- a/Makefile
|
||||||
|
+++ b/Makefile
|
||||||
|
@@ -20,7 +20,8 @@ all: dwl
|
||||||
|
dwl: dwl.c client.h config.h ime.h util.h config.mk cursor-shape-v1-protocol.h \
|
||||||
|
ext-image-copy-capture-v1-protocol.h \
|
||||||
|
pointer-constraints-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.h \
|
||||||
|
- wlr-output-power-management-unstable-v1-protocol.h xdg-shell-protocol.h
|
||||||
|
+ wlr-output-power-management-unstable-v1-protocol.h xdg-shell-protocol.h \
|
||||||
|
+ simple_scratchpad.h
|
||||||
|
$(CC) dwl.c $(DWLCFLAGS) $(LDFLAGS) $(LDLIBS) -o $@
|
||||||
|
|
||||||
|
# wayland-scanner is a tool which generates C headers and rigging for Wayland
|
||||||
diff --git a/config.def.h b/config.def.h
|
diff --git a/config.def.h b/config.def.h
|
||||||
index 8a6eda0..a527e09 100644
|
index 13c5322..acd44d9 100644
|
||||||
--- a/config.def.h
|
--- a/config.def.h
|
||||||
+++ b/config.def.h
|
+++ b/config.def.h
|
||||||
@@ -14,6 +14,7 @@ static const float urgentcolor[] = COLOR(0xff0000ff);
|
@@ -15,6 +15,7 @@ static const float urgentcolor[] = COLOR(0xff0000ff);
|
||||||
/* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */
|
/* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */
|
||||||
static const float fullscreen_bg[] = {0.0f, 0.0f, 0.0f, 1.0f}; /* You can also use glsl colors */
|
static const float fullscreen_bg[] = {0.0f, 0.0f, 0.0f, 1.0f}; /* You can also use glsl colors */
|
||||||
|
|
||||||
@@ -35,27 +49,27 @@ index 8a6eda0..a527e09 100644
|
|||||||
{ MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} },
|
{ MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} },
|
||||||
@@ -144,6 +148,9 @@ static const Key keys[] = {
|
@@ -144,6 +148,9 @@ static const Key keys[] = {
|
||||||
{ MODKEY, XKB_KEY_period, focusmon, {.i = WLR_DIRECTION_RIGHT} },
|
{ 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_comma, tagmon, {.i = WLR_DIRECTION_LEFT} },
|
||||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_greater, tagmon, {.i = WLR_DIRECTION_RIGHT} },
|
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_period, tagmon, {.i = WLR_DIRECTION_RIGHT} },
|
||||||
+ { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_1, setscratchpad, {.i = 0} },
|
+ { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_1, setscratchpad, {.i = 0} },
|
||||||
+ { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_2, setscratchpad, {.i = 1} },
|
+ { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_2, setscratchpad, {.i = 1} },
|
||||||
+ { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_3, setscratchpad, {.i = 2} },
|
+ { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_3, setscratchpad, {.i = 2} },
|
||||||
TAGKEYS( XKB_KEY_1, XKB_KEY_exclam, 0),
|
TAGKEYS( XKB_KEY_1, 0),
|
||||||
TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1),
|
TAGKEYS( XKB_KEY_2, 1),
|
||||||
TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2),
|
TAGKEYS( XKB_KEY_3, 2),
|
||||||
diff --git a/dwl.c b/dwl.c
|
diff --git a/dwl.c b/dwl.c
|
||||||
index 8101ffa..1c858a8 100644
|
index 4cfd0fd..91a7628 100644
|
||||||
--- a/dwl.c
|
--- a/dwl.c
|
||||||
+++ b/dwl.c
|
+++ b/dwl.c
|
||||||
@@ -143,6 +143,7 @@ typedef struct {
|
@@ -159,6 +159,7 @@ typedef struct {
|
||||||
|
unsigned int bw;
|
||||||
uint32_t tags;
|
uint32_t tags;
|
||||||
int isfloating, isurgent, isfullscreen;
|
int isfloating, isurgent, isfullscreen;
|
||||||
uint32_t resize; /* configure serial of a pending resize */
|
|
||||||
+ struct wl_list link_temp;
|
+ struct wl_list link_temp;
|
||||||
} Client;
|
} Client;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -244,6 +245,7 @@ typedef struct {
|
@@ -260,6 +261,7 @@ typedef struct {
|
||||||
} SessionLock;
|
} SessionLock;
|
||||||
|
|
||||||
/* function declarations */
|
/* function declarations */
|
||||||
@@ -63,7 +77,7 @@ index 8101ffa..1c858a8 100644
|
|||||||
static void applybounds(Client *c, struct wlr_box *bbox);
|
static void applybounds(Client *c, struct wlr_box *bbox);
|
||||||
static void applyrules(Client *c);
|
static void applyrules(Client *c);
|
||||||
static void arrange(Monitor *m);
|
static void arrange(Monitor *m);
|
||||||
@@ -318,6 +320,7 @@ static void printstatus(void);
|
@@ -335,6 +337,7 @@ static void printstatus(void);
|
||||||
static void powermgrsetmode(struct wl_listener *listener, void *data);
|
static void powermgrsetmode(struct wl_listener *listener, void *data);
|
||||||
static void quit(const Arg *arg);
|
static void quit(const Arg *arg);
|
||||||
static void rendermon(struct wl_listener *listener, void *data);
|
static void rendermon(struct wl_listener *listener, void *data);
|
||||||
@@ -71,7 +85,7 @@ index 8101ffa..1c858a8 100644
|
|||||||
static void requestdecorationmode(struct wl_listener *listener, void *data);
|
static void requestdecorationmode(struct wl_listener *listener, void *data);
|
||||||
static void requeststartdrag(struct wl_listener *listener, void *data);
|
static void requeststartdrag(struct wl_listener *listener, void *data);
|
||||||
static void requestmonstate(struct wl_listener *listener, void *data);
|
static void requestmonstate(struct wl_listener *listener, void *data);
|
||||||
@@ -331,6 +334,7 @@ static void setlayout(const Arg *arg);
|
@@ -348,6 +351,7 @@ static void setlayout(const Arg *arg);
|
||||||
static void setmfact(const Arg *arg);
|
static void setmfact(const Arg *arg);
|
||||||
static void setmon(Client *c, Monitor *m, uint32_t newtags);
|
static void setmon(Client *c, Monitor *m, uint32_t newtags);
|
||||||
static void setpsel(struct wl_listener *listener, void *data);
|
static void setpsel(struct wl_listener *listener, void *data);
|
||||||
@@ -79,7 +93,7 @@ index 8101ffa..1c858a8 100644
|
|||||||
static void setsel(struct wl_listener *listener, void *data);
|
static void setsel(struct wl_listener *listener, void *data);
|
||||||
static void setup(void);
|
static void setup(void);
|
||||||
static void spawn(const Arg *arg);
|
static void spawn(const Arg *arg);
|
||||||
@@ -340,6 +344,7 @@ static void tagmon(const Arg *arg);
|
@@ -357,6 +361,7 @@ static void tagmon(const Arg *arg);
|
||||||
static void tile(Monitor *m);
|
static void tile(Monitor *m);
|
||||||
static void togglefloating(const Arg *arg);
|
static void togglefloating(const Arg *arg);
|
||||||
static void togglefullscreen(const Arg *arg);
|
static void togglefullscreen(const Arg *arg);
|
||||||
@@ -87,19 +101,16 @@ index 8101ffa..1c858a8 100644
|
|||||||
static void toggletag(const Arg *arg);
|
static void toggletag(const Arg *arg);
|
||||||
static void toggleview(const Arg *arg);
|
static void toggleview(const Arg *arg);
|
||||||
static void unlocksession(struct wl_listener *listener, void *data);
|
static void unlocksession(struct wl_listener *listener, void *data);
|
||||||
@@ -459,6 +464,11 @@ static struct wlr_xwayland *xwayland;
|
@@ -484,6 +489,8 @@ static struct wlr_xwayland *xwayland;
|
||||||
/* attempt to encapsulate suck into one file */
|
|
||||||
#include "client.h"
|
|
||||||
|
|
||||||
+static struct wl_list scratchpad_clients[SCRATCHPAD_COUNT];
|
#include "ime.h"
|
||||||
+static int scratchpad_visible[SCRATCHPAD_COUNT];
|
|
||||||
+static int scratchpad_sel = 0;
|
+#include "simple_scratchpad.h"
|
||||||
+#include "simple_scratchpad.c"
|
|
||||||
+
|
+
|
||||||
/* function implementations */
|
/* function implementations */
|
||||||
void
|
void
|
||||||
applybounds(Client *c, struct wlr_box *bbox)
|
applybounds(Client *c, struct wlr_box *bbox)
|
||||||
@@ -1332,10 +1342,21 @@ void
|
@@ -1427,10 +1434,21 @@ void
|
||||||
destroynotify(struct wl_listener *listener, void *data)
|
destroynotify(struct wl_listener *listener, void *data)
|
||||||
{
|
{
|
||||||
/* Called when the xdg_toplevel is destroyed. */
|
/* Called when the xdg_toplevel is destroyed. */
|
||||||
@@ -122,7 +133,7 @@ index 8101ffa..1c858a8 100644
|
|||||||
#ifdef XWAYLAND
|
#ifdef XWAYLAND
|
||||||
if (c->type != XDGShell) {
|
if (c->type != XDGShell) {
|
||||||
wl_list_remove(&c->activate.link);
|
wl_list_remove(&c->activate.link);
|
||||||
@@ -2337,11 +2358,24 @@ setcursorshape(struct wl_listener *listener, void *data)
|
@@ -2490,11 +2508,24 @@ setcursorshape(struct wl_listener *listener, void *data)
|
||||||
void
|
void
|
||||||
setfloating(Client *c, int floating)
|
setfloating(Client *c, int floating)
|
||||||
{
|
{
|
||||||
@@ -148,7 +159,7 @@ index 8101ffa..1c858a8 100644
|
|||||||
wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen ||
|
wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen ||
|
||||||
(p && p->isfullscreen) ? LyrFS
|
(p && p->isfullscreen) ? LyrFS
|
||||||
: c->isfloating ? LyrFloat : LyrTile]);
|
: c->isfloating ? LyrFloat : LyrTile]);
|
||||||
@@ -2561,6 +2595,11 @@ setup(void)
|
@@ -2714,6 +2745,11 @@ setup(void)
|
||||||
*/
|
*/
|
||||||
wl_list_init(&clients);
|
wl_list_init(&clients);
|
||||||
wl_list_init(&fstack);
|
wl_list_init(&fstack);
|
||||||
@@ -160,26 +171,30 @@ index 8101ffa..1c858a8 100644
|
|||||||
|
|
||||||
xdg_shell = wlr_xdg_shell_create(dpy, 6);
|
xdg_shell = wlr_xdg_shell_create(dpy, 6);
|
||||||
wl_signal_add(&xdg_shell->events.new_toplevel, &new_xdg_toplevel);
|
wl_signal_add(&xdg_shell->events.new_toplevel, &new_xdg_toplevel);
|
||||||
diff --git a/simple_scratchpad.c b/simple_scratchpad.c
|
diff --git a/simple_scratchpad.h b/simple_scratchpad.h
|
||||||
new file mode 100644
|
new file mode 100644
|
||||||
index 0000000..0e23ddd
|
index 0000000..36a564e
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/simple_scratchpad.c
|
+++ b/simple_scratchpad.h
|
||||||
@@ -0,0 +1,85 @@
|
@@ -0,0 +1,89 @@
|
||||||
+/* ************************************************************************** */
|
+/* ************************************************************************** */
|
||||||
+/* @@@ @@@@@@@@ */
|
+/* @@@ @@@@@@@@ */
|
||||||
+/* @@@ @@@@@@@@@@ */
|
+/* @@@ @@@@@@@@@@ */
|
||||||
+/* @@! @@! @@@@ */
|
+/* @@! @@! @@@@ */
|
||||||
+/* !@! !@! @!@!@ */
|
+/* !@! !@! @!@!@ */
|
||||||
+/* simple_scratchpad.c @!! @!@ @! !@! */
|
+/* simple_scratchpad.h @!! @!@ @! !@! */
|
||||||
+/* !!! !@!!! !!! */
|
+/* !!! !@!!! !!! */
|
||||||
+/* By: julmajustus <julmajustus@tutanota.com> !!: !!:! !!! */
|
+/* By: julmajustus <julmajustus@tutanota.com> !!: !!:! !!! */
|
||||||
+/* ::! :!: !:! */
|
+/* ::! :!: !:! */
|
||||||
+/* Created: 2024/12/19 19:35:02 by jmakkone :: ::::::: :: */
|
+/* Created: 2024/12/19 19:35:02 by jmakkone :: ::::::: :: */
|
||||||
+/* Updated: 2026/05/20 23:56:35 by julmajustus : : : : : : */
|
+/* Updated: 2026/09/20 02:14:02 by julmajustus : : : : : : */
|
||||||
+/* */
|
+/* */
|
||||||
+/* ************************************************************************** */
|
+/* ************************************************************************** */
|
||||||
+
|
+
|
||||||
|
+static struct wl_list scratchpad_clients[SCRATCHPAD_COUNT];
|
||||||
|
+static int scratchpad_visible[SCRATCHPAD_COUNT];
|
||||||
|
+static int scratchpad_sel = 0;
|
||||||
|
+
|
||||||
+void
|
+void
|
||||||
+addscratchpad(const Arg *arg)
|
+addscratchpad(const Arg *arg)
|
||||||
+{
|
+{
|
||||||
@@ -252,5 +267,5 @@ index 0000000..0e23ddd
|
|||||||
+ scratchpad_sel = idx;
|
+ scratchpad_sel = idx;
|
||||||
+}
|
+}
|
||||||
--
|
--
|
||||||
2.53.0
|
2.55.0
|
||||||
|
|
||||||
@@ -1,16 +1,12 @@
|
|||||||
From f8f6f6e20db7eaa0800b16f698907cfffab5f93e Mon Sep 17 00:00:00 2001
|
From 0987dd26a7b5dd0071fdb509b5ef61e0efbcb6cd Mon Sep 17 00:00:00 2001
|
||||||
From: Guido Cella <guido@guidocella.xyz>
|
From: Guido Cella <guido@guidocella.xyz>
|
||||||
Date: Wed, 16 Sep 2026 20:22:31 +0200
|
Date: Thu, 17 Sep 2026 08:53:31 +0200
|
||||||
Subject: [PATCH] =?UTF-8?q?hide=20the=20mouse=20cursor=20if=20it=20isn?=
|
Subject: [PATCH] hide the cursor when it isn't being used
|
||||||
=?UTF-8?q?=E2=80=99t=20being=20used?=
|
|
||||||
MIME-Version: 1.0
|
|
||||||
Content-Type: text/plain; charset=UTF-8
|
|
||||||
Content-Transfer-Encoding: 8bit
|
|
||||||
|
|
||||||
---
|
---
|
||||||
config.def.h | 2 ++
|
config.def.h | 2 ++
|
||||||
dwl.c | 36 +++++++++++++++++++++++++++++++++++-
|
dwl.c | 40 +++++++++++++++++++++++++++++++++++++---
|
||||||
2 files changed, 37 insertions(+), 1 deletion(-)
|
2 files changed, 39 insertions(+), 3 deletions(-)
|
||||||
|
|
||||||
diff --git a/config.def.h b/config.def.h
|
diff --git a/config.def.h b/config.def.h
|
||||||
index 13c5322..45c3c76 100644
|
index 13c5322..45c3c76 100644
|
||||||
@@ -26,7 +22,7 @@ index 13c5322..45c3c76 100644
|
|||||||
#define MODKEY WLR_MODIFIER_ALT
|
#define MODKEY WLR_MODIFIER_ALT
|
||||||
|
|
||||||
diff --git a/dwl.c b/dwl.c
|
diff --git a/dwl.c b/dwl.c
|
||||||
index f7bda0b..aabaa0d 100644
|
index f7bda0b..c8a2f3d 100644
|
||||||
--- a/dwl.c
|
--- a/dwl.c
|
||||||
+++ b/dwl.c
|
+++ b/dwl.c
|
||||||
@@ -308,6 +308,8 @@ static void focusstack(const Arg *arg);
|
@@ -308,6 +308,8 @@ static void focusstack(const Arg *arg);
|
||||||
@@ -118,6 +114,24 @@ index f7bda0b..aabaa0d 100644
|
|||||||
|
|
||||||
/* Run the Wayland event loop. This does not return until you exit the
|
/* Run the Wayland event loop. This does not return until you exit the
|
||||||
* compositor. Starting the backend rigged up all of the necessary event
|
* compositor. Starting the backend rigged up all of the necessary event
|
||||||
|
@@ -2452,7 +2483,7 @@ setcursor(struct wl_listener *listener, void *data)
|
||||||
|
* use the provided surface as the cursor image. It will set the
|
||||||
|
* hardware cursor on the output that it's currently on and continue to
|
||||||
|
* do so as the cursor moves between outputs. */
|
||||||
|
- if (event->seat_client == seat->pointer_state.focused_client)
|
||||||
|
+ if (event->seat_client == seat->pointer_state.focused_client && !cursor_hidden)
|
||||||
|
wlr_cursor_set_surface(cursor, event->surface,
|
||||||
|
event->hotspot_x, event->hotspot_y);
|
||||||
|
}
|
||||||
|
@@ -2466,7 +2497,7 @@ setcursorshape(struct wl_listener *listener, void *data)
|
||||||
|
/* This can be sent by any client, so we check to make sure this one
|
||||||
|
* actually has pointer focus first. If so, we can tell the cursor to
|
||||||
|
* use the provided cursor shape. */
|
||||||
|
- if (event->seat_client == seat->pointer_state.focused_client)
|
||||||
|
+ if (event->seat_client == seat->pointer_state.focused_client && !cursor_hidden)
|
||||||
|
wlr_cursor_set_xcursor(cursor, cursor_mgr,
|
||||||
|
wlr_cursor_shape_v1_name(event->shape));
|
||||||
|
}
|
||||||
@@ -2768,6 +2799,8 @@ setup(void)
|
@@ -2768,6 +2799,8 @@ setup(void)
|
||||||
cursor_shape_mgr = wlr_cursor_shape_manager_v1_create(dpy, 1);
|
cursor_shape_mgr = wlr_cursor_shape_manager_v1_create(dpy, 1);
|
||||||
wl_signal_add(&cursor_shape_mgr->events.request_set_shape, &request_set_cursor_shape);
|
wl_signal_add(&cursor_shape_mgr->events.request_set_shape, &request_set_cursor_shape);
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
### Description
|
|
||||||
Largely based on [raphi](https://sr.ht/~raphi/)'s [somebar](https://sr.ht/~raphi/somebar/), this patch provides an ipc for wayland clients to get and set dwl state. The ipc is intended for status bars, but can also be scripted with tools like [dwlmsg](https://codeberg.org/notchoc/dwlmsg).
|
|
||||||
|
|
||||||
Status information to stdout is currently disabled as dwl tends to freeze. For now, `dwlmsg -w` should act as a drop-in replacement.
|
|
||||||
|
|
||||||
Note to [pertag](../pertag/) users: apply [this](./ipcpertag.patch) for ipc tagsetting to work as expected
|
|
||||||
|
|
||||||
### Download
|
|
||||||
- [git branch](https://codeberg.org/notchoc/dwl/src/branch/ipc)
|
|
||||||
- [2024-08-16](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/ipc/ipc.patch)
|
|
||||||
- [2024-07-29](https://codeberg.org/dwl/dwl-patches/raw/commit/d235f0f88ed069eca234da5a544fb1c6e19f1d33/patches/ipc/ipc.patch) don't focus other outputs (apply [this minipatch](./focus-tagset-output.patch) if you'd prefer that)
|
|
||||||
- [2024-07-16](https://codeberg.org/dwl/dwl-patches/raw/commit/642b2559d522034785c1c1203c6d426855ec19ca/patches/ipc/ipc.patch)
|
|
||||||
- [2024-06-30](https://codeberg.org/dwl/dwl-patches/raw/commit/9a751e5020133d3ab9219e68a43109c6f3c931a7/patches/ipc/ipc.patch)
|
|
||||||
- [2024-06-21](https://codeberg.org/dwl/dwl-patches/raw/commit/f96ee44cbaef06bd38b8fa29ac7ecba8b1b5abd5/patches/ipc/ipc.patch)
|
|
||||||
- [2024-06-19](https://codeberg.org/dwl/dwl-patches/raw/commit/e69afc7263b8d982a7923e5d4910f2e1f7140bb8/patches/ipc/ipc.patch)
|
|
||||||
- [2024-06-08](https://codeberg.org/dwl/dwl-patches/raw/commit/f8598a91b44acc3bd7e9041be97265bbce8fa219/patches/ipc/ipc.patch)
|
|
||||||
- [2024-03-13](https://codeberg.org/dwl/dwl-patches/raw/commit/0150cfebbcd85f2d6e6728afad345a11a0c45947/ipc/ipc.patch)
|
|
||||||
- [2024-02-20](https://codeberg.org/dwl/dwl-patches/raw/commit/0c5ae06e4bc1d7f641376e8fcb86b43bd48ce2ee/ipc/ipc.patch)
|
|
||||||
- [2023-10-28](https://gist.githubusercontent.com/fbushstone/b116c44340eb7a7878de1119dd931ca5/raw/ee66ac9e2a5dddd9b528df553e21080c2811e974/ipc-v2-fixed.patch) Updated version of 2023-04-29, prevents ipc from freezing the compositor in printstatus.
|
|
||||||
- [2023-04-29](https://github.com/djpohly/dwl/compare/main...madcowog:ipc-v2.patch) Use this for dwl-ipc-unstable-v2. If you are using commit [9d68554](https://github.com/djpohly/dwl/commit/9d68554c59a886b641d27a364884fb461af2d4f1) or later, use this. For status bars this protocol is supported by dwlb, Waybar and dwl-bar.
|
|
||||||
- [2023-04-29](https://github.com/djpohly/dwl/compare/main...madcowog:ipc-bbdf2.patch) Use this for dwl-ipc-unstable-v1. If you are using commit [bbdaf2a9](https://github.com/djpohly/dwl/commit/bbdf2a913b72e7a308ee0dfde6518a4285d4a775), [release 0.4](https://github.com/djpohly/dwl/releases/tag/v0.4) or earlier, use this. For status bars, this protocol is supported by dwl-bar.
|
|
||||||
- [2023-02-20](https://lists.sr.ht/~raphi/public-inbox/patches/39166) Use this for net-tapesoftware-dwl-wm-unstable-v1. If you are using commit [c69a2bec](https://github.com/djpohly/dwl/commit/c69a2bec3ff417fbc4ea8fec0a49096773e01e7d) or later, use this. For status bars this protocol is supported by somebar.
|
|
||||||
|
|
||||||
### Authors
|
|
||||||
- [MadcowOG](https://github.com/MadcowOG)
|
|
||||||
- [fbushstone](https://github.com/fbushstone)
|
|
||||||
- [notchoc](https://codeberg.org/notchoc)
|
|
||||||
- [snuk](https://codeberg.org/snuk)
|
|
||||||
Reference in New Issue
Block a user