diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/main.rs | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..8f9a8aa --- /dev/null +++ b/src/main.rs | |||
@@ -0,0 +1,197 @@ | |||
1 | use std::thread; | ||
2 | use std::time::{Duration, Instant}; | ||
3 | |||
4 | fn main() { | ||
5 | let win_width = 500u16; | ||
6 | let win_height = 500u16; | ||
7 | |||
8 | let (conn, screen_num) = xcb::Connection::connect(None).unwrap(); | ||
9 | let setup = conn.get_setup(); | ||
10 | let screen = setup.roots().nth(screen_num as usize).unwrap(); | ||
11 | |||
12 | let depths = screen.allowed_depths(); | ||
13 | let mut alpha_depths = depths.filter(|d| d.depth() == 32u8); | ||
14 | |||
15 | let visual = alpha_depths | ||
16 | .next() | ||
17 | .unwrap() | ||
18 | .visuals() | ||
19 | .nth(1 as usize) | ||
20 | .unwrap(); | ||
21 | |||
22 | let win_start_x = 0; | ||
23 | let win_start_y = 0; | ||
24 | |||
25 | let colormap = conn.generate_id(); | ||
26 | xcb::create_colormap( | ||
27 | &conn, | ||
28 | xcb::COLORMAP_ALLOC_NONE as u8, | ||
29 | colormap, | ||
30 | screen.root(), | ||
31 | visual.visual_id(), | ||
32 | ); | ||
33 | |||
34 | let win = conn.generate_id(); | ||
35 | xcb::create_window( | ||
36 | &conn, | ||
37 | 32u8, | ||
38 | win, | ||
39 | screen.root(), | ||
40 | win_start_x, | ||
41 | win_start_y, | ||
42 | win_width, | ||
43 | win_height, | ||
44 | 2, | ||
45 | xcb::WINDOW_CLASS_INPUT_OUTPUT as u16, | ||
46 | visual.visual_id(), | ||
47 | &[ | ||
48 | (xcb::CW_BACK_PIXEL, 0x00), | ||
49 | (xcb::CW_BORDER_PIXEL, 0x00), | ||
50 | //(xcb::CW_OVERRIDE_REDIRECT, 1u32), | ||
51 | (xcb::CW_EVENT_MASK, xcb::EVENT_MASK_EXPOSURE), | ||
52 | (xcb::CW_COLORMAP, colormap), | ||
53 | ], | ||
54 | ); | ||
55 | |||
56 | let gfx_ctx = conn.generate_id(); | ||
57 | xcb::create_gc( | ||
58 | &conn, | ||
59 | gfx_ctx, | ||
60 | win, | ||
61 | &[ | ||
62 | (xcb::GC_FOREGROUND, screen.white_pixel()), | ||
63 | (xcb::GC_GRAPHICS_EXPOSURES, 0), | ||
64 | (xcb::GC_LINE_WIDTH, 1), | ||
65 | ], | ||
66 | ); | ||
67 | |||
68 | xcb::free_colormap(&conn, colormap); | ||
69 | |||
70 | let win_type_atom = xcb::intern_atom(&conn, true, "_NET_WM_WINDOW_TYPE") | ||
71 | .get_reply() | ||
72 | .unwrap() | ||
73 | .atom(); | ||
74 | let win_menu_atom = xcb::intern_atom(&conn, true, "_NET_WM_WINDOW_TYPE_SPLASH") | ||
75 | .get_reply() | ||
76 | .unwrap() | ||
77 | .atom(); | ||
78 | |||
79 | let win_state_atom = xcb::intern_atom(&conn, true, "_NET_WM_STATE") | ||
80 | .get_reply() | ||
81 | .unwrap() | ||
82 | .atom(); | ||
83 | let win_on_top_atom = xcb::intern_atom(&conn, true, "_NET_WM_STATE_STAYS_ON_TOP") | ||
84 | .get_reply() | ||
85 | .unwrap() | ||
86 | .atom(); | ||
87 | |||
88 | xcb::change_property( | ||
89 | &conn, | ||
90 | xcb::PROP_MODE_REPLACE as u8, | ||
91 | win, | ||
92 | win_type_atom, | ||
93 | xcb::ATOM_ATOM, | ||
94 | 32, | ||
95 | &[win_menu_atom], | ||
96 | ); | ||
97 | xcb::change_property( | ||
98 | &conn, | ||
99 | xcb::PROP_MODE_APPEND as u8, | ||
100 | win, | ||
101 | win_state_atom, | ||
102 | xcb::ATOM_ATOM, | ||
103 | 32, | ||
104 | &[win_on_top_atom], | ||
105 | ); | ||
106 | |||
107 | let mut circles = (1u16..10u16) | ||
108 | .map(|i| { | ||
109 | xcb::Arc::new( | ||
110 | win_start_x + 25 * i as i16, | ||
111 | win_start_y + 25 * i as i16, | ||
112 | win_width - 50 * i, | ||
113 | win_height - 50 * i, | ||
114 | 0, | ||
115 | 360 << 6, | ||
116 | ) | ||
117 | }) | ||
118 | .collect::<Vec<xcb::Arc>>() | ||
119 | .into_iter(); | ||
120 | |||
121 | xcb::map_window(&conn, win); | ||
122 | conn.flush(); | ||
123 | |||
124 | loop { | ||
125 | let event = conn.wait_for_event(); | ||
126 | match event { | ||
127 | None => { | ||
128 | break; | ||
129 | } | ||
130 | Some(e) => { | ||
131 | let r = e.response_type() & !0x80; | ||
132 | match r { | ||
133 | xcb::EXPOSE => { | ||
134 | xcb::poly_arc(&conn, win, gfx_ctx, &[circles.next().unwrap()]); | ||
135 | conn.flush(); | ||
136 | break; | ||
137 | } | ||
138 | _ => { | ||
139 | break; | ||
140 | } | ||
141 | } | ||
142 | } | ||
143 | } | ||
144 | } | ||
145 | |||
146 | let pointer = xcb::query_pointer(&conn, win).get_reply().unwrap(); | ||
147 | let p_x = pointer.root_x(); | ||
148 | let p_y = pointer.root_y(); | ||
149 | |||
150 | move_win_to_cursor(&conn, win, win_width, win_height, p_x, p_y); | ||
151 | |||
152 | let loop_start = Instant::now(); | ||
153 | let anim_duration = Duration::from_millis(600); | ||
154 | let circle_duration = Duration::from_millis(60); | ||
155 | loop { | ||
156 | match circles.next() { | ||
157 | Some(c) => { | ||
158 | let _ = xcb::poly_arc(&conn, win, gfx_ctx, &[c]); | ||
159 | conn.flush(); | ||
160 | } | ||
161 | None => {} | ||
162 | }; | ||
163 | thread::sleep(circle_duration); | ||
164 | let now = Instant::now(); | ||
165 | if now.duration_since(loop_start) > anim_duration { | ||
166 | break; | ||
167 | } | ||
168 | } | ||
169 | thread::sleep(Duration::from_millis(100)); | ||
170 | } | ||
171 | |||
172 | fn move_win_to_cursor( | ||
173 | conn: &xcb::Connection, | ||
174 | win: u32, | ||
175 | win_width: u16, | ||
176 | win_height: u16, | ||
177 | p_x: i16, | ||
178 | p_y: i16, | ||
179 | ) { | ||
180 | let win_x = p_x - (win_width as i16) / 2; | ||
181 | let win_y = p_y - (win_height as i16) / 2; | ||
182 | xcb::configure_window( | ||
183 | &conn, | ||
184 | win, | ||
185 | &[ | ||
186 | ( | ||
187 | xcb::CONFIG_WINDOW_X as u16, | ||
188 | if win_x < 0 { 0 } else { win_x as u32 }, | ||
189 | ), | ||
190 | ( | ||
191 | xcb::CONFIG_WINDOW_Y as u16, | ||
192 | if win_y < 0 { 0 } else { win_y as u32 }, | ||
193 | ), | ||
194 | ], | ||
195 | ); | ||
196 | conn.flush(); | ||
197 | } | ||