source: mainline/uspace/app/shutdown-dlg/shutdown-dlg.c

Last change on this file was a188131, checked in by Jiri Svoboda <jiri@…>, 3 months ago

Add UI to system installer

  • Property mode set to 100644
File size: 13.6 KB
Line 
1/*
2 * Copyright (c) 2025 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup shutdown-dlg
30 * @{
31 */
32/** @file Shutdown dialog
33 */
34
35#include <gfx/coord.h>
36#include <gfx/render.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <str.h>
40#include <system.h>
41#include <ui/fixed.h>
42#include <ui/label.h>
43#include <ui/list.h>
44#include <ui/msgdialog.h>
45#include <ui/resource.h>
46#include <ui/selectdialog.h>
47#include <ui/ui.h>
48#include <ui/window.h>
49#include "shutdown-dlg.h"
50
51static void wnd_close(ui_window_t *, void *);
52static errno_t bg_wnd_paint(ui_window_t *, void *);
53static void shutdown_progress_destroy(shutdown_progress_t *);
54static errno_t shutdown_confirm_create(shutdown_dlg_t *);
55static errno_t shutdown_failed_msg_create(shutdown_dlg_t *);
56static errno_t shutdown_start(shutdown_dlg_t *, sd_action_t);
57
58static ui_window_cb_t bg_window_cb = {
59 .close = wnd_close,
60 .paint = bg_wnd_paint
61};
62
63static ui_window_cb_t progress_window_cb = {
64 .close = wnd_close
65};
66
67static void sd_shutdown_complete(void *);
68static void sd_shutdown_failed(void *);
69
70static system_cb_t sd_system_cb = {
71 .shutdown_complete = sd_shutdown_complete,
72 .shutdown_failed = sd_shutdown_failed
73};
74
75static void shutdown_confirm_bok(ui_select_dialog_t *, void *, void *);
76static void shutdown_confirm_bcancel(ui_select_dialog_t *, void *);
77static void shutdown_confirm_close(ui_select_dialog_t *, void *);
78
79static ui_select_dialog_cb_t shutdown_confirm_cb = {
80 .bok = shutdown_confirm_bok,
81 .bcancel = shutdown_confirm_bcancel,
82 .close = shutdown_confirm_close
83};
84
85static void shutdown_failed_msg_button(ui_msg_dialog_t *, void *, unsigned);
86static void shutdown_failed_msg_close(ui_msg_dialog_t *, void *);
87
88static ui_msg_dialog_cb_t shutdown_failed_msg_cb = {
89 .button = shutdown_failed_msg_button,
90 .close = shutdown_failed_msg_close
91};
92
93/** System shutdown complete.
94 *
95 * @param arg Argument (shutdown_dlg_t *)
96 */
97static void sd_shutdown_complete(void *arg)
98{
99 shutdown_dlg_t *sddlg = (shutdown_dlg_t *)arg;
100
101 ui_lock(sddlg->ui);
102 (void)ui_label_set_text(sddlg->progress->label,
103 "Shutdown complete. It is now safe to remove power.");
104 (void)ui_window_paint(sddlg->progress->window);
105 ui_unlock(sddlg->ui);
106}
107
108/** System shutdown failed.
109 *
110 * @param arg Argument (shutdown_dlg_t *)
111 */
112static void sd_shutdown_failed(void *arg)
113{
114 shutdown_dlg_t *sddlg = (shutdown_dlg_t *)arg;
115
116 ui_lock(sddlg->ui);
117 shutdown_progress_destroy(sddlg->progress);
118 sddlg->progress = NULL;
119 ui_window_destroy(sddlg->bgwindow);
120 sddlg->bgwindow = NULL;
121 (void)shutdown_failed_msg_create(sddlg);
122 ui_unlock(sddlg->ui);
123}
124
125/** Window close button was clicked.
126 *
127 * @param window Window
128 * @param arg Argument (shutdown_dlg_t *)
129 */
130static void wnd_close(ui_window_t *window, void *arg)
131{
132 (void)window;
133 (void)arg;
134}
135
136/** Paint background window.
137 *
138 * @param window Window
139 * @param arg Argument (shutdown_dlg_t *)
140 */
141static errno_t bg_wnd_paint(ui_window_t *window, void *arg)
142{
143 shutdown_dlg_t *sddlg = (shutdown_dlg_t *)arg;
144 gfx_rect_t app_rect;
145 gfx_context_t *gc;
146 errno_t rc;
147
148 gc = ui_window_get_gc(window);
149
150 rc = gfx_set_color(gc, sddlg->bg_color);
151 if (rc != EOK)
152 return rc;
153
154 ui_window_get_app_rect(window, &app_rect);
155
156 rc = gfx_fill_rect(gc, &app_rect);
157 if (rc != EOK)
158 return rc;
159
160 rc = gfx_update(gc);
161 if (rc != EOK)
162 return rc;
163
164 return EOK;
165}
166
167/** Create shutdown confirmation dialog.
168 *
169 * @param sddlg Shutdown dialog
170 * @return EOK on success or an error code
171 */
172static errno_t shutdown_confirm_create(shutdown_dlg_t *sddlg)
173{
174 ui_select_dialog_params_t params;
175 ui_select_dialog_t *dialog;
176 ui_list_entry_attr_t attr;
177 errno_t rc;
178
179 ui_select_dialog_params_init(&params);
180 params.caption = "Shutdown";
181 params.prompt = "Do you want to shut the system down?";
182 params.flags |= usdf_topmost | usdf_center;
183
184 rc = ui_select_dialog_create(sddlg->ui, &params, &dialog);
185 if (rc != EOK)
186 return rc;
187
188 /* Need an entry to select */
189 ui_list_entry_attr_init(&attr);
190
191 attr.caption = "Power off";
192 attr.arg = (void *)sd_poweroff;
193 rc = ui_select_dialog_append(dialog, &attr);
194 if (rc != EOK)
195 goto error;
196
197 attr.caption = "Restart";
198 attr.arg = (void *)sd_restart;
199 rc = ui_select_dialog_append(dialog, &attr);
200 if (rc != EOK)
201 goto error;
202
203 ui_select_dialog_set_cb(dialog, &shutdown_confirm_cb, sddlg);
204
205 (void)ui_select_dialog_paint(dialog);
206
207 return EOK;
208error:
209 ui_select_dialog_destroy(dialog);
210 return rc;
211}
212
213/** Create 'shutdown failed' message dialog.
214 *
215 * @param sddlg Shutdown dialog
216 * @return EOK on success or an error code
217 */
218static errno_t shutdown_failed_msg_create(shutdown_dlg_t *sddlg)
219{
220 ui_msg_dialog_params_t params;
221 ui_msg_dialog_t *dialog;
222 errno_t rc;
223
224 ui_msg_dialog_params_init(&params);
225 params.caption = "Shutdown failed";
226 params.text = "The system failed to shut down properly.";
227
228 rc = ui_msg_dialog_create(sddlg->ui, &params, &dialog);
229 if (rc != EOK)
230 return rc;
231
232 ui_msg_dialog_set_cb(dialog, &shutdown_failed_msg_cb, sddlg);
233
234 return EOK;
235}
236
237/** Shutdown confirm dialog OK button press.
238 *
239 * @param dialog Message dialog
240 * @param arg Argument (shutdown_dlg_t *)
241 * @param earg Entry argument
242 */
243static void shutdown_confirm_bok(ui_select_dialog_t *dialog, void *arg,
244 void *earg)
245{
246 shutdown_dlg_t *sddlg = (shutdown_dlg_t *) arg;
247
248 ui_select_dialog_destroy(dialog);
249
250 shutdown_start(sddlg, (sd_action_t)earg);
251}
252
253/** Shutdown confirm dialog Cancel button press.
254 *
255 * @param dialog Message dialog
256 * @param arg Argument (shutdown_dlg_t *)
257 */
258static void shutdown_confirm_bcancel(ui_select_dialog_t *dialog, void *arg)
259{
260 shutdown_dlg_t *sddlg = (shutdown_dlg_t *) arg;
261
262 ui_select_dialog_destroy(dialog);
263 ui_quit(sddlg->ui);
264}
265
266/** Shutdown confirm message dialog close request.
267 *
268 * @param dialog Message dialog
269 * @param arg Argument (shutdown_dlg_t *)
270 */
271static void shutdown_confirm_close(ui_select_dialog_t *dialog, void *arg)
272{
273 shutdown_dlg_t *sddlg = (shutdown_dlg_t *) arg;
274
275 ui_select_dialog_destroy(dialog);
276 ui_quit(sddlg->ui);
277}
278
279/** Shutdown faield message dialog button press.
280 *
281 * @param dialog Message dialog
282 * @param arg Argument (shutdown_dlg_t *)
283 * @param bnum Button number
284 */
285static void shutdown_failed_msg_button(ui_msg_dialog_t *dialog,
286 void *arg, unsigned bnum)
287{
288 shutdown_dlg_t *sddlg = (shutdown_dlg_t *) arg;
289
290 ui_msg_dialog_destroy(dialog);
291 ui_quit(sddlg->ui);
292}
293
294/** Shutdown failed message dialog close request.
295 *
296 * @param dialog Message dialog
297 * @param arg Argument (shutdown_dlg_t *)
298 */
299static void shutdown_failed_msg_close(ui_msg_dialog_t *dialog, void *arg)
300{
301 shutdown_dlg_t *sddlg = (shutdown_dlg_t *) arg;
302
303 ui_msg_dialog_destroy(dialog);
304 ui_quit(sddlg->ui);
305}
306
307/** Create shutdown progress window.
308 *
309 * @param sddlg Shutdown dialog
310 * @param rprogress Place to store pointer to new progress window
311 * @return EOK on success or an error code
312 */
313static errno_t shutdown_progress_create(shutdown_dlg_t *sddlg,
314 shutdown_progress_t **rprogress)
315{
316 ui_wnd_params_t params;
317 ui_window_t *window = NULL;
318 gfx_rect_t rect;
319 ui_resource_t *ui_res;
320 shutdown_progress_t *progress;
321 ui_fixed_t *fixed = NULL;
322 errno_t rc;
323
324 ui_wnd_params_init(&params);
325 params.caption = "Shut down";
326 params.style &= ~ui_wds_titlebar;
327 params.flags |= ui_wndf_topmost;
328 params.placement = ui_wnd_place_center;
329 if (ui_is_textmode(sddlg->ui)) {
330 params.rect.p0.x = 0;
331 params.rect.p0.y = 0;
332 params.rect.p1.x = 64;
333 params.rect.p1.y = 5;
334 } else {
335 params.rect.p0.x = 0;
336 params.rect.p0.y = 0;
337 params.rect.p1.x = 450;
338 params.rect.p1.y = 60;
339 }
340
341 progress = calloc(1, sizeof(shutdown_progress_t));
342 if (progress == NULL) {
343 rc = ENOMEM;
344 printf("Out of memory.\n");
345 goto error;
346 }
347
348 rc = ui_window_create(sddlg->ui, &params, &window);
349 if (rc != EOK) {
350 printf("Error creating window.\n");
351 goto error;
352 }
353
354 ui_window_set_cb(window, &progress_window_cb, (void *) &sddlg);
355
356 ui_res = ui_window_get_res(window);
357
358 rc = ui_fixed_create(&fixed);
359 if (rc != EOK) {
360 printf("Error creating fixed layout.\n");
361 goto error;
362 }
363
364 rc = ui_label_create(ui_res, "The system is shutting down...",
365 &progress->label);
366 if (rc != EOK) {
367 printf("Error creating label.\n");
368 goto error;
369 }
370
371 ui_window_get_app_rect(window, &rect);
372 ui_label_set_rect(progress->label, &rect);
373 ui_label_set_halign(progress->label, gfx_halign_center);
374 ui_label_set_valign(progress->label, gfx_valign_center);
375
376 rc = ui_fixed_add(fixed, ui_label_ctl(progress->label));
377 if (rc != EOK) {
378 printf("Error adding control to layout.\n");
379 ui_label_destroy(progress->label);
380 progress->label = NULL;
381 goto error;
382 }
383
384 ui_window_add(window, ui_fixed_ctl(fixed));
385 fixed = NULL;
386
387 rc = ui_window_paint(window);
388 if (rc != EOK) {
389 printf("Error painting window.\n");
390 goto error;
391 }
392
393 progress->window = window;
394 progress->fixed = fixed;
395 *rprogress = progress;
396 return EOK;
397error:
398 if (progress != NULL && progress->fixed != NULL)
399 ui_fixed_destroy(progress->fixed);
400 if (window != NULL)
401 ui_window_destroy(window);
402 if (progress != NULL)
403 free(progress);
404 return rc;
405}
406
407/** Destroy shutdown progress window.
408 *
409 * @param sddlg Shutdown dialog
410 * @param rprogress Place to store pointer to new progress window
411 * @return EOK on success or an error code
412 */
413static void shutdown_progress_destroy(shutdown_progress_t *progress)
414{
415 if (progress == NULL)
416 return;
417
418 ui_window_destroy(progress->window);
419 free(progress);
420}
421
422/** Start shutdown.
423 *
424 * @param sddlg Shutdown dialog
425 * @param action Shutdown actin
426 * @return EOK on success or an error code
427 */
428static errno_t shutdown_start(shutdown_dlg_t *sddlg, sd_action_t action)
429{
430 errno_t rc;
431
432 rc = shutdown_progress_create(sddlg, &sddlg->progress);
433 if (rc != EOK)
434 return rc;
435
436 rc = system_open(SYSTEM_DEFAULT, &sd_system_cb, sddlg, &sddlg->system);
437 if (rc != EOK) {
438 printf("Failed opening system control service.\n");
439 goto error;
440 }
441
442 rc = EINVAL;
443
444 switch (action) {
445 case sd_poweroff:
446 rc = system_poweroff(sddlg->system);
447 break;
448 case sd_restart:
449 rc = system_restart(sddlg->system);
450 break;
451 }
452
453 if (rc != EOK) {
454 printf("Failed requesting system shutdown.\n");
455 goto error;
456 }
457
458 return EOK;
459error:
460 return rc;
461}
462
463/** Run shutdown dialog on display. */
464static errno_t shutdown_dlg(const char *display_spec)
465{
466 ui_t *ui = NULL;
467 shutdown_dlg_t sddlg;
468 ui_wnd_params_t params;
469 errno_t rc;
470
471 memset((void *) &sddlg, 0, sizeof(sddlg));
472
473 rc = ui_create(display_spec, &ui);
474 if (rc != EOK) {
475 printf("Error creating UI on display %s.\n", display_spec);
476 goto error;
477 }
478
479 sddlg.ui = ui;
480
481 ui_wnd_params_init(&params);
482 params.caption = "Shutdown";
483 params.style &= ~ui_wds_decorated;
484 params.placement = ui_wnd_place_full_screen;
485 params.flags |= ui_wndf_topmost | ui_wndf_nofocus;
486
487 rc = ui_window_create(sddlg.ui, &params, &sddlg.bgwindow);
488 if (rc != EOK) {
489 printf("Error creating window.\n");
490 goto error;
491 }
492
493 ui_window_set_cb(sddlg.bgwindow, &bg_window_cb, (void *)&sddlg);
494
495 if (ui_is_textmode(sddlg.ui)) {
496 rc = gfx_color_new_ega(0x17, &sddlg.bg_color);
497 if (rc != EOK) {
498 printf("Error allocating color.\n");
499 goto error;
500 }
501 } else {
502 rc = gfx_color_new_rgb_i16(0x8000, 0xc800, 0xffff, &sddlg.bg_color);
503 if (rc != EOK) {
504 printf("Error allocating color.\n");
505 goto error;
506 }
507 }
508
509 rc = ui_window_paint(sddlg.bgwindow);
510 if (rc != EOK) {
511 printf("Error painting window.\n");
512 goto error;
513 }
514
515 (void)shutdown_confirm_create(&sddlg);
516
517 ui_run(ui);
518
519 shutdown_progress_destroy(sddlg.progress);
520 if (sddlg.bgwindow != NULL)
521 ui_window_destroy(sddlg.bgwindow);
522 if (sddlg.system != NULL)
523 system_close(sddlg.system);
524 gfx_color_delete(sddlg.bg_color);
525 ui_destroy(ui);
526
527 return EOK;
528error:
529 if (sddlg.system != NULL)
530 system_close(sddlg.system);
531 if (sddlg.bg_color != NULL)
532 gfx_color_delete(sddlg.bg_color);
533 if (sddlg.bgwindow != NULL)
534 ui_window_destroy(sddlg.bgwindow);
535 if (ui != NULL)
536 ui_destroy(ui);
537 return rc;
538}
539
540static void print_syntax(void)
541{
542 printf("Syntax: shutdown-dlg [-d <display-spec>]\n");
543}
544
545int main(int argc, char *argv[])
546{
547 const char *display_spec = UI_ANY_DEFAULT;
548 errno_t rc;
549 int i;
550
551 i = 1;
552 while (i < argc && argv[i][0] == '-') {
553 if (str_cmp(argv[i], "-d") == 0) {
554 ++i;
555 if (i >= argc) {
556 printf("Argument missing.\n");
557 print_syntax();
558 return 1;
559 }
560
561 display_spec = argv[i++];
562 } else {
563 printf("Invalid option '%s'.\n", argv[i]);
564 print_syntax();
565 return 1;
566 }
567 }
568
569 if (i < argc) {
570 print_syntax();
571 return 1;
572 }
573
574 rc = shutdown_dlg(display_spec);
575 if (rc != EOK)
576 return 1;
577
578 return 0;
579}
580
581/** @}
582 */
Note: See TracBrowser for help on using the repository browser.