summaryrefslogtreecommitdiff
path: root/src/clients.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/clients.rs')
-rw-r--r--src/clients.rs142
1 files changed, 77 insertions, 65 deletions
diff --git a/src/clients.rs b/src/clients.rs
index 75ed38a..f04fc36 100644
--- a/src/clients.rs
+++ b/src/clients.rs
@@ -1,5 +1,6 @@
use std::cmp::min;
+use crate::{config::BORDER_WIDTH, error::*, WM};
use xcb::{
x::{
ChangeWindowAttributes, ConfigWindow, ConfigureNotifyEvent, ConfigureRequestEvent,
@@ -11,11 +12,8 @@ use xcb::{
BaseEvent, Connection, Extension, Xid,
};
-use crate::{error::*, WM};
-const BORDER_WIDTH: u16 = 3;
-
impl WM<'_> {
- /// Update the client state's recorded monitors and monitor sizes
+ /// Update the client recorded monitors and monitor sizes
/// Returns true if any values changed, meaning windows should be re-tiled.
pub(crate) fn update_geometry(&mut self) -> Result<bool> {
let mut dirty = false;
@@ -75,7 +73,7 @@ impl WM<'_> {
Ok(())
}
- /// Handle a configure request, by checking it's valid and performing it if so
+ /// Perform configure requests if we're happy with them, or they're for an unmanaged window.
pub(crate) fn handle_configure_request(&mut self, e: ConfigureRequestEvent) -> Result<()> {
if let Some(c) = self.clients.find_client_mut(e.window()) {
// TODO: Allow changing some properties:
@@ -102,7 +100,7 @@ impl WM<'_> {
Ok(())
}
- /// Handle a destroyed window, removing it from the client list and rearranging.
+ /// Removing destroyed windows from the client list and rearrange.
pub(crate) fn handle_destroy_notify(&mut self, e: DestroyNotifyEvent) -> Result<()> {
if self.clients.remove_client(e.window()).is_some() {
self.clients.rearrange(self.conn);
@@ -112,7 +110,7 @@ impl WM<'_> {
Ok(())
}
- /// Map a window on request, starting to manage it if needed.
+ /// Map a window, starting to manage it if needed.
pub(crate) fn handle_map_request(&mut self, e: MapRequestEvent) -> Result<()> {
// Ignore already managed windows
if self.clients.find_client_mut(e.window()).is_some() {
@@ -124,6 +122,7 @@ impl WM<'_> {
.send_request(&GetWindowAttributes { window: e.window() }),
)?;
if attrs.override_redirect() {
+ // Something special, don't manage it just let it do its thing.
return Ok(());
}
@@ -135,7 +134,7 @@ impl WM<'_> {
Ok(())
}
- /// Handle a window being unmapped by updating its client state, or stop managing it.
+ /// When a window is unmapped, either stop managing it or update its state.
pub(crate) fn handle_unmap_notify(&mut self, e: UnmapNotifyEvent) -> Result<()> {
if self.clients.find_client_mut(e.window()).is_some() {
if e.is_from_send_event() {
@@ -143,7 +142,7 @@ impl WM<'_> {
} else {
self.clients.remove_client(e.window());
self.clients.rearrange(self.conn);
- // TODO: 'disown' the window - unmange(c, 0)
+ // TODO: 'disown' the window - unmanage(c, 0)
}
}
@@ -198,7 +197,7 @@ impl WM<'_> {
// TODO: updatewmhints
// XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
- c.select_input(
+ c.set_event_mask(
conn,
EventMask::ENTER_WINDOW
| EventMask::FOCUS_CHANGE
@@ -220,32 +219,17 @@ impl WM<'_> {
pub struct ClientState {
/// The current arranging function.
/// This function is expected to ensure that all clients are the correct size, reconfigure them if needed, and map/unmap as needed.
+ /// The connection will be flushed after it is called.
arrange: &'static dyn Fn(&mut MonitorInfo, &Connection),
+
+ /// A client list for each monitor.
mons: Vec<MonitorInfo>,
+ /// Co-ordinates to the currently focused window.
focused: (usize, usize),
}
-impl Default for ClientState {
- fn default() -> Self {
- Self {
- arrange: &tile,
- focused: (0, 0),
- mons: vec![],
- }
- }
-}
-
-impl std::fmt::Debug for ClientState {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- f.debug_struct("ClientState")
- .field("focused", &self.focused)
- .field("mons", &self.mons)
- .finish()
- }
-}
-
-/// Info stored for a single monitor
+/// Info stored for each monitor
#[derive(Debug)]
pub struct MonitorInfo {
/// Clients attached to that monitor
@@ -256,35 +240,22 @@ pub struct MonitorInfo {
}
impl MonitorInfo {
- fn clients_tiled_mut(&mut self) -> impl Iterator<Item = &mut Client> {
+ /// Iterate over all tiled clients, returning a mutable reference to each.
+ pub fn clients_tiled_mut(&mut self) -> impl Iterator<Item = &mut Client> {
// TODO: tag filtering, floating
self.clients.iter_mut()
}
}
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub struct MonitorGeometry {
- pub x_org: i16,
- pub y_org: i16,
- pub width: u16,
- pub height: u16,
-}
-
-impl From<ScreenInfo> for MonitorGeometry {
- fn from(value: ScreenInfo) -> Self {
- Self {
- x_org: value.x_org,
- y_org: value.y_org,
- width: value.width,
- height: value.height,
- }
+impl ClientState {
+ /// Get the amount of monitors this state is currently aware of
+ pub fn monitor_count(&self) -> usize {
+ self.mons.len()
}
-}
-impl ClientState {
- /// Set the new amount of screens, moving clients away if necessary
+ /// Set the new amount of screens, without unmanaging any clients.
pub fn truncate_screens(&mut self, new_size: usize) {
- // hack: double borrow stuff
+ // hack: working around double borrow stuff
let mut moved_clients = vec![];
for old in self.mons.drain(new_size - self.mons.len()..self.mons.len()) {
moved_clients.extend(old.clients.into_iter());
@@ -292,7 +263,7 @@ impl ClientState {
self.mons[0].clients.extend(moved_clients);
}
- /// Set the info for the given screen, resizing the monitor list if necessary.
+ /// Set the given screen's geometry, resizing the monitor list if necessary.
/// Returns true if the new info is different from the old one.
pub fn set_monitor_geometry(&mut self, i: usize, info: MonitorGeometry) -> bool {
while i >= self.mons.len() {
@@ -304,26 +275,20 @@ impl ClientState {
dirty
}
- /// Get the amount of monitors this state is currently aware of
- pub fn monitor_count(&self) -> usize {
- self.mons.len()
- }
-
/// Find the [`Client`] corresponding to the given window
pub fn find_client_mut(&mut self, window: Window) -> Option<&mut Client> {
- self.mons
- .iter_mut()
- .flat_map(|mi| mi.clients.iter_mut())
- .find(|c| c.window == window)
+ let (mon, i) = self.find_client_pos(window)?;
+ Some(&mut self.mons[mon].clients[i])
}
/// Find the position of the client with the given window, returning (monitor, index)
- pub(crate) fn find_client_pos(&mut self, window: Window) -> Option<(usize, usize)> {
+ pub fn find_client_pos(&mut self, window: Window) -> Option<(usize, usize)> {
for (pos_mon, mon) in self.mons.iter_mut().enumerate() {
if let Some(pos) = mon.clients.iter().position(|c| c.window == window) {
return Some((pos_mon, pos));
}
}
+
None
}
@@ -384,6 +349,7 @@ impl ClientState {
(self.arrange)(&mut self.mons[mon], conn);
}
+ /// Get the currently focused monitor
fn focused_mon(&self) -> usize {
self.focused.0
}
@@ -404,6 +370,7 @@ pub struct Client {
}
impl Client {
+ /// Send a configure configure notify event with the current geometry.
/// This function does not check for success, so conn.flush() should be called after.
fn configure_notify(&self, conn: &Connection) {
conn.send_request(&SendEvent {
@@ -425,6 +392,7 @@ impl Client {
}
/// Set this client's geometry, also updating the X11 window if needed.
+ /// This function does not check for success, so conn.flush() should be called after.
fn set_geom(
&mut self,
conn: &Connection,
@@ -458,8 +426,8 @@ impl Client {
});
}
- /// Set the border of the X11 window to the given value.
- /// This sends a request but doesn't wait for the response.
+ /// Set the border colour of the X11 window to the given value (see `crate::colours::Colours`)
+ /// This function does not check for success, so conn.flush() should be called after.
pub fn set_border(&self, conn: &Connection, colour: u32) {
conn.send_request(&ChangeWindowAttributes {
window: self.window(),
@@ -468,6 +436,7 @@ impl Client {
}
/// Ensure this client is currently mapped / visible
+ /// This function does not check for success, so conn.flush() should be called after.
pub fn ensure_mapped(&mut self, conn: &Connection) {
if !self.mapped {
conn.send_request(&MapWindow {
@@ -478,6 +447,7 @@ impl Client {
}
/// Ensure this client is currently unmapped / invisible
+ /// This function does not check for success, so conn.flush() should be called after.
pub fn ensure_unmapped(&mut self, conn: &Connection) {
if self.mapped {
conn.send_request(&UnmapWindow {
@@ -492,7 +462,9 @@ impl Client {
self.window
}
- fn select_input(&self, conn: &Connection, event_mask: EventMask) {
+ /// Set the event mask for this window
+ /// This function does not check for success, so conn.flush() should be called after.
+ fn set_event_mask(&self, conn: &Connection, event_mask: EventMask) {
conn.send_request(&ChangeWindowAttributes {
window: self.window(),
value_list: &[Cw::EventMask(event_mask)],
@@ -514,6 +486,7 @@ impl Default for MonitorInfo {
}
}
+/// A simple tiling function
fn tile(mon: &mut MonitorInfo, conn: &Connection) {
if mon.clients.is_empty() {
return;
@@ -569,3 +542,42 @@ fn tile(mon: &mut MonitorInfo, conn: &Connection) {
c.ensure_mapped(conn);
}
}
+
+impl Default for ClientState {
+ fn default() -> Self {
+ Self {
+ arrange: &tile,
+ focused: (0, 0),
+ mons: vec![],
+ }
+ }
+}
+
+impl std::fmt::Debug for ClientState {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.debug_struct("ClientState")
+ .field("focused", &self.focused)
+ .field("mons", &self.mons)
+ .finish()
+ }
+}
+
+/// Info on the monitor's geometry.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct MonitorGeometry {
+ pub x_org: i16,
+ pub y_org: i16,
+ pub width: u16,
+ pub height: u16,
+}
+
+impl From<ScreenInfo> for MonitorGeometry {
+ fn from(value: ScreenInfo) -> Self {
+ Self {
+ x_org: value.x_org,
+ y_org: value.y_org,
+ width: value.width,
+ height: value.height,
+ }
+ }
+}