<commit_before>use std::cell::{Ref, RefCell, RefMut};
use std::ffi::CString;
use std::io::Write;
use std::os::raw::{c_long, c_int, c_uchar, c_uint, c_ulong, c_void};
use std::mem::{size_of, zeroed};
use std::ptr::{null, null_mut};
use std::rc::Rc;
use std::slice;

use x11::xlib;

use atoms::Atoms;
use config::Config;
use util;

#[derive(Clone, Debug)]
pub struct Rect {
    pub x: c_int,
    pub y: c_int,
    pub width: c_int,
    pub height: c_int,
}

impl Default for Rect {
    fn default() -> Rect {
        Rect {
            x: -1,
            y: -1,
            width: -1,
            height: -1,
        }
    }
}

impl Rect {
    pub fn new(x: c_int, y: c_int, width: c_int, height: c_int) -> Rect {
        Rect {
            x: x,
            y: y,
            width: width,
            height: height,
        }
    }
}

pub struct Client {
    pub atoms: Rc<Atoms>,
    config: Rc<Config>,
    pub tag: c_uchar,
    pub title: String,
    root: xlib::Window,
    class: String,
    was_floating: bool,
    is_floating: bool,
    is_sticky: bool,
    is_dialog: bool,
    is_maximized: bool,
    is_fullscreen: bool,
    is_dock: bool,
    is_above: bool,
    normal_border_color: c_ulong,
    focused_border_color: c_ulong,
    pub display: *mut xlib::Display,
    pub window: c_ulong,
    pub old_rect: Rect,
    pub rect: Rect,
    pub border: c_int,
    pub old_border: c_int,
    pub weight: i32,
}

impl Client {
    pub fn new(config: Rc<Config>,
               display: *mut xlib::Display,
               root: xlib::Window,
               window: c_ulong,
               tag: c_uchar,
               atoms: Rc<Atoms>)
               -> Client {
        let mut class_hint: xlib::XClassHint = unsafe { zeroed() };
        let mut client = Client {
            config: config,
            display: display,
            root: root,
            window: window,
            tag: tag,
            atoms: atoms,
            title: "broken".to_string(),
            class: "broken".to_string(),
            was_floating: false,
            is_floating: false,
            is_dialog: false,
            is_sticky: false,
            is_maximized: false,
            is_fullscreen: false,
            is_dock: false,
            is_above: false,
            focused_border_color: 0,
            normal_border_color: 0,
            old_rect: Rect::default(),
            rect: Rect::default(),
            border: 0,
            old_border: 0,
            weight: -1,
        };
        unsafe {
            xlib::XGetClassHint(display, window, &mut class_hint);
            if !class_hint.res_class.is_null() {
                client.class =
                    CString::from_raw(class_hint.res_class).to_string_lossy().into_owned();
            }
        }
        client
    }

    pub fn save_window_size(&mut self) {
        self.old_rect = self.rect.clone();
        log!("Save window size: old rect: {:?}", self.old_rect);
    }

    pub fn set_size(&mut self, x: c_int, y: c_int, width: c_int, height: c_int) {
        self.rect = Rect {
            x: x,
            y: y,
            width: width,
            height: height,
        };
    }
}

#[derive(Clone)]
pub struct ClientW(Rc<RefCell<Client>>);
pub type ClientL = Vec<ClientW>;

impl ClientW {
    pub fn new(config: Rc<Config>,
               display: *mut xlib::Display,
               root: xlib::Window,
               window: c_ulong,
               tag: c_uchar,
               atoms: Rc<Atoms>)
               -> ClientW {
        ClientW(Rc::new(RefCell::new(Client::new(config, display, root, window, tag, atoms))))
    }

    pub fn borrow(&self) -> Ref<Client> {
        self.0.borrow()
    }

    pub fn borrow_mut(&mut self) -> RefMut<Client> {
        self.0.borrow_mut()
    }

    pub fn get_title(&self) -> String {
        self.borrow().title.clone()
    }

    pub fn update_title(&mut self) {
        self.borrow_mut().title =
            util::get_text_prop(self.display(), self.window(), self.atoms().net_wm_name)
                .or(util::get_text_prop(self.display(), self.window(), xlib::XA_WM_NAME))
                .unwrap_or("Unknown".to_string());
    }

    pub fn get_class<'a>(&self) -> String {
        // TODO: Revisit: unnecessary clone.
        self.borrow().class.clone()
    }

    pub fn is_fullscreen(&self) -> bool {
        self.borrow().is_fullscreen
    }

    pub fn is_floating(&self) -> bool {
        self.borrow().is_floating
    }

    pub fn is_above(&self) -> bool {
        self.borrow().is_above
    }

    pub fn is_sticky(&self) -> bool {
        self.borrow().is_sticky
    }

    pub fn is_dock(&self) -> bool {
        self.borrow().is_dock
    }

    pub fn atoms(&self) -> Rc<Atoms> {
        self.borrow().atoms.clone()
    }

    pub fn is_dialog(&self) -> bool {
        if let Some(atom) = self.get_atom(self.borrow().atoms.net_wm_window_type) {
            atom == self.borrow().atoms.net_wm_window_type_dialog
        } else {
            false
        }
    }

    pub fn is_maximized(&self) -> bool {
        self.borrow().is_maximized
    }

    pub fn get_atom(&self, atom: xlib::Atom) -> Option<xlib::Atom> {
        let mut da: xlib::Atom = 0;
        let mut di: c_int = 0;
        let mut dl: c_ulong = 0;
        let mut c: *mut c_uchar = null_mut();
        unsafe {
            let ret = xlib::XGetWindowProperty(self.display(),
                                               self.window(),
                                               atom,
                                               0,
                                               size_of::<xlib::Atom>() as c_long,
                                               0,
                                               xlib::XA_ATOM,
                                               &mut da,
                                               &mut di,
                                               &mut dl,
                                               &mut dl,
                                               &mut c);
            if ret == xlib::Success as c_int && !c.is_null() {
                log!("Success atom!");
                let result = *(c as *mut xlib::Atom);
                log!("Success deref!");
                xlib::XFree(c as *mut c_void);
                log!("Return!");
                return Some(result);
            }
            None
        }
    }

    pub fn set_floating(&mut self, floating: bool) {
        let was_floating = self.borrow().is_floating;
        self.borrow_mut().was_floating = was_floating;
        self.borrow_mut().is_floating = floating;
    }

    pub fn set_sticky(&mut self, sticky: bool) {
        self.borrow_mut().is_sticky = sticky;
    }

    pub fn set_dock(&mut self, dock: bool) {
        self.borrow_mut().is_dock = dock;
    }

    pub fn set_above(&mut self, above: bool) {
        self.borrow_mut().is_above = above;
    }

    pub fn set_maximized(&mut self, maximized: bool) {
        self.borrow_mut().is_maximized = maximized;
    }

    pub fn set_fullscreen(&mut self, rect: Rect, fullscreen: bool) {
        if fullscreen {
            unsafe {
                xlib::XChangeProperty(self.display(),
                                      self.window(),
                                      self.atoms().net_wm_state,
                                      xlib::XA_ATOM,
                                      32,
                                      xlib::PropModeReplace,
                                      (&self.atoms().net_wm_state_fullscreen as *const u64) as *const u8,
                                      1);
            }
            self.borrow_mut().is_fullscreen = true;
            self.set_floating(true);
            self.resize(rect, false);
            self.raise_window();
        } else {
            unsafe {
                xlib::XChangeProperty(self.display(),
                                      self.window(),
                                      self.atoms().net_wm_state,
                                      xlib::XA_ATOM,
                                      32,
                                      xlib::PropModeReplace,
                                      null(),
                                      0);
            }
            let was_floating = self.borrow().was_floating;
            self.set_floating(was_floating);
            self.borrow_mut().is_fullscreen = false;
            let old_rect = self.borrow().old_rect.clone();
            self.resize(old_rect, false);
        }
    }

    pub fn display(&self) -> *mut xlib::Display {
        self.borrow().display
    }
    pub fn tag(&self) -> c_uchar {
        self.borrow().tag
    }

    pub fn window(&self) -> c_ulong {
        self.borrow().window
    }

    pub fn show(&mut self, visible: bool) {
        let rect = self.get_rect();
        if visible {
            self.move_window(rect.x, rect.y, false);
        } else {
            self.move_window(-10 * rect.width, rect.y, false);
        }
    }

    pub fn get_rect(&self) -> Rect {
        self.borrow().rect.clone()
    }

    pub fn move_window(&mut self, x: c_int, y: c_int, save: bool) {
        if save {
            self.borrow_mut().save_window_size();
            self.borrow_mut().rect.x = x;
            self.borrow_mut().rect.y = y;
        }
        unsafe {
            xlib::XMoveWindow(self.borrow().display, self.borrow().window, x, y);
        }
    }

    pub fn resize(&mut self, rect: Rect, temporary: bool) {
        if !temporary {
            self.borrow_mut().save_window_size();
            self.borrow_mut().set_size(rect.x, rect.y, rect.width, rect.height);
        }
        let mut xc: xlib::XWindowChanges = unsafe { zeroed() };
        xc.x = rect.x;
        xc.y = rect.y;
        xc.width = rect.width;
        xc.height = rect.height;
        unsafe {
            xlib::XConfigureWindow(self.display(),
                                   self.window(),
                                   (xlib::CWX | xlib::CWY | xlib::CWWidth | xlib::CWHeight) as u32,
                                   &mut xc);
            xlib::XSync(self.display(), 0);
        }
    }

    pub fn configure(&mut self) {
        let mut ce: xlib::XConfigureEvent = unsafe { zeroed() };
        let rect = self.get_rect();<commit_msg>Add an invalidate hack.<commit_after>use std::cell::{Ref, RefCell, RefMut};
use std::ffi::CString;
use std::io::Write;
use std::os::raw::{c_long, c_int, c_uchar, c_uint, c_ulong, c_void};
use std::mem::{size_of, zeroed};
use std::ptr::{null, null_mut};
use std::rc::Rc;
use std::slice;

use x11::xlib;

use atoms::Atoms;
use config::Config;
use util;

#[derive(Clone, Debug)]
pub struct Rect {
    pub x: c_int,
    pub y: c_int,
    pub width: c_int,
    pub height: c_int,
}

impl Default for Rect {
    fn default() -> Rect {
        Rect {
            x: -1,
            y: -1,
            width: -1,
            height: -1,
        }
    }
}

impl Rect {
    pub fn new(x: c_int, y: c_int, width: c_int, height: c_int) -> Rect {
        Rect {
            x: x,
            y: y,
            width: width,
            height: height,
        }
    }
}

pub struct Client {
    pub atoms: Rc<Atoms>,
    config: Rc<Config>,
    pub tag: c_uchar,
    pub title: String,
    root: xlib::Window,
    class: String,
    was_floating: bool,
    is_floating: bool,
    is_sticky: bool,
    is_dialog: bool,
    is_maximized: bool,
    is_fullscreen: bool,
    is_dock: bool,
    is_above: bool,
    normal_border_color: c_ulong,
    focused_border_color: c_ulong,
    pub display: *mut xlib::Display,
    pub window: c_ulong,
    pub old_rect: Rect,
    pub rect: Rect,
    pub border: c_int,
    pub old_border: c_int,
    pub weight: i32,
}

impl Client {
    pub fn new(config: Rc<Config>,
               display: *mut xlib::Display,
               root: xlib::Window,
               window: c_ulong,
               tag: c_uchar,
               atoms: Rc<Atoms>)
               -> Client {
        let mut class_hint: xlib::XClassHint = unsafe { zeroed() };
        let mut client = Client {
            config: config,
            display: display,
            root: root,
            window: window,
            tag: tag,
            atoms: atoms,
            title: "broken".to_string(),
            class: "broken".to_string(),
            was_floating: false,
            is_floating: false,
            is_dialog: false,
            is_sticky: false,
            is_maximized: false,
            is_fullscreen: false,
            is_dock: false,
            is_above: false,
            focused_border_color: 0,
            normal_border_color: 0,
            old_rect: Rect::default(),
            rect: Rect::default(),
            border: 0,
            old_border: 0,
            weight: -1,
        };
        unsafe {
            xlib::XGetClassHint(display, window, &mut class_hint);
            if !class_hint.res_class.is_null() {
                client.class =
                    CString::from_raw(class_hint.res_class).to_string_lossy().into_owned();
            }
        }
        client
    }

    pub fn save_window_size(&mut self) {
        self.old_rect = self.rect.clone();
        log!("Save window size: old rect: {:?}", self.old_rect);
    }

    pub fn set_size(&mut self, x: c_int, y: c_int, width: c_int, height: c_int) {
        self.rect = Rect {
            x: x,
            y: y,
            width: width,
            height: height,
        };
    }
}

#[derive(Clone)]
pub struct ClientW(Rc<RefCell<Client>>);
pub type ClientL = Vec<ClientW>;

impl ClientW {
    pub fn new(config: Rc<Config>,
               display: *mut xlib::Display,
               root: xlib::Window,
               window: c_ulong,
               tag: c_uchar,
               atoms: Rc<Atoms>)
               -> ClientW {
        ClientW(Rc::new(RefCell::new(Client::new(config, display, root, window, tag, atoms))))
    }

    pub fn borrow(&self) -> Ref<Client> {
        self.0.borrow()
    }

    pub fn borrow_mut(&mut self) -> RefMut<Client> {
        self.0.borrow_mut()
    }

    pub fn get_title(&self) -> String {
        self.borrow().title.clone()
    }

    pub fn update_title(&mut self) {
        self.borrow_mut().title =
            util::get_text_prop(self.display(), self.window(), self.atoms().net_wm_name)
                .or(util::get_text_prop(self.display(), self.window(), xlib::XA_WM_NAME))
                .unwrap_or("Unknown".to_string());
    }

    pub fn get_class<'a>(&self) -> String {
        // TODO: Revisit: unnecessary clone.
        self.borrow().class.clone()
    }

    pub fn is_fullscreen(&self) -> bool {
        self.borrow().is_fullscreen
    }

    pub fn is_floating(&self) -> bool {
        self.borrow().is_floating
    }

    pub fn is_above(&self) -> bool {
        self.borrow().is_above
    }

    pub fn is_sticky(&self) -> bool {
        self.borrow().is_sticky
    }

    pub fn is_dock(&self) -> bool {
        self.borrow().is_dock
    }

    pub fn atoms(&self) -> Rc<Atoms> {
        self.borrow().atoms.clone()
    }

    pub fn is_dialog(&self) -> bool {
        if let Some(atom) = self.get_atom(self.borrow().atoms.net_wm_window_type) {
            atom == self.borrow().atoms.net_wm_window_type_dialog
        } else {
            false
        }
    }

    pub fn is_maximized(&self) -> bool {
        self.borrow().is_maximized
    }

    pub fn get_atom(&self, atom: xlib::Atom) -> Option<xlib::Atom> {
        let mut da: xlib::Atom = 0;
        let mut di: c_int = 0;
        let mut dl: c_ulong = 0;
        let mut c: *mut c_uchar = null_mut();
        unsafe {
            let ret = xlib::XGetWindowProperty(self.display(),
                                               self.window(),
                                               atom,
                                               0,
                                               size_of::<xlib::Atom>() as c_long,
                                               0,
                                               xlib::XA_ATOM,
                                               &mut da,
                                               &mut di,
                                               &mut dl,
                                               &mut dl,
                                               &mut c);
            if ret == xlib::Success as c_int && !c.is_null() {
                log!("Success atom!");
                let result = *(c as *mut xlib::Atom);
                log!("Success deref!");
                xlib::XFree(c as *mut c_void);
                log!("Return!");
                return Some(result);
            }
            None
        }
    }

    pub fn set_floating(&mut self, floating: bool) {
        let was_floating = self.borrow().is_floating;
        self.borrow_mut().was_floating = was_floating;
        self.borrow_mut().is_floating = floating;
    }

    pub fn set_sticky(&mut self, sticky: bool) {
        self.borrow_mut().is_sticky = sticky;
    }

    pub fn set_dock(&mut self, dock: bool) {
        self.borrow_mut().is_dock = dock;
    }

    pub fn set_above(&mut self, above: bool) {
        self.borrow_mut().is_above = above;
    }

    pub fn set_maximized(&mut self, maximized: bool) {
        self.borrow_mut().is_maximized = maximized;
    }

    pub fn set_fullscreen(&mut self, rect: Rect, fullscreen: bool) {
        if fullscreen {
            unsafe {
                xlib::XChangeProperty(self.display(),
                                      self.window(),
                                      self.atoms().net_wm_state,
                                      xlib::XA_ATOM,
                                      32,
                                      xlib::PropModeReplace,
                                      (&self.atoms().net_wm_state_fullscreen as *const u64) as *const u8,
                                      1);
            }
            self.borrow_mut().is_fullscreen = true;
            self.set_floating(true);
            self.resize(rect, false);
            self.raise_window();
        } else {
            unsafe {
                xlib::XChangeProperty(self.display(),
                                      self.window(),
                                      self.atoms().net_wm_state,
                                      xlib::XA_ATOM,
                                      32,
                                      xlib::PropModeReplace,
                                      null(),
                                      0);
            }
            let was_floating = self.borrow().was_floating;
            self.set_floating(was_floating);
            self.borrow_mut().is_fullscreen = false;
            let old_rect = self.borrow().old_rect.clone();
            self.resize(old_rect, false);
        }
    }

    pub fn display(&self) -> *mut xlib::Display {
        self.borrow().display
    }
    pub fn tag(&self) -> c_uchar {
        self.borrow().tag
    }

    pub fn window(&self) -> c_ulong {
        self.borrow().window
    }

    pub fn show(&mut self, visible: bool) {
        let rect = self.get_rect();
        if visible {
            self.move_window(rect.x, rect.y, false);
            self.invalidate();
        } else {
            self.move_window(-10 * rect.width, rect.y, false);
        }
    }

    pub fn get_rect(&self) -> Rect {
        self.borrow().rect.clone()
    }

    pub fn move_window(&mut self, x: c_int, y: c_int, save: bool) {
        if save {
            self.borrow_mut().save_window_size();
            self.borrow_mut().rect.x = x;
            self.borrow_mut().rect.y = y;
        }
        unsafe {
            xlib::XMoveWindow(self.borrow().display, self.borrow().window, x, y);
        }
    }

    pub fn invalidate(&self) {
        unsafe {
            xlib::XClearArea(self.display(), self.window(), 0, 0, 1, 1, 1);
        }
    }

    pub fn resize(&mut self, rect: Rect, temporary: bool) {
        if !temporary {
            self.borrow_mut().save_window_size();
            self.borrow_mut().set_size(rect.x, rect.y, rect.width, rect.height);
        }
        let mut xc: xlib::XWindowChanges = unsafe { zeroed() };
        xc.x = rect.x;
        xc.y = rect.y;
        xc.width = rect.width;
        xc.height = rect.height;
        unsafe {
            xlib::XConfigureWindow(self.display(),
                                   self.window(),
                                   (xlib::CWX | xlib::CWY | xlib::CWWidth | xlib::CWHeight) as u32,
                                   &mut xc);
            xlib::XSync(self.display(), 0);
        }
    }

    pub fn configure(&mut self) {
        let mut ce: xlib::XConfigureEvent = unsafe { zeroed() };
        let rect = self.get_rect();
{'fraction_non_alphanumeric': 0.12125734090690286, 'fraction_numerical': 0.003514007894483489, 'mean_word_length': 1.366981884470776, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 75, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 78, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1592954', 'n_tokens_mistral': 6433, 'n_tokens_neox': 6222, 'n_words': 1352}