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