summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoruint23 <[email protected]>2025-04-21 18:55:06 +0100
committeruint23 <[email protected]>2025-04-21 18:55:06 +0100
commit94e37e2eea875928a56d00f6c664c0c3485ed1b7 (patch)
treef354505561d69a11bcd79597034a8285c26c1ba2
parentd6ce3bb17489efa982717196d1ccf3f325bc0012 (diff)
Added: Swapping windows with the mouse
added swap with mouse ability. hold mod + shift and drag around.
-rw-r--r--src/config.h1
-rw-r--r--src/defs.h10
-rw-r--r--src/sxwm.c184
3 files changed, 158 insertions, 37 deletions
diff --git a/src/config.h b/src/config.h
index 03058fd..342a54b 100644
--- a/src/config.h
+++ b/src/config.h
@@ -63,6 +63,7 @@
#define BORDER_WIDTH 1
#define BORDER_FOC_COL "#c0cbff"
#define BORDER_UFOC_COL "#555555"
+#define BORDER_SWAP_COL "#fff4c0"
#define MASTER_WIDTH 0.6
#define RESIZE_MASTER_AMT 1
diff --git a/src/defs.h b/src/defs.h
index 623baf3..2cdc933 100644
--- a/src/defs.h
+++ b/src/defs.h
@@ -9,7 +9,7 @@
#define ulong unsigned long
#define u_char unsigned char
-#define SXWM_VERSION "sxwm ver. 1.0.0"
+#define SXWM_VERSION "sxwm ver. 1.1.0"
#define SXWM_AUTHOR "(C) Abhinav Prasai 2025"
#define SXWM_LICINFO "See LICENSE for more info"
@@ -70,7 +70,13 @@ void moveto_ws9(void) { move_to_workspace(8); update_net_client_list(); }\
#define MAXCLIENTS 99
#define MAXGAPS 100
-enum { DRAG_NONE, DRAG_MOVE, DRAG_RESIZE } drag_mode = DRAG_NONE;
+typedef enum {
+ DRAG_NONE,
+ DRAG_MOVE,
+ DRAG_RESIZE,
+ DRAG_SWAP
+} DragMode;
+
typedef void (*EventHandler)(XEvent *);
typedef union {
diff --git a/src/sxwm.c b/src/sxwm.c
index c61d9c0..b6bb007 100644
--- a/src/sxwm.c
+++ b/src/sxwm.c
@@ -65,6 +65,7 @@ void scan_existing_windows(void);
void setup(void);
void setup_atoms(void);
void spawn(const char **cmd);
+void swap_clients(Client *a, Client *b);
void tile(void);
void toggle_floating(void);
void toggle_floating_global(void);
@@ -94,7 +95,9 @@ Atom atom_net_workarea;
Cursor c_normal, c_move, c_resize;
Client *workspaces[NUM_WORKSPACES] = { NULL };
uint current_ws = 0;
+DragMode drag_mode = DRAG_NONE;
Client *drag_client = NULL;
+Client *swap_target = NULL;
Client *focused = NULL;
EventHandler evtable[LASTEvent];
Display *dpy;
@@ -106,6 +109,7 @@ Bool global_floating = False;
ulong last_motion_time = 0;
ulong border_foc_col;
ulong border_ufoc_col;
+ulong border_swap_col;
float master_frac = MASTER_WIDTH;
uint gaps = GAPS;
uint scr_width;
@@ -301,8 +305,28 @@ hdl_button(XEvent *xev)
continue;
}
- if (((e->state & MOD) && e->button == Button1 && !c->floating) ||
- ((e->state & MOD) && e->button == Button3 && !c->floating)) {
+ /* begin swap drag mode */
+ if ((e->state & MOD) && (e->state & ShiftMask) && e->button == Button1 && !c->floating) {
+ drag_client = c;
+ drag_start_x = e->x_root;
+ drag_start_y = e->y_root;
+ drag_orig_x = c->x;
+ drag_orig_y = c->y;
+ drag_orig_w = c->w;
+ drag_orig_h = c->h;
+ drag_mode = DRAG_SWAP;
+ XGrabPointer(dpy, root, True,
+ ButtonReleaseMask | PointerMotionMask,
+ GrabModeAsync, GrabModeAsync,
+ None, c_move, CurrentTime);
+ focused = c;
+ XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
+ XSetWindowBorder(dpy, c->win, border_swap_col);
+ XRaiseWindow(dpy, c->win);
+ return;
+ }
+
+ if ((e->state & MOD) && (e->button == Button1 || e->button == Button3) && !c->floating) {
focused = c;
toggle_floating();
}
@@ -317,20 +341,21 @@ hdl_button(XEvent *xev)
Cursor cur = (e->button == Button1) ? c_move : c_resize;
XGrabPointer(dpy, root, True,
- ButtonReleaseMask|PointerMotionMask,
- GrabModeAsync, GrabModeAsync,
- None, cur, CurrentTime);
-
- drag_client = c;
- drag_start_x = e->x_root;
- drag_start_y = e->y_root;
- drag_orig_x = c->x;
- drag_orig_y = c->y;
- drag_orig_w = c->w;
- drag_orig_h = c->h;
- drag_mode = (e->button == Button1 ? DRAG_MOVE : DRAG_RESIZE);
- focused = c;
- XSetInputFocus(dpy, w, RevertToPointerRoot, CurrentTime);
+ ButtonReleaseMask | PointerMotionMask,
+ GrabModeAsync, GrabModeAsync,
+ None, cur, CurrentTime);
+
+ drag_client = c;
+ drag_start_x = e->x_root;
+ drag_start_y = e->y_root;
+ drag_orig_x = c->x;
+ drag_orig_y = c->y;
+ drag_orig_w = c->w;
+ drag_orig_h = c->h;
+ drag_mode = (e->button == Button1) ? DRAG_MOVE : DRAG_RESIZE;
+ focused = c;
+
+ XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
update_borders();
XRaiseWindow(dpy, c->win);
return;
@@ -341,9 +366,22 @@ void
hdl_button_release(XEvent *xev)
{
(void)xev;
+
+ if (drag_mode == DRAG_SWAP) {
+ if (swap_target) {
+ XSetWindowBorder(dpy, swap_target->win,
+ (swap_target == focused ? border_foc_col : border_ufoc_col));
+ swap_clients(drag_client, swap_target);
+ }
+ tile();
+ update_borders();
+ }
+
XUngrabPointer(dpy, CurrentTime);
- drag_mode = DRAG_NONE;
+
+ drag_mode = DRAG_NONE;
drag_client = NULL;
+ swap_target = NULL;
}
void
@@ -393,7 +431,7 @@ hdl_config_req(XEvent *xev)
if (!c || c->floating || c->fullscreen) {
- /* allow the client to configure itself */
+ /* allow client to configure itself */
XWindowChanges wc = { .x = e->x, .y = e->y,
.width = e->width, .height = e->height,
.border_width = e->border_width,
@@ -402,7 +440,6 @@ hdl_config_req(XEvent *xev)
return;
}
- /* managed and tiling – ignore size hints unless it’s fixed */
if (c->fixed) {
return;
}
@@ -491,6 +528,45 @@ hdl_keypress(XEvent *xev)
}
void
+swap_clients(Client *a, Client *b)
+{
+ if (!a || !b || a == b) {
+ return;
+ }
+
+ Client **head = &workspaces[current_ws];
+ Client **pa = head, **pb = head;
+
+ while (*pa && *pa != a) pa = &(*pa)->next;
+ while (*pb && *pb != b) pb = &(*pb)->next;
+
+ if (!*pa || !*pb) {
+ return;
+ }
+
+ /* if next to it swap */
+ if (*pa == b && *pb == a) {
+ Client *tmp = b->next;
+ b->next = a;
+ a->next = tmp;
+ *pa = b;
+ return;
+ }
+
+ /* full swap */
+ Client *ta = *pa;
+ Client *tb = *pb;
+ Client *ta_next = ta->next;
+ Client *tb_next = tb->next;
+
+ *pa = tb;
+ tb->next = ta_next == tb ? ta : ta_next;
+
+ *pb = ta;
+ ta->next = tb_next == ta ? tb : tb_next;
+}
+
+void
hdl_map_req(XEvent *xev)
{
XConfigureRequestEvent *cr = &xev->xconfigurerequest;
@@ -605,18 +681,53 @@ void
hdl_motion(XEvent *xev)
{
XMotionEvent *e = &xev->xmotion;
+
if ((drag_mode == DRAG_NONE || !drag_client) ||
- (e->time - last_motion_time <= (1000 / MOTION_THROTTLE))) {
+ (e->time - last_motion_time <= (1000 / MOTION_THROTTLE))) {
return;
}
-
last_motion_time = e->time;
- int dx = e->x_root - drag_start_x;
- int dy = e->y_root - drag_start_y;
- int nx = drag_orig_x + dx;
- int ny = drag_orig_y + dy;
- if (drag_mode == DRAG_MOVE) {
+ if (drag_mode == DRAG_SWAP) {
+ Window root_ret, child;
+ int rx, ry, wx, wy;
+ uint mask;
+ XQueryPointer(dpy, root, &root_ret, &child, &rx, &ry, &wx, &wy, &mask);
+
+ static Client *last_swap_target = NULL;
+ Client *new_target = NULL;
+
+ for (Client *c = workspaces[current_ws]; c; c = c->next) {
+ if (c == drag_client || c->floating) {
+ continue;
+ }
+ if (c->win == child) {
+ new_target = c;
+ break;
+ }
+ }
+
+ if (new_target != last_swap_target) {
+ if (last_swap_target) {
+ XSetWindowBorder(dpy, last_swap_target->win,
+ (last_swap_target == focused ? border_foc_col : border_ufoc_col));
+ }
+ if (new_target) {
+ XSetWindowBorder(dpy, new_target->win, border_swap_col);
+ }
+ last_swap_target = new_target;
+ }
+
+ swap_target = new_target;
+ return;
+ }
+
+ else if (drag_mode == DRAG_MOVE) {
+ int dx = e->x_root - drag_start_x;
+ int dy = e->y_root - drag_start_y;
+ int nx = drag_orig_x + dx;
+ int ny = drag_orig_y + dy;
+
int outer_w = drag_client->w + 2 * BORDER_WIDTH;
int outer_h = drag_client->h + 2 * BORDER_WIDTH;
@@ -626,7 +737,6 @@ hdl_motion(XEvent *xev)
nx = scr_width - outer_w;
}
- /* snap y */
if (UDIST(ny, 0) <= SNAP_DISTANCE) {
ny = 0;
} else if (UDIST(ny + outer_h, scr_height) <= SNAP_DISTANCE) {
@@ -644,15 +754,14 @@ hdl_motion(XEvent *xev)
drag_client->y = ny;
}
-
- else {
- /* resize clamp is 20px */
+ else if (drag_mode == DRAG_RESIZE) {
+ int dx = e->x_root - drag_start_x;
+ int dy = e->y_root - drag_start_y;
int nw = drag_orig_w + dx;
int nh = drag_orig_h + dy;
drag_client->w = nw < 20 ? 20 : nw;
drag_client->h = nh < 20 ? 20 : nh;
- XResizeWindow(dpy, drag_client->win,
- drag_client->w, drag_client->h);
+ XResizeWindow(dpy, drag_client->win, drag_client->w, drag_client->h);
}
}
@@ -667,11 +776,11 @@ hdl_root_property(XEvent *xev)
long *val = NULL;
Atom actual;
int fmt;
- unsigned long n, after;
+ ulong n, after;
if (XGetWindowProperty(dpy, root, atom_net_current_desktop,
0, 1, False, XA_CARDINAL,
&actual, &fmt, &n, &after,
- (unsigned char**)&val) == Success &&
+ (u_char**)&val) == Success &&
val) {
change_workspace((uint)val[0]);
XFree(val);
@@ -900,9 +1009,13 @@ setup(void)
SubstructureNotifyMask |
KeyPressMask |
PropertyChangeMask);
+
XGrabButton(dpy, Button1, MOD, root,
True, ButtonPressMask | ButtonReleaseMask|PointerMotionMask,
GrabModeAsync, GrabModeAsync, None, None);
+ XGrabButton(dpy, Button1, MOD | ShiftMask, root, True,
+ ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
+ GrabModeAsync, GrabModeAsync, None, None);
XGrabButton(dpy, Button3, MOD, root,
True, ButtonPressMask | ButtonReleaseMask|PointerMotionMask,
GrabModeAsync, GrabModeAsync, None, None);
@@ -926,6 +1039,7 @@ setup(void)
border_foc_col = parse_col(BORDER_FOC_COL);
border_ufoc_col = parse_col(BORDER_UFOC_COL);
+ border_swap_col = parse_col(BORDER_SWAP_COL);
scan_existing_windows();
}
@@ -1373,7 +1487,7 @@ change_workspace(uint ws)
int
xerr(Display *dpy, XErrorEvent *ee)
{
- /* ignore noise and non fatal errors */
+ /* ignore noise & non fatal errors */
const struct {
uint req, code;
} ignore[] = {