libmars 0.6.2

Library to build window managers and accompanying utilities
Documentation
extern crate x11;

use std::fmt::{Display, Formatter, Result};
use x11::xlib;
use std::ffi::*;

use crate::*;

enum_with_values! {
    #[derive(Clone, Copy, Debug, PartialEq, Eq)]
    vis pub enum X11Atom {
        // ICCCM
        UTF8String,
        WMClass,
        WMDeleteWindow,
        WMIconName,
        WMIconSize,
        WMName,
        WMNormalHints,
        WMProtocols,
        WMState,

        // EWMH
        NetActiveWindow,
        NetClientList,
        NetClientListStacking,
        NetCloseWindow,
        NetCurrentDesktop,
        NetDesktopGeometry,
        NetDesktopNames,
        NetDesktopViewport,
        NetNumberOfDesktops,
        NetSupported,
        NetSupportingWMCheck,
        NetSystemTray,
        NetSystemTrayOpcode,
        NetSystemTrayOrientation,
        NetWMDesktop,
        NetWMName,
        NetWMState,
        NetWMStateFullscreen,
        NetWMWindowType,
        NetWMWindowTypeDesktop,
        NetWMWindowTypeDialog,
        NetWMWindowTypeDock,
        NetWMWindowTypeMenu,
        NetWMWindowTypeNotification,
        NetWMWindowTypeSplash,
        NetWorkarea,

        // Motif
        MotifWMHints,

        // XEMBED
        Manager,
        Xembed,
        XembedInfo,

        // TODO add custom hints for pinned, tiled
        // MARS (custom)
        MarsCenter,
        MarsStatus,
        MarsWMStateTiled
    }
}

impl Display for X11Atom {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        let string = match self {
            X11Atom::UTF8String => "UTF8_STRING",
            X11Atom::WMClass => "WM_CLASS",
            X11Atom::WMDeleteWindow => "WM_DELETE_WINDOW",
            X11Atom::WMIconName => "WM_ICON_NAME",
            X11Atom::WMIconSize => "WM_ICON_SIZE",
            X11Atom::WMProtocols => "WM_PROTOCOLS",
            X11Atom::WMName => "WM_NAME",
            X11Atom::WMNormalHints => "WM_NORMAL_HINTS",
            X11Atom::WMState => "WM_STATE",

            X11Atom::NetActiveWindow => "_NET_ACTIVE_WINDOW",
            X11Atom::NetClientList => "_NET_CLIENT_LIST",
            X11Atom::NetClientListStacking => "_NET_CLIENT_LIST_STACKING",
            X11Atom::NetCloseWindow => "_NET_CLOSE_WINDOW",
            X11Atom::NetCurrentDesktop => "_NET_CURRENT_DESKTOP",
            X11Atom::NetDesktopGeometry => "_NET_DESKTOP_GEOMETRY",
            X11Atom::NetDesktopNames => "_NET_DESKTOP_NAMES",
            X11Atom::NetDesktopViewport => "_NET_DESKTOP_VIEWPORT",
            X11Atom::NetNumberOfDesktops => "_NET_NUMBER_OF_DESKTOPS",
            X11Atom::NetSupported => "_NET_SUPPORTED",
            X11Atom::NetSupportingWMCheck => "_NET_SUPPORTING_WM_CHECK",
            X11Atom::NetSystemTray => "_NET_SYSTEM_TRAY_S0",
            X11Atom::NetSystemTrayOpcode => "_NET_SYSTEM_TRAY_OPCODE",
            X11Atom::NetSystemTrayOrientation => "_NET_SYSTEM_TRAY_ORIENTATION",
            X11Atom::NetWMDesktop => "_NET_WM_DESKTOP",
            X11Atom::NetWMName => "_NET_WM_NAME",
            X11Atom::NetWMState => "_NET_WM_STATE",
            X11Atom::NetWMStateFullscreen => "_NET_WM_STATE_FULLSCREEN",
            X11Atom::NetWMWindowType => "_NET_WM_WINDOW_TYPE",
            X11Atom::NetWMWindowTypeDock => "_NET_WM_WINDOW_TYPE_DOCK",
            X11Atom::NetWMWindowTypeDesktop => "_NET_WM_WINDOW_TYPE_DESKTOP",
            X11Atom::NetWMWindowTypeDialog => "_NET_WM_WINDOW_TYPE_DIALOG",
            X11Atom::NetWMWindowTypeMenu => "_NET_WM_WINDOW_TYPE_MENU",
            X11Atom::NetWMWindowTypeNotification => "_NET_WM_WINDOW_TYPE_NOTIFICATION",
            X11Atom::NetWMWindowTypeSplash => "_NET_WM_WINDOW_TYPE_SPLASH",
            X11Atom::NetWorkarea => "_NET_WORKAREA",

            X11Atom::MotifWMHints => "_MOTIF_WM_HINTS",

            X11Atom::Manager => "MANAGER",
            X11Atom::Xembed => "_XEMBED",
            X11Atom::XembedInfo => "_XEMBED_INFO",

            X11Atom::MarsCenter => "_MARS_CENTER",
            X11Atom::MarsStatus => "_MARS_STATUS",
            X11Atom::MarsWMStateTiled => "_MARS_WM_STATE_TILED",
        };
        write!(f, "{}", string)
    }
}

impl X11Atom {
    pub fn from_xlib_atom(display: *mut xlib::Display, atom: xlib::Atom) -> Option<X11Atom> {
        let name = unsafe {
            let raw_string = xlib::XGetAtomName(display, atom);
            // FIXME use CStr and XFree instead
            CString::from_raw(raw_string).into_string().unwrap()
        };
        for atom in Self::VALUES {
            if atom.to_string() == name {
                return Some(*atom);
            }
        }
        None
    }

    pub fn to_xlib_atom(&self, display: *mut xlib::Display) -> xlib::Atom {
        let atom_name = CString::new(self.to_string()).unwrap().into_raw();
        unsafe {
            xlib::XInternAtom(display, atom_name, xlib::False)
        }
    }
}

pub fn atom_name(display: *mut xlib::Display, atom: xlib::Atom) -> Option<String> {
    unsafe {
        let name_ptr = xlib::XGetAtomName(display, atom);
        if name_ptr.is_null() {
            None
        } else {
            let name = CStr::from_ptr(name_ptr).to_string_lossy().to_string();
            xlib::XFree(name_ptr as *mut c_void);
            Some(name)
        }
    }
}