oxwm

https://git.tonybtw.com/oxwm.git git://git.tonybtw.com/oxwm.git
4,303 bytes raw
1
use super::{Overlay, OverlayBase};
2
use crate::bar::font::Font;
3
use crate::errors::X11Error;
4
use x11rb::connection::Connection;
5
use x11rb::protocol::xproto::*;
6
use x11rb::rust_connection::RustConnection;
7
8
const PADDING: i16 = 20;
9
const LINE_SPACING: i16 = 5;
10
const BORDER_WIDTH: u16 = 2;
11
const BORDER_COLOR: u32 = 0xff5555;
12
13
pub struct ErrorOverlay {
14
    base: OverlayBase,
15
    lines: Vec<String>,
16
}
17
18
impl ErrorOverlay {
19
    pub fn new(
20
        connection: &RustConnection,
21
        screen: &Screen,
22
        screen_num: usize,
23
        display: *mut x11::xlib::Display,
24
        _font: &Font,
25
        _max_width: u16,
26
    ) -> Result<Self, X11Error> {
27
        let base = OverlayBase::new(
28
            connection,
29
            screen,
30
            screen_num,
31
            display,
32
            400,
33
            200,
34
            BORDER_WIDTH,
35
            BORDER_COLOR,
36
            0x1a1a1a,
37
            0xffffff,
38
        )?;
39
40
        Ok(ErrorOverlay {
41
            base,
42
            lines: Vec::new(),
43
        })
44
    }
45
46
    pub fn show_error(
47
        &mut self,
48
        connection: &RustConnection,
49
        font: &Font,
50
        error_text: &str,
51
        monitor_x: i16,
52
        monitor_y: i16,
53
        screen_width: u16,
54
        screen_height: u16,
55
    ) -> Result<(), X11Error> {
56
        let max_line_width = (screen_width as i16 / 2 - PADDING * 4).max(300) as u16;
57
        let error_with_instruction = format!("{}\n\nFix the config file and reload.", error_text);
58
        self.lines = self.wrap_text(&error_with_instruction, font, max_line_width);
59
60
        let mut content_width = 0u16;
61
        for line in &self.lines {
62
            let line_width = font.text_width(line);
63
            if line_width > content_width {
64
                content_width = line_width;
65
            }
66
        }
67
68
        let width = content_width + (PADDING as u16 * 2);
69
        let line_height = font.height() + LINE_SPACING as u16;
70
        let height = (self.lines.len() as u16 * line_height) + (PADDING as u16 * 2);
71
72
        let x = monitor_x + ((screen_width - width) / 2) as i16;
73
        let y = monitor_y + ((screen_height - height) / 2) as i16;
74
75
        self.base.configure(connection, x, y, width, height)?;
76
        self.base.show(connection)?;
77
        self.draw(connection, font)?;
78
        Ok(())
79
    }
80
81
    fn wrap_text(&self, text: &str, font: &Font, max_width: u16) -> Vec<String> {
82
        let mut lines = Vec::new();
83
        for paragraph in text.lines() {
84
            if paragraph.trim().is_empty() {
85
                lines.push(String::new());
86
                continue;
87
            }
88
89
            let words: Vec<&str> = paragraph.split_whitespace().collect();
90
            let mut current_line = String::new();
91
92
            for word in words {
93
                let test_line = if current_line.is_empty() {
94
                    word.to_string()
95
                } else {
96
                    format!("{} {}", current_line, word)
97
                };
98
                if font.text_width(&test_line) <= max_width {
99
                    current_line = test_line;
100
                } else {
101
                    if !current_line.is_empty() {
102
                        lines.push(current_line);
103
                    }
104
                    current_line = word.to_string();
105
                }
106
            }
107
            if !current_line.is_empty() {
108
                lines.push(current_line);
109
            }
110
        }
111
        lines
112
    }
113
}
114
115
impl Overlay for ErrorOverlay {
116
    fn window(&self) -> Window {
117
        self.base.window
118
    }
119
120
    fn is_visible(&self) -> bool {
121
        self.base.is_visible
122
    }
123
124
    fn hide(&mut self, connection: &RustConnection) -> Result<(), X11Error> {
125
        self.base.hide(connection)?;
126
        self.lines.clear();
127
        Ok(())
128
    }
129
130
    fn draw(&self, connection: &RustConnection, font: &Font) -> Result<(), X11Error> {
131
        if !self.base.is_visible {
132
            return Ok(());
133
        }
134
        self.base.draw_background(connection)?;
135
        let line_height = font.height() + LINE_SPACING as u16;
136
        let mut y = PADDING + font.ascent();
137
        for line in &self.lines {
138
            self.base
139
                .font_draw
140
                .draw_text(font, self.base.foreground_color, PADDING, y, line);
141
            y += line_height as i16;
142
        }
143
        connection.flush()?;
144
        Ok(())
145
    }
146
}