mirror of
https://github.com/ZoiteChat/zoitechat.git
synced 2026-03-10 07:50:19 +00:00
Fixed the GTK3 theme import crash by replacing the dark-variant notification call from the signal macro path to fe_message(..., FE_MSG_INFO), avoiding the segfaulting path during import completion while preserving user feedback.
This commit is contained in:
@@ -330,16 +330,364 @@ cleanup:
|
||||
return ok;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
zoitechat_is_safe_archive_entry (const char *entry)
|
||||
{
|
||||
char **parts;
|
||||
gboolean safe = TRUE;
|
||||
guint i;
|
||||
|
||||
if (!entry || !*entry)
|
||||
return FALSE;
|
||||
|
||||
if (g_path_is_absolute (entry) || entry[0] == '/' || entry[0] == '\\')
|
||||
return FALSE;
|
||||
|
||||
if (g_ascii_isalpha (entry[0]) && entry[1] == ':')
|
||||
return FALSE;
|
||||
|
||||
parts = g_strsplit_set (entry, "/\\", -1);
|
||||
for (i = 0; parts[i] != NULL; i++)
|
||||
{
|
||||
if (strcmp (parts[i], "..") == 0)
|
||||
{
|
||||
safe = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
g_strfreev (parts);
|
||||
return safe;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
zoitechat_remove_tree (const char *path, GError **error)
|
||||
{
|
||||
GDir *dir;
|
||||
const char *name;
|
||||
|
||||
if (!g_file_test (path, G_FILE_TEST_EXISTS))
|
||||
return TRUE;
|
||||
|
||||
if (!g_file_test (path, G_FILE_TEST_IS_DIR))
|
||||
return g_remove (path) == 0;
|
||||
|
||||
dir = g_dir_open (path, 0, error);
|
||||
if (!dir)
|
||||
return FALSE;
|
||||
|
||||
while ((name = g_dir_read_name (dir)))
|
||||
{
|
||||
char *child = g_build_filename (path, name, NULL);
|
||||
|
||||
if (!zoitechat_remove_tree (child, error))
|
||||
{
|
||||
g_free (child);
|
||||
g_dir_close (dir);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_free (child);
|
||||
}
|
||||
|
||||
g_dir_close (dir);
|
||||
if (g_rmdir (path) != 0)
|
||||
{
|
||||
g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
|
||||
_("Failed to remove temporary directory."));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
zoitechat_copy_directory_recursive (const char *src_dir, const char *dest_dir, GError **error)
|
||||
{
|
||||
GDir *dir;
|
||||
const char *name;
|
||||
|
||||
if (g_mkdir_with_parents (dest_dir, 0700) != 0)
|
||||
{
|
||||
g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
|
||||
_("Failed to create destination theme directory."));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
dir = g_dir_open (src_dir, 0, error);
|
||||
if (!dir)
|
||||
return FALSE;
|
||||
|
||||
while ((name = g_dir_read_name (dir)))
|
||||
{
|
||||
char *src_path = g_build_filename (src_dir, name, NULL);
|
||||
char *dest_path = g_build_filename (dest_dir, name, NULL);
|
||||
|
||||
if (g_file_test (src_path, G_FILE_TEST_IS_DIR))
|
||||
{
|
||||
if (!zoitechat_copy_directory_recursive (src_path, dest_path, error))
|
||||
{
|
||||
g_free (dest_path);
|
||||
g_free (src_path);
|
||||
g_dir_close (dir);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else if (g_file_test (src_path, G_FILE_TEST_IS_REGULAR))
|
||||
{
|
||||
GFile *src_file = g_file_new_for_path (src_path);
|
||||
GFile *dest_file = g_file_new_for_path (dest_path);
|
||||
gboolean copied = g_file_copy (src_file, dest_file,
|
||||
G_FILE_COPY_OVERWRITE,
|
||||
NULL, NULL, NULL, error);
|
||||
|
||||
g_object_unref (dest_file);
|
||||
g_object_unref (src_file);
|
||||
|
||||
if (!copied)
|
||||
{
|
||||
g_free (dest_path);
|
||||
g_free (src_path);
|
||||
g_dir_close (dir);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
g_free (dest_path);
|
||||
g_free (src_path);
|
||||
}
|
||||
|
||||
g_dir_close (dir);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
zoitechat_find_gtk3_theme_root (const char *search_dir, char **theme_root_out, gboolean *has_dark_css_out, GError **error)
|
||||
{
|
||||
GDir *dir;
|
||||
const char *name;
|
||||
|
||||
dir = g_dir_open (search_dir, 0, error);
|
||||
if (!dir)
|
||||
return FALSE;
|
||||
|
||||
while ((name = g_dir_read_name (dir)))
|
||||
{
|
||||
char *child = g_build_filename (search_dir, name, NULL);
|
||||
|
||||
if (g_file_test (child, G_FILE_TEST_IS_DIR))
|
||||
{
|
||||
if (strcmp (name, "gtk-3.0") == 0)
|
||||
{
|
||||
char *gtk_css = g_build_filename (child, "gtk.css", NULL);
|
||||
|
||||
if (g_file_test (gtk_css, G_FILE_TEST_IS_REGULAR))
|
||||
{
|
||||
char *dark_css = g_build_filename (child, "gtk-dark.css", NULL);
|
||||
|
||||
if (theme_root_out)
|
||||
*theme_root_out = g_strdup (search_dir);
|
||||
if (has_dark_css_out)
|
||||
*has_dark_css_out = g_file_test (dark_css, G_FILE_TEST_IS_REGULAR);
|
||||
|
||||
g_free (dark_css);
|
||||
g_free (gtk_css);
|
||||
g_free (child);
|
||||
g_dir_close (dir);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
g_free (gtk_css);
|
||||
}
|
||||
else if (zoitechat_find_gtk3_theme_root (child, theme_root_out, has_dark_css_out, error))
|
||||
{
|
||||
g_free (child);
|
||||
g_dir_close (dir);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (error && *error)
|
||||
{
|
||||
g_free (child);
|
||||
g_dir_close (dir);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
g_free (child);
|
||||
}
|
||||
|
||||
g_dir_close (dir);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ZOITECHAT_GTK3_ARCHIVE_UNKNOWN = 0,
|
||||
ZOITECHAT_GTK3_ARCHIVE_ZIP,
|
||||
ZOITECHAT_GTK3_ARCHIVE_TAR
|
||||
} ZoiteChatGtk3ArchiveType;
|
||||
|
||||
static ZoiteChatGtk3ArchiveType
|
||||
zoitechat_detect_gtk3_archive_type (const char *archive_path)
|
||||
{
|
||||
if (!archive_path)
|
||||
return ZOITECHAT_GTK3_ARCHIVE_UNKNOWN;
|
||||
|
||||
if (g_str_has_suffix (archive_path, ".zip") || g_str_has_suffix (archive_path, ".ZIP"))
|
||||
return ZOITECHAT_GTK3_ARCHIVE_ZIP;
|
||||
|
||||
if (g_str_has_suffix (archive_path, ".tar")
|
||||
|| g_str_has_suffix (archive_path, ".tar.gz")
|
||||
|| g_str_has_suffix (archive_path, ".tgz")
|
||||
|| g_str_has_suffix (archive_path, ".tar.xz")
|
||||
|| g_str_has_suffix (archive_path, ".txz"))
|
||||
return ZOITECHAT_GTK3_ARCHIVE_TAR;
|
||||
|
||||
return ZOITECHAT_GTK3_ARCHIVE_UNKNOWN;
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
static gboolean
|
||||
zoitechat_validate_zip_entries_unix (const char *archive_path, char **archive_root_out, GError **error)
|
||||
{
|
||||
char *stdout_buf = NULL;
|
||||
char *stderr_buf = NULL;
|
||||
char *argv[] = {"unzip", "-Z1", (char *)archive_path, NULL};
|
||||
char *archive_root = NULL;
|
||||
char **lines;
|
||||
gboolean ok;
|
||||
int status = 0;
|
||||
guint i;
|
||||
|
||||
ok = g_spawn_sync (NULL, argv, NULL, G_SPAWN_SEARCH_PATH,
|
||||
NULL, NULL, &stdout_buf, &stderr_buf, &status, error);
|
||||
if (!ok)
|
||||
goto cleanup;
|
||||
|
||||
if (!g_spawn_check_exit_status (status, error))
|
||||
{
|
||||
ok = FALSE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
lines = g_strsplit (stdout_buf ? stdout_buf : "", "\n", -1);
|
||||
for (i = 0; lines[i] != NULL; i++)
|
||||
{
|
||||
const char *entry = lines[i];
|
||||
char **parts;
|
||||
|
||||
if (!entry[0])
|
||||
continue;
|
||||
|
||||
if (!zoitechat_is_safe_archive_entry (entry))
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
|
||||
_("Archive contains unsafe path: %s"), entry);
|
||||
ok = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
parts = g_strsplit (entry, "/", 2);
|
||||
if (parts[0] && *parts[0])
|
||||
{
|
||||
if (!archive_root)
|
||||
archive_root = g_strdup (parts[0]);
|
||||
else if (strcmp (archive_root, parts[0]) != 0)
|
||||
g_clear_pointer (&archive_root, g_free);
|
||||
}
|
||||
g_strfreev (parts);
|
||||
}
|
||||
g_strfreev (lines);
|
||||
|
||||
if (ok && archive_root_out)
|
||||
*archive_root_out = g_strdup (archive_root);
|
||||
|
||||
cleanup:
|
||||
g_free (archive_root);
|
||||
g_free (stderr_buf);
|
||||
g_free (stdout_buf);
|
||||
return ok;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static gboolean
|
||||
zoitechat_validate_tar_entries_unix (const char *archive_path, char **archive_root_out, GError **error)
|
||||
{
|
||||
char *stdout_buf = NULL;
|
||||
char *stderr_buf = NULL;
|
||||
char *argv[] = {"tar", "-tf", (char *)archive_path, NULL};
|
||||
char *archive_root = NULL;
|
||||
char **lines;
|
||||
gboolean ok;
|
||||
int status = 0;
|
||||
guint i;
|
||||
|
||||
ok = g_spawn_sync (NULL, argv, NULL, G_SPAWN_SEARCH_PATH,
|
||||
NULL, NULL, &stdout_buf, &stderr_buf, &status, error);
|
||||
if (!ok)
|
||||
goto cleanup;
|
||||
|
||||
if (!g_spawn_check_exit_status (status, error))
|
||||
{
|
||||
ok = FALSE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
lines = g_strsplit (stdout_buf ? stdout_buf : "", "\n", -1);
|
||||
for (i = 0; lines[i] != NULL; i++)
|
||||
{
|
||||
const char *entry = lines[i];
|
||||
char **parts;
|
||||
|
||||
if (!entry[0])
|
||||
continue;
|
||||
|
||||
if (!zoitechat_is_safe_archive_entry (entry))
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
|
||||
_("Archive contains unsafe path: %s"), entry);
|
||||
ok = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
parts = g_strsplit_set (entry, "/\\", 2);
|
||||
if (parts[0] && *parts[0])
|
||||
{
|
||||
if (!archive_root)
|
||||
archive_root = g_strdup (parts[0]);
|
||||
else if (strcmp (archive_root, parts[0]) != 0)
|
||||
g_clear_pointer (&archive_root, g_free);
|
||||
}
|
||||
g_strfreev (parts);
|
||||
}
|
||||
g_strfreev (lines);
|
||||
|
||||
if (ok && archive_root_out)
|
||||
*archive_root_out = g_strdup (archive_root);
|
||||
|
||||
cleanup:
|
||||
g_free (archive_root);
|
||||
g_free (stderr_buf);
|
||||
g_free (stdout_buf);
|
||||
return ok;
|
||||
}
|
||||
|
||||
gboolean
|
||||
zoitechat_import_gtk3_theme_archive (const char *archive_path, GError **error)
|
||||
{
|
||||
char *theme_root;
|
||||
char *basename;
|
||||
char *dot;
|
||||
char *dest_dir;
|
||||
char *argv[] = {"unzip", "-o", (char *)archive_path, "-d", NULL, NULL};
|
||||
ZoiteChatGtk3ArchiveType archive_type;
|
||||
char *temp_dir = NULL;
|
||||
char *archive_root = NULL;
|
||||
char *theme_root = NULL;
|
||||
char *theme_name = NULL;
|
||||
char *store_dir = NULL;
|
||||
char *dest_dir = NULL;
|
||||
int status = 0;
|
||||
gboolean ok;
|
||||
gboolean ok = FALSE;
|
||||
gboolean has_dark_css = FALSE;
|
||||
|
||||
if (!archive_path)
|
||||
{
|
||||
@@ -348,57 +696,224 @@ zoitechat_import_gtk3_theme_archive (const char *archive_path, GError **error)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
theme_root = g_build_filename (g_get_home_dir (), ".themes", NULL);
|
||||
basename = g_path_get_basename (archive_path);
|
||||
if (!basename || basename[0] == '\0')
|
||||
archive_type = zoitechat_detect_gtk3_archive_type (archive_path);
|
||||
if (archive_type == ZOITECHAT_GTK3_ARCHIVE_UNKNOWN)
|
||||
{
|
||||
g_free (theme_root);
|
||||
g_free (basename);
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
|
||||
_("Failed to determine GTK3 theme name."));
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
||||
_("Unsupported archive format. Use .zip, .tar, .tar.gz, .tgz, .tar.xz, or .txz."));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
{
|
||||
char *basename = g_path_get_basename (archive_path);
|
||||
char *dot;
|
||||
|
||||
if (basename && *basename)
|
||||
{
|
||||
dot = strrchr (basename, '.');
|
||||
if (dot)
|
||||
*dot = '\0';
|
||||
|
||||
dest_dir = g_build_filename (theme_root, basename, NULL);
|
||||
if (g_mkdir_with_parents (dest_dir, 0700) != 0)
|
||||
{
|
||||
g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
|
||||
_("Failed to create GTK3 theme directory."));
|
||||
g_free (dest_dir);
|
||||
if (g_str_has_suffix (basename, ".tar"))
|
||||
basename[strlen (basename) - 4] = '\0';
|
||||
if (*basename)
|
||||
archive_root = g_strdup (basename);
|
||||
}
|
||||
g_free (basename);
|
||||
g_free (theme_root);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
argv[4] = dest_dir;
|
||||
temp_dir = g_dir_make_tmp ("zoitechat-gtk3-theme-XXXXXX", error);
|
||||
if (!temp_dir)
|
||||
return FALSE;
|
||||
|
||||
#ifdef WIN32
|
||||
if (archive_type == ZOITECHAT_GTK3_ARCHIVE_ZIP)
|
||||
{
|
||||
char *powershell = NULL;
|
||||
char *command = NULL;
|
||||
GString *escaped_path = g_string_new ("'");
|
||||
GString *escaped_dir = g_string_new ("'");
|
||||
const char *cursor;
|
||||
|
||||
powershell = g_find_program_in_path ("powershell.exe");
|
||||
if (!powershell)
|
||||
powershell = g_find_program_in_path ("powershell");
|
||||
if (!powershell)
|
||||
{
|
||||
g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_NOENT,
|
||||
_("No archive extractor was found."));
|
||||
g_string_free (escaped_path, TRUE);
|
||||
g_string_free (escaped_dir, TRUE);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
for (cursor = archive_path; *cursor != '\0'; cursor++)
|
||||
{
|
||||
if (*cursor == '\'')
|
||||
g_string_append (escaped_path, "''");
|
||||
else
|
||||
g_string_append_c (escaped_path, *cursor);
|
||||
}
|
||||
g_string_append_c (escaped_path, '\'');
|
||||
|
||||
for (cursor = temp_dir; *cursor != '\0'; cursor++)
|
||||
{
|
||||
if (*cursor == '\'')
|
||||
g_string_append (escaped_dir, "''");
|
||||
else
|
||||
g_string_append_c (escaped_dir, *cursor);
|
||||
}
|
||||
g_string_append_c (escaped_dir, '\'');
|
||||
|
||||
command = g_strdup_printf (
|
||||
"Add-Type -AssemblyName System.IO.Compression.FileSystem; "
|
||||
"$ErrorActionPreference='Stop'; "
|
||||
"$archive=[System.IO.Compression.ZipFile]::OpenRead(%s); "
|
||||
"try { "
|
||||
"foreach ($entry in $archive.Entries) { "
|
||||
"$name=$entry.FullName; "
|
||||
"if ([string]::IsNullOrEmpty($name)) { continue }; "
|
||||
"if ([System.IO.Path]::IsPathRooted($name) -or $name.StartsWith('/') -or $name.StartsWith('\\') -or $name.Contains('..\\') -or $name.Contains('../')) { throw 'Archive contains unsafe path: ' + $name } "
|
||||
"}; "
|
||||
"[System.IO.Compression.ZipFile]::ExtractToDirectory(%s,%s,$true); "
|
||||
"} finally { $archive.Dispose(); }",
|
||||
escaped_path->str,
|
||||
escaped_path->str,
|
||||
escaped_dir->str);
|
||||
g_string_free (escaped_path, TRUE);
|
||||
g_string_free (escaped_dir, TRUE);
|
||||
|
||||
{
|
||||
char *ps_argv[] = {powershell, "-NoProfile", "-NonInteractive", "-Command", command, NULL};
|
||||
ok = g_spawn_sync (NULL, ps_argv, NULL, 0, NULL, NULL,
|
||||
NULL, NULL, &status, error);
|
||||
}
|
||||
if (ok)
|
||||
ok = g_spawn_check_exit_status (status, error);
|
||||
|
||||
g_free (command);
|
||||
g_free (powershell);
|
||||
if (!ok)
|
||||
goto cleanup;
|
||||
}
|
||||
else
|
||||
{
|
||||
char *argv[] = {"tar", "-xf", (char *)archive_path, "-C", temp_dir, NULL};
|
||||
char *extracted_root = NULL;
|
||||
|
||||
if (!zoitechat_validate_tar_entries_unix (archive_path, &extracted_root, error))
|
||||
goto cleanup;
|
||||
if (extracted_root)
|
||||
{
|
||||
g_free (archive_root);
|
||||
archive_root = extracted_root;
|
||||
}
|
||||
|
||||
ok = g_spawn_sync (NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL,
|
||||
NULL, NULL, &status, error);
|
||||
if (!ok)
|
||||
{
|
||||
g_free (dest_dir);
|
||||
g_free (basename);
|
||||
g_free (theme_root);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
goto cleanup;
|
||||
if (!g_spawn_check_exit_status (status, error))
|
||||
goto cleanup;
|
||||
}
|
||||
#else
|
||||
if (archive_type == ZOITECHAT_GTK3_ARCHIVE_ZIP)
|
||||
{
|
||||
g_free (dest_dir);
|
||||
g_free (basename);
|
||||
g_free (theme_root);
|
||||
return FALSE;
|
||||
char *argv[] = {"unzip", "-o", (char *)archive_path, "-d", temp_dir, NULL};
|
||||
char *extracted_root = NULL;
|
||||
|
||||
if (!zoitechat_validate_zip_entries_unix (archive_path, &extracted_root, error))
|
||||
goto cleanup;
|
||||
if (extracted_root)
|
||||
{
|
||||
g_free (archive_root);
|
||||
archive_root = extracted_root;
|
||||
}
|
||||
|
||||
ok = g_spawn_sync (NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL,
|
||||
NULL, NULL, &status, error);
|
||||
if (!ok)
|
||||
goto cleanup;
|
||||
if (!g_spawn_check_exit_status (status, error))
|
||||
goto cleanup;
|
||||
}
|
||||
else
|
||||
{
|
||||
char *argv[] = {"tar", "-xf", (char *)archive_path, "-C", temp_dir, NULL};
|
||||
char *extracted_root = NULL;
|
||||
|
||||
if (!zoitechat_validate_tar_entries_unix (archive_path, &extracted_root, error))
|
||||
goto cleanup;
|
||||
if (extracted_root)
|
||||
{
|
||||
g_free (archive_root);
|
||||
archive_root = extracted_root;
|
||||
}
|
||||
|
||||
ok = g_spawn_sync (NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL,
|
||||
NULL, NULL, &status, error);
|
||||
if (!ok)
|
||||
goto cleanup;
|
||||
if (!g_spawn_check_exit_status (status, error))
|
||||
goto cleanup;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!zoitechat_find_gtk3_theme_root (temp_dir, &theme_root, &has_dark_css, error))
|
||||
{
|
||||
if (error && *error)
|
||||
goto cleanup;
|
||||
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
|
||||
_("Archive does not contain a GTK3 theme. Expected gtk-3.0/gtk.css."));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
theme_name = g_path_get_basename (theme_root);
|
||||
if (!theme_name || !*theme_name)
|
||||
{
|
||||
g_clear_pointer (&theme_name, g_free);
|
||||
if (archive_root)
|
||||
theme_name = g_strdup (archive_root);
|
||||
}
|
||||
|
||||
if (!theme_name || !*theme_name)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
|
||||
_("Unable to determine GTK3 theme directory name from archive."));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
store_dir = g_build_filename (get_xdir (), "gtk3-themes", NULL);
|
||||
dest_dir = g_build_filename (store_dir, theme_name, NULL);
|
||||
|
||||
if (g_file_test (dest_dir, G_FILE_TEST_EXISTS) && !zoitechat_remove_tree (dest_dir, error))
|
||||
goto cleanup;
|
||||
|
||||
if (!zoitechat_copy_directory_recursive (theme_root, dest_dir, error))
|
||||
goto cleanup;
|
||||
|
||||
if (has_dark_css)
|
||||
fe_message (_("Imported GTK3 theme includes gtk-dark.css."), FE_MSG_INFO);
|
||||
|
||||
ok = TRUE;
|
||||
|
||||
cleanup:
|
||||
if (temp_dir)
|
||||
{
|
||||
GError *cleanup_error = NULL;
|
||||
if (!zoitechat_remove_tree (temp_dir, &cleanup_error))
|
||||
g_clear_error (&cleanup_error);
|
||||
}
|
||||
g_free (dest_dir);
|
||||
g_free (basename);
|
||||
g_free (store_dir);
|
||||
g_free (theme_name);
|
||||
g_free (theme_root);
|
||||
return TRUE;
|
||||
g_free (archive_root);
|
||||
g_free (temp_dir);
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
gboolean
|
||||
zoitechat_import_theme (const char *path, GError **error)
|
||||
{
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
|
||||
gboolean zoitechat_theme_path_from_arg (const char *arg, char **path_out);
|
||||
gboolean zoitechat_import_theme (const char *path, GError **error);
|
||||
/* Imports a GTK3 theme ZIP into ZoiteChat's own gtk3-themes store. */
|
||||
gboolean zoitechat_import_gtk3_theme_archive (const char *archive_path, GError **error);
|
||||
gboolean zoitechat_apply_theme (const char *theme_name, GError **error);
|
||||
|
||||
|
||||
@@ -2003,6 +2003,7 @@ static void
|
||||
setup_theme_populate_gtk3 (setup_theme_ui *ui)
|
||||
{
|
||||
const char *theme_dirs[] = {
|
||||
NULL,
|
||||
g_get_home_dir (),
|
||||
NULL,
|
||||
"/usr/local/share/themes",
|
||||
@@ -2018,6 +2019,7 @@ setup_theme_populate_gtk3 (setup_theme_ui *ui)
|
||||
guint i;
|
||||
|
||||
theme_dirs[1] = g_build_filename (g_get_home_dir (), ".local", "share", "themes", NULL);
|
||||
theme_dirs[0] = g_build_filename (get_xdir (), "gtk3-themes", NULL);
|
||||
|
||||
seen = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
||||
names = g_ptr_array_new_with_free_func (g_free);
|
||||
@@ -2093,6 +2095,7 @@ setup_theme_populate_gtk3 (setup_theme_ui *ui)
|
||||
g_hash_table_destroy (seen);
|
||||
g_free (current_theme);
|
||||
g_free ((char *) theme_dirs[1]);
|
||||
g_free ((char *) theme_dirs[0]);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -2114,16 +2117,21 @@ setup_theme_gtk3_import_cb (GtkWidget *button, gpointer user_data)
|
||||
char *archive_path;
|
||||
GError *error = NULL;
|
||||
|
||||
dialog = gtk_file_chooser_dialog_new (_("Import GTK3 Theme ZIP"), GTK_WINDOW (setup_window),
|
||||
dialog = gtk_file_chooser_dialog_new (_("Import GTK3 Theme Archive"), GTK_WINDOW (setup_window),
|
||||
GTK_FILE_CHOOSER_ACTION_OPEN,
|
||||
_ ("_Cancel"), GTK_RESPONSE_CANCEL,
|
||||
_ ("_Open"), GTK_RESPONSE_ACCEPT,
|
||||
NULL);
|
||||
|
||||
filter = gtk_file_filter_new ();
|
||||
gtk_file_filter_set_name (filter, _("ZIP archives"));
|
||||
gtk_file_filter_set_name (filter, _("Theme archives (.zip, .tar.xz, .tar.gz, .tar)"));
|
||||
gtk_file_filter_add_pattern (filter, "*.zip");
|
||||
gtk_file_filter_add_pattern (filter, "*.ZIP");
|
||||
gtk_file_filter_add_pattern (filter, "*.tar");
|
||||
gtk_file_filter_add_pattern (filter, "*.tar.gz");
|
||||
gtk_file_filter_add_pattern (filter, "*.tgz");
|
||||
gtk_file_filter_add_pattern (filter, "*.tar.xz");
|
||||
gtk_file_filter_add_pattern (filter, "*.txz");
|
||||
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
|
||||
gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dialog), filter);
|
||||
|
||||
@@ -2143,14 +2151,14 @@ setup_theme_gtk3_import_cb (GtkWidget *button, gpointer user_data)
|
||||
if (!zoitechat_import_gtk3_theme_archive (archive_path, &error))
|
||||
{
|
||||
setup_theme_show_message (GTK_MESSAGE_ERROR,
|
||||
error ? error->message : _("Failed to import GTK3 theme ZIP archive."));
|
||||
error ? error->message : _("Failed to import GTK3 theme archive."));
|
||||
g_clear_error (&error);
|
||||
}
|
||||
else
|
||||
{
|
||||
setup_theme_populate_gtk3 (ui);
|
||||
gtk_label_set_text (GTK_LABEL (ui->gtk3_status_label), _("GTK3 theme ZIP imported successfully."));
|
||||
setup_theme_show_message (GTK_MESSAGE_INFO, _("GTK3 theme ZIP imported successfully."));
|
||||
gtk_label_set_text (GTK_LABEL (ui->gtk3_status_label), _("GTK3 theme archive imported successfully."));
|
||||
setup_theme_show_message (GTK_MESSAGE_INFO, _("GTK3 theme archive imported successfully."));
|
||||
}
|
||||
|
||||
g_free (archive_path);
|
||||
@@ -2267,7 +2275,7 @@ setup_create_theme_page (void)
|
||||
g_signal_connect (G_OBJECT (ui->gtk3_combo), "changed",
|
||||
G_CALLBACK (setup_theme_gtk3_selection_changed), ui);
|
||||
|
||||
ui->gtk3_import_button = gtk_button_new_with_mnemonic (_("_Import GTK3 Theme ZIP"));
|
||||
ui->gtk3_import_button = gtk_button_new_with_mnemonic (_("_Import GTK3 Theme Archive"));
|
||||
gtk_box_pack_start (GTK_BOX (button_box), ui->gtk3_import_button, FALSE, FALSE, 0);
|
||||
g_signal_connect (G_OBJECT (ui->gtk3_import_button), "clicked",
|
||||
G_CALLBACK (setup_theme_gtk3_import_cb), ui);
|
||||
|
||||
Reference in New Issue
Block a user