]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - LinuxGUI/Ventoy2Disk/GTK/ventoy_gtk.c
Optimization for GUI LiveCD
[Ventoy.git] / LinuxGUI / Ventoy2Disk / GTK / ventoy_gtk.c
1 /******************************************************************************
2 * ventoy_gtk.c
3 *
4 * Copyright (c) 2021, longpanda <admin@ventoy.net>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 3 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdint.h>
24 #include <string.h>
25 #include <stdarg.h>
26 #include <errno.h>
27 #include <time.h>
28 #include <unistd.h>
29 #include <linux/limits.h>
30
31 #include <ventoy_define.h>
32 #include <ventoy_json.h>
33 #include <ventoy_util.h>
34 #include <ventoy_disk.h>
35 #include <ventoy_http.h>
36
37 #include <gtk/gtk.h>
38 #include "ventoy_gtk.h"
39
40 int g_secure_boot_support = 0;
41 GtkWidget *g_topWindow = NULL;
42 GtkWidget *g_partCfgWindow = NULL;
43 GtkBuilder *g_pXmlBuilder = NULL;
44 GtkComboBoxText *g_dev_combobox = NULL;
45 GtkButton *g_refresh_button = NULL;
46 GtkButton *g_install_button = NULL;
47 GtkButton *g_update_button = NULL;
48 GtkMenu *g_lang_menu = NULL;;
49 GtkCheckMenuItem *g_menu_item_secure_boot = NULL;
50 GtkCheckMenuItem *g_menu_item_mbr = NULL;
51 GtkCheckMenuItem *g_menu_item_gpt = NULL;
52 GtkCheckMenuItem *g_menu_item_show_all = NULL;
53 GtkLabel *g_device_title = NULL;
54 GtkLabel *g_label_local_part_style = NULL;
55 GtkLabel *g_label_dev_part_style = NULL;
56 GtkLabel *g_label_local_ver = NULL;
57 GtkLabel *g_label_disk_ver = NULL;
58 GtkLabel *g_label_status = NULL;
59 GtkImage *g_image_secure_local = NULL;
60 GtkImage *g_image_secure_device = NULL;
61 GtkToggleButton *g_part_align_checkbox = NULL;
62 GtkToggleButton *g_part_preserve_checkbox = NULL;
63 GtkEntry *g_part_reserve_space_value = NULL;
64 GtkComboBoxText *g_part_space_unit_combox = NULL;
65 GtkProgressBar *g_progress_bar = NULL;
66 VTOY_JSON *g_languages_json = NULL;
67 int g_languages_toggled_proc = 0;
68 int g_dev_changed_proc = 0;
69 gboolean g_align_part_with_4k = TRUE;
70 gboolean g_preserve_space_check = FALSE;
71 int g_preserve_space_unit = 1;
72 int g_preserve_space_number = 0;
73 gboolean g_thread_run = FALSE;
74
75 const char *language_string(const char *id)
76 {
77 const char *pName = NULL;
78 VTOY_JSON *node = NULL;
79 const char *pCurLang = ventoy_code_get_cur_language();
80
81 for (node = g_languages_json->pstChild; node; node = node->pstNext)
82 {
83 pName = vtoy_json_get_string_ex(node->pstChild, "name");
84 if (0 == g_strcmp0(pName, pCurLang))
85 {
86 break;
87 }
88 }
89
90 if (NULL == node)
91 {
92 return "xxx";
93 }
94
95 return vtoy_json_get_string_ex(node->pstChild, id);
96 }
97
98 int msgbox(GtkMessageType type, GtkButtonsType buttons, const char *strid)
99 {
100 int ret;
101 GtkWidget *pMsgBox = NULL;
102
103 pMsgBox = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, type, buttons, "%s", language_string(strid));
104
105 ret = gtk_dialog_run(GTK_DIALOG(pMsgBox));
106 gtk_widget_destroy(pMsgBox);
107
108 return ret;
109 }
110
111
112 static void set_item_visible(const char *id, int visible)
113 {
114 GtkWidget *pWidget = NULL;
115
116 pWidget = GTK_WIDGET(gtk_builder_get_object(g_pXmlBuilder, id));
117 if (visible)
118 {
119 gtk_widget_show(pWidget);
120 }
121 else
122 {
123 gtk_widget_hide(pWidget);
124 }
125 }
126
127 static void init_part_style_menu(void)
128 {
129 int style;
130
131 style = ventoy_code_get_cur_part_style();
132 gtk_check_menu_item_set_active(g_menu_item_mbr, (0 == style));
133 gtk_check_menu_item_set_active(g_menu_item_gpt, (1 == style));
134 gtk_label_set_text(g_label_local_part_style, style ? "GPT" : "MBR");
135 }
136
137 static void select_language(const char *lang)
138 {
139 const char *pName = NULL;
140 const char *pPos = NULL;
141 const char *pDevice = NULL;
142 VTOY_JSON *node = NULL;
143 char device[256];
144
145 for (node = g_languages_json->pstChild; node; node = node->pstNext)
146 {
147 pName = vtoy_json_get_string_ex(node->pstChild, "name");
148 if (0 == g_strcmp0(pName, lang))
149 {
150 break;
151 }
152 }
153
154 if (NULL == node)
155 {
156 return;
157 }
158
159 pDevice = gtk_label_get_text(g_device_title);
160 if (pDevice && (pPos = strchr(pDevice, '[')) != NULL)
161 {
162 g_snprintf(device, sizeof(device), "%s %s", vtoy_json_get_string_ex(node->pstChild, "STR_DEVICE"), pPos);
163 gtk_label_set_text(g_device_title, device);
164 }
165 else
166 {
167 gtk_label_set_text(g_device_title, vtoy_json_get_string_ex(node->pstChild, "STR_DEVICE"));
168 }
169
170 LANG_LABEL_TEXT("label_local_ver", "STR_LOCAL_VER");
171 LANG_LABEL_TEXT("label_device_ver", "STR_DISK_VER");
172
173 LANG_LABEL_TEXT("label_status", "STR_STATUS");
174
175 LANG_BUTTON_TEXT("button_install", "STR_INSTALL");
176 LANG_BUTTON_TEXT("button_update", "STR_UPDATE");
177
178 LANG_MENU_ITEM_TEXT("menu_option", "STR_MENU_OPTION");
179 LANG_MENU_ITEM_TEXT("menu_item_secure", "STR_MENU_SECURE_BOOT");
180 LANG_MENU_ITEM_TEXT("menu_part_style", "STR_MENU_PART_STYLE");
181 LANG_MENU_ITEM_TEXT("menu_item_part_cfg", "STR_MENU_PART_CFG");
182 LANG_MENU_ITEM_TEXT("menu_item_clear", "STR_MENU_CLEAR");
183 LANG_MENU_ITEM_TEXT("menu_item_show_all", "STR_SHOW_ALL_DEV");
184
185 LANG_BUTTON_TEXT("space_check_btn", "STR_PRESERVE_SPACE");
186 LANG_BUTTON_TEXT("space_align_btn", "STR_PART_ALIGN_4KB");
187 LANG_BUTTON_TEXT("button_partcfg_ok", "STR_BTN_OK");
188 LANG_BUTTON_TEXT("button_partcfg_cancel", "STR_BTN_CANCEL");
189
190 gtk_window_set_title(GTK_WINDOW(g_partCfgWindow), vtoy_json_get_string_ex(node->pstChild, "STR_MENU_PART_CFG"));
191
192 /*
193 * refresh screen
194 */
195
196 gtk_widget_hide(g_topWindow);
197 gtk_widget_show(g_topWindow);
198 }
199
200
201 void on_secure_boot_toggled(GtkMenuItem *menuItem, gpointer data)
202 {
203 g_secure_boot_support = 1 - g_secure_boot_support;
204
205 if (g_secure_boot_support)
206 {
207 gtk_widget_show((GtkWidget *)g_image_secure_local);
208 }
209 else
210 {
211 gtk_widget_hide((GtkWidget *)g_image_secure_local);
212 }
213 }
214
215 void on_devlist_changed(GtkWidget *widget, gpointer data)
216 {
217 int active;
218 ventoy_disk *cur = NULL;
219 char version[512];
220
221 if (g_dev_changed_proc == 0)
222 {
223 return;
224 }
225
226 gtk_widget_set_sensitive(GTK_WIDGET(g_update_button), FALSE);
227
228 gtk_widget_hide((GtkWidget *)g_image_secure_device);
229 gtk_label_set_markup(g_label_disk_ver, "");
230 gtk_label_set_text(g_label_dev_part_style, "");
231
232 active = gtk_combo_box_get_active((GtkComboBox *)g_dev_combobox);
233 if (active < 0 || active >= g_disk_num)
234 {
235 vlog("invalid active combox id %d\n", active);
236 return;
237 }
238
239 cur = g_disk_list + active;
240 if (cur->vtoydata.ventoy_valid)
241 {
242 if (cur->vtoydata.secure_boot_flag)
243 {
244 gtk_widget_show((GtkWidget *)g_image_secure_device);
245 }
246 else
247 {
248 gtk_widget_hide((GtkWidget *)g_image_secure_device);
249 }
250
251 if (g_secure_boot_support != cur->vtoydata.secure_boot_flag)
252 {
253 gtk_check_menu_item_set_active(g_menu_item_secure_boot, 1 - g_secure_boot_support);
254 }
255
256 g_snprintf(version, sizeof(version), VTOY_VER_FMT, cur->vtoydata.ventoy_ver);
257 gtk_label_set_markup(g_label_disk_ver, version);
258 gtk_label_set_text(g_label_dev_part_style, cur->vtoydata.partition_style ? "GPT" : "MBR");
259
260 gtk_widget_set_sensitive(GTK_WIDGET(g_update_button), TRUE);
261 }
262 else
263 {
264 if (g_secure_boot_support)
265 {
266 gtk_check_menu_item_set_active(g_menu_item_secure_boot, 1 - g_secure_boot_support);
267 }
268 }
269 }
270
271
272 void on_language_toggled(GtkMenuItem *menuItem, gpointer data)
273 {
274 const char *cur_lang = NULL;
275
276 if (g_languages_toggled_proc == 0)
277 {
278 return;
279 }
280
281 cur_lang = ventoy_code_get_cur_language();
282 if (g_strcmp0(cur_lang, (char *)data) != 0)
283 {
284 ventoy_code_set_cur_language((char *)data);
285 select_language((char *)data);
286 }
287 }
288
289 void on_part_style_toggled(GtkMenuItem *menuItem, gpointer data)
290 {
291 int style;
292
293 style = ventoy_code_get_cur_part_style();
294 ventoy_code_set_cur_part_style(1 - style);
295
296 gtk_label_set_text(g_label_local_part_style, style ? "MBR" : "GPT");
297 }
298
299 static ventoy_disk *select_active_dev(const char *select, int *activeid)
300 {
301 int i;
302 int alldev;
303 ventoy_disk *cur = NULL;
304
305 alldev = ventoy_code_get_cur_show_all();
306
307 /* find the match one */
308 if (select)
309 {
310 for (i = 0; i < g_disk_num; i++)
311 {
312 cur = g_disk_list + i;
313 if (alldev == 0 && cur->type != VTOY_DEVICE_USB)
314 {
315 continue;
316 }
317
318 if (strcmp(cur->disk_name, select) == 0)
319 {
320 *activeid = i;
321 return cur;
322 }
323 }
324 }
325
326 /* find the first one that installed with Ventoy */
327 for (i = 0; i < g_disk_num; i++)
328 {
329 cur = g_disk_list + i;
330 if (alldev == 0 && cur->type != VTOY_DEVICE_USB)
331 {
332 continue;
333 }
334
335 if (cur->vtoydata.ventoy_valid)
336 {
337 *activeid = i;
338 return cur;
339 }
340 }
341
342 /* find the first USB interface device */
343 for (i = 0; i < g_disk_num; i++)
344 {
345 cur = g_disk_list + i;
346 if (alldev == 0 && cur->type != VTOY_DEVICE_USB)
347 {
348 continue;
349 }
350
351 if (cur->type == VTOY_DEVICE_USB)
352 {
353 *activeid = i;
354 return cur;
355 }
356 }
357
358 /* use the first one */
359 for (i = 0; i < g_disk_num; i++)
360 {
361 cur = g_disk_list + i;
362 if (alldev == 0 && cur->type != VTOY_DEVICE_USB)
363 {
364 continue;
365 }
366
367 *activeid = i;
368 return cur;
369 }
370
371 return NULL;
372 }
373
374 static void fill_dev_list(const char *select)
375 {
376 int i;
377 int alldev;
378 int activeid;
379 int count = 0;
380 char line[512];
381 ventoy_disk *cur = NULL;
382 ventoy_disk *active = NULL;
383 GtkListStore *store = NULL;
384
385 g_dev_changed_proc = 0;
386
387 alldev = ventoy_code_get_cur_show_all();
388
389 vlog("fill_dev_list total disk: %d showall:%d\n", g_disk_num, alldev);
390
391 /* gtk_combo_box_text_remove_all */
392 store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(g_dev_combobox)));
393 gtk_list_store_clear(store);
394
395 for (i = 0; i < g_disk_num; i++)
396 {
397 cur = g_disk_list + i;
398
399 if (alldev == 0 && cur->type != VTOY_DEVICE_USB)
400 {
401 continue;
402 }
403
404 g_snprintf(line, sizeof(line), "%s [%s] %s", cur->disk_name, cur->human_readable_size, cur->disk_model);
405 gtk_combo_box_text_append_text(g_dev_combobox, line);
406 count++;
407 }
408
409 active = select_active_dev(select, &activeid);
410 if (active)
411 {
412 vlog("combox count:%d, active:%s id:%d\n", count, active->disk_name, activeid);
413 gtk_combo_box_set_active((GtkComboBox *)g_dev_combobox, activeid);
414 gtk_widget_set_sensitive(GTK_WIDGET(g_install_button), TRUE);
415 gtk_widget_set_sensitive(GTK_WIDGET(g_update_button), active->vtoydata.ventoy_valid);
416 }
417 else
418 {
419 vlog("combox count:%d, no active id\n", count);
420 gtk_widget_set_sensitive(GTK_WIDGET(g_install_button), FALSE);
421 gtk_widget_set_sensitive(GTK_WIDGET(g_update_button), FALSE);
422 }
423
424 g_dev_changed_proc = 1;
425 on_devlist_changed(NULL, NULL);
426 }
427
428
429 void on_show_all_toggled(GtkMenuItem *menuItem, gpointer data)
430 {
431 int show_all = ventoy_code_get_cur_show_all();
432
433 ventoy_code_set_cur_show_all(1 - show_all);
434 fill_dev_list(NULL);
435 }
436
437 void on_button_refresh_clicked(GtkWidget *widget, gpointer data)
438 {
439 if (g_thread_run || ventoy_code_is_busy())
440 {
441 msgbox(GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "STR_WAIT_PROCESS");
442 return;
443 }
444
445 ventoy_code_refresh_device();
446 fill_dev_list(NULL);
447 }
448
449 static void set_progress_bar_percent(int percent)
450 {
451 char *pos = NULL;
452 const char *text = NULL;
453 char tmp[128];
454
455 gtk_progress_bar_set_fraction(g_progress_bar, percent * 1.0 / 100);
456 vlog("set percent %d\n", percent);
457
458 text = language_string("STR_STATUS");
459 if (percent == 0)
460 {
461 gtk_label_set_text(g_label_status, text);
462 }
463 else
464 {
465 g_snprintf(tmp, sizeof(tmp), "%s", text);
466 pos = strchr(tmp, '-');
467 if (pos)
468 {
469 g_snprintf(pos + 2, sizeof(tmp), "%d%%", percent);
470 gtk_label_set_text(g_label_status, tmp);
471 }
472 }
473 }
474
475 void on_clear_ventoy(GtkMenuItem *menuItem, gpointer data)
476 {
477 int ret;
478 int active;
479 char buf[1024];
480 char out[256];
481 char disk_name[32];
482 ventoy_disk *cur = NULL;
483
484 if (g_thread_run || ventoy_code_is_busy())
485 {
486 msgbox(GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "STR_WAIT_PROCESS");
487 return;
488 }
489
490 active = gtk_combo_box_get_active((GtkComboBox *)g_dev_combobox);
491 if (active < 0 || active >= g_disk_num)
492 {
493 vlog("invalid active combox id %d\n", active);
494 return;
495 }
496
497 if (GTK_RESPONSE_CANCEL == msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK_CANCEL, "STR_INSTALL_TIP"))
498 {
499 return;
500 }
501
502 if (GTK_RESPONSE_CANCEL == msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK_CANCEL, "STR_INSTALL_TIP2"))
503 {
504 return;
505 }
506
507 gtk_widget_set_sensitive (GTK_WIDGET(g_refresh_button), FALSE);
508 gtk_widget_set_sensitive (GTK_WIDGET(g_install_button), FALSE);
509 gtk_widget_set_sensitive (GTK_WIDGET(g_update_button), FALSE);
510 g_thread_run = TRUE;
511
512
513 cur = g_disk_list + active;
514 g_snprintf(disk_name, sizeof(disk_name), "%s", cur->disk_name);
515 g_snprintf(buf, sizeof(buf), "{\"method\":\"clean\",\"disk\":\"%s\"}", disk_name);
516
517 out[0] = 0;
518 ventoy_func_handler(buf, out, sizeof(out));
519 vlog("func handler clean <%s>\n", out);
520
521 if (strstr(out, "success"))
522 {
523 ret = ventoy_code_get_result();
524 ventoy_code_refresh_device();
525 cur = NULL;
526 }
527 else
528 {
529 ret = 1;
530 }
531
532 if (ret == 0)
533 {
534 msgbox(GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "STR_CLEAR_SUCCESS");
535 }
536 else
537 {
538 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "STR_CLEAR_FAILED");
539 }
540
541 set_progress_bar_percent(0);
542 gtk_widget_set_sensitive(GTK_WIDGET(g_refresh_button), TRUE);
543 gtk_widget_set_sensitive(GTK_WIDGET(g_install_button), TRUE);
544 gtk_widget_set_sensitive(GTK_WIDGET(g_update_button), TRUE);
545
546 fill_dev_list(disk_name);
547 g_thread_run = FALSE;
548 }
549
550 static int install_proc(ventoy_disk *cur)
551 {
552 int ret = 0;
553 int pos = 0;
554 int buflen = 0;
555 int percent = 0;
556 char buf[1024];
557 char dec[64];
558 char out[256];
559 char disk_name[32];
560 long long space;
561
562 vlog("install_thread ...\n");
563
564 g_snprintf(disk_name, sizeof(disk_name), "%s", cur->disk_name);
565
566 buflen = sizeof(buf);
567 VTOY_JSON_FMT_BEGIN(pos, buf, buflen);
568 VTOY_JSON_FMT_OBJ_BEGIN();
569 VTOY_JSON_FMT_STRN("method", "install");
570 VTOY_JSON_FMT_STRN("disk", disk_name);
571
572 if (g_preserve_space_check)
573 {
574 space = g_preserve_space_number;
575 if (g_preserve_space_unit == 1)
576 {
577 space = space * 1024 * 1024 * 1024LL;
578 }
579 else
580 {
581 space = space * 1024 * 1024LL;
582 }
583
584 snprintf(dec, sizeof(dec), "%lld", space);
585 VTOY_JSON_FMT_STRN("reserve_space", dec);
586 }
587 else
588 {
589 VTOY_JSON_FMT_STRN("reserve_space", "0");
590 }
591
592 VTOY_JSON_FMT_UINT("partstyle", ventoy_code_get_cur_part_style());
593 VTOY_JSON_FMT_UINT("secure_boot", g_secure_boot_support);
594 VTOY_JSON_FMT_UINT("align_4kb", g_align_part_with_4k);
595 VTOY_JSON_FMT_OBJ_END();
596 VTOY_JSON_FMT_END(pos);
597
598 out[0] = 0;
599 ventoy_func_handler(buf, out, sizeof(out));
600 vlog("func handler install <%s>\n", out);
601
602 if (strstr(out, "success"))
603 {
604 while (percent != 100)
605 {
606 percent = ventoy_code_get_percent();
607 set_progress_bar_percent(percent);
608 GTK_MSG_ITERATION();
609 usleep(50 * 1000);
610 }
611
612 ret = ventoy_code_get_result();
613 ventoy_code_refresh_device();
614 cur = NULL;
615 }
616 else
617 {
618 ret = 1;
619 }
620
621 if (ret)
622 {
623 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "STR_INSTALL_FAILED");
624 }
625 else
626 {
627 msgbox(GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "STR_INSTALL_SUCCESS");
628 }
629
630 set_progress_bar_percent(0);
631 gtk_widget_set_sensitive(GTK_WIDGET(g_refresh_button), TRUE);
632 gtk_widget_set_sensitive(GTK_WIDGET(g_install_button), TRUE);
633 gtk_widget_set_sensitive(GTK_WIDGET(g_update_button), TRUE);
634
635 fill_dev_list(disk_name);
636 g_thread_run = FALSE;
637
638 return 0;
639 }
640
641 void on_button_install_clicked(GtkWidget *widget, gpointer data)
642 {
643 int active;
644 long long size;
645 long long space;
646 ventoy_disk *cur = NULL;
647
648 if (g_thread_run || ventoy_code_is_busy())
649 {
650 msgbox(GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "STR_WAIT_PROCESS");
651 return;
652 }
653
654 active = gtk_combo_box_get_active((GtkComboBox *)g_dev_combobox);
655 if (active < 0 || active >= g_disk_num)
656 {
657 vlog("invalid active combox id %d\n", active);
658 return;
659 }
660
661 cur = g_disk_list + active;
662
663 if (ventoy_code_get_cur_part_style() == 0 && cur->size_in_byte > 2199023255552ULL)
664 {
665 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "STR_DISK_2TB_MBR_ERROR");
666 return;
667 }
668
669 if (g_preserve_space_check)
670 {
671 space = g_preserve_space_number;
672 if (g_preserve_space_unit == 1)
673 {
674 space = space * 1024;
675 }
676 else
677 {
678 space = space;
679 }
680
681 size = cur->size_in_byte / SIZE_1MB;
682 if (size <= space || (size - space) <= (VTOYEFI_PART_BYTES / SIZE_1MB))
683 {
684 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "STR_SPACE_VAL_INVALID");
685 vlog("reserved space value too big ...\n");
686 return;
687 }
688 }
689
690 if (GTK_RESPONSE_CANCEL == msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK_CANCEL, "STR_INSTALL_TIP"))
691 {
692 return;
693 }
694
695 if (GTK_RESPONSE_CANCEL == msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK_CANCEL, "STR_INSTALL_TIP2"))
696 {
697 return;
698 }
699
700 gtk_widget_set_sensitive (GTK_WIDGET(g_refresh_button), FALSE);
701 gtk_widget_set_sensitive (GTK_WIDGET(g_install_button), FALSE);
702 gtk_widget_set_sensitive (GTK_WIDGET(g_update_button), FALSE);
703
704 g_thread_run = TRUE;
705
706 install_proc(cur);
707 }
708
709
710 static int update_proc(ventoy_disk *cur)
711 {
712 int ret = 0;
713 int percent = 0;
714 char buf[1024];
715 char out[256];
716 char disk_name[32];
717
718 g_snprintf(disk_name, sizeof(disk_name), "%s", cur->disk_name);
719 g_snprintf(buf, sizeof(buf), "{\"method\":\"update\",\"disk\":\"%s\",\"secure_boot\":%d}",
720 disk_name, g_secure_boot_support);
721
722 out[0] = 0;
723 ventoy_func_handler(buf, out, sizeof(out));
724 vlog("func handler update <%s>\n", out);
725
726 if (strstr(out, "success"))
727 {
728 while (percent != 100)
729 {
730 percent = ventoy_code_get_percent();
731 set_progress_bar_percent(percent);
732 GTK_MSG_ITERATION();
733 usleep(50 * 1000);
734 }
735
736 ret = ventoy_code_get_result();
737 ventoy_code_refresh_device();
738 cur = NULL;
739 }
740 else
741 {
742 ret = 1;
743 }
744
745 if (ret)
746 {
747 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "STR_UPDATE_FAILED");
748 }
749 else
750 {
751 msgbox(GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "STR_UPDATE_SUCCESS");
752 }
753
754 set_progress_bar_percent(0);
755 gtk_widget_set_sensitive(GTK_WIDGET(g_refresh_button), TRUE);
756 gtk_widget_set_sensitive(GTK_WIDGET(g_install_button), TRUE);
757 gtk_widget_set_sensitive(GTK_WIDGET(g_update_button), TRUE);
758
759 fill_dev_list(disk_name);
760 g_thread_run = FALSE;
761
762 return 0;
763 }
764
765
766 void on_button_update_clicked(GtkWidget *widget, gpointer data)
767 {
768 int active;
769 ventoy_disk *cur = NULL;
770
771 if (g_thread_run || ventoy_code_is_busy())
772 {
773 msgbox(GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "STR_WAIT_PROCESS");
774 return;
775 }
776
777 active = gtk_combo_box_get_active((GtkComboBox *)g_dev_combobox);
778 if (active < 0 || active >= g_disk_num)
779 {
780 vlog("invalid active combox id %d\n", active);
781 return;
782 }
783 cur = g_disk_list + active;
784
785 if (cur->vtoydata.ventoy_valid == 0)
786 {
787 vlog("invalid ventoy version.\n");
788 return;
789 }
790
791 if (GTK_RESPONSE_CANCEL == msgbox(GTK_MESSAGE_INFO, GTK_BUTTONS_OK_CANCEL, "STR_UPDATE_TIP"))
792 {
793 return;
794 }
795
796 gtk_widget_set_sensitive (GTK_WIDGET(g_refresh_button), FALSE);
797 gtk_widget_set_sensitive (GTK_WIDGET(g_install_button), FALSE);
798 gtk_widget_set_sensitive (GTK_WIDGET(g_update_button), FALSE);
799
800 g_thread_run = TRUE;
801
802 update_proc(cur);
803 }
804
805 static gint lang_compare(gconstpointer a, gconstpointer b)
806 {
807 const char *name1 = (const char *)a;
808 const char *name2 = (const char *)b;
809
810 if (strncmp(name1, "Chinese Simplified", 18) == 0)
811 {
812 return -1;
813 }
814 else if (strncmp(name2, "Chinese Simplified", 18) == 0)
815 {
816 return 1;
817 }
818 else
819 {
820 return g_strcmp0(name1, name2);
821 }
822 }
823
824 static int load_languages(void)
825 {
826 int size = 0;
827 char *pBuf = NULL;
828 char *pCur = NULL;
829 const char *pCurLang = NULL;
830 const char *pName = NULL;
831 VTOY_JSON *json = NULL;
832 VTOY_JSON *node = NULL;
833 VTOY_JSON *lang = NULL;
834 GSList *pGroup = NULL;
835 GList *pNameNode = NULL;
836 GList *pNameList = NULL;
837 GtkRadioMenuItem *pItem = NULL;
838
839 vlog("load_languages ...\n");
840
841 pCurLang = ventoy_code_get_cur_language();
842 if (pCurLang[0] == 0)
843 {
844 pName = getenv("LANG");
845 if (pName && strncmp(pName, "zh_CN", 5) == 0)
846 {
847 ventoy_code_set_cur_language("Chinese Simplified (简体中文)");
848 }
849 else
850 {
851 ventoy_code_set_cur_language("English (English)");
852 }
853 pCurLang = ventoy_code_get_cur_language();
854 }
855
856 vlog("current language <%s>\n", pCurLang);
857
858 ventoy_read_file_to_buf("./tool/languages.json", 1, (void **)&pBuf, &size);
859
860 json = vtoy_json_create();
861 vtoy_json_parse(json, pBuf);
862 g_languages_json = json;
863
864 for (node = json->pstChild; node; node = node->pstNext)
865 {
866 pName = vtoy_json_get_string_ex(node->pstChild, "name");
867 if (pName)
868 {
869 pNameList = g_list_append(pNameList, (gpointer)pName);
870 }
871
872 for (lang = node->pstChild; lang; lang = lang->pstNext)
873 {
874 if (lang->enDataType == JSON_TYPE_STRING)
875 {
876 pCur = lang->unData.pcStrVal;
877 while (*pCur)
878 {
879 if (*pCur == '#')
880 {
881 *pCur = '\r';
882 }
883 else if (*pCur == '@')
884 {
885 *pCur = '\n';
886 }
887 pCur++;
888 }
889 }
890 }
891 }
892
893 pNameList = g_list_sort(pNameList, lang_compare);
894
895 for (pNameNode = g_list_first(pNameList); pNameNode; pNameNode = g_list_next(pNameNode))
896 {
897 pName = (char *)(pNameNode->data);
898 pItem = (GtkRadioMenuItem *)gtk_radio_menu_item_new_with_label(pGroup, pName);
899 pGroup = gtk_radio_menu_item_get_group(pItem);
900
901 if (strcmp(pCurLang, pName) == 0)
902 {
903 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(pItem), TRUE);
904 }
905
906 g_signal_connect(pItem, "toggled", G_CALLBACK(on_language_toggled), (gpointer)pName);
907 gtk_widget_show((GtkWidget *)pItem);
908 gtk_menu_shell_append(GTK_MENU_SHELL(g_lang_menu), (GtkWidget *)pItem);
909 }
910
911 g_list_free(pNameList);
912 free(pBuf);
913
914 select_language(pCurLang);
915 g_languages_toggled_proc = 1;
916
917 return 0;
918 }
919
920 void on_part_cfg_ok(GtkWidget *widget, gpointer data)
921 {
922 const char *pos = NULL;
923 const char *input = NULL;
924 char device[256];
925 gboolean checked = gtk_toggle_button_get_active(g_part_preserve_checkbox);
926
927 if (checked)
928 {
929 input = gtk_entry_get_text(g_part_reserve_space_value);
930 if (input == NULL || input[0] == 0)
931 {
932 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "STR_SPACE_VAL_INVALID");
933 return;
934 }
935
936 for (pos = input; *pos; pos++)
937 {
938 if (*pos < '0' || *pos >= '9')
939 {
940 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "STR_SPACE_VAL_INVALID");
941 return;
942 }
943 }
944
945 g_preserve_space_unit = gtk_combo_box_get_active((GtkComboBox *)g_part_space_unit_combox);
946 g_preserve_space_number = (int)strtol(input, NULL, 10);
947
948 g_snprintf(device, sizeof(device), "%s [ -%d%s ]",
949 language_string("STR_DEVICE"), g_preserve_space_number,
950 g_preserve_space_unit ? "GB" : "MB");
951 gtk_label_set_text(g_device_title, device);
952 }
953 else
954 {
955 gtk_label_set_text(g_device_title, language_string("STR_DEVICE"));
956 }
957
958 g_preserve_space_check = checked;
959 g_align_part_with_4k = gtk_toggle_button_get_active(g_part_align_checkbox);
960 gtk_widget_hide(g_partCfgWindow);
961 }
962
963 void on_part_cfg_cancel(GtkWidget *widget, gpointer data)
964 {
965 gtk_widget_hide(g_partCfgWindow);
966 }
967
968 int on_part_cfg_close(GtkWidget *widget, gpointer data)
969 {
970 gtk_widget_hide(g_partCfgWindow);
971 return TRUE;
972 }
973
974 void on_part_config(GtkMenuItem *menuItem, gpointer data)
975 {
976 char value[64];
977
978 gtk_toggle_button_set_active(g_part_align_checkbox, g_align_part_with_4k);
979 gtk_toggle_button_set_active(g_part_preserve_checkbox, g_preserve_space_check);
980 gtk_widget_set_sensitive(GTK_WIDGET(g_part_reserve_space_value), g_preserve_space_check);
981 gtk_widget_set_sensitive(GTK_WIDGET(g_part_space_unit_combox), g_preserve_space_check);
982
983 if (g_preserve_space_check)
984 {
985 g_snprintf(value, sizeof(value), "%d", g_preserve_space_number);
986 gtk_entry_set_text(g_part_reserve_space_value, value);
987 gtk_combo_box_set_active((GtkComboBox *)g_part_space_unit_combox, g_preserve_space_unit);
988 }
989
990 gtk_widget_show_all(g_partCfgWindow);
991 }
992
993 void on_reserve_space_toggled(GtkMenuItem *menuItem, gpointer data)
994 {
995 gboolean checked = gtk_toggle_button_get_active(g_part_preserve_checkbox);
996
997 gtk_widget_set_sensitive(GTK_WIDGET(g_part_reserve_space_value), checked);
998 gtk_widget_set_sensitive(GTK_WIDGET(g_part_space_unit_combox), checked);
999 }
1000
1001 static void init_part_cfg_window(GtkBuilder *pBuilder)
1002 {
1003 #if GTK_CHECK_VERSION(3, 0, 0)
1004 GtkWidget *pHeader = NULL;
1005
1006 pHeader = gtk_header_bar_new();
1007 gtk_header_bar_set_show_close_button(GTK_HEADER_BAR(pHeader), FALSE);
1008 gtk_window_set_titlebar (GTK_WINDOW(g_partCfgWindow), pHeader);
1009 gtk_window_set_title(GTK_WINDOW(g_partCfgWindow), "Partition Configuration");
1010 #endif
1011
1012 gtk_combo_box_set_active((GtkComboBox *)g_part_space_unit_combox, g_preserve_space_unit);
1013 gtk_widget_set_sensitive (GTK_WIDGET(g_part_reserve_space_value), FALSE);
1014 gtk_widget_set_sensitive (GTK_WIDGET(g_part_space_unit_combox), FALSE);
1015
1016 SIGNAL("space_check_btn", "toggled", on_reserve_space_toggled);
1017
1018 SIGNAL("button_partcfg_ok", "clicked", on_part_cfg_ok);
1019 SIGNAL("button_partcfg_cancel", "clicked", on_part_cfg_cancel);
1020 SIGNAL("part_cfg_dlg", "delete_event", on_part_cfg_close);
1021 }
1022
1023 void on_init_window(GtkBuilder *pBuilder)
1024 {
1025 GSList *pGroup = NULL;
1026 char version[512];
1027
1028 vlog("on_init_window ...\n");
1029
1030 g_pXmlBuilder = pBuilder;
1031 g_topWindow = BUILDER_ITEM(GtkWidget, "window");
1032 g_partCfgWindow = BUILDER_ITEM(GtkWidget, "part_cfg_dlg");
1033
1034 g_dev_combobox = BUILDER_ITEM(GtkComboBoxText, "combobox_devlist");
1035 g_refresh_button = BUILDER_ITEM(GtkButton, "button_refresh");
1036 g_install_button = BUILDER_ITEM(GtkButton, "button_install");
1037 g_update_button = BUILDER_ITEM(GtkButton, "button_update");
1038
1039 g_lang_menu = BUILDER_ITEM(GtkMenu, "submenu_language");
1040 g_menu_item_secure_boot = BUILDER_ITEM(GtkCheckMenuItem, "menu_item_secure");
1041 g_menu_item_mbr = BUILDER_ITEM(GtkCheckMenuItem, "menu_item_mbr");
1042 g_menu_item_gpt = BUILDER_ITEM(GtkCheckMenuItem, "menu_item_gpt");
1043 g_menu_item_show_all = BUILDER_ITEM(GtkCheckMenuItem, "menu_item_show_all");
1044
1045 g_device_title = BUILDER_ITEM(GtkLabel, "label_device");
1046 g_label_local_part_style = BUILDER_ITEM(GtkLabel, "label_local_part_style");
1047 g_label_dev_part_style = BUILDER_ITEM(GtkLabel, "label_dev_part_style");
1048
1049 g_label_local_ver = BUILDER_ITEM(GtkLabel, "label_local_ver_value");
1050 g_label_disk_ver = BUILDER_ITEM(GtkLabel, "label_dev_ver_value");
1051
1052 g_label_status = BUILDER_ITEM(GtkLabel, "label_status");
1053
1054 g_image_secure_local = BUILDER_ITEM(GtkImage, "image_secure_local");
1055 g_image_secure_device = BUILDER_ITEM(GtkImage, "image_secure_dev");
1056
1057 g_part_preserve_checkbox = BUILDER_ITEM(GtkToggleButton, "space_check_btn");
1058 g_part_align_checkbox = BUILDER_ITEM(GtkToggleButton, "space_align_btn");
1059
1060 g_part_reserve_space_value = BUILDER_ITEM(GtkEntry, "entry_reserve_space");
1061 g_part_space_unit_combox = BUILDER_ITEM(GtkComboBoxText, "comboboxtext_unit");
1062
1063 g_progress_bar = BUILDER_ITEM(GtkProgressBar, "progressbar1");
1064
1065 init_part_cfg_window(pBuilder);
1066
1067 /* for gtk2 */
1068 gtk_frame_set_shadow_type(BUILDER_ITEM(GtkFrame, "frame_dummy1"), GTK_SHADOW_NONE);
1069 gtk_frame_set_shadow_type(BUILDER_ITEM(GtkFrame, "frame_dummy2"), GTK_SHADOW_NONE);
1070
1071 /* join group */
1072 pGroup = gtk_radio_menu_item_get_group((GtkRadioMenuItem *)g_menu_item_mbr);
1073 gtk_radio_menu_item_set_group((GtkRadioMenuItem *)g_menu_item_gpt, pGroup);
1074
1075 gtk_widget_hide((GtkWidget *)g_image_secure_local);
1076 gtk_widget_hide((GtkWidget *)g_image_secure_device);
1077
1078 g_snprintf(version, sizeof(version), VTOY_VER_FMT, ventoy_get_local_version());
1079 gtk_label_set_markup(g_label_local_ver, version);
1080
1081 init_part_style_menu();
1082 gtk_check_menu_item_set_active(g_menu_item_show_all, ventoy_code_get_cur_show_all());
1083
1084 load_languages();
1085
1086 SIGNAL("combobox_devlist", "changed", on_devlist_changed);
1087
1088 SIGNAL("button_refresh", "clicked", on_button_refresh_clicked);
1089 SIGNAL("button_install", "clicked", on_button_install_clicked);
1090 SIGNAL("button_update", "clicked", on_button_update_clicked);
1091
1092 SIGNAL("menu_item_secure", "toggled", on_secure_boot_toggled);
1093 SIGNAL("menu_item_mbr", "toggled", on_part_style_toggled);
1094 SIGNAL("menu_item_show_all", "toggled", on_show_all_toggled);
1095
1096 SIGNAL("menu_item_part_cfg", "activate", on_part_config);
1097 SIGNAL("menu_item_clear", "activate", on_clear_ventoy);
1098
1099 fill_dev_list(NULL);
1100
1101 return;
1102 }
1103
1104 int on_exit_window(GtkWidget *widget, gpointer data)
1105 {
1106 vlog("on_exit_window ...\n");
1107
1108 if (g_thread_run || ventoy_code_is_busy())
1109 {
1110 msgbox(GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "STR_WAIT_PROCESS");
1111 return TRUE;
1112 }
1113
1114 ventoy_code_save_cfg();
1115 return FALSE;
1116 }
1117