File: basic_window.rs

package info (click to toggle)
rust-xcb 1.6.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,904 kB
  • sloc: xml: 19,003; sh: 11; makefile: 2
file content (141 lines) | stat: -rw-r--r-- 4,464 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
use xcb::{x, Xid};

xcb::atoms_struct! {
    #[derive(Debug)]
    struct Atoms {
        wm_protocols    => b"WM_PROTOCOLS",
        wm_del_window   => b"WM_DELETE_WINDOW",
        wm_state        => b"_NET_WM_STATE",
        wm_state_maxv   => b"_NET_WM_STATE_MAXIMIZED_VERT",
        wm_state_maxh   => b"_NET_WM_STATE_MAXIMIZED_HORZ",
    }
}

fn main() -> xcb::Result<()> {
    let (conn, screen_num) = xcb::Connection::connect(None).unwrap();
    let setup = conn.get_setup();
    let screen = setup.roots().nth(screen_num as usize).unwrap();

    let window: x::Window = conn.generate_id();

    println!("window: {}", window.resource_id());
    println!("root: {}", screen.root().resource_id());
    println!("root_visual: {}", screen.root_visual());

    conn.send_request(&x::CreateWindow {
        depth: x::COPY_FROM_PARENT as u8,
        wid: window,
        parent: screen.root(),
        x: 0,
        y: 0,
        width: 150,
        height: 150,
        border_width: 10,
        class: x::WindowClass::InputOutput,
        visual: screen.root_visual(),
        value_list: &[
            x::Cw::BackPixel(screen.white_pixel()),
            x::Cw::EventMask(x::EventMask::EXPOSURE | x::EventMask::KEY_PRESS),
        ],
    });

    conn.send_request(&x::MapWindow { window });

    let title = "Basic Window";

    conn.send_request(&x::ChangeProperty {
        mode: x::PropMode::Replace,
        window,
        property: x::ATOM_WM_NAME,
        r#type: x::ATOM_STRING,
        data: title.as_bytes(),
    });

    conn.flush()?;

    // retrieving title
    let cookie = conn.send_request(&x::GetProperty {
        delete: false,
        window,
        property: x::ATOM_WM_NAME,
        r#type: x::ATOM_STRING,
        long_offset: 0,
        long_length: 1024,
    });
    let reply = conn.wait_for_reply(cookie)?;
    assert_eq!(reply.value::<u8>(), title.as_bytes());

    // retrieving a few atoms
    let atoms = Atoms::intern_all(&conn)?;
    println!("atoms = {:#?}", atoms);

    // activate the sending of close event through `x::Event::ClientMessage`
    // either the request must be checked as follow, or conn.flush() must be called before entering the loop
    conn.send_and_check_request(&x::ChangeProperty {
        mode: x::PropMode::Replace,
        window,
        property: atoms.wm_protocols,
        r#type: x::ATOM_ATOM,
        data: &[atoms.wm_del_window],
    })?;

    let mut maximized = false;

    loop {
        let event = match conn.wait_for_event() {
            Err(xcb::Error::Connection(err)) => {
                panic!("unexpected I/O error: {}", err);
            }
            Err(xcb::Error::Protocol(err)) => {
                panic!("unexpected protocol error: {:#?}", err);
            }
            Ok(event) => event,
        };

        println!("Received event {:#?}", event);
        match event {
            xcb::Event::X(x::Event::KeyPress(ev)) => {
                println!("Key '{}' pressed", ev.detail());

                if ev.detail() == 0x3a {
                    // M (on qwerty)

                    // toggle maximized

                    let data = x::ClientMessageData::Data32([
                        if maximized { 0 } else { 1 },
                        atoms.wm_state_maxv.resource_id(),
                        atoms.wm_state_maxh.resource_id(),
                        0,
                        0,
                    ]);

                    let event = x::ClientMessageEvent::new(window, atoms.wm_state, data);

                    conn.send_request(&x::SendEvent {
                        propagate: false,
                        destination: x::SendEventDest::Window(screen.root()),
                        event_mask: x::EventMask::STRUCTURE_NOTIFY,
                        event: &event,
                    });

                    conn.flush()?;

                    maximized = !maximized;
                } else if ev.detail() == 0x18 {
                    // Q (on qwerty)
                    break Ok(());
                }
            }
            xcb::Event::X(x::Event::ClientMessage(ev)) => {
                if let x::ClientMessageData::Data32([atom, ..]) = ev.data() {
                    if atom == atoms.wm_del_window.resource_id() {
                        // window "x" button clicked by user, we gracefully exit
                        break Ok(());
                    }
                }
            }
            _ => {}
        }
    }
}