fix: native GTK theme import, proper file:// paths

This commit is contained in:
2026-03-16 10:45:29 -06:00
parent 0bcd369426
commit 0f5dfb147e
5 changed files with 184 additions and 86 deletions

View File

@@ -508,36 +508,72 @@ chanlist_match_topic_button_toggled (GtkWidget * wid, server *serv)
serv->gui->chanlist_match_wants_topic = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (wid)); serv->gui->chanlist_match_wants_topic = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (wid));
} }
static GSList *
chanlist_get_selection (server *serv, int column)
{
GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (serv->gui->chanlist_list));
GtkTreeModel *model = GET_MODEL (serv);
GList *rows;
GList *cur;
GSList *result = NULL;
rows = gtk_tree_selection_get_selected_rows (sel, &model);
for (cur = rows; cur != NULL; cur = cur->next)
{
GtkTreeIter iter;
char *value;
if (gtk_tree_model_get_iter (model, &iter, (GtkTreePath *)cur->data))
{
gtk_tree_model_get (model, &iter, column, &value, -1);
result = g_slist_prepend (result, value);
}
}
g_list_free_full (rows, (GDestroyNotify) gtk_tree_path_free);
return g_slist_reverse (result);
}
static char * static char *
chanlist_get_selected (server *serv, gboolean get_topic) chanlist_get_selected (server *serv, gboolean get_topic)
{ {
char *chan; GSList *selection = chanlist_get_selection (serv, get_topic ? COL_TOPIC : COL_CHANNEL);
GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (serv->gui->chanlist_list)); char *value;
GtkTreeModel *model;
GtkTreeIter iter;
if (!gtk_tree_selection_get_selected (sel, &model, &iter)) if (!selection)
return NULL; return NULL;
gtk_tree_model_get (model, &iter, get_topic ? COL_TOPIC : COL_CHANNEL, &chan, -1); value = selection->data;
return chan; selection->data = NULL;
g_slist_free_full (selection, g_free);
return value;
} }
static void static void
chanlist_join (GtkWidget * wid, server *serv) chanlist_join (GtkWidget * wid, server *serv)
{ {
char tbuf[CHANLEN + 6]; char tbuf[CHANLEN + 6];
char *chan = chanlist_get_selected (serv, FALSE); GSList *selection;
if (chan) GSList *item;
gboolean joined = FALSE;
selection = chanlist_get_selection (serv, COL_CHANNEL);
for (item = selection; item != NULL; item = item->next)
{ {
if (serv->connected && (strcmp (chan, "*") != 0)) char *chan = item->data;
if (serv->connected && strcmp (chan, "*") != 0)
{ {
g_snprintf (tbuf, sizeof (tbuf), "join %s", chan); g_snprintf (tbuf, sizeof (tbuf), "join %s", chan);
handle_command (serv->server_session, tbuf, FALSE); handle_command (serv->server_session, tbuf, FALSE);
} else joined = TRUE;
gdk_display_beep (gdk_display_get_default ()); }
g_free (chan);
} }
if (!joined && selection)
gdk_display_beep (gdk_display_get_default ());
g_slist_free_full (selection, g_free);
} }
static void static void
@@ -656,23 +692,47 @@ chanlist_menu_destroy (GtkWidget *menu, gpointer userdata)
static void static void
chanlist_copychannel (GtkWidget *item, server *serv) chanlist_copychannel (GtkWidget *item, server *serv)
{ {
char *chan = chanlist_get_selected (serv, FALSE); GSList *selection = chanlist_get_selection (serv, COL_CHANNEL);
if (chan) GSList *cur;
GString *text;
if (!selection)
return;
text = g_string_new ("");
for (cur = selection; cur != NULL; cur = cur->next)
{ {
gtkutil_copy_to_clipboard (item, NULL, chan); if (text->len)
g_free (chan); g_string_append_c (text, '\n');
g_string_append (text, (char *)cur->data);
} }
gtkutil_copy_to_clipboard (item, NULL, text->str);
g_string_free (text, TRUE);
g_slist_free_full (selection, g_free);
} }
static void static void
chanlist_copytopic (GtkWidget *item, server *serv) chanlist_copytopic (GtkWidget *item, server *serv)
{ {
char *topic = chanlist_get_selected (serv, TRUE); GSList *selection = chanlist_get_selection (serv, COL_TOPIC);
if (topic) GSList *cur;
GString *text;
if (!selection)
return;
text = g_string_new ("");
for (cur = selection; cur != NULL; cur = cur->next)
{ {
gtkutil_copy_to_clipboard (item, NULL, topic); if (text->len)
g_free (topic); g_string_append_c (text, '\n');
g_string_append (text, (char *)cur->data);
} }
gtkutil_copy_to_clipboard (item, NULL, text->str);
g_string_free (text, TRUE);
g_slist_free_full (selection, g_free);
} }
static gboolean static gboolean
@@ -689,10 +749,12 @@ chanlist_button_cb (GtkTreeView *tree, GdkEventButton *event, server *serv)
if (!gtk_tree_view_get_path_at_pos (tree, event->x, event->y, &path, 0, 0, 0)) if (!gtk_tree_view_get_path_at_pos (tree, event->x, event->y, &path, 0, 0, 0))
return FALSE; return FALSE;
/* select what they right-clicked on */
sel = gtk_tree_view_get_selection (tree); sel = gtk_tree_view_get_selection (tree);
gtk_tree_selection_unselect_all (sel); if (!gtk_tree_selection_path_is_selected (sel, path))
gtk_tree_selection_select_path (sel, path); {
gtk_tree_selection_unselect_all (sel);
gtk_tree_selection_select_path (sel, path);
}
gtk_tree_path_free (path); gtk_tree_path_free (path);
menu = gtk_menu_new (); menu = gtk_menu_new ();
@@ -879,6 +941,7 @@ chanlist_opengui (server *serv, int do_refresh)
chanlist_add_column (view, COL_USERS, 50, _("Users"), TRUE); chanlist_add_column (view, COL_USERS, 50, _("Users"), TRUE);
chanlist_add_column (view, COL_TOPIC, 50, _("Topic"), FALSE); chanlist_add_column (view, COL_TOPIC, 50, _("Topic"), FALSE);
gtk_tree_view_set_grid_lines (GTK_TREE_VIEW (view), GTK_TREE_VIEW_GRID_LINES_HORIZONTAL); gtk_tree_view_set_grid_lines (GTK_TREE_VIEW (view), GTK_TREE_VIEW_GRID_LINES_HORIZONTAL);
gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (view)), GTK_SELECTION_MULTIPLE);
/* this is a speed up, but no horizontal scrollbar :( */ /* this is a speed up, but no horizontal scrollbar :( */
/*gtk_tree_view_set_fixed_height_mode (GTK_TREE_VIEW (view), TRUE);*/ /*gtk_tree_view_set_fixed_height_mode (GTK_TREE_VIEW (view), TRUE);*/
gtk_widget_show (view); gtk_widget_show (view);

View File

@@ -1339,22 +1339,61 @@ fe_open_url_inner (const char *url)
g_free (escaped_url); g_free (escaped_url);
} }
static gboolean
fe_open_url_is_local_path (const char *url)
{
if (g_path_is_absolute (url) || g_file_test (url, G_FILE_TEST_EXISTS))
return TRUE;
#ifdef WIN32
if (g_ascii_isalpha (url[0]) && url[1] == ':' &&
(url[2] == '\\' || url[2] == '/'))
return TRUE;
if (url[0] == '\\' && url[1] == '\\')
return TRUE;
#endif
return FALSE;
}
void void
fe_open_url (const char *url) fe_open_url (const char *url)
{ {
int url_type = url_check_word (url); int url_type = url_check_word (url);
char *uri; char *uri;
char *path;
char *path_uri;
if (fe_open_url_is_local_path (url))
{
path = g_canonicalize_filename (url, NULL);
path_uri = g_filename_to_uri (path, NULL, NULL);
g_free (path);
if (path_uri)
{
fe_open_url_inner (path_uri);
g_free (path_uri);
return;
}
}
/* gvfs likes file:// */ /* gvfs likes file:// */
if (url_type == WORD_PATH) if (url_type == WORD_PATH)
{ {
#ifndef WIN32 path = g_canonicalize_filename (url, NULL);
uri = g_strconcat ("file://", url, NULL); path_uri = g_filename_to_uri (path, NULL, NULL);
fe_open_url_inner (uri); g_free (path);
g_free (uri); if (path_uri)
#else {
fe_open_url_inner (url); fe_open_url_inner (path_uri);
#endif g_free (path_uri);
}
else
{
fe_open_url_inner (url);
}
} }
/* IPv6 addr. Add http:// */ /* IPv6 addr. Add http:// */
else if (url_type == WORD_HOST6) else if (url_type == WORD_HOST6)

View File

@@ -670,7 +670,7 @@ mg_spellcheck_cb (SexySpellEntry *entry, gchar *word, gpointer data)
{ {
/* This can cause freezes on long words, nicks arn't very long anyway. */ /* This can cause freezes on long words, nicks arn't very long anyway. */
if (strlen (word) > 20) if (strlen (word) > 20)
return TRUE; return FALSE;
/* Ignore anything we think is a valid url */ /* Ignore anything we think is a valid url */
if (url_check_word (word) != 0) if (url_check_word (word) != 0)

View File

@@ -964,6 +964,9 @@ default_word_check(SexySpellEntry *entry, const gchar *word)
/* We only want to check words */ /* We only want to check words */
return FALSE; return FALSE;
} }
if (g_utf8_strlen (word, -1) > 20)
return FALSE;
for (li = entry->priv->dict_list; li; li = g_slist_next (li)) { for (li = entry->priv->dict_list; li; li = g_slist_next (li)) {
struct EnchantDict *dict = (struct EnchantDict *) li->data; struct EnchantDict *dict = (struct EnchantDict *) li->data;
if (enchant_dict_check(dict, word, strlen(word)) == 0) { if (enchant_dict_check(dict, word, strlen(word)) == 0) {
@@ -1161,13 +1164,34 @@ check_color:
} }
} }
static gboolean
attr_list_has_attrs (PangoAttrList *attrs)
{
PangoAttrIterator *it;
GSList *list;
gboolean has = FALSE;
if (!attrs)
return FALSE;
it = pango_attr_list_get_iterator (attrs);
if (!it)
return FALSE;
list = pango_attr_iterator_get_attrs (it);
has = (list != NULL);
g_slist_free_full (list, (GDestroyNotify) pango_attribute_destroy);
pango_attr_iterator_destroy (it);
return has;
}
static void static void
sexy_spell_entry_recheck_all(SexySpellEntry *entry) sexy_spell_entry_recheck_all(SexySpellEntry *entry)
{ {
GdkRectangle rect; GdkRectangle rect;
GtkAllocation allocation; GtkAllocation allocation;
GtkWidget *widget = GTK_WIDGET(entry); GtkWidget *widget = GTK_WIDGET(entry);
PangoLayout *layout;
int length, i, text_len; int length, i, text_len;
const char *text; const char *text;
@@ -1196,8 +1220,7 @@ sexy_spell_entry_recheck_all(SexySpellEntry *entry)
} }
} }
layout = gtk_entry_get_layout(GTK_ENTRY(entry)); gtk_entry_set_attributes (GTK_ENTRY (entry), attr_list_has_attrs (entry->priv->attr_list) ? entry->priv->attr_list : NULL);
pango_layout_set_attributes(layout, entry->priv->attr_list);
if (gtk_widget_get_realized (GTK_WIDGET(entry))) if (gtk_widget_get_realized (GTK_WIDGET(entry)))
{ {
@@ -1213,13 +1236,6 @@ sexy_spell_entry_recheck_all(SexySpellEntry *entry)
static gboolean static gboolean
sexy_spell_entry_draw(GtkWidget *widget, cairo_t *cr) sexy_spell_entry_draw(GtkWidget *widget, cairo_t *cr)
{ {
SexySpellEntry *entry = SEXY_SPELL_ENTRY(widget);
GtkEntry *gtk_entry = GTK_ENTRY(widget);
PangoLayout *layout;
layout = gtk_entry_get_layout(gtk_entry);
pango_layout_set_attributes(layout, entry->priv->attr_list);
return GTK_WIDGET_CLASS(parent_class)->draw (widget, cr); return GTK_WIDGET_CLASS(parent_class)->draw (widget, cr);
} }

View File

@@ -1392,26 +1392,34 @@ theme_preferences_populate_gtk3 (theme_preferences_ui *ui)
g_ptr_array_unref (themes); g_ptr_array_unref (themes);
} }
static void
theme_preferences_gtk3_import_path (theme_preferences_ui *ui, char *path)
{
char *id = NULL;
GError *error = NULL;
if (!zoitechat_gtk3_theme_service_import (path, &id, &error))
theme_preferences_show_message (ui, GTK_MESSAGE_ERROR,
error ? error->message : _("Failed to import GTK3 theme."));
g_clear_error (&error);
g_free (id);
g_free (path);
theme_preferences_populate_gtk3 (ui);
}
static void static void
theme_preferences_gtk3_import_cb (GtkWidget *button, gpointer user_data) theme_preferences_gtk3_import_cb (GtkWidget *button, gpointer user_data)
{ {
theme_preferences_ui *ui = user_data; theme_preferences_ui *ui = user_data;
GtkWidget *dialog; GtkFileChooserNative *dialog;
GtkFileFilter *filter; GtkFileFilter *filter;
GtkWidget *folder_dialog;
char *path; char *path;
char *id = NULL;
GError *error = NULL;
gint response;
(void)button; (void)button;
dialog = gtk_file_chooser_dialog_new (_("Import GTK3 Theme"), ui->parent, dialog = gtk_file_chooser_native_new (_("Import GTK3 Theme"), ui->parent,
GTK_FILE_CHOOSER_ACTION_OPEN, GTK_FILE_CHOOSER_ACTION_OPEN,
_("Import _Folder"), 1, _("_Import"),
_("_Cancel"), GTK_RESPONSE_CANCEL, _("_Cancel"));
_("_Import"), GTK_RESPONSE_ACCEPT,
NULL);
theme_manager_attach_window (dialog);
gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (dialog), TRUE); gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (dialog), TRUE);
gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), FALSE); gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), FALSE);
filter = gtk_file_filter_new (); filter = gtk_file_filter_new ();
@@ -1426,43 +1434,15 @@ theme_preferences_gtk3_import_cb (GtkWidget *button, gpointer user_data)
gtk_file_filter_add_pattern (filter, "*.tbz"); gtk_file_filter_add_pattern (filter, "*.tbz");
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter); gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
response = gtk_dialog_run (GTK_DIALOG (dialog)); if (gtk_native_dialog_run (GTK_NATIVE_DIALOG (dialog)) != GTK_RESPONSE_ACCEPT)
if (response == 1)
{ {
gtk_widget_destroy (dialog); g_object_unref (dialog);
folder_dialog = gtk_file_chooser_dialog_new (_("Import GTK3 Theme Folder"), ui->parent,
GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_Import"), GTK_RESPONSE_ACCEPT,
NULL);
theme_manager_attach_window (folder_dialog);
gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (folder_dialog), TRUE);
if (gtk_dialog_run (GTK_DIALOG (folder_dialog)) != GTK_RESPONSE_ACCEPT)
{
gtk_widget_destroy (folder_dialog);
return;
}
path = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (folder_dialog));
gtk_widget_destroy (folder_dialog);
}
else if (response == GTK_RESPONSE_ACCEPT)
{
path = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
gtk_widget_destroy (dialog);
}
else
{
gtk_widget_destroy (dialog);
return; return;
} }
if (!zoitechat_gtk3_theme_service_import (path, &id, &error)) path = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
theme_preferences_show_message (ui, GTK_MESSAGE_ERROR, g_object_unref (dialog);
error ? error->message : _("Failed to import GTK3 theme.")); theme_preferences_gtk3_import_path (ui, path);
g_clear_error (&error);
g_free (path);
theme_preferences_populate_gtk3 (ui);
} }
static void static void