chiark / gitweb /
18d3a367aa781abdeefded08bbe43ddc49f5199b
[elogind.git] / systemadm.vala
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 }