mirror of https://github.com/ventoy/Ventoy
1141 lines
32 KiB
C
1141 lines
32 KiB
C
/******************************************************************************
|
|
* ventoy_gtk.c
|
|
*
|
|
* Copyright (c) 2021, longpanda <admin@ventoy.net>
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation; either version 3 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <stdarg.h>
|
|
#include <errno.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
#include <linux/limits.h>
|
|
|
|
#include <ventoy_define.h>
|
|
#include <ventoy_json.h>
|
|
#include <ventoy_util.h>
|
|
#include <ventoy_disk.h>
|
|
#include <ventoy_http.h>
|
|
|
|
#include <gtk/gtk.h>
|
|
#include <gdk/gdkkeysyms.h>
|
|
#include "ventoy_gtk.h"
|
|
|
|
int g_secure_boot_support = 0;
|
|
GtkWidget *g_topWindow = NULL;
|
|
GtkWidget *g_partCfgWindow = NULL;
|
|
GtkBuilder *g_pXmlBuilder = NULL;
|
|
GtkComboBoxText *g_dev_combobox = NULL;
|
|
GtkButton *g_refresh_button = NULL;
|
|
GtkButton *g_install_button = NULL;
|
|
GtkButton *g_update_button = NULL;
|
|
GtkMenu *g_lang_menu = NULL;;
|
|
GtkCheckMenuItem *g_menu_item_secure_boot = NULL;
|
|
GtkCheckMenuItem *g_menu_item_mbr = NULL;
|
|
GtkCheckMenuItem *g_menu_item_gpt = NULL;
|
|
GtkCheckMenuItem *g_menu_item_show_all = NULL;
|
|
GtkLabel *g_device_title = NULL;
|
|
GtkLabel *g_label_local_part_style = NULL;
|
|
GtkLabel *g_label_dev_part_style = NULL;
|
|
GtkLabel *g_label_local_ver = NULL;
|
|
GtkLabel *g_label_disk_ver = NULL;
|
|
GtkLabel *g_label_status = NULL;
|
|
GtkImage *g_image_secure_local = NULL;
|
|
GtkImage *g_image_secure_device = NULL;
|
|
GtkToggleButton *g_part_align_checkbox = NULL;
|
|
GtkToggleButton *g_part_preserve_checkbox = NULL;
|
|
GtkEntry *g_part_reserve_space_value = NULL;
|
|
GtkComboBoxText *g_part_space_unit_combox = NULL;
|
|
GtkProgressBar *g_progress_bar = NULL;
|
|
VTOY_JSON *g_languages_json = NULL;
|
|
int g_languages_toggled_proc = 0;
|
|
int g_dev_changed_proc = 0;
|
|
gboolean g_align_part_with_4k = TRUE;
|
|
gboolean g_preserve_space_check = FALSE;
|
|
int g_preserve_space_unit = 1;
|
|
int g_preserve_space_number = 0;
|
|
gboolean g_thread_run = FALSE;
|
|
|
|
const char *language_string(const char *id)
|
|
{
|
|
const char *pName = NULL;
|
|
VTOY_JSON *node = NULL;
|
|
const char *pCurLang = ventoy_code_get_cur_language();
|
|
|
|
for (node = g_languages_json->pstChild; node; node = node->pstNext)
|
|
{
|
|
pName = vtoy_json_get_string_ex(node->pstChild, "name");
|
|
if (0 == g_strcmp0(pName, pCurLang))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (NULL == node)
|
|
{
|
|
return "xxx";
|
|
}
|
|
|
|
return vtoy_json_get_string_ex(node->pstChild, id);
|
|
}
|
|
|
|
int msgbox(GtkMessageType type, GtkButtonsType buttons, const char *strid)
|
|
{
|
|
int ret;
|
|
GtkWidget *pMsgBox = NULL;
|
|
|
|
pMsgBox = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, type, buttons, "%s", language_string(strid));
|
|
|
|
ret = gtk_dialog_run(GTK_DIALOG(pMsgBox));
|
|
gtk_widget_destroy(pMsgBox);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
static void set_item_visible(const char *id, int visible)
|
|
{
|
|
GtkWidget *pWidget = NULL;
|
|
|
|
pWidget = GTK_WIDGET(gtk_builder_get_object(g_pXmlBuilder, id));
|
|
if (visible)
|
|
{
|
|
gtk_widget_show(pWidget);
|
|
}
|
|
else
|
|
{
|
|
gtk_widget_hide(pWidget);
|
|
}
|
|
}
|
|
|
|
static void init_part_style_menu(void)
|
|
{
|
|
int style;
|
|
|
|
style = ventoy_code_get_cur_part_style();
|
|
gtk_check_menu_item_set_active(g_menu_item_mbr, (0 == style));
|
|
gtk_check_menu_item_set_active(g_menu_item_gpt, (1 == style));
|
|
gtk_label_set_text(g_label_local_part_style, style ? "GPT" : "MBR");
|
|
}
|
|
|
|
static void select_language(const char *lang)
|
|
{
|
|
const char *pName = NULL;
|
|
const char *pPos = NULL;
|
|
const char *pDevice = NULL;
|
|
VTOY_JSON *node = NULL;
|
|
char device[256];
|
|
|
|
for (node = g_languages_json->pstChild; node; node = node->pstNext)
|
|
{
|
|
pName = vtoy_json_get_string_ex(node->pstChild, "name");
|
|
if (0 == g_strcmp0(pName, lang))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (NULL == node)
|
|
{
|
|
return;
|
|
}
|
|
|
|
pDevice = gtk_label_get_text(g_device_title);
|
|
if (pDevice && (pPos = strchr(pDevice, '[')) != NULL)
|
|
{
|
|
g_snprintf(device, sizeof(device), "%s %s", vtoy_json_get_string_ex(node->pstChild, "STR_DEVICE"), pPos);
|
|
gtk_label_set_text(g_device_title, device);
|
|
}
|
|
else
|
|
{
|
|
gtk_label_set_text(g_device_title, vtoy_json_get_string_ex(node->pstChild, "STR_DEVICE"));
|
|
}
|
|
|
|
LANG_LABEL_TEXT("label_local_ver", "STR_LOCAL_VER");
|
|
LANG_LABEL_TEXT("label_device_ver", "STR_DISK_VER");
|
|
|
|
LANG_LABEL_TEXT("label_status", "STR_STATUS");
|
|
|
|
LANG_BUTTON_TEXT("button_install", "STR_INSTALL");
|
|
LANG_BUTTON_TEXT("button_update", "STR_UPDATE");
|
|
|
|
LANG_MENU_ITEM_TEXT("menu_option", "STR_MENU_OPTION");
|
|
LANG_MENU_ITEM_TEXT("menu_item_secure", "STR_MENU_SECURE_BOOT");
|
|
LANG_MENU_ITEM_TEXT("menu_part_style", "STR_MENU_PART_STYLE");
|
|
LANG_MENU_ITEM_TEXT("menu_item_part_cfg", "STR_MENU_PART_CFG");
|
|
LANG_MENU_ITEM_TEXT("menu_item_clear", "STR_MENU_CLEAR");
|
|
LANG_MENU_ITEM_TEXT("menu_item_show_all", "STR_SHOW_ALL_DEV");
|
|
|
|
LANG_BUTTON_TEXT("space_check_btn", "STR_PRESERVE_SPACE");
|
|
LANG_BUTTON_TEXT("space_align_btn", "STR_PART_ALIGN_4KB");
|
|
LANG_BUTTON_TEXT("button_partcfg_ok", "STR_BTN_OK");
|
|
LANG_BUTTON_TEXT("button_partcfg_cancel", "STR_BTN_CANCEL");
|
|
|
|
gtk_window_set_title(GTK_WINDOW(g_partCfgWindow), vtoy_json_get_string_ex(node->pstChild, "STR_MENU_PART_CFG"));
|
|
|
|
/*
|
|
* refresh screen
|
|
*/
|
|
|
|
gtk_widget_hide(g_topWindow);
|
|
gtk_widget_show(g_topWindow);
|
|
}
|
|
|
|
|
|
void on_secure_boot_toggled(GtkMenuItem *menuItem, gpointer data)
|
|
{
|
|
g_secure_boot_support = 1 - g_secure_boot_support;
|
|
|
|
if (g_secure_boot_support)
|
|
{
|
|
gtk_widget_show((GtkWidget *)g_image_secure_local);
|
|
}
|
|
else
|
|
{
|
|
gtk_widget_hide((GtkWidget *)g_image_secure_local);
|
|
}
|
|
}
|
|
|
|
void on_devlist_changed(GtkWidget *widget, gpointer data)
|
|
{
|
|
int active;
|
|
ventoy_disk *cur = NULL;
|
|
char version[512];
|
|
|
|
if (g_dev_changed_proc == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
gtk_widget_set_sensitive(GTK_WIDGET(g_update_button), FALSE);
|
|
|
|
gtk_widget_hide((GtkWidget *)g_image_secure_device);
|
|
gtk_label_set_markup(g_label_disk_ver, "");
|
|
gtk_label_set_text(g_label_dev_part_style, "");
|
|
|
|
active = gtk_combo_box_get_active((GtkComboBox *)g_dev_combobox);
|
|
if (active < 0 || active >= g_disk_num)
|
|
{
|
|
vlog("invalid active combox id %d\n", active);
|
|
return;
|
|
}
|
|
|
|
cur = g_disk_list + active;
|
|
if (cur->vtoydata.ventoy_valid)
|
|
{
|
|
if (cur->vtoydata.secure_boot_flag)
|
|
{
|
|
gtk_widget_show((GtkWidget *)g_image_secure_device);
|
|
}
|
|
else
|
|
{
|
|
gtk_widget_hide((GtkWidget *)g_image_secure_device);
|
|
}
|
|
|
|
if (g_secure_boot_support != cur->vtoydata.secure_boot_flag)
|
|
{
|
|
gtk_check_menu_item_set_active(g_menu_item_secure_boot, 1 - g_secure_boot_support);
|
|
}
|
|
|
|
g_snprintf(version, sizeof(version), VTOY_VER_FMT, cur->vtoydata.ventoy_ver);
|
|
gtk_label_set_markup(g_label_disk_ver, version);
|
|
gtk_label_set_text(g_label_dev_part_style, cur->vtoydata.partition_style ? "GPT" : "MBR");
|
|
|
|
gtk_widget_set_sensitive(GTK_WIDGET(g_update_button), TRUE);
|
|
}
|
|
else
|
|
{
|
|
if (!g_secure_boot_support)
|
|
{
|
|
gtk_check_menu_item_set_active(g_menu_item_secure_boot, 1 - g_secure_boot_support);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void on_language_toggled(GtkMenuItem *menuItem, gpointer data)
|
|
{
|
|
const char *cur_lang = NULL;
|
|
|
|
if (g_languages_toggled_proc == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
cur_lang = ventoy_code_get_cur_language();
|
|
if (g_strcmp0(cur_lang, (char *)data) != 0)
|
|
{
|
|
ventoy_code_set_cur_language((char *)data);
|
|
select_language((char *)data);
|
|
}
|
|
}
|
|
|
|
void on_part_style_toggled(GtkMenuItem *menuItem, gpointer data)
|
|
{
|
|
int style;
|
|
|
|
style = ventoy_code_get_cur_part_style();
|
|
ventoy_code_set_cur_part_style(1 - style);
|
|
|
|
gtk_label_set_text(g_label_local_part_style, style ? "MBR" : "GPT");
|
|
}
|
|
|
|
static ventoy_disk *select_active_dev(const char *select, int *activeid)
|
|
{
|
|
int i;
|
|
int alldev;
|
|
ventoy_disk *cur = NULL;
|
|
|
|
alldev = ventoy_code_get_cur_show_all();
|
|
|
|
/* find the match one */
|
|
if (select)
|
|
{
|
|
for (i = 0; i < g_disk_num; i++)
|
|
{
|
|
cur = g_disk_list + i;
|
|
if (alldev == 0 && cur->type != VTOY_DEVICE_USB)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (strcmp(cur->disk_name, select) == 0)
|
|
{
|
|
*activeid = i;
|
|
return cur;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* find the first one that installed with Ventoy */
|
|
for (i = 0; i < g_disk_num; i++)
|
|
{
|
|
cur = g_disk_list + i;
|
|
if (alldev == 0 && cur->type != VTOY_DEVICE_USB)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (cur->vtoydata.ventoy_valid)
|
|
{
|
|
*activeid = i;
|
|
return cur;
|
|
}
|
|
}
|
|
|
|
/* find the first USB interface device */
|
|
for (i = 0; i < g_disk_num; i++)
|
|
{
|
|
cur = g_disk_list + i;
|
|
if (alldev == 0 && cur->type != VTOY_DEVICE_USB)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (cur->type == VTOY_DEVICE_USB)
|
|
{
|
|
*activeid = i;
|
|
return cur;
|
|
}
|
|
}
|
|
|
|
/* use the first one */
|
|
for (i = 0; i < g_disk_num; i++)
|
|
{
|
|
cur = g_disk_list + i;
|
|
if (alldev == 0 && cur->type != VTOY_DEVICE_USB)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
*activeid = i;
|
|
return cur;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void fill_dev_list(const char *select)
|
|
{
|
|
int i;
|
|
int alldev;
|
|
int activeid;
|
|
int count = 0;
|
|
char line[512];
|
|
ventoy_disk *cur = NULL;
|
|
ventoy_disk *active = NULL;
|
|
GtkListStore *store = NULL;
|
|
|
|
g_dev_changed_proc = 0;
|
|
|
|
alldev = ventoy_code_get_cur_show_all();
|
|
|
|
vlog("fill_dev_list total disk: %d showall:%d\n", g_disk_num, alldev);
|
|
|
|
/* gtk_combo_box_text_remove_all */
|
|
store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(g_dev_combobox)));
|
|
gtk_list_store_clear(store);
|
|
|
|
for (i = 0; i < g_disk_num; i++)
|
|
{
|
|
cur = g_disk_list + i;
|
|
|
|
if (alldev == 0 && cur->type != VTOY_DEVICE_USB)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
g_snprintf(line, sizeof(line), "%s [%s] %s", cur->disk_name, cur->human_readable_size, cur->disk_model);
|
|
gtk_combo_box_text_append_text(g_dev_combobox, line);
|
|
count++;
|
|
}
|
|
|
|
active = select_active_dev(select, &activeid);
|
|
if (active)
|
|
{
|
|
vlog("combox count:%d, active:%s id:%d\n", count, active->disk_name, activeid);
|
|
gtk_combo_box_set_active((GtkComboBox *)g_dev_combobox, activeid);
|
|
gtk_widget_set_sensitive(GTK_WIDGET(g_install_button), TRUE);
|
|
gtk_widget_set_sensitive(GTK_WIDGET(g_update_button), active->vtoydata.ventoy_valid);
|
|
}
|
|
else
|
|
{
|
|
vlog("combox count:%d, no active id\n", count);
|
|
gtk_widget_set_sensitive(GTK_WIDGET(g_install_button), FALSE);
|
|
gtk_widget_set_sensitive(GTK_WIDGET(g_update_button), FALSE);
|
|
}
|
|
|
|
g_dev_changed_proc = 1;
|
|
on_devlist_changed(NULL, NULL);
|
|
}
|
|
|
|
|
|
void on_show_all_toggled(GtkMenuItem *menuItem, gpointer data)
|
|
{
|
|
int show_all = ventoy_code_get_cur_show_all();
|
|
|
|
ventoy_code_set_cur_show_all(1 - show_all);
|
|
fill_dev_list(NULL);
|
|
}
|
|
|
|
void on_button_refresh_clicked(GtkWidget *widget, gpointer data)
|
|
{
|
|
if (g_thread_run || ventoy_code_is_busy())
|
|
{
|
|
msgbox(GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "STR_WAIT_PROCESS");
|
|
return;
|
|
}
|
|
|
|
ventoy_code_refresh_device();
|
|
fill_dev_list(NULL);
|
|
}
|
|
|
|
static void set_progress_bar_percent(int percent)
|
|
{
|
|
char *pos = NULL;
|
|
const char *text = NULL;
|
|
char tmp[128];
|
|
|
|
gtk_progress_bar_set_fraction(g_progress_bar, percent * 1.0 / 100);
|
|
vlog("set percent %d\n", percent);
|
|
|
|
text = language_string("STR_STATUS");
|
|
if (percent == 0)
|
|
{
|
|
gtk_label_set_text(g_label_status, text);
|
|
}
|
|
else
|
|
{
|
|
g_snprintf(tmp, sizeof(tmp), "%s", text);
|
|
pos = strchr(tmp, '-');
|
|
if (pos)
|
|
{
|
|
g_snprintf(pos + 2, sizeof(tmp), "%d%%", percent);
|
|
gtk_label_set_text(g_label_status, tmp);
|
|
}
|
|
}
|
|
}
|
|
|
|
void on_clear_ventoy(GtkMenuItem *menuItem, gpointer data)
|
|
{
|
|
int ret;
|
|
int active;
|
|
char buf[1024];
|
|
char out[256];
|
|
char disk_name[32];
|
|
ventoy_disk *cur = NULL;
|
|
|
|
if (g_thread_run || ventoy_code_is_busy())
|
|
{
|
|
msgbox(GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "STR_WAIT_PROCESS");
|
|
return;
|
|
}
|
|
|
|
active = gtk_combo_box_get_active((GtkComboBox *)g_dev_combobox);
|
|
if (active < 0 || active >= g_disk_num)
|
|
{
|
|
vlog("invalid active combox id %d\n", active);
|
|
return;
|
|
}
|
|
|
|
if (GTK_RESPONSE_OK != msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK_CANCEL, "STR_INSTALL_TIP"))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (GTK_RESPONSE_OK != msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK_CANCEL, "STR_INSTALL_TIP2"))
|
|
{
|
|
return;
|
|
}
|
|
|
|
gtk_widget_set_sensitive (GTK_WIDGET(g_refresh_button), FALSE);
|
|
gtk_widget_set_sensitive (GTK_WIDGET(g_install_button), FALSE);
|
|
gtk_widget_set_sensitive (GTK_WIDGET(g_update_button), FALSE);
|
|
g_thread_run = TRUE;
|
|
|
|
|
|
cur = g_disk_list + active;
|
|
g_snprintf(disk_name, sizeof(disk_name), "%s", cur->disk_name);
|
|
g_snprintf(buf, sizeof(buf), "{\"method\":\"clean\",\"disk\":\"%s\"}", disk_name);
|
|
|
|
out[0] = 0;
|
|
ventoy_func_handler(buf, out, sizeof(out));
|
|
vlog("func handler clean <%s>\n", out);
|
|
|
|
if (strstr(out, "success"))
|
|
{
|
|
ret = ventoy_code_get_result();
|
|
ventoy_code_refresh_device();
|
|
cur = NULL;
|
|
}
|
|
else
|
|
{
|
|
ret = 1;
|
|
}
|
|
|
|
if (ret == 0)
|
|
{
|
|
msgbox(GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "STR_CLEAR_SUCCESS");
|
|
}
|
|
else
|
|
{
|
|
msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "STR_CLEAR_FAILED");
|
|
}
|
|
|
|
set_progress_bar_percent(0);
|
|
gtk_widget_set_sensitive(GTK_WIDGET(g_refresh_button), TRUE);
|
|
gtk_widget_set_sensitive(GTK_WIDGET(g_install_button), TRUE);
|
|
gtk_widget_set_sensitive(GTK_WIDGET(g_update_button), TRUE);
|
|
|
|
fill_dev_list(disk_name);
|
|
g_thread_run = FALSE;
|
|
}
|
|
|
|
static int install_proc(ventoy_disk *cur)
|
|
{
|
|
int ret = 0;
|
|
int pos = 0;
|
|
int buflen = 0;
|
|
int percent = 0;
|
|
char buf[1024];
|
|
char dec[64];
|
|
char out[256];
|
|
char disk_name[32];
|
|
long long space;
|
|
|
|
vlog("install_thread ...\n");
|
|
|
|
g_snprintf(disk_name, sizeof(disk_name), "%s", cur->disk_name);
|
|
|
|
buflen = sizeof(buf);
|
|
VTOY_JSON_FMT_BEGIN(pos, buf, buflen);
|
|
VTOY_JSON_FMT_OBJ_BEGIN();
|
|
VTOY_JSON_FMT_STRN("method", "install");
|
|
VTOY_JSON_FMT_STRN("disk", disk_name);
|
|
|
|
if (g_preserve_space_check)
|
|
{
|
|
space = g_preserve_space_number;
|
|
if (g_preserve_space_unit == 1)
|
|
{
|
|
space = space * 1024 * 1024 * 1024LL;
|
|
}
|
|
else
|
|
{
|
|
space = space * 1024 * 1024LL;
|
|
}
|
|
|
|
snprintf(dec, sizeof(dec), "%lld", space);
|
|
VTOY_JSON_FMT_STRN("reserve_space", dec);
|
|
}
|
|
else
|
|
{
|
|
VTOY_JSON_FMT_STRN("reserve_space", "0");
|
|
}
|
|
|
|
VTOY_JSON_FMT_UINT("partstyle", ventoy_code_get_cur_part_style());
|
|
VTOY_JSON_FMT_UINT("secure_boot", g_secure_boot_support);
|
|
VTOY_JSON_FMT_UINT("align_4kb", g_align_part_with_4k);
|
|
VTOY_JSON_FMT_OBJ_END();
|
|
VTOY_JSON_FMT_END(pos);
|
|
|
|
out[0] = 0;
|
|
ventoy_func_handler(buf, out, sizeof(out));
|
|
vlog("func handler install <%s>\n", out);
|
|
|
|
if (strstr(out, "success"))
|
|
{
|
|
while (percent != 100)
|
|
{
|
|
percent = ventoy_code_get_percent();
|
|
set_progress_bar_percent(percent);
|
|
GTK_MSG_ITERATION();
|
|
usleep(50 * 1000);
|
|
}
|
|
|
|
ret = ventoy_code_get_result();
|
|
ventoy_code_refresh_device();
|
|
cur = NULL;
|
|
}
|
|
else
|
|
{
|
|
ret = 1;
|
|
}
|
|
|
|
if (ret)
|
|
{
|
|
msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "STR_INSTALL_FAILED");
|
|
}
|
|
else
|
|
{
|
|
msgbox(GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "STR_INSTALL_SUCCESS");
|
|
}
|
|
|
|
set_progress_bar_percent(0);
|
|
gtk_widget_set_sensitive(GTK_WIDGET(g_refresh_button), TRUE);
|
|
gtk_widget_set_sensitive(GTK_WIDGET(g_install_button), TRUE);
|
|
gtk_widget_set_sensitive(GTK_WIDGET(g_update_button), TRUE);
|
|
|
|
fill_dev_list(disk_name);
|
|
g_thread_run = FALSE;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void on_button_install_clicked(GtkWidget *widget, gpointer data)
|
|
{
|
|
int active;
|
|
long long size;
|
|
long long space;
|
|
ventoy_disk *cur = NULL;
|
|
|
|
if (g_thread_run || ventoy_code_is_busy())
|
|
{
|
|
msgbox(GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "STR_WAIT_PROCESS");
|
|
return;
|
|
}
|
|
|
|
active = gtk_combo_box_get_active((GtkComboBox *)g_dev_combobox);
|
|
if (active < 0 || active >= g_disk_num)
|
|
{
|
|
vlog("invalid active combox id %d\n", active);
|
|
return;
|
|
}
|
|
|
|
cur = g_disk_list + active;
|
|
|
|
if (cur->is4kn)
|
|
{
|
|
msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "STR_4KN_UNSUPPORTED");
|
|
return;
|
|
}
|
|
|
|
if (ventoy_code_get_cur_part_style() == 0 && cur->size_in_byte > 2199023255552ULL)
|
|
{
|
|
msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "STR_DISK_2TB_MBR_ERROR");
|
|
return;
|
|
}
|
|
|
|
if (g_preserve_space_check)
|
|
{
|
|
space = g_preserve_space_number;
|
|
if (g_preserve_space_unit == 1)
|
|
{
|
|
space = space * 1024;
|
|
}
|
|
else
|
|
{
|
|
space = space;
|
|
}
|
|
|
|
size = cur->size_in_byte / SIZE_1MB;
|
|
if (size <= space || (size - space) <= (VTOYEFI_PART_BYTES / SIZE_1MB))
|
|
{
|
|
msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "STR_SPACE_VAL_INVALID");
|
|
vlog("reserved space value too big ...\n");
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (GTK_RESPONSE_OK != msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK_CANCEL, "STR_INSTALL_TIP"))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (GTK_RESPONSE_OK != msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK_CANCEL, "STR_INSTALL_TIP2"))
|
|
{
|
|
return;
|
|
}
|
|
|
|
gtk_widget_set_sensitive (GTK_WIDGET(g_refresh_button), FALSE);
|
|
gtk_widget_set_sensitive (GTK_WIDGET(g_install_button), FALSE);
|
|
gtk_widget_set_sensitive (GTK_WIDGET(g_update_button), FALSE);
|
|
|
|
g_thread_run = TRUE;
|
|
|
|
install_proc(cur);
|
|
}
|
|
|
|
|
|
static int update_proc(ventoy_disk *cur)
|
|
{
|
|
int ret = 0;
|
|
int percent = 0;
|
|
char buf[1024];
|
|
char out[256];
|
|
char disk_name[32];
|
|
|
|
g_snprintf(disk_name, sizeof(disk_name), "%s", cur->disk_name);
|
|
g_snprintf(buf, sizeof(buf), "{\"method\":\"update\",\"disk\":\"%s\",\"secure_boot\":%d}",
|
|
disk_name, g_secure_boot_support);
|
|
|
|
out[0] = 0;
|
|
ventoy_func_handler(buf, out, sizeof(out));
|
|
vlog("func handler update <%s>\n", out);
|
|
|
|
if (strstr(out, "success"))
|
|
{
|
|
while (percent != 100)
|
|
{
|
|
percent = ventoy_code_get_percent();
|
|
set_progress_bar_percent(percent);
|
|
GTK_MSG_ITERATION();
|
|
usleep(50 * 1000);
|
|
}
|
|
|
|
ret = ventoy_code_get_result();
|
|
ventoy_code_refresh_device();
|
|
cur = NULL;
|
|
}
|
|
else
|
|
{
|
|
ret = 1;
|
|
}
|
|
|
|
if (ret)
|
|
{
|
|
msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "STR_UPDATE_FAILED");
|
|
}
|
|
else
|
|
{
|
|
msgbox(GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "STR_UPDATE_SUCCESS");
|
|
}
|
|
|
|
set_progress_bar_percent(0);
|
|
gtk_widget_set_sensitive(GTK_WIDGET(g_refresh_button), TRUE);
|
|
gtk_widget_set_sensitive(GTK_WIDGET(g_install_button), TRUE);
|
|
gtk_widget_set_sensitive(GTK_WIDGET(g_update_button), TRUE);
|
|
|
|
fill_dev_list(disk_name);
|
|
g_thread_run = FALSE;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
void on_button_update_clicked(GtkWidget *widget, gpointer data)
|
|
{
|
|
int active;
|
|
ventoy_disk *cur = NULL;
|
|
|
|
if (g_thread_run || ventoy_code_is_busy())
|
|
{
|
|
msgbox(GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "STR_WAIT_PROCESS");
|
|
return;
|
|
}
|
|
|
|
active = gtk_combo_box_get_active((GtkComboBox *)g_dev_combobox);
|
|
if (active < 0 || active >= g_disk_num)
|
|
{
|
|
vlog("invalid active combox id %d\n", active);
|
|
return;
|
|
}
|
|
cur = g_disk_list + active;
|
|
|
|
if (cur->vtoydata.ventoy_valid == 0)
|
|
{
|
|
vlog("invalid ventoy version.\n");
|
|
return;
|
|
}
|
|
|
|
if (GTK_RESPONSE_OK != msgbox(GTK_MESSAGE_INFO, GTK_BUTTONS_OK_CANCEL, "STR_UPDATE_TIP"))
|
|
{
|
|
return;
|
|
}
|
|
|
|
gtk_widget_set_sensitive (GTK_WIDGET(g_refresh_button), FALSE);
|
|
gtk_widget_set_sensitive (GTK_WIDGET(g_install_button), FALSE);
|
|
gtk_widget_set_sensitive (GTK_WIDGET(g_update_button), FALSE);
|
|
|
|
g_thread_run = TRUE;
|
|
|
|
update_proc(cur);
|
|
}
|
|
|
|
static gint lang_compare(gconstpointer a, gconstpointer b)
|
|
{
|
|
const char *name1 = (const char *)a;
|
|
const char *name2 = (const char *)b;
|
|
|
|
if (strncmp(name1, "Chinese Simplified", 18) == 0)
|
|
{
|
|
return -1;
|
|
}
|
|
else if (strncmp(name2, "Chinese Simplified", 18) == 0)
|
|
{
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
return g_strcmp0(name1, name2);
|
|
}
|
|
}
|
|
|
|
static int load_languages(void)
|
|
{
|
|
int size = 0;
|
|
char *pBuf = NULL;
|
|
char *pCur = NULL;
|
|
const char *pCurLang = NULL;
|
|
const char *pName = NULL;
|
|
VTOY_JSON *json = NULL;
|
|
VTOY_JSON *node = NULL;
|
|
VTOY_JSON *lang = NULL;
|
|
GSList *pGroup = NULL;
|
|
GList *pNameNode = NULL;
|
|
GList *pNameList = NULL;
|
|
GtkRadioMenuItem *pItem = NULL;
|
|
|
|
vlog("load_languages ...\n");
|
|
|
|
pCurLang = ventoy_code_get_cur_language();
|
|
if (pCurLang[0] == 0)
|
|
{
|
|
pName = getenv("LANG");
|
|
if (pName && strncmp(pName, "zh_CN", 5) == 0)
|
|
{
|
|
ventoy_code_set_cur_language("Chinese Simplified (简体中文)");
|
|
}
|
|
else
|
|
{
|
|
ventoy_code_set_cur_language("English (English)");
|
|
}
|
|
pCurLang = ventoy_code_get_cur_language();
|
|
}
|
|
|
|
vlog("current language <%s>\n", pCurLang);
|
|
|
|
ventoy_read_file_to_buf("./tool/languages.json", 1, (void **)&pBuf, &size);
|
|
|
|
json = vtoy_json_create();
|
|
vtoy_json_parse(json, pBuf);
|
|
g_languages_json = json;
|
|
|
|
for (node = json->pstChild; node; node = node->pstNext)
|
|
{
|
|
pName = vtoy_json_get_string_ex(node->pstChild, "name");
|
|
if (pName)
|
|
{
|
|
pNameList = g_list_append(pNameList, (gpointer)pName);
|
|
}
|
|
|
|
for (lang = node->pstChild; lang; lang = lang->pstNext)
|
|
{
|
|
if (lang->enDataType == JSON_TYPE_STRING)
|
|
{
|
|
pCur = lang->unData.pcStrVal;
|
|
while (*pCur)
|
|
{
|
|
if (*pCur == '#')
|
|
{
|
|
*pCur = '\r';
|
|
}
|
|
else if (*pCur == '@')
|
|
{
|
|
*pCur = '\n';
|
|
}
|
|
pCur++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pNameList = g_list_sort(pNameList, lang_compare);
|
|
|
|
for (pNameNode = g_list_first(pNameList); pNameNode; pNameNode = g_list_next(pNameNode))
|
|
{
|
|
pName = (char *)(pNameNode->data);
|
|
pItem = (GtkRadioMenuItem *)gtk_radio_menu_item_new_with_label(pGroup, pName);
|
|
pGroup = gtk_radio_menu_item_get_group(pItem);
|
|
|
|
if (strcmp(pCurLang, pName) == 0)
|
|
{
|
|
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(pItem), TRUE);
|
|
}
|
|
|
|
g_signal_connect(pItem, "toggled", G_CALLBACK(on_language_toggled), (gpointer)pName);
|
|
gtk_widget_show((GtkWidget *)pItem);
|
|
gtk_menu_shell_append(GTK_MENU_SHELL(g_lang_menu), (GtkWidget *)pItem);
|
|
}
|
|
|
|
g_list_free(pNameList);
|
|
free(pBuf);
|
|
|
|
select_language(pCurLang);
|
|
g_languages_toggled_proc = 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void on_part_cfg_ok(GtkWidget *widget, gpointer data)
|
|
{
|
|
const char *pos = NULL;
|
|
const char *input = NULL;
|
|
char device[256];
|
|
gboolean checked = gtk_toggle_button_get_active(g_part_preserve_checkbox);
|
|
|
|
if (checked)
|
|
{
|
|
input = gtk_entry_get_text(g_part_reserve_space_value);
|
|
if (input == NULL || input[0] == 0)
|
|
{
|
|
msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "STR_SPACE_VAL_INVALID");
|
|
return;
|
|
}
|
|
|
|
for (pos = input; *pos; pos++)
|
|
{
|
|
if (*pos < '0' || *pos > '9')
|
|
{
|
|
msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "STR_SPACE_VAL_INVALID");
|
|
return;
|
|
}
|
|
}
|
|
|
|
g_preserve_space_unit = gtk_combo_box_get_active((GtkComboBox *)g_part_space_unit_combox);
|
|
g_preserve_space_number = (int)strtol(input, NULL, 10);
|
|
|
|
g_snprintf(device, sizeof(device), "%s [ -%d%s ]",
|
|
language_string("STR_DEVICE"), g_preserve_space_number,
|
|
g_preserve_space_unit ? "GB" : "MB");
|
|
gtk_label_set_text(g_device_title, device);
|
|
}
|
|
else
|
|
{
|
|
gtk_label_set_text(g_device_title, language_string("STR_DEVICE"));
|
|
}
|
|
|
|
g_preserve_space_check = checked;
|
|
g_align_part_with_4k = gtk_toggle_button_get_active(g_part_align_checkbox);
|
|
gtk_widget_hide(g_partCfgWindow);
|
|
}
|
|
|
|
void on_part_cfg_cancel(GtkWidget *widget, gpointer data)
|
|
{
|
|
gtk_widget_hide(g_partCfgWindow);
|
|
}
|
|
|
|
int on_part_cfg_close(GtkWidget *widget, gpointer data)
|
|
{
|
|
gtk_widget_hide(g_partCfgWindow);
|
|
return TRUE;
|
|
}
|
|
|
|
void on_part_config(GtkMenuItem *menuItem, gpointer data)
|
|
{
|
|
char value[64];
|
|
|
|
gtk_toggle_button_set_active(g_part_align_checkbox, g_align_part_with_4k);
|
|
gtk_toggle_button_set_active(g_part_preserve_checkbox, g_preserve_space_check);
|
|
gtk_widget_set_sensitive(GTK_WIDGET(g_part_reserve_space_value), g_preserve_space_check);
|
|
gtk_widget_set_sensitive(GTK_WIDGET(g_part_space_unit_combox), g_preserve_space_check);
|
|
|
|
if (g_preserve_space_check)
|
|
{
|
|
g_snprintf(value, sizeof(value), "%d", g_preserve_space_number);
|
|
gtk_entry_set_text(g_part_reserve_space_value, value);
|
|
gtk_combo_box_set_active((GtkComboBox *)g_part_space_unit_combox, g_preserve_space_unit);
|
|
}
|
|
|
|
gtk_widget_show_all(g_partCfgWindow);
|
|
}
|
|
|
|
void on_reserve_space_toggled(GtkMenuItem *menuItem, gpointer data)
|
|
{
|
|
gboolean checked = gtk_toggle_button_get_active(g_part_preserve_checkbox);
|
|
|
|
gtk_widget_set_sensitive(GTK_WIDGET(g_part_reserve_space_value), checked);
|
|
gtk_widget_set_sensitive(GTK_WIDGET(g_part_space_unit_combox), checked);
|
|
}
|
|
|
|
static void init_part_cfg_window(GtkBuilder *pBuilder)
|
|
{
|
|
#if GTK_CHECK_VERSION(3, 0, 0)
|
|
GtkWidget *pHeader = NULL;
|
|
|
|
pHeader = gtk_header_bar_new();
|
|
gtk_header_bar_set_show_close_button(GTK_HEADER_BAR(pHeader), FALSE);
|
|
gtk_window_set_titlebar (GTK_WINDOW(g_partCfgWindow), pHeader);
|
|
gtk_window_set_title(GTK_WINDOW(g_partCfgWindow), "Partition Configuration");
|
|
#endif
|
|
|
|
gtk_combo_box_set_active((GtkComboBox *)g_part_space_unit_combox, g_preserve_space_unit);
|
|
gtk_widget_set_sensitive (GTK_WIDGET(g_part_reserve_space_value), FALSE);
|
|
gtk_widget_set_sensitive (GTK_WIDGET(g_part_space_unit_combox), FALSE);
|
|
|
|
SIGNAL("space_check_btn", "toggled", on_reserve_space_toggled);
|
|
|
|
SIGNAL("button_partcfg_ok", "clicked", on_part_cfg_ok);
|
|
SIGNAL("button_partcfg_cancel", "clicked", on_part_cfg_cancel);
|
|
SIGNAL("part_cfg_dlg", "delete_event", on_part_cfg_close);
|
|
}
|
|
|
|
static void add_accelerator(GtkAccelGroup *agMain, void *widget, const char *signal, guint accel_key)
|
|
{
|
|
gtk_widget_add_accelerator(GTK_WIDGET(widget), signal, agMain, accel_key, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
|
|
gtk_widget_add_accelerator(GTK_WIDGET(widget), signal, agMain, accel_key, GDK_SHIFT_MASK | GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
|
|
}
|
|
|
|
void on_init_window(GtkBuilder *pBuilder)
|
|
{
|
|
GSList *pGroup = NULL;
|
|
GtkAccelGroup *agMain = NULL;
|
|
char version[512];
|
|
|
|
vlog("on_init_window ...\n");
|
|
|
|
g_pXmlBuilder = pBuilder;
|
|
g_topWindow = BUILDER_ITEM(GtkWidget, "window");
|
|
g_partCfgWindow = BUILDER_ITEM(GtkWidget, "part_cfg_dlg");
|
|
|
|
g_dev_combobox = BUILDER_ITEM(GtkComboBoxText, "combobox_devlist");
|
|
g_refresh_button = BUILDER_ITEM(GtkButton, "button_refresh");
|
|
g_install_button = BUILDER_ITEM(GtkButton, "button_install");
|
|
g_update_button = BUILDER_ITEM(GtkButton, "button_update");
|
|
|
|
g_lang_menu = BUILDER_ITEM(GtkMenu, "submenu_language");
|
|
g_menu_item_secure_boot = BUILDER_ITEM(GtkCheckMenuItem, "menu_item_secure");
|
|
g_menu_item_mbr = BUILDER_ITEM(GtkCheckMenuItem, "menu_item_mbr");
|
|
g_menu_item_gpt = BUILDER_ITEM(GtkCheckMenuItem, "menu_item_gpt");
|
|
g_menu_item_show_all = BUILDER_ITEM(GtkCheckMenuItem, "menu_item_show_all");
|
|
|
|
g_device_title = BUILDER_ITEM(GtkLabel, "label_device");
|
|
g_label_local_part_style = BUILDER_ITEM(GtkLabel, "label_local_part_style");
|
|
g_label_dev_part_style = BUILDER_ITEM(GtkLabel, "label_dev_part_style");
|
|
|
|
g_label_local_ver = BUILDER_ITEM(GtkLabel, "label_local_ver_value");
|
|
g_label_disk_ver = BUILDER_ITEM(GtkLabel, "label_dev_ver_value");
|
|
|
|
g_label_status = BUILDER_ITEM(GtkLabel, "label_status");
|
|
|
|
g_image_secure_local = BUILDER_ITEM(GtkImage, "image_secure_local");
|
|
g_image_secure_device = BUILDER_ITEM(GtkImage, "image_secure_dev");
|
|
|
|
g_part_preserve_checkbox = BUILDER_ITEM(GtkToggleButton, "space_check_btn");
|
|
g_part_align_checkbox = BUILDER_ITEM(GtkToggleButton, "space_align_btn");
|
|
|
|
g_part_reserve_space_value = BUILDER_ITEM(GtkEntry, "entry_reserve_space");
|
|
g_part_space_unit_combox = BUILDER_ITEM(GtkComboBoxText, "comboboxtext_unit");
|
|
|
|
g_progress_bar = BUILDER_ITEM(GtkProgressBar, "progressbar1");
|
|
|
|
init_part_cfg_window(pBuilder);
|
|
|
|
/* for gtk2 */
|
|
gtk_frame_set_shadow_type(BUILDER_ITEM(GtkFrame, "frame_dummy1"), GTK_SHADOW_NONE);
|
|
gtk_frame_set_shadow_type(BUILDER_ITEM(GtkFrame, "frame_dummy2"), GTK_SHADOW_NONE);
|
|
|
|
/* join group */
|
|
pGroup = gtk_radio_menu_item_get_group((GtkRadioMenuItem *)g_menu_item_mbr);
|
|
gtk_radio_menu_item_set_group((GtkRadioMenuItem *)g_menu_item_gpt, pGroup);
|
|
|
|
gtk_widget_hide((GtkWidget *)g_image_secure_local);
|
|
gtk_widget_hide((GtkWidget *)g_image_secure_device);
|
|
|
|
g_snprintf(version, sizeof(version), VTOY_VER_FMT, ventoy_get_local_version());
|
|
gtk_label_set_markup(g_label_local_ver, version);
|
|
|
|
init_part_style_menu();
|
|
gtk_check_menu_item_set_active(g_menu_item_show_all, ventoy_code_get_cur_show_all());
|
|
|
|
load_languages();
|
|
|
|
SIGNAL("combobox_devlist", "changed", on_devlist_changed);
|
|
|
|
SIGNAL("button_refresh", "clicked", on_button_refresh_clicked);
|
|
SIGNAL("button_install", "clicked", on_button_install_clicked);
|
|
SIGNAL("button_update", "clicked", on_button_update_clicked);
|
|
|
|
SIGNAL("menu_item_secure", "toggled", on_secure_boot_toggled);
|
|
SIGNAL("menu_item_mbr", "toggled", on_part_style_toggled);
|
|
SIGNAL("menu_item_show_all", "toggled", on_show_all_toggled);
|
|
|
|
SIGNAL("menu_item_part_cfg", "activate", on_part_config);
|
|
SIGNAL("menu_item_clear", "activate", on_clear_ventoy);
|
|
|
|
agMain = gtk_accel_group_new();
|
|
gtk_window_add_accel_group(GTK_WINDOW(g_topWindow), agMain);
|
|
add_accelerator(agMain, g_dev_combobox, "popup", GDK_KEY_d);
|
|
add_accelerator(agMain, g_install_button, "clicked", GDK_KEY_i);
|
|
add_accelerator(agMain, g_update_button, "clicked", GDK_KEY_u);
|
|
add_accelerator(agMain, g_refresh_button, "clicked", GDK_KEY_r);
|
|
|
|
gtk_check_menu_item_set_active(g_menu_item_secure_boot, 1 - g_secure_boot_support);
|
|
|
|
fill_dev_list(NULL);
|
|
|
|
return;
|
|
}
|
|
|
|
int on_exit_window(GtkWidget *widget, gpointer data)
|
|
{
|
|
vlog("on_exit_window ...\n");
|
|
|
|
if (g_thread_run || ventoy_code_is_busy())
|
|
{
|
|
msgbox(GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "STR_WAIT_PROCESS");
|
|
return TRUE;
|
|
}
|
|
|
|
ventoy_code_save_cfg();
|
|
return FALSE;
|
|
}
|
|
|