diff --git a/src/common/outbound.c b/src/common/outbound.c index e166a672..32233f05 100644 --- a/src/common/outbound.c +++ b/src/common/outbound.c @@ -3774,37 +3774,29 @@ cmd_url (struct session *sess, char *tbuf, char *word[], char *word_eol[]) if (zoitechat_theme_path_from_arg (word[2], &theme_path)) { GError *error = NULL; - char *basename = g_path_get_basename (theme_path); - char *dot = strrchr (basename, '.'); - char *message; + char *theme_name = NULL; - if (dot) - *dot = '\0'; - - if (zoitechat_import_theme (theme_path, &error)) + if (zoitechat_import_gtk3_theme_archive (theme_path, &theme_name, &error)) { - if (zoitechat_apply_theme (basename, &error)) + if (theme_name) { - message = g_strdup_printf (_("Theme \"%s\" imported and applied."), basename); + char *message = g_strdup_printf (_("GTK3 theme \"%s\" imported. Use Theme settings to apply it."), theme_name); fe_message (message, FE_MSG_INFO); - handle_command (sess, "gui apply", FALSE); g_free (message); } else { - fe_message (error ? error->message : _("Theme imported, but failed to apply."), - FE_MSG_ERROR); - g_clear_error (&error); + fe_message (_("GTK3 theme imported. Use Theme settings to apply it."), FE_MSG_INFO); } } else { - fe_message (error ? error->message : _("Failed to import theme."), + fe_message (error ? error->message : _("Failed to import GTK3 theme archive."), FE_MSG_ERROR); g_clear_error (&error); } - g_free (basename); + g_free (theme_name); g_free (theme_path); return TRUE; } diff --git a/src/common/zoitechat.c b/src/common/zoitechat.c index 1f9fd1e4..d421a023 100644 --- a/src/common/zoitechat.c +++ b/src/common/zoitechat.c @@ -113,7 +113,7 @@ gboolean zoitechat_theme_path_from_arg (const char *arg, char **path_out) { char *path = NULL; - const char *ext; + gboolean valid_ext = FALSE; if (!arg) return FALSE; @@ -126,11 +126,21 @@ zoitechat_theme_path_from_arg (const char *arg, char **path_out) if (!path) return FALSE; - ext = strrchr (path, '.'); - if (!g_file_test (path, G_FILE_TEST_IS_REGULAR) || - !ext || - (g_ascii_strcasecmp (ext, ".zct") != 0 && - g_ascii_strcasecmp (ext, ".hct") != 0)) + if (g_file_test (path, G_FILE_TEST_IS_REGULAR)) + { + char *path_lower = g_ascii_strdown (path, -1); + + valid_ext = g_str_has_suffix (path_lower, ".zip") + || g_str_has_suffix (path_lower, ".tar") + || g_str_has_suffix (path_lower, ".tar.gz") + || g_str_has_suffix (path_lower, ".tgz") + || g_str_has_suffix (path_lower, ".tar.xz") + || g_str_has_suffix (path_lower, ".txz"); + + g_free (path_lower); + } + + if (!valid_ext) { g_free (path); return FALSE; @@ -252,84 +262,6 @@ zoitechat_remote_win32 (void) #endif -static gboolean -zoitechat_copy_theme_file (const char *src, const char *dest, GError **error) -{ - char *data = NULL; - gsize len = 0; - - if (!g_file_get_contents (src, &data, &len, error)) - return FALSE; - - if (!g_file_set_contents (dest, data, len, error)) - { - g_free (data); - return FALSE; - } - - g_free (data); - return TRUE; -} - -gboolean -zoitechat_apply_theme (const char *theme_name, GError **error) -{ - char *theme_dir; - char *colors_src; - char *colors_dest; - char *events_src; - char *events_dest; - gboolean ok = FALSE; - - if (!theme_name || !*theme_name) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, - _("No theme name specified.")); - return FALSE; - } - - theme_dir = g_build_filename (get_xdir (), "themes", theme_name, NULL); - colors_src = g_build_filename (theme_dir, "colors.conf", NULL); - colors_dest = g_build_filename (get_xdir (), "colors.conf", NULL); - events_src = g_build_filename (theme_dir, "pevents.conf", NULL); - events_dest = g_build_filename (get_xdir (), "pevents.conf", NULL); - - if (!g_file_test (colors_src, G_FILE_TEST_IS_REGULAR)) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, - _("This theme is missing a colors.conf file.")); - goto cleanup; - } - - if (!zoitechat_copy_theme_file (colors_src, colors_dest, error)) - goto cleanup; - - if (g_file_test (events_src, G_FILE_TEST_IS_REGULAR)) - { - if (!zoitechat_copy_theme_file (events_src, events_dest, error)) - goto cleanup; - } - else if (g_file_test (events_dest, G_FILE_TEST_EXISTS)) - { - if (g_unlink (events_dest) != 0) - { - g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno), - _("Failed to remove existing event settings.")); - goto cleanup; - } - } - - ok = TRUE; - -cleanup: - g_free (events_dest); - g_free (events_src); - g_free (colors_dest); - g_free (colors_src); - g_free (theme_dir); - return ok; -} - static gboolean zoitechat_is_safe_archive_entry (const char *entry) { @@ -686,7 +618,9 @@ cleanup: } gboolean -zoitechat_import_gtk3_theme_archive (const char *archive_path, GError **error) +zoitechat_import_gtk3_theme_archive (const char *archive_path, + char **theme_name_out, + GError **error) { ZoiteChatGtk3ArchiveType archive_type; char *temp_dir = NULL; @@ -700,6 +634,9 @@ zoitechat_import_gtk3_theme_archive (const char *archive_path, GError **error) gboolean has_dark_css = FALSE; gboolean missing_gtk_css = FALSE; + if (theme_name_out) + *theme_name_out = NULL; + if (!archive_path) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, @@ -910,6 +847,9 @@ zoitechat_import_gtk3_theme_archive (const char *archive_path, GError **error) if (has_dark_css) fe_message (_("Imported GTK3 theme includes gtk-dark.css."), FE_MSG_INFO); + if (theme_name_out) + *theme_name_out = g_strdup (theme_name); + ok = TRUE; cleanup: @@ -929,159 +869,6 @@ cleanup: } -gboolean -zoitechat_import_theme (const char *path, GError **error) -{ - char *themes_dir; - char *basename; - char *dot; - char *theme_dir; - char *argv[] = {"unzip", "-o", (char *)path, "-d", NULL, NULL}; - int status = 0; - gboolean ok; -#ifdef WIN32 - char *command = NULL; - char *powershell = NULL; -#endif - - if (!path) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, - _("No theme file specified.")); - return FALSE; - } - - themes_dir = g_build_filename (get_xdir (), "themes", NULL); - basename = g_path_get_basename (path); - if (!basename || basename[0] == '\0') - { - g_free (themes_dir); - g_free (basename); - g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, - _("Failed to determine theme name.")); - return FALSE; - } - - dot = strrchr (basename, '.'); - if (dot) - *dot = '\0'; - - theme_dir = g_build_filename (themes_dir, basename, NULL); - if (g_mkdir_with_parents (theme_dir, 0700) != 0) - { - g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno), - _("Failed to create theme directory.")); - g_free (theme_dir); - g_free (basename); - g_free (themes_dir); - return FALSE; - } - -#ifdef WIN32 - 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.")); - ok = FALSE; - } - else - { - GString *escaped_path = g_string_new ("'"); - GString *escaped_dir = g_string_new ("'"); - const char *cursor; - - for (cursor = 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 = theme_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 WindowsBase; " - "$ErrorActionPreference='Stop'; " - "$package=[System.IO.Packaging.Package]::Open(%s); " - "try { " - "foreach ($part in $package.GetParts()) { " - "$relative=$part.Uri.OriginalString.TrimStart('/'); " - "if ([string]::IsNullOrEmpty($relative)) { continue }; " - "$destPath=[System.IO.Path]::Combine(%s, $relative); " - "$destDir=[System.IO.Path]::GetDirectoryName($destPath); " - "if ($destDir -and -not (Test-Path -LiteralPath $destDir)) { " - "[System.IO.Directory]::CreateDirectory($destDir) | Out-Null " - "}; " - "$partStream=$part.GetStream(); " - "$fileStream=[System.IO.File]::Open($destPath,[System.IO.FileMode]::Create,[System.IO.FileAccess]::Write); " - "$partStream.CopyTo($fileStream); " - "$fileStream.Dispose(); " - "$partStream.Dispose(); " - "} " - "} finally { $package.Close(); }", - 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); - } - } -#else - argv[4] = theme_dir; - ok = g_spawn_sync (NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, - NULL, NULL, &status, error); -#endif - if (!ok) - { -#ifdef WIN32 - g_free (command); - g_free (powershell); -#endif - g_free (theme_dir); - g_free (basename); - g_free (themes_dir); - return FALSE; - } - - if (!g_spawn_check_exit_status (status, error)) - { -#ifdef WIN32 - g_free (command); - g_free (powershell); -#endif - g_free (theme_dir); - g_free (basename); - g_free (themes_dir); - return FALSE; - } - -#ifdef WIN32 - g_free (command); - g_free (powershell); -#endif - - g_free (theme_dir); - g_free (basename); - g_free (themes_dir); - return TRUE; -} /* * Update the priority queue of the "interesting sessions" @@ -1411,37 +1198,29 @@ irc_init (session *sess) if (zoitechat_theme_path_from_arg (arg_url, &theme_path)) { GError *error = NULL; - char *basename = g_path_get_basename (theme_path); - char *dot = strrchr (basename, '.'); - char *message; + char *theme_name = NULL; - if (dot) - *dot = '\0'; - - if (zoitechat_import_theme (theme_path, &error)) + if (zoitechat_import_gtk3_theme_archive (theme_path, &theme_name, &error)) { - if (zoitechat_apply_theme (basename, &error)) + if (theme_name) { - message = g_strdup_printf (_("Theme \"%s\" imported and applied."), basename); + char *message = g_strdup_printf (_("GTK3 theme \"%s\" imported. Use Theme settings to apply it."), theme_name); fe_message (message, FE_MSG_INFO); - handle_command (sess, "gui apply", FALSE); g_free (message); } else { - fe_message (error ? error->message : _("Theme imported, but failed to apply."), - FE_MSG_ERROR); - g_clear_error (&error); + fe_message (_("GTK3 theme imported. Use Theme settings to apply it."), FE_MSG_INFO); } } else { - fe_message (error ? error->message : _("Failed to import theme."), + fe_message (error ? error->message : _("Failed to import GTK3 theme archive."), FE_MSG_ERROR); g_clear_error (&error); } - g_free (basename); + g_free (theme_name); } else { @@ -1463,37 +1242,29 @@ irc_init (session *sess) if (zoitechat_theme_path_from_arg (arg_urls[i], &theme_path)) { GError *error = NULL; - char *basename = g_path_get_basename (theme_path); - char *dot = strrchr (basename, '.'); - char *message; + char *theme_name = NULL; - if (dot) - *dot = '\0'; - - if (zoitechat_import_theme (theme_path, &error)) + if (zoitechat_import_gtk3_theme_archive (theme_path, &theme_name, &error)) { - if (zoitechat_apply_theme (basename, &error)) + if (theme_name) { - message = g_strdup_printf (_("Theme \"%s\" imported and applied."), basename); + char *message = g_strdup_printf (_("GTK3 theme \"%s\" imported. Use Theme settings to apply it."), theme_name); fe_message (message, FE_MSG_INFO); - handle_command (sess, "gui apply", FALSE); g_free (message); } else { - fe_message (error ? error->message : _("Theme imported, but failed to apply."), - FE_MSG_ERROR); - g_clear_error (&error); + fe_message (_("GTK3 theme imported. Use Theme settings to apply it."), FE_MSG_INFO); } } else { - fe_message (error ? error->message : _("Failed to import theme."), + fe_message (error ? error->message : _("Failed to import GTK3 theme archive."), FE_MSG_ERROR); g_clear_error (&error); } - g_free (basename); + g_free (theme_name); } else { diff --git a/src/common/zoitechat.h b/src/common/zoitechat.h index 3e62b3a0..fcd762c6 100644 --- a/src/common/zoitechat.h +++ b/src/common/zoitechat.h @@ -30,10 +30,10 @@ #define ZOITECHAT_H 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); +/* Imports a GTK3 theme archive into ZoiteChat's own gtk3-themes store. */ +gboolean zoitechat_import_gtk3_theme_archive (const char *archive_path, + char **theme_name_out, + GError **error); #ifdef USE_OPENSSL #ifdef __APPLE__ diff --git a/src/fe-gtk/setup.c b/src/fe-gtk/setup.c index 0b941963..f2a7a2df 100644 --- a/src/fe-gtk/setup.c +++ b/src/fe-gtk/setup.c @@ -66,9 +66,6 @@ void setup_apply_real (int new_pix, int do_ulist, int do_layout, int do_identd); typedef struct { - GtkWidget *zoitechat_combo; - GtkWidget *zoitechat_apply_button; - GtkWidget *zoitechat_status_label; GtkWidget *gtk3_combo; GtkWidget *gtk3_import_button; GtkWidget *gtk3_apply_button; @@ -1900,122 +1897,6 @@ setup_theme_show_message (GtkMessageType message_type, const char *primary) gtk_widget_destroy (dialog); } -static void -setup_theme_populate (setup_theme_ui *ui) -{ - char *themes_dir; - GDir *dir; - const char *name; - GtkTreeModel *model; - GtkTreeIter iter; - int count; - - model = gtk_combo_box_get_model (GTK_COMBO_BOX (ui->zoitechat_combo)); - while (gtk_tree_model_get_iter_first (model, &iter)) - gtk_combo_box_text_remove (GTK_COMBO_BOX_TEXT (ui->zoitechat_combo), 0); - - themes_dir = g_build_filename (get_xdir (), "themes", NULL); - if (!g_file_test (themes_dir, G_FILE_TEST_IS_DIR)) - g_mkdir_with_parents (themes_dir, 0700); - - dir = g_dir_open (themes_dir, 0, NULL); - if (dir) - { - while ((name = g_dir_read_name (dir))) - { - char *path = g_build_filename (themes_dir, name, NULL); - if (g_file_test (path, G_FILE_TEST_IS_DIR)) - gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (ui->zoitechat_combo), name); - g_free (path); - } - g_dir_close (dir); - } - - count = gtk_tree_model_iter_n_children (gtk_combo_box_get_model (GTK_COMBO_BOX (ui->zoitechat_combo)), NULL); - if (count > 0) - gtk_combo_box_set_active (GTK_COMBO_BOX (ui->zoitechat_combo), 0); - - gtk_widget_set_sensitive (ui->zoitechat_apply_button, count > 0); - gtk_label_set_text (GTK_LABEL (ui->zoitechat_status_label), - count > 0 ? _("Select a ZoiteChat theme to apply colors and events.") : _("No ZoiteChat themes found.")); - - g_free (themes_dir); -} - -static void -setup_theme_refresh_cb (GtkWidget *button, gpointer user_data) -{ - setup_theme_ui *ui = user_data; - - setup_theme_populate (ui); -} - -static void -setup_theme_open_folder_cb (GtkWidget *button, gpointer user_data) -{ - char *themes_dir; - - themes_dir = g_build_filename (get_xdir (), "themes", NULL); - g_mkdir_with_parents (themes_dir, 0700); - fe_open_url (themes_dir); - g_free (themes_dir); -} - -static void -setup_theme_selection_changed (GtkComboBox *combo, gpointer user_data) -{ - setup_theme_ui *ui = user_data; - gboolean has_selection = gtk_combo_box_get_active (combo) >= 0; - - gtk_widget_set_sensitive (ui->zoitechat_apply_button, has_selection); -} - -static void -setup_theme_apply_cb (GtkWidget *button, gpointer user_data) -{ - setup_theme_ui *ui = user_data; - GtkWidget *dialog; - gint response; - char *theme; - GError *error = NULL; - - theme = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (ui->zoitechat_combo)); - if (!theme) - return; - - dialog = gtk_message_dialog_new (GTK_WINDOW (setup_window), GTK_DIALOG_MODAL, - GTK_MESSAGE_WARNING, GTK_BUTTONS_OK_CANCEL, - "%s", _("Applying a theme will overwrite your current colors and event settings.\nContinue?")); - /* Window classes are required for GTK CSS selectors like - * .zoitechat-dark / .zoitechat-light. */ - fe_apply_theme_to_toplevel (dialog); - response = gtk_dialog_run (GTK_DIALOG (dialog)); - gtk_widget_destroy (dialog); - - if (response != GTK_RESPONSE_OK) - { - g_free (theme); - return; - } - - if (!zoitechat_apply_theme (theme, &error)) - { - setup_theme_show_message (GTK_MESSAGE_ERROR, error ? error->message : _("Failed to apply theme.")); - g_clear_error (&error); - goto cleanup; - } - - palette_load (); - fe_apply_theme_for_mode (prefs.hex_gui_dark_mode, NULL); - color_change = TRUE; - setup_apply_real (0, TRUE, FALSE, FALSE); - - setup_theme_show_message (GTK_MESSAGE_INFO, _("ZoiteChat theme applied. Palette and event settings were updated.")); - -cleanup: - g_free (theme); -} - static void setup_gtk3_theme_populate (setup_theme_ui *ui) { @@ -2157,7 +2038,7 @@ setup_theme_gtk3_import_cb (GtkWidget *button, gpointer user_data) if (!archive_path) return; - if (!zoitechat_import_gtk3_theme_archive (archive_path, &error)) + if (!zoitechat_import_gtk3_theme_archive (archive_path, NULL, &error)) { setup_theme_show_message (GTK_MESSAGE_ERROR, error ? error->message : _("Failed to import GTK3 theme archive.")); @@ -2233,61 +2114,12 @@ setup_create_theme_page (void) GtkWidget *hbox; GtkWidget *button_box; GtkWidget *frame; - char *themes_dir; - char *markup; ui = g_new0 (setup_theme_ui, 1); box = gtkutil_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 6); gtk_container_set_border_width (GTK_CONTAINER (box), 6); - frame = gtk_frame_new (_("ZoiteChat Theme")); - gtk_box_pack_start (GTK_BOX (box), frame, FALSE, FALSE, 0); - - hbox = gtkutil_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 6); - gtk_container_set_border_width (GTK_CONTAINER (hbox), 6); - gtk_container_add (GTK_CONTAINER (frame), hbox); - - themes_dir = g_build_filename (get_xdir (), "themes", NULL); - markup = g_markup_printf_escaped (_("Theme files are loaded from %s."), themes_dir); - label = gtk_label_new (NULL); - gtk_label_set_markup (GTK_LABEL (label), markup); - gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); - gtk_widget_set_halign (label, GTK_ALIGN_START); - gtk_widget_set_valign (label, GTK_ALIGN_CENTER); - gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); - g_free (markup); - g_free (themes_dir); - - button_box = gtkutil_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 6); - gtk_box_pack_start (GTK_BOX (hbox), button_box, FALSE, FALSE, 0); - - ui->zoitechat_combo = gtk_combo_box_text_new (); - gtk_box_pack_start (GTK_BOX (button_box), ui->zoitechat_combo, TRUE, TRUE, 0); - g_signal_connect (G_OBJECT (ui->zoitechat_combo), "changed", - G_CALLBACK (setup_theme_selection_changed), ui); - - label = gtk_button_new_with_mnemonic (_("Apply _ZoiteChat Theme")); - ui->zoitechat_apply_button = label; - gtk_box_pack_start (GTK_BOX (button_box), label, FALSE, FALSE, 0); - g_signal_connect (G_OBJECT (label), "clicked", - G_CALLBACK (setup_theme_apply_cb), ui); - - label = gtk_button_new_with_mnemonic (_("_Refresh")); - gtk_box_pack_start (GTK_BOX (button_box), label, FALSE, FALSE, 0); - g_signal_connect (G_OBJECT (label), "clicked", - G_CALLBACK (setup_theme_refresh_cb), ui); - - label = gtk_button_new_with_mnemonic (_("_Open Folder")); - gtk_box_pack_start (GTK_BOX (button_box), label, FALSE, FALSE, 0); - g_signal_connect (G_OBJECT (label), "clicked", - G_CALLBACK (setup_theme_open_folder_cb), ui); - - ui->zoitechat_status_label = gtk_label_new (NULL); - gtk_widget_set_halign (ui->zoitechat_status_label, GTK_ALIGN_START); - gtk_widget_set_valign (ui->zoitechat_status_label, GTK_ALIGN_CENTER); - gtk_box_pack_start (GTK_BOX (hbox), ui->zoitechat_status_label, FALSE, FALSE, 0); - frame = gtk_frame_new (_("GTK3 Theme")); gtk_box_pack_start (GTK_BOX (box), frame, FALSE, FALSE, 0); @@ -2328,7 +2160,6 @@ setup_create_theme_page (void) gtk_widget_set_valign (ui->gtk3_status_label, GTK_ALIGN_CENTER); gtk_box_pack_start (GTK_BOX (hbox), ui->gtk3_status_label, FALSE, FALSE, 0); - setup_theme_populate (ui); setup_gtk3_theme_populate (ui); g_object_set_data_full (G_OBJECT (box), "setup-theme-ui", ui, setup_theme_ui_free);