]>
Commit | Line | Data |
---|---|---|
501c7d0b LP |
1 | using Gtk; |
2 | using GLib; | |
3 | using DBus; | |
4 | using Pango; | |
5 | ||
6 | public class LeftLabel : Label { | |
7 | public LeftLabel(string? text = null) { | |
8 | if (text != null) | |
9 | set_markup("<b>%s</b>".printf(text)); | |
10 | set_alignment(1, 0); | |
11 | set_padding(6, 0); | |
12 | } | |
13 | } | |
14 | ||
15 | public class RightLabel : Label { | |
16 | public RightLabel(string? text = null) { | |
17 | set_text_or_na(text); | |
18 | set_alignment(0, 1); | |
19 | set_ellipsize(EllipsizeMode.START); | |
20 | set_selectable(true); | |
21 | } | |
22 | ||
23 | public void set_text_or_na(string? text = null) { | |
24 | if (text == null || text == "") | |
25 | set_markup("<i>n/a</i>"); | |
26 | else | |
27 | set_text(text); | |
28 | } | |
29 | } | |
30 | ||
31 | public class MainWindow : Window { | |
32 | ||
33 | private TreeView unit_view; | |
34 | private TreeView job_view; | |
35 | ||
36 | private ListStore unit_model; | |
37 | private ListStore job_model; | |
38 | ||
39 | private Button start_button; | |
40 | private Button stop_button; | |
41 | private Button restart_button; | |
42 | private Button reload_button; | |
43 | private Button cancel_button; | |
44 | ||
45 | private Connection bus; | |
46 | private Manager manager; | |
47 | ||
48 | private RightLabel unit_id_label; | |
49 | private RightLabel unit_description_label; | |
50 | private RightLabel unit_load_state_label; | |
51 | private RightLabel unit_active_state_label; | |
52 | private RightLabel unit_load_path_label; | |
53 | private RightLabel unit_active_enter_timestamp_label; | |
54 | private RightLabel unit_active_exit_timestamp_label; | |
55 | private RightLabel unit_can_start_label; | |
56 | private RightLabel unit_can_reload_label; | |
57 | ||
58 | private RightLabel job_id_label; | |
59 | private RightLabel job_state_label; | |
60 | private RightLabel job_type_label; | |
61 | ||
62 | public MainWindow() throws DBus.Error { | |
63 | title = "systemdadm"; | |
64 | position = WindowPosition.CENTER; | |
65 | set_default_size(1000, 700); | |
66 | set_border_width(12); | |
67 | destroy.connect(Gtk.main_quit); | |
68 | ||
69 | Notebook notebook = new Notebook(); | |
70 | add(notebook); | |
71 | ||
72 | Box unit_vbox = new VBox(false, 6); | |
73 | notebook.append_page(unit_vbox, new Label("Units")); | |
74 | unit_vbox.set_border_width(12); | |
75 | ||
76 | Box job_vbox = new VBox(false, 6); | |
77 | notebook.append_page(job_vbox, new Label("Jobs")); | |
78 | job_vbox.set_border_width(12); | |
79 | ||
80 | ||
81 | unit_model = new ListStore(6, typeof(string), typeof(string), typeof(string), typeof(string), typeof(string), typeof(string), typeof(string)); | |
82 | job_model = new ListStore(5, typeof(string), typeof(string), typeof(string), typeof(string), typeof(string), typeof(string)); | |
83 | ||
84 | unit_view = new TreeView.with_model(unit_model); | |
85 | job_view = new TreeView.with_model(job_model); | |
86 | ||
87 | unit_view.cursor_changed.connect(unit_changed); | |
88 | job_view.cursor_changed.connect(job_changed); | |
89 | ||
90 | unit_view.insert_column_with_attributes(-1, "Unit", new CellRendererText(), "text", 0); | |
91 | unit_view.insert_column_with_attributes(-1, "Description", new CellRendererText(), "text", 1); | |
92 | unit_view.insert_column_with_attributes(-1, "Load State", new CellRendererText(), "text", 2); | |
93 | unit_view.insert_column_with_attributes(-1, "Active State", new CellRendererText(), "text", 3); | |
94 | unit_view.insert_column_with_attributes(-1, "Job", new CellRendererText(), "text", 4); | |
95 | ||
96 | job_view.insert_column_with_attributes(-1, "Job", new CellRendererText(), "text", 0); | |
97 | job_view.insert_column_with_attributes(-1, "Unit", new CellRendererText(), "text", 1); | |
98 | job_view.insert_column_with_attributes(-1, "Type", new CellRendererText(), "text", 2); | |
99 | job_view.insert_column_with_attributes(-1, "State", new CellRendererText(), "text", 3); | |
100 | ||
101 | ScrolledWindow scroll = new ScrolledWindow(null, null); | |
102 | scroll.set_policy(PolicyType.AUTOMATIC, PolicyType.AUTOMATIC); | |
103 | scroll.set_shadow_type(ShadowType.IN); | |
104 | scroll.add(unit_view); | |
105 | unit_vbox.pack_start(scroll, true, true, 0); | |
106 | ||
107 | scroll = new ScrolledWindow(null, null); | |
108 | scroll.set_policy(PolicyType.AUTOMATIC, PolicyType.AUTOMATIC); | |
109 | scroll.set_shadow_type(ShadowType.IN); | |
110 | scroll.add(job_view); | |
111 | job_vbox.pack_start(scroll, true, true, 0); | |
112 | ||
113 | unit_id_label = new RightLabel(); | |
114 | unit_description_label = new RightLabel(); | |
115 | unit_load_state_label = new RightLabel(); | |
116 | unit_active_state_label = new RightLabel(); | |
117 | unit_load_path_label = new RightLabel(); | |
118 | unit_active_enter_timestamp_label = new RightLabel(); | |
119 | unit_active_exit_timestamp_label = new RightLabel(); | |
120 | unit_can_start_label = new RightLabel(); | |
121 | unit_can_reload_label = new RightLabel(); | |
122 | ||
123 | job_id_label = new RightLabel(); | |
124 | job_state_label = new RightLabel(); | |
125 | job_type_label = new RightLabel(); | |
126 | ||
127 | Table unit_table = new Table(9, 2, false); | |
128 | unit_table.set_row_spacings(6); | |
129 | unit_table.set_border_width(12); | |
130 | unit_vbox.pack_start(unit_table, false, true, 0); | |
131 | ||
132 | Table job_table = new Table(2, 2, false); | |
133 | job_table.set_row_spacings(6); | |
134 | job_table.set_border_width(12); | |
135 | job_vbox.pack_start(job_table, false, true, 0); | |
136 | ||
137 | unit_table.attach(new LeftLabel("Id:"), 0, 1, 0, 1, AttachOptions.FILL, AttachOptions.FILL, 0, 0); | |
138 | unit_table.attach(unit_id_label, 1, 2, 0, 1, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); | |
139 | unit_table.attach(new LeftLabel("Description:"), 0, 1, 1, 2, AttachOptions.FILL, AttachOptions.FILL, 0, 0); | |
140 | unit_table.attach(unit_description_label, 1, 2, 1, 2, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); | |
141 | unit_table.attach(new LeftLabel("Load State:"), 0, 1, 2, 3, AttachOptions.FILL, AttachOptions.FILL, 0, 0); | |
142 | unit_table.attach(unit_load_state_label, 1, 2, 2, 3, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); | |
143 | unit_table.attach(new LeftLabel("Active State:"), 0, 1, 3, 4, AttachOptions.FILL, AttachOptions.FILL, 0, 0); | |
144 | unit_table.attach(unit_active_state_label, 1, 2, 3, 4, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); | |
145 | unit_table.attach(new LeftLabel("Load Path:"), 0, 1, 4, 5, AttachOptions.FILL, AttachOptions.FILL, 0, 0); | |
146 | unit_table.attach(unit_load_path_label, 1, 2, 4, 5, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); | |
147 | unit_table.attach(new LeftLabel("Active Enter Timestamp:"), 0, 1, 5, 6, AttachOptions.FILL, AttachOptions.FILL, 0, 0); | |
148 | unit_table.attach(unit_active_enter_timestamp_label, 1, 2, 5, 6, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); | |
149 | unit_table.attach(new LeftLabel("Active Exit Timestamp:"), 0, 1, 6, 7, AttachOptions.FILL, AttachOptions.FILL, 0, 0); | |
150 | unit_table.attach(unit_active_exit_timestamp_label, 1, 2, 6, 7, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); | |
151 | unit_table.attach(new LeftLabel("Can Start/Stop:"), 0, 1, 7, 8, AttachOptions.FILL, AttachOptions.FILL, 0, 0); | |
152 | unit_table.attach(unit_can_start_label, 1, 2, 7, 8, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); | |
153 | unit_table.attach(new LeftLabel("Can Reload:"), 0, 1, 8, 9, AttachOptions.FILL, AttachOptions.FILL, 0, 0); | |
154 | unit_table.attach(unit_can_reload_label, 1, 2, 8, 9, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); | |
155 | ||
156 | job_table.attach(new LeftLabel("Id:"), 0, 1, 0, 1, AttachOptions.FILL, AttachOptions.FILL, 0, 0); | |
157 | job_table.attach(job_id_label, 1, 2, 0, 1, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); | |
158 | job_table.attach(new LeftLabel("State:"), 0, 1, 1, 2, AttachOptions.FILL, AttachOptions.FILL, 0, 0); | |
159 | job_table.attach(job_state_label, 1, 2, 1, 2, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); | |
160 | job_table.attach(new LeftLabel("Type:"), 0, 1, 2, 3, AttachOptions.FILL, AttachOptions.FILL, 0, 0); | |
161 | job_table.attach(job_type_label, 1, 2, 2, 3, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); | |
162 | ||
163 | ButtonBox bbox = new HButtonBox(); | |
164 | bbox.set_layout(ButtonBoxStyle.START); | |
165 | bbox.set_spacing(6); | |
166 | unit_vbox.pack_start(bbox, false, true, 0); | |
167 | ||
168 | start_button = new Button.with_mnemonic("_Start"); | |
169 | stop_button = new Button.with_mnemonic("Sto_p"); | |
170 | reload_button = new Button.with_mnemonic("_Reload"); | |
171 | restart_button = new Button.with_mnemonic("Res_tart"); | |
172 | ||
173 | start_button.clicked.connect(on_start); | |
174 | stop_button.clicked.connect(on_stop); | |
175 | reload_button.clicked.connect(on_reload); | |
176 | restart_button.clicked.connect(on_restart); | |
177 | ||
178 | bbox.pack_start(start_button, false, true, 0); | |
179 | bbox.pack_start(stop_button, false, true, 0); | |
180 | bbox.pack_start(restart_button, false, true, 0); | |
181 | bbox.pack_start(reload_button, false, true, 0); | |
182 | ||
183 | bbox = new HButtonBox(); | |
184 | bbox.set_layout(ButtonBoxStyle.START); | |
185 | bbox.set_spacing(6); | |
186 | job_vbox.pack_start(bbox, false, true, 0); | |
187 | ||
188 | cancel_button = new Button.with_mnemonic("_Cancel"); | |
189 | ||
190 | cancel_button.clicked.connect(on_cancel); | |
191 | ||
192 | bbox.pack_start(cancel_button, false, true, 0); | |
193 | ||
194 | bus = Bus.get(BusType.SESSION); | |
195 | ||
196 | manager = bus.get_object ( | |
197 | "org.freedesktop.systemd1", | |
198 | "/org/freedesktop/systemd1", | |
199 | "org.freedesktop.systemd1") as Manager; | |
200 | ||
201 | clear_unit(); | |
202 | populate_unit_model(); | |
203 | populate_job_model(); | |
204 | } | |
205 | ||
206 | public void populate_unit_model() throws DBus.Error { | |
207 | unit_model.clear(); | |
208 | ||
209 | var list = manager.list_units(); | |
210 | ||
211 | foreach (var i in list) { | |
212 | TreeIter iter; | |
213 | ||
214 | unit_model.append(out iter); | |
215 | unit_model.set(iter, | |
216 | 0, i.id, | |
217 | 1, i.description, | |
218 | 2, i.load_state, | |
219 | 3, i.active_state, | |
220 | 4, i.job_type != "" ? "→ %s".printf(i.job_type) : "", | |
221 | 5, i.unit_path); | |
222 | } | |
223 | } | |
224 | ||
225 | public void populate_job_model() throws DBus.Error { | |
226 | job_model.clear(); | |
227 | ||
228 | var list = manager.list_jobs(); | |
229 | ||
230 | foreach (var i in list) { | |
231 | TreeIter iter; | |
232 | ||
233 | job_model.append(out iter); | |
234 | job_model.set(iter, | |
235 | 0, "%u".printf(i.id), | |
236 | 1, i.name, | |
237 | 2, "→ %s".printf(i.type), | |
238 | 3, i.state, | |
239 | 4, i.job_path); | |
240 | } | |
241 | } | |
242 | ||
243 | public Unit? get_current_unit() { | |
244 | TreePath p; | |
245 | unit_view.get_cursor(out p, null); | |
246 | ||
247 | if (p == null) | |
248 | return null; | |
249 | ||
250 | TreeIter iter; | |
251 | string path; | |
252 | ||
253 | unit_model.get_iter(out iter, p); | |
254 | unit_model.get(iter, 5, out path); | |
255 | ||
256 | return bus.get_object ( | |
257 | "org.freedesktop.systemd1", | |
258 | path, | |
259 | "org.freedesktop.systemd1.Unit") as Unit; | |
260 | } | |
261 | ||
262 | public void unit_changed() { | |
263 | Unit u = get_current_unit(); | |
264 | ||
265 | if (u == null) | |
266 | clear_unit(); | |
267 | else | |
268 | show_unit(u); | |
269 | } | |
270 | ||
271 | public void clear_unit() { | |
272 | start_button.set_sensitive(false); | |
273 | stop_button.set_sensitive(false); | |
274 | reload_button.set_sensitive(false); | |
275 | restart_button.set_sensitive(false); | |
276 | ||
277 | unit_id_label.set_text_or_na(); | |
278 | unit_description_label.set_text_or_na(); | |
279 | unit_load_state_label.set_text_or_na(); | |
280 | unit_active_state_label.set_text_or_na(); | |
281 | unit_load_path_label.set_text_or_na(); | |
282 | unit_active_enter_timestamp_label.set_text_or_na(); | |
283 | unit_active_exit_timestamp_label.set_text_or_na(); | |
284 | unit_can_reload_label.set_text_or_na(); | |
285 | unit_can_start_label.set_text_or_na(); | |
286 | } | |
287 | ||
288 | public void show_unit(Unit unit) { | |
289 | unit_id_label.set_text_or_na(unit.id); | |
290 | unit_description_label.set_text_or_na(unit.description); | |
291 | unit_load_state_label.set_text_or_na(unit.load_state); | |
292 | unit_active_state_label.set_text_or_na(unit.active_state); | |
293 | unit_load_path_label.set_text_or_na(unit.load_path); | |
294 | ||
295 | uint64 t = unit.active_enter_timestamp; | |
296 | if (t > 0) { | |
297 | TimeVal tv = { (long) (t / 1000000), (long) (t % 1000000) }; | |
298 | unit_active_enter_timestamp_label.set_text_or_na(tv.to_iso8601()); | |
299 | } else | |
300 | unit_active_enter_timestamp_label.set_text_or_na(); | |
301 | ||
302 | t = unit.active_exit_timestamp; | |
303 | if (t > 0) { | |
304 | TimeVal tv = { (long) (t / 1000000), (long) (t % 1000000) }; | |
305 | unit_active_exit_timestamp_label.set_text_or_na(tv.to_iso8601()); | |
306 | } else | |
307 | unit_active_exit_timestamp_label.set_text_or_na(); | |
308 | ||
309 | bool b = unit.can_start; | |
310 | start_button.set_sensitive(b); | |
311 | stop_button.set_sensitive(b); | |
312 | restart_button.set_sensitive(b); | |
313 | unit_can_start_label.set_text_or_na(b ? "Yes" : "No"); | |
314 | ||
315 | b = unit.can_reload; | |
316 | reload_button.set_sensitive(b); | |
317 | unit_can_reload_label.set_text_or_na(b ? "Yes" : "No"); | |
318 | } | |
319 | ||
320 | public Job? get_current_job() { | |
321 | TreePath p; | |
322 | job_view.get_cursor(out p, null); | |
323 | ||
324 | if (p == null) | |
325 | return null; | |
326 | ||
327 | TreeIter iter; | |
328 | string path; | |
329 | ||
330 | job_model.get_iter(out iter, p); | |
331 | job_model.get(iter, 4, out path); | |
332 | ||
333 | return bus.get_object ( | |
334 | "org.freedesktop.systemd1", | |
335 | path, | |
336 | "org.freedesktop.systemd1.Job") as Job; | |
337 | } | |
338 | ||
339 | public void job_changed() { | |
340 | Job j = get_current_job(); | |
341 | ||
342 | if (j == null) | |
343 | clear_job(); | |
344 | else | |
345 | show_job(j); | |
346 | } | |
347 | ||
348 | public void clear_job() { | |
349 | job_id_label.set_text_or_na(); | |
350 | job_state_label.set_text_or_na(); | |
351 | job_type_label.set_text_or_na(); | |
352 | } | |
353 | ||
354 | public void show_job(Job job) { | |
355 | job_id_label.set_text_or_na("%u".printf(job.id)); | |
356 | job_state_label.set_text_or_na(job.state); | |
357 | job_type_label.set_text_or_na(job.job_type); | |
358 | } | |
359 | ||
360 | public void on_start() { | |
361 | Unit u = get_current_unit(); | |
362 | ||
363 | if (u == null) | |
364 | return; | |
365 | ||
366 | try { | |
367 | u.start("replace"); | |
368 | } catch (DBus.Error e) { | |
369 | message("%s", e.message); | |
370 | } | |
371 | } | |
372 | ||
373 | public void on_stop() { | |
374 | Unit u = get_current_unit(); | |
375 | ||
376 | if (u == null) | |
377 | return; | |
378 | ||
379 | try { | |
380 | u.stop("replace"); | |
381 | } catch (DBus.Error e) { | |
382 | message("%s", e.message); | |
383 | } | |
384 | } | |
385 | ||
386 | public void on_reload() { | |
387 | Unit u = get_current_unit(); | |
388 | ||
389 | if (u == null) | |
390 | return; | |
391 | ||
392 | try { | |
393 | u.reload("replace"); | |
394 | } catch (DBus.Error e) { | |
395 | message("%s", e.message); | |
396 | } | |
397 | } | |
398 | ||
399 | public void on_restart() { | |
400 | Unit u = get_current_unit(); | |
401 | ||
402 | if (u == null) | |
403 | return; | |
404 | ||
405 | try { | |
406 | u.restart("replace"); | |
407 | } catch (DBus.Error e) { | |
408 | message("%s", e.message); | |
409 | } | |
410 | } | |
411 | ||
412 | public void on_cancel() { | |
413 | Job j = get_current_job(); | |
414 | ||
415 | if (j == null) | |
416 | return; | |
417 | ||
418 | try { | |
419 | j.cancel(); | |
420 | } catch (DBus.Error e) { | |
421 | message("%s", e.message); | |
422 | } | |
423 | } | |
424 | } | |
425 | ||
426 | int main (string[] args) { | |
427 | Gtk.init(ref args); | |
428 | ||
429 | try { | |
430 | MainWindow window = new MainWindow(); | |
431 | window.show_all(); | |
432 | } catch (DBus.Error e) { | |
433 | message("%s", e.message); | |
434 | } | |
435 | ||
436 | Gtk.main(); | |
437 | return 0; | |
438 | } |