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