Skip to content

Commit

Permalink
Add systray patch (#22)
Browse files Browse the repository at this point in the history
* add systray config options

* add xembed #defines

* add atoms

* add Systray struct

* add most of the code, minus remaining systray functions

* impl updatesystrayicongeom

* impl updatesystrayiconstate

* impl wintosystrayicon

* impl systraytomon

* const -> static to prevent constant comparison error lint

* impl updatesystray

* handle clippy
  • Loading branch information
ntBre authored Aug 29, 2024
1 parent 4e8b60e commit c0d03ca
Show file tree
Hide file tree
Showing 8 changed files with 781 additions and 75 deletions.
13 changes: 13 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,19 @@ use rwm::{Arg, Button, Key, Layout, Rule};
pub const BORDERPX: c_uint = 3;
// Snap pixel
pub const SNAP: c_uint = 32;

/// 0: sloppy systray follows selected monitor, >0: pin systray to monitor x
pub static SYSTRAYPINNING: c_uint = 0;
/// 0: systray in the right corner, >0: systray on left of status text
pub const SYSTRAYONLEFT: c_uint = 0;
/// systray spacing
pub const SYSTRAYSPACING: c_uint = 2;
/// 1: if pinning fails, display systray on the first monitor, False: display
/// systray on the last monitor
pub const SYSTRAYPINNINGFAILFIRST: c_int = 1;
/// 0 means no systray
pub const SHOWSYSTRAY: c_int = 1;

/// 0 means no bar
pub const SHOWBAR: c_int = 1;
/// 0 means bottom bar
Expand Down
11 changes: 11 additions & 0 deletions src/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ pub enum Net {
WMName,
WMState,
WMCheck,
SystemTray,
SystemTrayOP,
SystemTrayOrientation,
SystemTrayOrientationHorz,
WMFullscreen,
ActiveWindow,
WMWindowType,
Expand All @@ -47,6 +51,13 @@ pub enum Net {
Last,
}

pub enum XEmbed {
Manager,
XEmbed,
XEmbedInfo,
Last,
}

/// Clr scheme index
pub enum Col {
Fg,
Expand Down
255 changes: 231 additions & 24 deletions src/handlers.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,44 @@
use std::{
ffi::{c_int, c_uint},
ffi::{c_int, c_long, c_uint},
mem::MaybeUninit,
ptr::{addr_of, addr_of_mut, null_mut},
};

use x11::xlib::{
self, CWBorderWidth, CWHeight, CWWidth, CurrentTime, False, KeyCode,
MappingKeyboard, NotifyInferior, NotifyNormal, PropertyDelete,
ReplayPointer, XEvent, XWindowAttributes, CWX, CWY, XA_WM_HINTS,
XA_WM_NAME, XA_WM_NORMAL_HINTS, XA_WM_TRANSIENT_FOR,
self, CWBackPixel, CWBorderWidth, CWHeight, CWWidth, CurrentTime, False,
KeyCode, MappingKeyboard, NotifyInferior, NotifyNormal, PropertyChangeMask,
PropertyDelete, ReplayPointer, ResizeRedirectMask, StructureNotifyMask,
XAddToSaveSet, XChangeWindowAttributes, XEvent, XGetWindowAttributes,
XMapRaised, XReparentWindow, XSelectInput, XSetWindowAttributes, XSync,
XWindowAttributes, CWX, CWY, XA_WM_HINTS, XA_WM_NAME, XA_WM_NORMAL_HINTS,
XA_WM_TRANSIENT_FOR,
};

use rwm::{Arg, Monitor, Window};
use rwm::{
enums::{Col, Scheme, XEmbed},
Arg, Client, Monitor, Window,
};

use crate::{
arrange, cleanmask,
config::{BUTTONS, KEYS, TAGS},
config::{self, BUTTONS, KEYS, TAGS},
configure, drawbar, drawbars, drw,
enums::{Clk, Net},
focus, grabkeys, height, is_visible, manage, recttomon, resizeclient,
restack, setclientstate, setfocus, setfullscreen, seturgent, textw,
unfocus, unmanage, updatebars, updategeom, updatestatus, updatetitle,
updatewindowtype, updatewmhints, width, wintoclient, wintomon, BH, DPY,
DRW, MONS, NETATOM, ROOT, SELMON, SH, STEXT, SW, WITHDRAWN_STATE,
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,
util::ecalloc,
width, wintoclient, wintomon, wintosystrayicon,
xembed::{
SYSTEM_TRAY_REQUEST_DOCK, XEMBED_EMBEDDED_NOTIFY,
XEMBED_EMBEDDED_VERSION, XEMBED_FOCUS_IN, XEMBED_MODALITY_ON,
XEMBED_WINDOW_ACTIVATE,
},
BH, DPY, DRW, MONS, NETATOM, NORMAL_STATE, ROOT, SCHEME, SELMON, SH, STEXT,
SW, SYSTRAY, WITHDRAWN_STATE,
};

pub(crate) fn buttonpress(e: *mut XEvent) {
Expand Down Expand Up @@ -57,7 +74,11 @@ pub(crate) fn buttonpress(e: *mut XEvent) {
} else if ev.x < x + textw(addr_of!((*SELMON).ltsymbol) as *const _)
{
click = Clk::LtSymbol;
} else if ev.x > (*SELMON).ww - textw(addr_of!(STEXT) as *const _) {
} else if ev.x
> (*SELMON).ww
- textw(addr_of!(STEXT) as *const _)
- getsystraywidth() as i32
{
click = Clk::StatusText;
} else {
click = Clk::WinTitle;
Expand Down Expand Up @@ -92,7 +113,140 @@ pub(crate) fn buttonpress(e: *mut XEvent) {
pub(crate) fn clientmessage(e: *mut XEvent) {
unsafe {
let cme = &(*e).client_message;
let c = wintoclient(cme.window);
let mut c = wintoclient(cme.window);

if config::SHOWSYSTRAY != 0
&& cme.window == (*SYSTRAY).win
&& cme.message_type == NETATOM[Net::SystemTrayOP as usize]
{
// add systray icons
if cme.data.get_long(1) == SYSTEM_TRAY_REQUEST_DOCK as c_long {
c = ecalloc(1, size_of::<Client>()).cast();
}
(*c).win = cme.data.get_long(2) as u64;
if (*c).win == 0 {
libc::free(c.cast());
return;
}
(*c).mon = SELMON;
(*c).next = (*SYSTRAY).icons;
(*SYSTRAY).icons = c;
let mut wa = MaybeUninit::uninit();
if XGetWindowAttributes(DPY, (*c).win, wa.as_mut_ptr()) == 0 {
// use sane defaults
(*wa.as_mut_ptr()).width = BH;
(*wa.as_mut_ptr()).height = BH;
(*wa.as_mut_ptr()).border_width = 0;
}
let wa = wa.assume_init();
// Safety: we already returned if c was null in ecalloc. could have
// done this earlier too
let c = &mut *c;

c.x = 0;
c.oldx = 0;
c.y = 0;
c.oldy = 0;

c.w = wa.width;
c.oldw = wa.width;

c.h = wa.height;
c.oldh = wa.height;

c.oldbw = wa.border_width;
c.bw = 0;
c.isfloating = 1;

// reuse tags field as mapped status
c.tags = 1;
updatesizehints(c);
updatesystrayicongeom(c, wa.width, wa.height);
XAddToSaveSet(DPY, c.win);
XSelectInput(
DPY,
c.win,
StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask,
);
XReparentWindow(DPY, c.win, (*SYSTRAY).win, 0, 0);
// use parent's background color
let mut swa = XSetWindowAttributes {
background_pixmap: 0,
background_pixel: get_scheme_color(
SCHEME,
Scheme::Norm as usize,
Col::Bg as usize,
)
.pixel,
border_pixmap: 0,
border_pixel: 0,
bit_gravity: 0,
win_gravity: 0,
backing_store: 0,
backing_planes: 0,
backing_pixel: 0,
save_under: 0,
event_mask: 0,
do_not_propagate_mask: 0,
override_redirect: 0,
colormap: 0,
cursor: 0,
};
XChangeWindowAttributes(DPY, c.win, CWBackPixel, &mut swa);
// TODO this looks like the wrong index. xembed should be used to
// index xatom. this could be coincidentally correct since they're
// all integers though. the net atom at the same index would be
// Net::WMName
sendevent(
c.win,
NETATOM[XEmbed::XEmbed as usize],
StructureNotifyMask as i32,
CurrentTime as i64,
XEMBED_EMBEDDED_NOTIFY as i64,
0,
(*SYSTRAY).win as i64,
XEMBED_EMBEDDED_VERSION as i64,
);

// FIXME (original author) not sure if I have to send these events
// too
sendevent(
c.win,
NETATOM[XEmbed::XEmbed as usize],
StructureNotifyMask as i32,
CurrentTime as i64,
XEMBED_FOCUS_IN as i64,
0,
(*SYSTRAY).win as i64,
XEMBED_EMBEDDED_VERSION as i64,
);
sendevent(
c.win,
NETATOM[XEmbed::XEmbed as usize],
StructureNotifyMask as i32,
CurrentTime as i64,
XEMBED_WINDOW_ACTIVATE as i64,
0,
(*SYSTRAY).win as i64,
XEMBED_EMBEDDED_VERSION as i64,
);
sendevent(
c.win,
NETATOM[XEmbed::XEmbed as usize],
StructureNotifyMask as i32,
CurrentTime as i64,
XEMBED_MODALITY_ON as i64,
0,
(*SYSTRAY).win as i64,
XEMBED_EMBEDDED_VERSION as i64,
);
XSync(DPY, False);
resizebarwin(SELMON);
updatesystray();
setclientstate(c, NORMAL_STATE);

return;
}

if c.is_null() {
return;
Expand Down Expand Up @@ -217,14 +371,7 @@ pub(crate) fn configurenotify(e: *mut XEvent) {
}
c = (*c).next;
}
xlib::XMoveResizeWindow(
DPY,
(*m).barwin,
(*m).wx,
(*m).by,
(*m).ww as u32,
BH as u32,
);
resizebarwin(m);
m = (*m).next;
}
focus(null_mut());
Expand All @@ -237,9 +384,16 @@ pub(crate) fn configurenotify(e: *mut XEvent) {
pub(crate) fn destroynotify(e: *mut XEvent) {
unsafe {
let ev = &(*e).destroy_window;
let c = wintoclient(ev.window);
let mut c = wintoclient(ev.window);
if !c.is_null() {
unmanage(c, 1);
} else {
c = wintosystrayicon(ev.window);
if !c.is_null() {
removesystrayicon(c);
resizebarwin(SELMON);
updatesystray();
}
}
}
}
Expand Down Expand Up @@ -272,6 +426,9 @@ pub(crate) fn expose(e: *mut XEvent) {
let m = wintomon(ev.window);
if !m.is_null() {
drawbar(m);
if m == SELMON {
updatesystray();
}
}
}
}
Expand Down Expand Up @@ -345,6 +502,21 @@ pub(crate) fn maprequest(e: *mut XEvent) {
// in its previous state.
unsafe {
let ev = &(*e).map_request;
let i = wintosystrayicon(ev.window);
if !i.is_null() {
sendevent(
(*i).win,
NETATOM[XEmbed::XEmbed as usize],
StructureNotifyMask as i32,
CurrentTime as i64,
XEMBED_WINDOW_ACTIVATE as i64,
0,
(*SYSTRAY).win as i64,
XEMBED_EMBEDDED_VERSION as i64,
);
resizebarwin(SELMON);
updatesystray();
}
log::trace!("maprequest: XGetWindowAttributes");
let res = xlib::XGetWindowAttributes(DPY, ev.window, addr_of_mut!(WA));
// XGetWindowAttributes returns a zero if the function fails
Expand Down Expand Up @@ -380,6 +552,19 @@ pub(crate) fn propertynotify(e: *mut XEvent) {
unsafe {
let mut trans: Window = 0;
let ev = &mut (*e).property;

let c = wintosystrayicon(ev.window);
if !c.is_null() {
if ev.atom == XA_WM_NORMAL_HINTS {
updatesizehints(c);
updatesystrayicongeom(c, (*c).w, (*c).h);
} else {
updatesystrayiconstate(c, ev);
}
resizebarwin(SELMON);
updatesystray();
}

if ev.window == ROOT && ev.atom == XA_WM_NAME {
updatestatus();
} else if ev.state == PropertyDelete {
Expand Down Expand Up @@ -429,13 +614,35 @@ pub(crate) fn unmapnotify(e: *mut XEvent) {
log::trace!("unmapnotify");
unsafe {
let ev = &(*e).unmap;
let c = wintoclient(ev.window);
let mut c = wintoclient(ev.window);
if !c.is_null() {
if ev.send_event != 0 {
setclientstate(c, WITHDRAWN_STATE);
} else {
unmanage(c, 0);
}
} else {
c = wintosystrayicon(ev.window);
if !c.is_null() {
// KLUDGE (systray author) sometimes icons occasionally unmap
// their windows but do _not_ destroy them. we map those windows
// back
XMapRaised(DPY, (*c).win);
updatesystray();
}
}
}
}

pub(crate) fn resizerequest(e: *mut XEvent) {
log::trace!("resizerequest");
unsafe {
let ev = &(*e).resize_request;
let i = wintosystrayicon(ev.window);
if !i.is_null() {
updatesystrayicongeom(i, ev.width, ev.height);
resizebarwin(SELMON);
updatesystray();
}
}
}
Loading

0 comments on commit c0d03ca

Please sign in to comment.