From f5bf38fce7e8d7a8038f57f08b2f69a64548e612 Mon Sep 17 00:00:00 2001 From: Brent Westbrook Date: Sat, 31 Aug 2024 13:57:39 -0400 Subject: [PATCH 1/8] update Rule struct, add st example --- src/config.rs | 36 +++++++++++++++++++++++++++++++++--- src/lib.rs | 24 +++--------------------- 2 files changed, 36 insertions(+), 24 deletions(-) diff --git a/src/config.rs b/src/config.rs index d9217b9..4800743 100644 --- a/src/config.rs +++ b/src/config.rs @@ -20,6 +20,8 @@ use rwm::{Arg, Button, Key, Layout, Rule}; pub const BORDERPX: c_uint = 3; // Snap pixel pub const SNAP: c_uint = 32; +/// Swallow floating windows by default +pub const SWALLOWFLOATING: bool = false; /// 0: sloppy systray follows selected monitor, >0: pin systray to monitor x pub static SYSTRAYPINNING: c_uint = 0; @@ -56,9 +58,37 @@ pub static COLORS: LazyLock<[[&CStr; 3]; 2]> = LazyLock::new(|| { pub const TAGS: [&CStr; 9] = [c"1", c"2", c"3", c"4", c"5", c"6", c"7", c"8", c"9"]; -pub const RULES: [Rule; 2] = [ - Rule::new(c"Gimp", null(), null(), 0, 1, -1), - Rule::new(c"Firefox", null(), null(), 1 << 8, 0, -1), +pub const RULES: [Rule; 3] = [ + Rule { + class: c"Gimp".as_ptr(), + instance: null(), + title: null(), + tags: 0, + isfloating: 1, + isterminal: false, + noswallow: false, + monitor: -1, + }, + Rule { + class: c"Firefox".as_ptr(), + instance: null(), + title: null(), + tags: 1 << 8, + isfloating: 0, + isterminal: false, + noswallow: true, + monitor: -1, + }, + Rule { + class: c"st-256color".as_ptr(), + instance: null(), + title: null(), + tags: 0, + isfloating: 0, + isterminal: true, + noswallow: false, + monitor: -1, + }, ]; // layouts diff --git a/src/lib.rs b/src/lib.rs index efc8bea..f59ba3e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -use std::ffi::{c_char, c_int, c_uint, c_void, CStr}; +use std::ffi::{c_char, c_int, c_uint, c_void}; use x11::xlib::KeySym; @@ -75,29 +75,11 @@ pub struct Rule { pub title: *const c_char, pub tags: c_uint, pub isfloating: c_int, + pub isterminal: bool, + pub noswallow: bool, pub monitor: c_int, } -impl Rule { - pub const fn new( - class: &'static CStr, - instance: *const i8, - title: *const i8, - tags: c_uint, - isfloating: c_int, - monitor: c_int, - ) -> Self { - Self { - class: class.as_ptr(), - instance, - title, - tags, - isfloating, - monitor, - } - } -} - pub struct Systray { pub win: Window, pub icons: *mut Client, From af855a9d6587010cd8b820a69d679af92e8bcf86 Mon Sep 17 00:00:00 2001 From: Brent Westbrook Date: Sat, 31 Aug 2024 13:59:01 -0400 Subject: [PATCH 2/8] update Client --- src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index f59ba3e..fbfd187 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -171,8 +171,12 @@ pub struct Client { pub neverfocus: c_int, pub oldstate: c_int, pub isfullscreen: bool, + pub isterminal: bool, + pub noswallow: bool, + pub pid: libc::pid_t, pub next: *mut Client, pub snext: *mut Client, + pub swallowing: *mut Client, pub mon: *mut Monitor, pub win: Window, } From cf6a50c14a29c6e8110822d2cfdb14913e8386de Mon Sep 17 00:00:00 2001 From: Brent Westbrook Date: Sat, 31 Aug 2024 14:07:06 -0400 Subject: [PATCH 3/8] make isfloating bool --- src/config.rs | 6 +++--- src/handlers.rs | 16 ++++++++-------- src/key_handlers.rs | 17 ++++++++--------- src/lib.rs | 6 +++--- src/main.rs | 24 ++++++++++++------------ 5 files changed, 34 insertions(+), 35 deletions(-) diff --git a/src/config.rs b/src/config.rs index 4800743..44c6acd 100644 --- a/src/config.rs +++ b/src/config.rs @@ -64,7 +64,7 @@ pub const RULES: [Rule; 3] = [ instance: null(), title: null(), tags: 0, - isfloating: 1, + isfloating: true, isterminal: false, noswallow: false, monitor: -1, @@ -74,7 +74,7 @@ pub const RULES: [Rule; 3] = [ instance: null(), title: null(), tags: 1 << 8, - isfloating: 0, + isfloating: false, isterminal: false, noswallow: true, monitor: -1, @@ -84,7 +84,7 @@ pub const RULES: [Rule; 3] = [ instance: null(), title: null(), tags: 0, - isfloating: 0, + isfloating: false, isterminal: true, noswallow: false, monitor: -1, diff --git a/src/handlers.rs b/src/handlers.rs index 2c5d9e6..9355e13 100644 --- a/src/handlers.rs +++ b/src/handlers.rs @@ -1,5 +1,5 @@ use std::{ - ffi::{c_int, c_long, c_uint}, + ffi::{c_long, c_uint}, mem::MaybeUninit, ptr::{addr_of, addr_of_mut, null_mut}, }; @@ -156,7 +156,7 @@ pub(crate) fn clientmessage(e: *mut XEvent) { c.oldbw = wa.border_width; c.bw = 0; - c.isfloating = 1; + c.isfloating = true; // reuse tags field as mapped status c.tags = 1; @@ -280,7 +280,7 @@ pub(crate) fn configurerequest(e: *mut XEvent) { if !c.is_null() { if (ev.value_mask & CWBorderWidth as u64) != 0 { (*c).bw = ev.border_width; - } else if (*c).isfloating != 0 + } else if (*c).isfloating || (*(*SELMON).lt[(*SELMON).sellt as usize]).arrange.is_none() { let m = (*c).mon; @@ -304,10 +304,10 @@ pub(crate) fn configurerequest(e: *mut XEvent) { assert!(!m.is_null()); let c = &mut *c; let m = &mut *m; - if (c.x + c.w) > m.mx + m.mw && c.isfloating != 0 { + if (c.x + c.w) > m.mx + m.mw && c.isfloating { c.x = m.mx + (m.mw / 2 - width(c) / 2); // center x } - if (c.y + c.h) > m.my + m.mh && c.isfloating != 0 { + if (c.y + c.h) > m.my + m.mh && c.isfloating { c.y = m.my + (m.mh / 2 - height(c) / 2); // center y } if (ev.value_mask & (CWX | CWY) as u64) != 0 @@ -577,12 +577,12 @@ pub(crate) fn propertynotify(e: *mut XEvent) { let c = &mut *c; match ev.atom { XA_WM_TRANSIENT_FOR => { - if c.isfloating == 0 + if !c.isfloating && (xlib::XGetTransientForHint(DPY, c.win, &mut trans) != 0) { - c.isfloating = !wintoclient(trans).is_null() as c_int; - if c.isfloating != 0 { + c.isfloating = !wintoclient(trans).is_null(); + if c.isfloating { arrange(c.mon); } } diff --git a/src/key_handlers.rs b/src/key_handlers.rs index 229cb5c..aec0063 100644 --- a/src/key_handlers.rs +++ b/src/key_handlers.rs @@ -136,7 +136,7 @@ pub(crate) unsafe extern "C" fn zoom(_arg: *const Arg) { let mut c = (*SELMON).sel; if (*(*SELMON).lt[(*SELMON).sellt as usize]).arrange.is_none() || c.is_null() - || (*c).isfloating != 0 + || (*c).isfloating { return; } @@ -261,10 +261,9 @@ pub(crate) unsafe extern "C" fn togglefloating(_arg: *const Arg) { // no support for fullscreen windows return; } - (*(*SELMON).sel).isfloating = ((*(*SELMON).sel).isfloating == 0 - || (*(*SELMON).sel).isfixed != 0) - as c_int; - if (*(*SELMON).sel).isfloating != 0 { + (*(*SELMON).sel).isfloating = + !(*(*SELMON).sel).isfloating || (*(*SELMON).sel).isfixed != 0; + if (*(*SELMON).sel).isfloating { let sel = &mut *(*SELMON).sel; resize(sel, sel.x, sel.y, sel.w, sel.h, 0); } @@ -474,7 +473,7 @@ pub(crate) unsafe extern "C" fn movemouse(_arg: *const Arg) { { ny = (*SELMON).wy + (*SELMON).wh - height(c); } - if c.isfloating == 0 + if !c.isfloating && (*(*SELMON).lt[(*SELMON).sellt as usize]) .arrange .is_some() @@ -486,7 +485,7 @@ pub(crate) unsafe extern "C" fn movemouse(_arg: *const Arg) { if (*(*SELMON).lt[(*SELMON).sellt as usize]) .arrange .is_none() - || c.isfloating != 0 + || c.isfloating { resize(c, nx, ny, c.w, c.h, 1); } @@ -572,7 +571,7 @@ pub(crate) unsafe extern "C" fn resizemouse(_arg: *const Arg) { && (*c.mon).wx + nw <= (*SELMON).wx + (*SELMON).ww && (*c.mon).wy + nh >= (*SELMON).wy && (*c.mon).wy + nh <= (*SELMON).wy + (*SELMON).wh - && c.isfloating == 0 + && !c.isfloating && (*(*SELMON).lt[(*SELMON).sellt as usize]) .arrange .is_some() @@ -584,7 +583,7 @@ pub(crate) unsafe extern "C" fn resizemouse(_arg: *const Arg) { if (*(*SELMON).lt[(*SELMON).sellt as usize]) .arrange .is_none() - || c.isfloating != 0 + || c.isfloating { resize(c, c.x, c.y, nw, nh, 1); } diff --git a/src/lib.rs b/src/lib.rs index fbfd187..adc713c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -74,7 +74,7 @@ pub struct Rule { pub instance: *const c_char, pub title: *const c_char, pub tags: c_uint, - pub isfloating: c_int, + pub isfloating: bool, pub isterminal: bool, pub noswallow: bool, pub monitor: c_int, @@ -166,10 +166,10 @@ pub struct Client { pub oldbw: c_int, pub tags: c_uint, pub isfixed: c_int, - pub isfloating: c_int, + pub isfloating: bool, pub isurgent: c_int, pub neverfocus: c_int, - pub oldstate: c_int, + pub oldstate: bool, pub isfullscreen: bool, pub isterminal: bool, pub noswallow: bool, diff --git a/src/main.rs b/src/main.rs index cbd3d4f..7764819 100644 --- a/src/main.rs +++ b/src/main.rs @@ -639,7 +639,7 @@ fn restack(m: *mut Monitor) { if (*m).sel.is_null() { return; } - if (*(*m).sel).isfloating != 0 + if (*(*m).sel).isfloating || (*(*m).lt[(*m).sellt as usize]).arrange.is_none() { xlib::XRaiseWindow(DPY, (*(*m).sel).win); @@ -656,7 +656,7 @@ fn restack(m: *mut Monitor) { }; let mut c = (*m).stack; while !c.is_null() { - if (*c).isfloating == 0 && is_visible(c) { + if !(*c).isfloating && is_visible(c) { xlib::XConfigureWindow( DPY, (*c).win, @@ -686,7 +686,7 @@ fn showhide(c: *mut Client) { if ((*(*(*c).mon).lt[(*(*c).mon).sellt as usize]) .arrange .is_none() - || (*c).isfloating != 0) + || (*c).isfloating) && !(*c).isfullscreen { resize(c, (*c).x, (*c).y, (*c).w, (*c).h, 0); @@ -839,7 +839,7 @@ fn applysizehints( *w = BH; } if RESIZE_HINTS != 0 - || (*c).isfloating != 0 + || (*c).isfloating || (*(*(*c).mon).lt[(*(*c).mon).sellt as usize]) .arrange .is_none() @@ -992,7 +992,7 @@ fn detach(c: *mut Client) { fn nexttiled(mut c: *mut Client) -> *mut Client { log::trace!("nexttiled"); unsafe { - while !c.is_null() && ((*c).isfloating != 0 || !is_visible(c)) { + while !c.is_null() && ((*c).isfloating || !is_visible(c)) { c = (*c).next; } c @@ -1517,7 +1517,7 @@ fn drawbar(m: *mut Monitor) { (*(*m).sel).name.as_ptr(), 0, ); - if (*(*m).sel).isfloating != 0 { + if (*(*m).sel).isfloating { drw::rect( DRW, x + boxs as i32, @@ -2324,11 +2324,11 @@ fn manage(w: Window, wa: *mut xlib::XWindowAttributes) { | StructureNotifyMask, ); grabbuttons(c, false); - if (*c).isfloating == 0 { - (*c).oldstate = (trans != 0 || (*c).isfixed != 0) as c_int; + if !(*c).isfloating { + (*c).oldstate = trans != 0 || (*c).isfixed != 0; (*c).isfloating = (*c).oldstate; } - if (*c).isfloating != 0 { + if (*c).isfloating { xlib::XRaiseWindow(DPY, (*c).win); } attach(c); @@ -2394,7 +2394,7 @@ fn updatewindowtype(c: *mut Client) { setfullscreen(c, true); } if wtype == NETATOM[Net::WMWindowTypeDialog as usize] { - (*c).isfloating = 1; + (*c).isfloating = true; } } } @@ -2419,7 +2419,7 @@ fn setfullscreen(c: *mut Client, fullscreen: bool) { (*c).oldstate = (*c).isfloating; (*c).oldbw = (*c).bw; (*c).bw = 0; - (*c).isfloating = 1; + (*c).isfloating = true; resizeclient( c, (*(*c).mon).mx, @@ -2520,7 +2520,7 @@ fn applyrules(c: *mut Client) { res_class: std::ptr::null_mut(), }; // rule matching - (*c).isfloating = 0; + (*c).isfloating = false; (*c).tags = 0; xlib::XGetClassHint(DPY, (*c).win, &mut ch); let class = if !ch.res_class.is_null() { From 3ad7c55a8f20b943d8aae0cddd4628977965b857 Mon Sep 17 00:00:00 2001 From: Brent Westbrook Date: Sat, 31 Aug 2024 14:11:01 -0400 Subject: [PATCH 4/8] impl swallow, add XCON --- src/main.rs | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index 7764819..15e9948 100644 --- a/src/main.rs +++ b/src/main.rs @@ -38,8 +38,8 @@ use rwm::{Arg, Client, Cursor, Layout, Monitor, Pertag, Systray, Window}; use config::{ BUTTONS, COLORS, FONTS, KEYS, LAYOUTS, RESIZE_HINTS, RULES, SHOWSYSTRAY, - SYSTRAYONLEFT, SYSTRAYPINNING, SYSTRAYPINNINGFAILFIRST, SYSTRAYSPACING, - TAGS, + SWALLOWFLOATING, SYSTRAYONLEFT, SYSTRAYPINNING, SYSTRAYPINNINGFAILFIRST, + SYSTRAYSPACING, TAGS, }; use drw::Drw; use enums::{Clk, Col, Cur, Net, Scheme, WM}; @@ -169,6 +169,8 @@ static mut ROOT: Window = 0; static mut WMCHECKWIN: Window = 0; +static mut XCON: *mut xcb_connection_t = null_mut(); + static mut RUNNING: bool = true; /// sum of left and right padding for text @@ -2542,6 +2544,8 @@ fn applyrules(c: *mut Client) { && (r.instance.is_null() || !libc::strstr(instance.as_ptr(), r.instance).is_null()) { + (*c).isterminal = r.isterminal; + (*c).noswallow = r.noswallow; (*c).isfloating = r.isfloating; (*c).tags |= r.tags; let mut m = MONS; @@ -2567,6 +2571,35 @@ fn applyrules(c: *mut Client) { } } +fn swallow(p: *mut Client, c: *mut Client) { + unsafe { + let c = &mut *c; + if c.noswallow || c.isterminal { + return; + } + if c.noswallow && !SWALLOWFLOATING && c.isfloating { + return; + } + detach(c); + detachstack(c); + + setclientstate(c, WITHDRAWN_STATE); + let p = &mut *p; + XUnmapWindow(DPY, p.win); + p.swallowing = c; + c.mon = p.mon; + + std::mem::swap(&mut p.win, &mut c.win); + updatetitle(p); + XMoveResizeWindow(DPY, p.win, p.x, p.y, p.w as u32, p.h as u32); + arrange(p.mon); + configure(p); + updateclientlist(); + } +} + +fn unswallow(c: *mut Client) {} + // #define TAGMASK ((1 << LENGTH(tags)) - 1) const TAGMASK: u32 = (1 << TAGS.len()) - 1; const BUTTONMASK: i64 = ButtonPressMask | ButtonReleaseMask; @@ -2635,6 +2668,7 @@ fn getstate(w: Window) -> c_long { mod config; mod drw; pub use rwm::enums; +use x11::xlib_xcb::xcb_connection_t; use xembed::{ XEMBED_EMBEDDED_VERSION, XEMBED_MAPPED, XEMBED_WINDOW_ACTIVATE, XEMBED_WINDOW_DEACTIVATE, From 7b128f753ea4dee130c142ffe9e8022ba5b22b8e Mon Sep 17 00:00:00 2001 From: Brent Westbrook Date: Sat, 31 Aug 2024 14:13:41 -0400 Subject: [PATCH 5/8] impl unswallow --- src/main.rs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 15e9948..b6fdd45 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2598,7 +2598,26 @@ fn swallow(p: *mut Client, c: *mut Client) { } } -fn unswallow(c: *mut Client) {} +fn unswallow(c: *mut Client) { + unsafe { + let c = &mut *c; + + c.win = (*c.swallowing).win; + + libc::free(c.swallowing.cast()); + c.swallowing = null_mut(); + + // unfullscreen the client + setfullscreen(c, false); + updatetitle(c); + arrange(c.mon); + XMapWindow(DPY, c.win); + XMoveResizeWindow(DPY, c.win, c.x, c.y, c.w as u32, c.h as u32); + setclientstate(c, NORMAL_STATE); + focus(null_mut()); + arrange(c.mon); + } +} // #define TAGMASK ((1 << LENGTH(tags)) - 1) const TAGMASK: u32 = (1 << TAGS.len()) - 1; From 1406d5c792bd56565ea045068f85f7638f2a0f03 Mon Sep 17 00:00:00 2001 From: Brent Westbrook Date: Sat, 31 Aug 2024 14:51:37 -0400 Subject: [PATCH 6/8] progress on swallowing with horrifying process management --- src/handlers.rs | 13 +++-- src/main.rs | 131 +++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 122 insertions(+), 22 deletions(-) diff --git a/src/handlers.rs b/src/handlers.rs index 9355e13..972ccff 100644 --- a/src/handlers.rs +++ b/src/handlers.rs @@ -388,11 +388,16 @@ pub(crate) fn destroynotify(e: *mut XEvent) { if !c.is_null() { unmanage(c, 1); } else { - c = wintosystrayicon(ev.window); + c = swallowingclient(ev.window); if !c.is_null() { - removesystrayicon(c); - resizebarwin(SELMON); - updatesystray(); + unmanage((*c).swallowing, 1); + } else { + c = wintosystrayicon(ev.window); + if !c.is_null() { + removesystrayicon(c); + resizebarwin(SELMON); + updatesystray(); + } } } } diff --git a/src/main.rs b/src/main.rs index b6fdd45..bcc132c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,36 +2,37 @@ use std::cmp::max; use std::ffi::{c_char, c_int, c_uint, c_ulong, CStr}; +use std::io::Read; use std::mem::size_of_val; use std::mem::{size_of, MaybeUninit}; use std::ptr::{addr_of, addr_of_mut, null_mut}; use std::sync::LazyLock; use key_handlers::view; -use libc::{c_long, c_uchar, sigaction}; +use libc::{c_long, c_uchar, pid_t, sigaction}; use rwm::enums::XEmbed; use x11::keysym::XK_Num_Lock; use x11::xft::XftColor; use x11::xlib::{ - self, Above, AnyButton, AnyKey, AnyModifier, BadAccess, BadDrawable, - BadMatch, BadWindow, Below, ButtonPressMask, ButtonReleaseMask, - CWBackPixel, CWBackPixmap, CWBorderWidth, CWCursor, CWEventMask, CWHeight, - CWOverrideRedirect, CWSibling, CWStackMode, CWWidth, ClientMessage, - ControlMask, CopyFromParent, CurrentTime, Display, EnterWindowMask, - ExposureMask, False, FocusChangeMask, GrabModeAsync, GrabModeSync, - InputHint, IsViewable, LeaveWindowMask, LockMask, Mod1Mask, Mod2Mask, - Mod3Mask, Mod4Mask, Mod5Mask, NoEventMask, PAspect, PBaseSize, PMaxSize, - PMinSize, PResizeInc, PSize, ParentRelative, PointerMotionMask, + self, Above, AnyButton, AnyKey, AnyModifier, AnyPropertyType, BadAccess, + BadDrawable, BadMatch, BadWindow, Below, ButtonPressMask, + ButtonReleaseMask, CWBackPixel, CWBackPixmap, CWBorderWidth, CWCursor, + CWEventMask, CWHeight, CWOverrideRedirect, CWSibling, CWStackMode, CWWidth, + ClientMessage, ControlMask, CopyFromParent, CurrentTime, Display, + EnterWindowMask, ExposureMask, False, FocusChangeMask, GrabModeAsync, + GrabModeSync, InputHint, IsViewable, LeaveWindowMask, LockMask, Mod1Mask, + Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask, NoEventMask, PAspect, PBaseSize, + PMaxSize, PMinSize, PResizeInc, PSize, ParentRelative, PointerMotionMask, PointerRoot, PropModeAppend, PropModeReplace, PropertyChangeMask, RevertToPointerRoot, ShiftMask, StructureNotifyMask, SubstructureNotifyMask, SubstructureRedirectMask, Success, True, XChangeProperty, XChangeWindowAttributes, XConfigureWindow, XCreateSimpleWindow, XDestroyWindow, XErrorEvent, XFillRectangle, XFree, - XGetSelectionOwner, XInternAtom, XMapRaised, XMapSubwindows, XMapWindow, - XMoveResizeWindow, XPropertyEvent, XSelectInput, XSetErrorHandler, - XSetForeground, XSetSelectionOwner, XSetWindowAttributes, XSync, - XUnmapWindow, XWindowChanges, CWX, CWY, XA_ATOM, XA_CARDINAL, XA_STRING, - XA_WINDOW, XA_WM_NAME, + XGetSelectionOwner, XGetWindowProperty, XInternAtom, XMapRaised, + XMapSubwindows, XMapWindow, XMoveResizeWindow, XPropertyEvent, + XSelectInput, XSetErrorHandler, XSetForeground, XSetSelectionOwner, + XSetWindowAttributes, XSync, XUnmapWindow, XWindowChanges, CWX, CWY, + XA_ATOM, XA_CARDINAL, XA_STRING, XA_WINDOW, XA_WM_NAME, }; use rwm::{Arg, Client, Cursor, Layout, Monitor, Pertag, Systray, Window}; @@ -2076,6 +2077,21 @@ fn unmanage(c: *mut Client, destroyed: c_int) { sibling: 0, stack_mode: 0, }; + + if !(*c).swallowing.is_null() { + unswallow(c); + return; + } + + let s = swallowingclient((*c).win); + if !s.is_null() { + libc::free((*s).swallowing.cast()); + (*s).swallowing = null_mut(); + arrange(m); + focus(null_mut()); + return; + } + detach(c); detachstack(c); if destroyed == 0 { @@ -2096,12 +2112,82 @@ fn unmanage(c: *mut Client, destroyed: c_int) { xlib::XUngrabServer(DPY); } libc::free(c.cast()); - focus(null_mut()); - updateclientlist(); - arrange(m); + + if s.is_null() { + arrange(m); + focus(null_mut()); + updateclientlist(); + } } } +/// I'm just using the OpenBSD version of the code in the patch rather than the +/// Linux version that uses XCB +fn winpid(w: Window) -> pid_t { + let result; + + unsafe { + let mut type_: Atom = 0; + let mut format: c_int = 0; + let mut len: c_ulong = 0; + let mut bytes: c_ulong = 0; + let mut prop: *mut c_uchar = null_mut(); + if XGetWindowProperty( + DPY, + w, + XInternAtom(DPY, c"_NET_WM_PID".as_ptr(), 0), + 0, + 1, + False, + AnyPropertyType as u64, + &mut type_, + &mut format, + &mut len, + &mut bytes, + &mut prop, + ) != Success as i32 + || prop.is_null() + { + return 0; + } + let ret = *(prop as *mut pid_t); + XFree(prop.cast()); + result = ret; + } + + result +} + +/// this looks insane... rust has std::os::unix::process::parent_id, but it +/// doesn't take any arguments. we need to get the parent of a specific process +/// here, so we read from /proc +fn getparentprocess(p: pid_t) -> pid_t { + let filename = format!("/proc/{p}/stat"); + let Ok(mut f) = std::fs::File::open(filename) else { + return 0; + }; + let mut buf = Vec::new(); + let Ok(_) = f.read_to_end(&mut buf) else { + return 0; + }; + let Ok(s) = String::from_utf8(buf) else { + return 0; + }; + // trying to emulate fscanf(f, "%*u %*s %*c %u", &v); which should give the + // 3rd field + match s.split_ascii_whitespace().nth(3).map(str::parse) { + Some(Ok(p)) => p, + _ => 0, + } +} + +fn isdescprocess(p: pid_t, mut c: pid_t) -> pid_t { + while p != c && c != 0 { + c = getparentprocess(c); + } + c +} + fn updateclientlist() { unsafe { xlib::XDeleteProperty(DPY, ROOT, NETATOM[Net::ClientList as usize]); @@ -2253,6 +2339,7 @@ fn manage(w: Window, wa: *mut xlib::XWindowAttributes) { let wa = *wa; let c: *mut Client = util::ecalloc(1, size_of::()) as *mut _; (*c).win = w; + (*c).pid = winpid(w); (*c).x = wa.x; (*c).oldx = wa.x; (*c).y = wa.y; @@ -2263,6 +2350,8 @@ fn manage(w: Window, wa: *mut xlib::XWindowAttributes) { (*c).oldh = wa.height; (*c).oldbw = wa.border_width; + let mut term: *mut Client; + updatetitle(c); log::trace!("manage: XGetTransientForHint"); if xlib::XGetTransientForHint(DPY, w, &mut trans) != 0 { @@ -2271,14 +2360,17 @@ fn manage(w: Window, wa: *mut xlib::XWindowAttributes) { (*c).mon = (*t).mon; (*c).tags = (*t).tags; } else { + // NOTE must keep in sync with else below (*c).mon = SELMON; applyrules(c); + term = termforwin(c); } } else { // copied else case from above because the condition is supposed // to be xgettransientforhint && (t = wintoclient) (*c).mon = SELMON; applyrules(c); + term = termforwin(c); } if (*c).x + width(c) > ((*(*c).mon).wx + (*(*c).mon).ww) as i32 { (*c).x = ((*(*c).mon).wx + (*(*c).mon).ww) as i32 - width(c); @@ -2361,6 +2453,9 @@ fn manage(w: Window, wa: *mut xlib::XWindowAttributes) { (*(*c).mon).sel = c; arrange((*c).mon); xlib::XMapWindow(DPY, (*c).win); + if !term.is_null() { + swallow(term, c); + } focus(std::ptr::null_mut()); } } From d6262f426f67360ecb3c59aa6967e1138ce67961 Mon Sep 17 00:00:00 2001 From: Brent Westbrook Date: Sat, 31 Aug 2024 21:52:54 -0400 Subject: [PATCH 7/8] finish swallowing? --- src/handlers.rs | 8 ++++---- src/main.rs | 43 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/src/handlers.rs b/src/handlers.rs index 972ccff..ad2e166 100644 --- a/src/handlers.rs +++ b/src/handlers.rs @@ -26,10 +26,10 @@ use crate::{ enums::{Clk, Net}, focus, get_scheme_color, getsystraywidth, grabkeys, height, is_visible, manage, recttomon, removesystrayicon, resizebarwin, resizeclient, restack, - sendevent, setclientstate, setfocus, setfullscreen, seturgent, textw, - unfocus, unmanage, updatebars, updategeom, updatesizehints, updatestatus, - updatesystray, updatesystrayicongeom, updatesystrayiconstate, updatetitle, - updatewindowtype, updatewmhints, + sendevent, setclientstate, setfocus, setfullscreen, seturgent, + swallowingclient, textw, unfocus, unmanage, updatebars, updategeom, + updatesizehints, updatestatus, updatesystray, updatesystrayicongeom, + updatesystrayiconstate, updatetitle, updatewindowtype, updatewmhints, util::ecalloc, width, wintoclient, wintomon, wintosystrayicon, xembed::{ diff --git a/src/main.rs b/src/main.rs index bcc132c..750045c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2188,6 +2188,47 @@ fn isdescprocess(p: pid_t, mut c: pid_t) -> pid_t { c } +fn termforwin(w: *const Client) -> *mut Client { + unsafe { + let w = &*w; + + if w.pid == 0 || w.isterminal { + return null_mut(); + } + + let mut c; + let mut m; + + cfor!((m = MONS; !m.is_null(); m = (*m).next) { + cfor!((c = (*m).clients; !c.is_null(); c = (*c).next) { + if (*c).isterminal && (*c).swallowing.is_null() + && (*c).pid != 0 && isdescprocess((*c).pid, w.pid) != 0 { + return c; + } + }); + }); + } + + null_mut() +} + +fn swallowingclient(w: Window) -> *mut Client { + unsafe { + let mut c; + let mut m; + + cfor!((m = MONS; !m.is_null(); m = (*m).next) { + cfor!((c = (*m).clients; !c.is_null(); c = (*c).next) { + if !(*c).swallowing.is_null() && (*(*c).swallowing).win == w { + return c; + } + }); + }); + + null_mut() + } +} + fn updateclientlist() { unsafe { xlib::XDeleteProperty(DPY, ROOT, NETATOM[Net::ClientList as usize]); @@ -2350,7 +2391,7 @@ fn manage(w: Window, wa: *mut xlib::XWindowAttributes) { (*c).oldh = wa.height; (*c).oldbw = wa.border_width; - let mut term: *mut Client; + let mut term: *mut Client = null_mut(); updatetitle(c); log::trace!("manage: XGetTransientForHint"); From 0825871978cdf1434c035f77f082c8c879d3c9e7 Mon Sep 17 00:00:00 2001 From: Brent Westbrook Date: Sat, 31 Aug 2024 21:53:03 -0400 Subject: [PATCH 8/8] delete unused xcon --- src/main.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main.rs b/src/main.rs index 750045c..648d85b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -170,8 +170,6 @@ static mut ROOT: Window = 0; static mut WMCHECKWIN: Window = 0; -static mut XCON: *mut xcb_connection_t = null_mut(); - static mut RUNNING: bool = true; /// sum of left and right padding for text @@ -2823,7 +2821,6 @@ fn getstate(w: Window) -> c_long { mod config; mod drw; pub use rwm::enums; -use x11::xlib_xcb::xcb_connection_t; use xembed::{ XEMBED_EMBEDDED_VERSION, XEMBED_MAPPED, XEMBED_WINDOW_ACTIVATE, XEMBED_WINDOW_DEACTIVATE,