#include #include #include "../../common/zoitechat.h" #include "../../common/zoitechatc.h" #include #include #include "../gtkutil.h" #include "../../common/fe.h" #include "../../common/util.h" #include "../../common/cfgfiles.h" #include "../../common/gtk3-theme-service.h" #include "theme-gtk3.h" #include "theme-manager.h" #include "theme-preferences.h" typedef struct { GtkWindow *parent; GtkWidget *gtk3_combo; GtkWidget *gtk3_remove; gboolean gtk3_populating; struct zoitechatprefs *setup_prefs; } theme_preferences_ui; typedef struct { GtkWidget *button; ThemeSemanticToken token; gboolean *color_change_flag; gpointer manager_ui; } theme_color_dialog_data; typedef struct { GtkWidget *row; GtkWidget *button; GtkWidget *entry; GtkWidget *preview; ThemeSemanticToken token; char *search_text; gboolean *color_change_flag; GtkWindow *parent; gpointer manager_ui; } theme_color_manager_row; typedef struct { theme_color_manager_row *row; GdkRGBA original; gboolean has_original; } theme_manager_live_picker_data; typedef struct { GPtrArray *rows; GtkWidget *search_entry; gboolean *color_change_flag; GtkWidget *preview_window; GtkWidget *preview_chat; GtkWidget *preview_selected; GtkWidget *preview_marker; GtkWidget *preview_tab_new_data; GtkWidget *preview_tab_new_message; GtkWidget *preview_tab_highlight; GtkWidget *preview_tab_away; GtkWidget *preview_spell; } theme_color_manager_ui; #define COLOR_MANAGER_RESPONSE_RESET 1 static void theme_preferences_manager_row_free (gpointer data) { theme_color_manager_row *row = data; if (!row) return; g_free (row->search_text); g_free (row); } static void theme_preferences_manager_ui_free (gpointer data) { theme_color_manager_ui *ui = data; if (!ui) return; if (ui->rows) g_ptr_array_unref (ui->rows); g_free (ui); } static void theme_preferences_manager_update_preview (theme_color_manager_ui *ui) { GdkRGBA text_fg; GdkRGBA text_bg; GdkRGBA sel_fg; GdkRGBA sel_bg; GdkRGBA marker; GdkRGBA tab_new_data; GdkRGBA tab_new_message; GdkRGBA tab_highlight; GdkRGBA tab_away; GdkRGBA spell; GtkWidget *label; if (!ui) return; if (!theme_get_color (THEME_TOKEN_TEXT_FOREGROUND, &text_fg) || !theme_get_color (THEME_TOKEN_TEXT_BACKGROUND, &text_bg) || !theme_get_color (THEME_TOKEN_SELECTION_FOREGROUND, &sel_fg) || !theme_get_color (THEME_TOKEN_SELECTION_BACKGROUND, &sel_bg) || !theme_get_color (THEME_TOKEN_MARKER, &marker) || !theme_get_color (THEME_TOKEN_TAB_NEW_DATA, &tab_new_data) || !theme_get_color (THEME_TOKEN_TAB_NEW_MESSAGE, &tab_new_message) || !theme_get_color (THEME_TOKEN_TAB_HIGHLIGHT, &tab_highlight) || !theme_get_color (THEME_TOKEN_TAB_AWAY, &tab_away) || !theme_get_color (THEME_TOKEN_SPELL, &spell)) return; gtkutil_apply_palette (ui->preview_window, &text_bg, &text_fg, NULL); gtkutil_apply_palette (ui->preview_chat, &text_bg, &text_fg, NULL); label = g_object_get_data (G_OBJECT (ui->preview_chat), "zoitechat-preview-label"); if (GTK_IS_WIDGET (label)) gtkutil_apply_palette (label, NULL, &text_fg, NULL); gtkutil_apply_palette (ui->preview_selected, &sel_bg, &sel_fg, NULL); label = g_object_get_data (G_OBJECT (ui->preview_selected), "zoitechat-preview-label"); if (GTK_IS_WIDGET (label)) gtkutil_apply_palette (label, NULL, &sel_fg, NULL); gtkutil_apply_palette (ui->preview_marker, &marker, &text_fg, NULL); label = g_object_get_data (G_OBJECT (ui->preview_marker), "zoitechat-preview-label"); if (GTK_IS_WIDGET (label)) gtkutil_apply_palette (label, NULL, &text_fg, NULL); gtkutil_apply_palette (ui->preview_tab_new_data, &tab_new_data, &text_fg, NULL); label = g_object_get_data (G_OBJECT (ui->preview_tab_new_data), "zoitechat-preview-label"); if (GTK_IS_WIDGET (label)) gtkutil_apply_palette (label, NULL, &text_fg, NULL); gtkutil_apply_palette (ui->preview_tab_new_message, &tab_new_message, &text_fg, NULL); label = g_object_get_data (G_OBJECT (ui->preview_tab_new_message), "zoitechat-preview-label"); if (GTK_IS_WIDGET (label)) gtkutil_apply_palette (label, NULL, &text_fg, NULL); gtkutil_apply_palette (ui->preview_tab_highlight, &tab_highlight, &text_fg, NULL); label = g_object_get_data (G_OBJECT (ui->preview_tab_highlight), "zoitechat-preview-label"); if (GTK_IS_WIDGET (label)) gtkutil_apply_palette (label, NULL, &text_fg, NULL); gtkutil_apply_palette (ui->preview_tab_away, &tab_away, &text_fg, NULL); label = g_object_get_data (G_OBJECT (ui->preview_tab_away), "zoitechat-preview-label"); if (GTK_IS_WIDGET (label)) gtkutil_apply_palette (label, NULL, &text_fg, NULL); gtkutil_apply_palette (ui->preview_spell, &text_bg, &spell, NULL); label = g_object_get_data (G_OBJECT (ui->preview_spell), "zoitechat-preview-label"); if (GTK_IS_WIDGET (label)) gtkutil_apply_palette (label, NULL, &spell, NULL); } static GtkWidget * theme_preferences_manager_preview_item_new (const char *text) { GtkWidget *box; GtkWidget *label; box = gtk_event_box_new (); gtk_event_box_set_visible_window (GTK_EVENT_BOX (box), TRUE); gtk_container_set_border_width (GTK_CONTAINER (box), 3); label = gtk_label_new (text); gtk_widget_set_halign (label, GTK_ALIGN_START); gtk_container_add (GTK_CONTAINER (box), label); g_object_set_data (G_OBJECT (box), "zoitechat-preview-label", label); return box; } static GtkWidget * theme_preferences_manager_create_preview (theme_color_manager_ui *ui) { GtkWidget *frame; GtkWidget *vbox; GtkWidget *header; GtkWidget *chat_box; GtkWidget *tabs_box; GtkWidget *label; frame = gtk_frame_new (_("Live preview")); vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6); gtk_container_set_border_width (GTK_CONTAINER (vbox), 8); gtk_container_add (GTK_CONTAINER (frame), vbox); ui->preview_window = gtk_event_box_new (); gtk_event_box_set_visible_window (GTK_EVENT_BOX (ui->preview_window), TRUE); gtk_container_set_border_width (GTK_CONTAINER (ui->preview_window), 8); gtk_box_pack_start (GTK_BOX (vbox), ui->preview_window, TRUE, TRUE, 0); chat_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6); gtk_container_add (GTK_CONTAINER (ui->preview_window), chat_box); header = gtk_label_new (_("#zoitechat-preview")); gtk_widget_set_halign (header, GTK_ALIGN_START); gtk_box_pack_start (GTK_BOX (chat_box), header, FALSE, FALSE, 0); ui->preview_chat = theme_preferences_manager_preview_item_new (_(" Example chat message")); gtk_box_pack_start (GTK_BOX (chat_box), ui->preview_chat, FALSE, FALSE, 0); ui->preview_selected = theme_preferences_manager_preview_item_new (_("Selected text example")); gtk_box_pack_start (GTK_BOX (chat_box), ui->preview_selected, FALSE, FALSE, 0); ui->preview_marker = theme_preferences_manager_preview_item_new (_("Marker line")); gtk_widget_set_hexpand (ui->preview_marker, TRUE); gtk_box_pack_start (GTK_BOX (chat_box), ui->preview_marker, FALSE, FALSE, 0); ui->preview_spell = theme_preferences_manager_preview_item_new (_("mispelled wrd")); gtk_box_pack_start (GTK_BOX (chat_box), ui->preview_spell, FALSE, FALSE, 0); label = gtk_label_new (_("Tab states")); gtk_widget_set_halign (label, GTK_ALIGN_START); gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); tabs_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4); gtk_box_pack_start (GTK_BOX (vbox), tabs_box, FALSE, FALSE, 0); ui->preview_tab_new_data = theme_preferences_manager_preview_item_new (_("New data")); gtk_widget_set_hexpand (ui->preview_tab_new_data, TRUE); gtk_box_pack_start (GTK_BOX (tabs_box), ui->preview_tab_new_data, TRUE, TRUE, 0); ui->preview_tab_new_message = theme_preferences_manager_preview_item_new (_("New message")); gtk_widget_set_hexpand (ui->preview_tab_new_message, TRUE); gtk_box_pack_start (GTK_BOX (tabs_box), ui->preview_tab_new_message, TRUE, TRUE, 0); ui->preview_tab_highlight = theme_preferences_manager_preview_item_new (_("Highlight")); gtk_widget_set_hexpand (ui->preview_tab_highlight, TRUE); gtk_box_pack_start (GTK_BOX (tabs_box), ui->preview_tab_highlight, TRUE, TRUE, 0); ui->preview_tab_away = theme_preferences_manager_preview_item_new (_("Away")); gtk_widget_set_hexpand (ui->preview_tab_away, TRUE); gtk_box_pack_start (GTK_BOX (tabs_box), ui->preview_tab_away, TRUE, TRUE, 0); theme_preferences_manager_update_preview (ui); return frame; } enum { GTK3_THEME_COL_ID = 0, GTK3_THEME_COL_LABEL, GTK3_THEME_COL_SOURCE, GTK3_THEME_COL_THUMBNAIL, GTK3_THEME_COL_COUNT }; #define LABEL_INDENT 12 static void theme_preferences_show_message (theme_preferences_ui *ui, GtkMessageType message_type, const char *primary) { GtkWidget *dialog; dialog = gtk_message_dialog_new (ui->parent, GTK_DIALOG_MODAL, message_type, GTK_BUTTONS_OK, "%s", primary); theme_manager_attach_window (dialog); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); } static void theme_preferences_color_button_apply (GtkWidget *button, const GdkRGBA *color) { GtkWidget *target = g_object_get_data (G_OBJECT (button), "zoitechat-color-box"); GtkWidget *apply_widget = GTK_IS_WIDGET (target) ? target : button; gtkutil_apply_palette (apply_widget, color, NULL, NULL); if (apply_widget != button) gtkutil_apply_palette (button, color, NULL, NULL); gtk_widget_queue_draw (button); } static void theme_preferences_color_response_cb (GtkDialog *dialog, gint response_id, gpointer user_data) { theme_color_dialog_data *data = user_data; if (response_id == GTK_RESPONSE_OK) { GdkRGBA rgba; gboolean changed = FALSE; gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (dialog), &rgba); theme_manager_set_token_color (ZOITECHAT_DARK_MODE_LIGHT, data->token, &rgba, &changed); if (data->color_change_flag) *data->color_change_flag = *data->color_change_flag || changed; theme_preferences_color_button_apply (data->button, &rgba); theme_preferences_manager_update_preview ((theme_color_manager_ui *) data->manager_ui); } gtk_widget_destroy (GTK_WIDGET (dialog)); g_free (data); } static void theme_preferences_color_cb (GtkWidget *button, gpointer userdata) { GtkWidget *dialog; ThemeSemanticToken token; GdkRGBA rgba; theme_color_dialog_data *data; token = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (button), "zoitechat-theme-token")); if (!theme_get_color (token, &rgba)) return; dialog = gtk_color_chooser_dialog_new (_("Select color"), GTK_WINDOW (userdata)); theme_manager_attach_window (dialog); gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (dialog), &rgba); gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); data = g_new0 (theme_color_dialog_data, 1); data->button = button; data->token = token; data->color_change_flag = g_object_get_data (G_OBJECT (button), "zoitechat-theme-color-change"); data->manager_ui = g_object_get_data (G_OBJECT (button), "zoitechat-theme-color-manager-ui"); g_signal_connect (dialog, "response", G_CALLBACK (theme_preferences_color_response_cb), data); gtk_widget_show (dialog); } static char * theme_preferences_format_hex (const GdkRGBA *color) { return g_strdup_printf ("#%02X%02X%02X", (guint) CLAMP (color->red * 255.0 + 0.5, 0.0, 255.0), (guint) CLAMP (color->green * 255.0 + 0.5, 0.0, 255.0), (guint) CLAMP (color->blue * 255.0 + 0.5, 0.0, 255.0)); } static char * theme_preferences_token_display_name (ThemeSemanticToken token) { if (token >= THEME_TOKEN_MIRC_0 && token <= THEME_TOKEN_MIRC_15) return g_strdup_printf (_("mIRC color %d"), token - THEME_TOKEN_MIRC_0); if (token >= THEME_TOKEN_MIRC_16 && token <= THEME_TOKEN_MIRC_31) return g_strdup_printf (_("Local color %d"), token - THEME_TOKEN_MIRC_0); switch (token) { case THEME_TOKEN_SELECTION_FOREGROUND: return g_strdup (_("Selected text foreground")); case THEME_TOKEN_SELECTION_BACKGROUND: return g_strdup (_("Selected text background")); case THEME_TOKEN_TEXT_FOREGROUND: return g_strdup (_("Text foreground")); case THEME_TOKEN_TEXT_BACKGROUND: return g_strdup (_("Text background")); case THEME_TOKEN_MARKER: return g_strdup (_("Marker line")); case THEME_TOKEN_TAB_NEW_DATA: return g_strdup (_("Tab: new data")); case THEME_TOKEN_TAB_HIGHLIGHT: return g_strdup (_("Tab: highlight")); case THEME_TOKEN_TAB_NEW_MESSAGE: return g_strdup (_("Tab: new message")); case THEME_TOKEN_TAB_AWAY: return g_strdup (_("Tab: away")); case THEME_TOKEN_SPELL: return g_strdup (_("Spell checker")); default: return g_strdup (_("Unknown color")); } } static void theme_preferences_manager_row_apply (theme_color_manager_row *row, const GdkRGBA *rgba) { char *hex; theme_preferences_color_button_apply (row->button, rgba); gtkutil_apply_palette (row->preview, rgba, NULL, NULL); hex = theme_preferences_format_hex (rgba); gtk_entry_set_text (GTK_ENTRY (row->entry), hex); g_free (hex); } static void theme_preferences_manager_row_commit (theme_color_manager_row *row, const GdkRGBA *rgba) { gboolean changed = FALSE; theme_manager_set_token_color (ZOITECHAT_DARK_MODE_LIGHT, row->token, rgba, &changed); if (row->color_change_flag) *row->color_change_flag = *row->color_change_flag || changed; theme_preferences_manager_row_apply (row, rgba); theme_preferences_manager_update_preview ((theme_color_manager_ui *) row->manager_ui); } static void theme_preferences_manager_entry_commit (theme_color_manager_row *row) { GdkRGBA rgba; const char *text = gtk_entry_get_text (GTK_ENTRY (row->entry)); if (!gdk_rgba_parse (&rgba, text)) { if (theme_get_color (row->token, &rgba)) theme_preferences_manager_row_apply (row, &rgba); return; } theme_preferences_manager_row_commit (row, &rgba); } static void theme_preferences_manager_entry_activate_cb (GtkEntry *entry, gpointer user_data) { (void) entry; theme_preferences_manager_entry_commit ((theme_color_manager_row *) user_data); } static gboolean theme_preferences_manager_entry_focus_out_cb (GtkWidget *widget, GdkEvent *event, gpointer user_data) { (void) widget; (void) event; theme_preferences_manager_entry_commit ((theme_color_manager_row *) user_data); return FALSE; } static void theme_preferences_manager_picker_notify_rgba_cb (GObject *object, GParamSpec *pspec, gpointer user_data) { theme_manager_live_picker_data *data = user_data; GdkRGBA rgba; (void) pspec; if (!data || !data->row) return; gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (object), &rgba); theme_preferences_manager_row_commit (data->row, &rgba); } static void theme_preferences_manager_picker_response_cb (GtkDialog *dialog, gint response_id, gpointer user_data) { theme_manager_live_picker_data *data = user_data; if (data && data->row && data->has_original && response_id != GTK_RESPONSE_OK) theme_preferences_manager_row_commit (data->row, &data->original); gtk_widget_destroy (GTK_WIDGET (dialog)); g_free (data); } static void theme_preferences_manager_pick_cb (GtkWidget *button, gpointer user_data) { theme_color_manager_row *row = user_data; GtkWidget *dialog; GdkRGBA rgba; theme_manager_live_picker_data *data; if (!theme_get_color (row->token, &rgba)) return; dialog = gtk_color_chooser_dialog_new (_("Select color"), row->parent); theme_manager_attach_window (dialog); gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (dialog), &rgba); gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); data = g_new0 (theme_manager_live_picker_data, 1); data->row = row; data->original = rgba; data->has_original = TRUE; g_signal_connect (G_OBJECT (dialog), "notify::rgba", G_CALLBACK (theme_preferences_manager_picker_notify_rgba_cb), data); g_signal_connect (G_OBJECT (dialog), "response", G_CALLBACK (theme_preferences_manager_picker_response_cb), data); gtk_widget_show (dialog); (void) button; } static gboolean theme_preferences_manager_row_matches (theme_color_manager_row *row, const char *needle) { if (!needle || !needle[0]) return TRUE; return strstr (row->search_text, needle) != NULL; } static void theme_preferences_manager_search_changed_cb (GtkEditable *editable, gpointer user_data) { theme_color_manager_ui *ui = user_data; char *needle_lower; size_t i; needle_lower = g_utf8_strdown (gtk_entry_get_text (GTK_ENTRY (editable)), -1); for (i = 0; i < ui->rows->len; i++) { theme_color_manager_row *row = g_ptr_array_index (ui->rows, i); gtk_widget_set_visible (row->row, theme_preferences_manager_row_matches (row, needle_lower)); } g_free (needle_lower); } static void theme_preferences_manager_refresh_rows (theme_color_manager_ui *ui) { size_t i; if (!ui || !ui->rows) return; for (i = 0; i < ui->rows->len; i++) { theme_color_manager_row *row = g_ptr_array_index (ui->rows, i); GdkRGBA rgba; if (theme_get_color (row->token, &rgba)) theme_preferences_manager_row_apply (row, &rgba); } theme_preferences_manager_update_preview (ui); } static void theme_preferences_manager_dialog_response_cb (GtkDialog *dialog, gint response_id, gpointer user_data) { theme_color_manager_ui *ui = user_data; if (response_id != COLOR_MANAGER_RESPONSE_RESET) return; { gboolean changed = FALSE; theme_manager_reset_mode_colors (ZOITECHAT_DARK_MODE_LIGHT, &changed); if (ui->color_change_flag) *ui->color_change_flag = *ui->color_change_flag || changed; } theme_preferences_manager_refresh_rows (ui); g_signal_stop_emission_by_name (dialog, "response"); } static GtkWidget * theme_preferences_create_color_manager_dialog (GtkWindow *parent, gboolean *color_change_flag) { GtkWidget *dialog; GtkWidget *content; GtkWidget *vbox; GtkWidget *content_hbox; GtkWidget *left_box; GtkWidget *search; GtkWidget *scroller; GtkWidget *list; GtkWidget *preview_frame; theme_color_manager_ui *ui; ThemeSemanticToken token; dialog = gtk_dialog_new_with_buttons (_("Manage client colors"), parent, GTK_DIALOG_MODAL, _("_Reset to GTK3 defaults"), COLOR_MANAGER_RESPONSE_RESET, _("_Close"), GTK_RESPONSE_CLOSE, NULL); theme_manager_attach_window (dialog); gtk_window_set_default_size (GTK_WINDOW (dialog), 760, 560); ui = g_new0 (theme_color_manager_ui, 1); ui->rows = g_ptr_array_new_with_free_func (theme_preferences_manager_row_free); ui->color_change_flag = color_change_flag; g_object_set_data_full (G_OBJECT (dialog), "zoitechat-theme-color-manager", ui, theme_preferences_manager_ui_free); g_signal_connect (G_OBJECT (dialog), "response", G_CALLBACK (theme_preferences_manager_dialog_response_cb), ui); content = gtk_dialog_get_content_area (GTK_DIALOG (dialog)); vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 8); gtk_container_set_border_width (GTK_CONTAINER (vbox), 8); gtk_widget_set_hexpand (vbox, TRUE); gtk_widget_set_vexpand (vbox, TRUE); gtk_box_pack_start (GTK_BOX (content), vbox, TRUE, TRUE, 0); content_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8); gtk_widget_set_hexpand (content_hbox, TRUE); gtk_widget_set_vexpand (content_hbox, TRUE); gtk_box_pack_start (GTK_BOX (vbox), content_hbox, TRUE, TRUE, 0); left_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 8); gtk_widget_set_hexpand (left_box, TRUE); gtk_widget_set_vexpand (left_box, TRUE); gtk_box_pack_start (GTK_BOX (content_hbox), left_box, TRUE, TRUE, 0); search = gtk_search_entry_new (); gtk_entry_set_placeholder_text (GTK_ENTRY (search), _("Search colors by name")); gtk_box_pack_start (GTK_BOX (left_box), search, FALSE, FALSE, 0); ui->search_entry = search; scroller = gtk_scrolled_window_new (NULL, NULL); gtk_widget_set_hexpand (scroller, TRUE); gtk_widget_set_vexpand (scroller, TRUE); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroller), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); gtk_box_pack_start (GTK_BOX (left_box), scroller, TRUE, TRUE, 0); list = gtk_list_box_new (); gtk_widget_set_hexpand (list, TRUE); gtk_widget_set_vexpand (list, TRUE); gtk_list_box_set_selection_mode (GTK_LIST_BOX (list), GTK_SELECTION_NONE); gtk_container_add (GTK_CONTAINER (scroller), list); preview_frame = theme_preferences_manager_create_preview (ui); gtk_widget_set_size_request (preview_frame, 300, -1); gtk_widget_set_hexpand (preview_frame, FALSE); gtk_widget_set_vexpand (preview_frame, TRUE); gtk_box_pack_start (GTK_BOX (content_hbox), preview_frame, FALSE, TRUE, 0); for (token = THEME_TOKEN_MIRC_0; token < THEME_TOKEN_COUNT; token++) { theme_color_manager_row *row; GtkWidget *list_row; GtkWidget *hbox; GtkWidget *name; GtkWidget *preview; GtkWidget *button; GtkWidget *entry; GdkRGBA rgba; char *display; char *search_text; char *token_code; list_row = gtk_list_box_row_new (); hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8); gtk_container_set_border_width (GTK_CONTAINER (hbox), 4); gtk_container_add (GTK_CONTAINER (list_row), hbox); display = theme_preferences_token_display_name (token); name = gtk_label_new (display); gtk_widget_set_halign (name, GTK_ALIGN_START); gtk_widget_set_hexpand (name, TRUE); gtk_box_pack_start (GTK_BOX (hbox), name, TRUE, TRUE, 0); preview = gtk_label_new (_("Preview")); gtk_widget_set_size_request (preview, 90, -1); gtk_widget_set_halign (preview, GTK_ALIGN_CENTER); gtk_box_pack_start (GTK_BOX (hbox), preview, FALSE, FALSE, 0); button = gtk_button_new_with_label (_("Choose…")); gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); entry = gtk_entry_new (); gtk_entry_set_width_chars (GTK_ENTRY (entry), 9); gtk_entry_set_max_length (GTK_ENTRY (entry), 9); gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, FALSE, 0); row = g_new0 (theme_color_manager_row, 1); row->row = list_row; row->button = button; row->entry = entry; row->preview = preview; row->token = token; row->color_change_flag = color_change_flag; row->parent = GTK_WINDOW (dialog); row->manager_ui = ui; token_code = g_strdup_printf ("token_%d", token); search_text = g_strconcat (display, " ", token_code, NULL); row->search_text = g_utf8_strdown (search_text, -1); g_free (token_code); g_free (search_text); if (theme_get_color (token, &rgba)) theme_preferences_manager_row_apply (row, &rgba); g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (theme_preferences_manager_pick_cb), row); g_object_set_data (G_OBJECT (button), "zoitechat-theme-color-manager-ui", ui); g_signal_connect (G_OBJECT (entry), "activate", G_CALLBACK (theme_preferences_manager_entry_activate_cb), row); g_signal_connect (G_OBJECT (entry), "focus-out-event", G_CALLBACK (theme_preferences_manager_entry_focus_out_cb), row); gtk_container_add (GTK_CONTAINER (list), list_row); g_ptr_array_add (ui->rows, row); g_free (display); } g_signal_connect (G_OBJECT (search), "changed", G_CALLBACK (theme_preferences_manager_search_changed_cb), ui); theme_preferences_manager_update_preview (ui); gtk_widget_show_all (dialog); return dialog; } static void theme_preferences_manage_colors_cb (GtkWidget *button, gpointer user_data) { gboolean *color_change_flag = user_data; gboolean old_changed = FALSE; GtkWidget *dialog; if (color_change_flag) old_changed = *color_change_flag; dialog = theme_preferences_create_color_manager_dialog (GTK_WINDOW (gtk_widget_get_toplevel (button)), color_change_flag); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); if (color_change_flag && *color_change_flag != old_changed) theme_manager_save_preferences (); } static void theme_preferences_create_color_button (GtkWidget *table, ThemeSemanticToken token, int row, int col, GtkWindow *parent, gboolean *color_change_flag) { GtkWidget *but; GtkWidget *label; GtkWidget *box; char buf[64]; GdkRGBA color; if (token > THEME_TOKEN_MIRC_31) strcpy (buf, "  "); else if (token < 10) sprintf (buf, " %d", token); else sprintf (buf, "%d", token); but = gtk_button_new (); label = gtk_label_new (" "); gtk_label_set_markup (GTK_LABEL (label), buf); box = gtk_event_box_new (); gtk_event_box_set_visible_window (GTK_EVENT_BOX (box), TRUE); gtk_container_add (GTK_CONTAINER (box), label); gtk_container_add (GTK_CONTAINER (but), box); gtk_widget_set_halign (box, GTK_ALIGN_CENTER); gtk_widget_set_valign (box, GTK_ALIGN_CENTER); gtk_widget_show (label); gtk_widget_show (box); g_object_set_data (G_OBJECT (but), "zoitechat-color", (gpointer)1); g_object_set_data (G_OBJECT (but), "zoitechat-color-box", box); g_object_set_data (G_OBJECT (but), "zoitechat-theme-token", GINT_TO_POINTER (token)); g_object_set_data (G_OBJECT (but), "zoitechat-theme-color-change", color_change_flag); gtk_grid_attach (GTK_GRID (table), but, col, row, 1, 1); g_signal_connect (G_OBJECT (but), "clicked", G_CALLBACK (theme_preferences_color_cb), parent); if (theme_get_color (token, &color)) theme_preferences_color_button_apply (but, &color); } static void theme_preferences_create_header (GtkWidget *table, int row, const char *labeltext) { GtkWidget *label; char buf[128]; if (row == 0) g_snprintf (buf, sizeof (buf), "%s", _(labeltext)); else g_snprintf (buf, sizeof (buf), "\n%s", _(labeltext)); label = gtk_label_new (NULL); gtk_label_set_markup (GTK_LABEL (label), buf); gtk_widget_set_halign (label, GTK_ALIGN_START); gtk_widget_set_valign (label, GTK_ALIGN_CENTER); gtk_grid_attach (GTK_GRID (table), label, 0, row, 4, 1); gtk_widget_set_margin_bottom (label, 5); } static void theme_preferences_create_other_color_l (GtkWidget *tab, const char *text, ThemeSemanticToken token, int row, GtkWindow *parent, gboolean *color_change_flag) { GtkWidget *label; label = gtk_label_new (text); gtk_widget_set_halign (label, GTK_ALIGN_START); gtk_widget_set_valign (label, GTK_ALIGN_CENTER); gtk_widget_set_margin_start (label, LABEL_INDENT); gtk_grid_attach (GTK_GRID (tab), label, 2, row, 1, 1); theme_preferences_create_color_button (tab, token, row, 3, parent, color_change_flag); } static void theme_preferences_create_other_color_r (GtkWidget *tab, const char *text, ThemeSemanticToken token, int row, GtkWindow *parent, gboolean *color_change_flag) { GtkWidget *label; label = gtk_label_new (text); gtk_widget_set_halign (label, GTK_ALIGN_START); gtk_widget_set_valign (label, GTK_ALIGN_CENTER); gtk_widget_set_margin_start (label, LABEL_INDENT); gtk_grid_attach (GTK_GRID (tab), label, 5, row, 4, 1); theme_preferences_create_color_button (tab, token, row, 9, parent, color_change_flag); } static void theme_preferences_strip_toggle_cb (GtkToggleButton *toggle, gpointer user_data) { int *field = user_data; *field = gtk_toggle_button_get_active (toggle); } static void theme_preferences_create_strip_toggle (GtkWidget *tab, int row, const char *text, int *field) { GtkWidget *toggle; toggle = gtk_check_button_new_with_label (text); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), *field); g_signal_connect (G_OBJECT (toggle), "toggled", G_CALLBACK (theme_preferences_strip_toggle_cb), field); gtk_grid_attach (GTK_GRID (tab), toggle, 2, row, 1, 1); } GtkWidget * theme_preferences_create_color_page (GtkWindow *parent, struct zoitechatprefs *setup_prefs, gboolean *color_change_flag) { GtkWidget *tab; GtkWidget *box; GtkWidget *label; GtkWidget *manage_colors_button; int i; box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_container_set_border_width (GTK_CONTAINER (box), 6); tab = gtk_grid_new (); gtk_container_set_border_width (GTK_CONTAINER (tab), 6); gtk_grid_set_row_spacing (GTK_GRID (tab), 2); gtk_grid_set_column_spacing (GTK_GRID (tab), 3); gtk_container_add (GTK_CONTAINER (box), tab); theme_preferences_create_header (tab, 0, N_("Text Colors")); label = gtk_label_new (_("mIRC colors:")); gtk_widget_set_halign (label, GTK_ALIGN_START); gtk_widget_set_valign (label, GTK_ALIGN_CENTER); gtk_widget_set_margin_start (label, LABEL_INDENT); gtk_grid_attach (GTK_GRID (tab), label, 2, 1, 1, 1); for (i = 0; i < 16; i++) theme_preferences_create_color_button (tab, THEME_TOKEN_MIRC_0 + i, 1, i + 3, parent, color_change_flag); label = gtk_label_new (_("Local colors:")); gtk_widget_set_halign (label, GTK_ALIGN_START); gtk_widget_set_valign (label, GTK_ALIGN_CENTER); gtk_widget_set_margin_start (label, LABEL_INDENT); gtk_grid_attach (GTK_GRID (tab), label, 2, 2, 1, 1); for (i = 16; i < 32; i++) theme_preferences_create_color_button (tab, THEME_TOKEN_MIRC_0 + i, 2, (i + 3) - 16, parent, color_change_flag); theme_preferences_create_other_color_l (tab, _("Foreground:"), THEME_TOKEN_TEXT_FOREGROUND, 3, parent, color_change_flag); theme_preferences_create_other_color_r (tab, _("Background:"), THEME_TOKEN_TEXT_BACKGROUND, 3, parent, color_change_flag); theme_preferences_create_header (tab, 5, N_("Selected Text")); theme_preferences_create_other_color_l (tab, _("Foreground:"), THEME_TOKEN_SELECTION_FOREGROUND, 6, parent, color_change_flag); theme_preferences_create_other_color_r (tab, _("Background:"), THEME_TOKEN_SELECTION_BACKGROUND, 6, parent, color_change_flag); theme_preferences_create_header (tab, 8, N_("Interface Colors")); theme_preferences_create_other_color_l (tab, _("New data:"), THEME_TOKEN_TAB_NEW_DATA, 9, parent, color_change_flag); theme_preferences_create_other_color_r (tab, _("Marker line:"), THEME_TOKEN_MARKER, 9, parent, color_change_flag); theme_preferences_create_other_color_l (tab, _("New message:"), THEME_TOKEN_TAB_NEW_MESSAGE, 10, parent, color_change_flag); theme_preferences_create_other_color_r (tab, _("Away user:"), THEME_TOKEN_TAB_AWAY, 10, parent, color_change_flag); theme_preferences_create_other_color_l (tab, _("Highlight:"), THEME_TOKEN_TAB_HIGHLIGHT, 11, parent, color_change_flag); theme_preferences_create_other_color_r (tab, _("Spell checker:"), THEME_TOKEN_SPELL, 11, parent, color_change_flag); theme_preferences_create_header (tab, 15, N_("Color Stripping")); theme_preferences_create_strip_toggle (tab, 16, _("Messages"), &setup_prefs->hex_text_stripcolor_msg); theme_preferences_create_strip_toggle (tab, 17, _("Scrollback"), &setup_prefs->hex_text_stripcolor_replay); theme_preferences_create_strip_toggle (tab, 18, _("Topic"), &setup_prefs->hex_text_stripcolor_topic); manage_colors_button = gtk_button_new_with_label (_("Manage all client colors…")); gtk_widget_set_halign (manage_colors_button, GTK_ALIGN_START); gtk_widget_set_margin_start (manage_colors_button, LABEL_INDENT); gtk_widget_set_margin_top (manage_colors_button, 10); gtk_box_pack_start (GTK_BOX (box), manage_colors_button, FALSE, FALSE, 0); g_signal_connect (G_OBJECT (manage_colors_button), "clicked", G_CALLBACK (theme_preferences_manage_colors_cb), color_change_flag); return box; } static void theme_preferences_open_gtk3_folder_cb (GtkWidget *button, gpointer user_data) { theme_preferences_ui *ui = user_data; GAppInfo *handler; char *themes_dir; (void)button; themes_dir = zoitechat_gtk3_theme_service_get_user_themes_dir (); g_mkdir_with_parents (themes_dir, 0700); handler = g_app_info_get_default_for_uri_scheme ("file"); if (!handler) { theme_preferences_show_message (ui, GTK_MESSAGE_ERROR, _("No application is configured to open folders.")); g_free (themes_dir); return; } g_object_unref (handler); fe_open_url (themes_dir); g_free (themes_dir); } static char * theme_preferences_gtk3_active_id (theme_preferences_ui *ui) { GtkTreeIter iter; GtkTreeModel *model; char *id = NULL; if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (ui->gtk3_combo), &iter)) return NULL; model = gtk_combo_box_get_model (GTK_COMBO_BOX (ui->gtk3_combo)); gtk_tree_model_get (model, &iter, GTK3_THEME_COL_ID, &id, -1); return id; } static void theme_preferences_gtk3_sync_remove_state (theme_preferences_ui *ui) { GtkTreeIter iter; GtkTreeModel *model; int source = -1; if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (ui->gtk3_combo), &iter)) { gtk_widget_set_sensitive (ui->gtk3_remove, FALSE); return; } model = gtk_combo_box_get_model (GTK_COMBO_BOX (ui->gtk3_combo)); gtk_tree_model_get (model, &iter, GTK3_THEME_COL_SOURCE, &source, -1); gtk_widget_set_sensitive (ui->gtk3_remove, source == ZOITECHAT_GTK3_THEME_SOURCE_USER); } static void theme_preferences_gtk3_changed_cb (GtkComboBox *combo, gpointer user_data) { theme_preferences_ui *ui = user_data; char *id; gboolean selection_changed; ThemeGtk3Variant variant; GError *error = NULL; (void) combo; theme_preferences_gtk3_sync_remove_state (ui); if (ui->gtk3_populating) return; id = theme_preferences_gtk3_active_id (ui); if (!id) return; variant = theme_gtk3_variant_for_theme (id); selection_changed = g_strcmp0 (prefs.hex_gui_gtk3_theme, id) != 0 || prefs.hex_gui_gtk3_variant != variant; g_strlcpy (prefs.hex_gui_gtk3_theme, id, sizeof (prefs.hex_gui_gtk3_theme)); prefs.hex_gui_gtk3_variant = variant; if (ui->setup_prefs) { g_strlcpy (ui->setup_prefs->hex_gui_gtk3_theme, id, sizeof (ui->setup_prefs->hex_gui_gtk3_theme)); ui->setup_prefs->hex_gui_gtk3_variant = prefs.hex_gui_gtk3_variant; } if (selection_changed && !theme_gtk3_apply_current (&error)) { theme_preferences_show_message (ui, GTK_MESSAGE_ERROR, error ? error->message : _("Failed to apply GTK3 theme.")); g_clear_error (&error); } g_free (id); } static GdkPixbuf * theme_preferences_load_thumbnail (const char *path) { char *data = NULL; gsize length = 0; GdkPixbufLoader *loader; GError *error = NULL; GdkPixbuf *pixbuf; GdkPixbuf *scaled; int width; int height; if (!path || !g_file_get_contents (path, &data, &length, &error)) { g_clear_error (&error); return NULL; } loader = gdk_pixbuf_loader_new (); if (!gdk_pixbuf_loader_write (loader, (const guchar *) data, length, &error)) { g_clear_error (&error); g_object_unref (loader); g_free (data); return NULL; } g_free (data); if (!gdk_pixbuf_loader_close (loader, &error)) { g_clear_error (&error); g_object_unref (loader); return NULL; } pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); if (!pixbuf) { g_object_unref (loader); return NULL; } width = gdk_pixbuf_get_width (pixbuf); height = gdk_pixbuf_get_height (pixbuf); if (width > 48 || height > 48) scaled = gdk_pixbuf_scale_simple (pixbuf, 48, 48, GDK_INTERP_BILINEAR); else scaled = gdk_pixbuf_copy (pixbuf); g_object_unref (loader); return scaled; } static void theme_preferences_populate_gtk3 (theme_preferences_ui *ui) { GPtrArray *themes; guint i; GtkTreeStore *store; GtkTreeIter iter; int active = -1; gboolean removed_selected_theme = FALSE; gboolean should_apply = FALSE; char *final_id; ThemeGtk3Variant final_variant = THEME_GTK3_VARIANT_PREFER_LIGHT; GError *error = NULL; store = GTK_TREE_STORE (gtk_combo_box_get_model (GTK_COMBO_BOX (ui->gtk3_combo))); ui->gtk3_populating = TRUE; gtk_tree_store_clear (store); themes = zoitechat_gtk3_theme_service_discover (); for (i = 0; i < themes->len; i++) { ZoitechatGtk3Theme *theme = g_ptr_array_index (themes, i); char *label = g_strdup_printf ("%s (%s)", theme->display_name, theme->source == ZOITECHAT_GTK3_THEME_SOURCE_USER ? _("user") : _("system")); GdkPixbuf *thumbnail = NULL; if (theme->thumbnail_path && g_file_test (theme->thumbnail_path, G_FILE_TEST_IS_REGULAR)) thumbnail = theme_preferences_load_thumbnail (theme->thumbnail_path); gtk_tree_store_append (store, &iter, NULL); gtk_tree_store_set (store, &iter, GTK3_THEME_COL_ID, theme->id, GTK3_THEME_COL_LABEL, label, GTK3_THEME_COL_SOURCE, theme->source, GTK3_THEME_COL_THUMBNAIL, thumbnail, -1); if (g_strcmp0 (prefs.hex_gui_gtk3_theme, theme->id) == 0) active = i; if (thumbnail) g_object_unref (thumbnail); g_free (label); } if (active >= 0) gtk_combo_box_set_active (GTK_COMBO_BOX (ui->gtk3_combo), active); else if (themes->len > 0) { gtk_combo_box_set_active (GTK_COMBO_BOX (ui->gtk3_combo), 0); if (prefs.hex_gui_gtk3_theme[0] != '\0') removed_selected_theme = TRUE; } else if (prefs.hex_gui_gtk3_theme[0] != '\0') removed_selected_theme = TRUE; gtk_widget_set_sensitive (ui->gtk3_combo, themes->len > 0); theme_preferences_gtk3_sync_remove_state (ui); ui->gtk3_populating = FALSE; final_id = theme_preferences_gtk3_active_id (ui); if (final_id) { final_variant = theme_gtk3_variant_for_theme (final_id); should_apply = g_strcmp0 (prefs.hex_gui_gtk3_theme, final_id) != 0 || prefs.hex_gui_gtk3_variant != final_variant || removed_selected_theme; g_strlcpy (prefs.hex_gui_gtk3_theme, final_id, sizeof (prefs.hex_gui_gtk3_theme)); if (ui->setup_prefs) g_strlcpy (ui->setup_prefs->hex_gui_gtk3_theme, final_id, sizeof (ui->setup_prefs->hex_gui_gtk3_theme)); g_free (final_id); } prefs.hex_gui_gtk3_variant = final_variant; if (ui->setup_prefs) ui->setup_prefs->hex_gui_gtk3_variant = final_variant; if (should_apply && !theme_gtk3_apply_current (&error)) { theme_preferences_show_message (ui, GTK_MESSAGE_ERROR, error ? error->message : _("Failed to apply GTK3 theme.")); g_clear_error (&error); } g_ptr_array_unref (themes); } static void theme_preferences_gtk3_import_cb (GtkWidget *button, gpointer user_data) { theme_preferences_ui *ui = user_data; GtkWidget *dialog; GtkFileFilter *filter; GtkWidget *folder_dialog; char *path; char *id = NULL; GError *error = NULL; gint response; (void)button; dialog = gtk_file_chooser_dialog_new (_("Import GTK3 Theme"), ui->parent, GTK_FILE_CHOOSER_ACTION_OPEN, _("Import _Folder"), 1, _("_Cancel"), GTK_RESPONSE_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_select_multiple (GTK_FILE_CHOOSER (dialog), FALSE); filter = gtk_file_filter_new (); gtk_file_filter_set_name (filter, _("Theme archives (*.zip, *.tar, *.tar.xz, *.tgz, *.tar.gz, *.tar.bz2)")); gtk_file_filter_add_pattern (filter, "*.zip"); gtk_file_filter_add_pattern (filter, "*.tar"); gtk_file_filter_add_pattern (filter, "*.tar.xz"); gtk_file_filter_add_pattern (filter, "*.txz"); gtk_file_filter_add_pattern (filter, "*.tar.gz"); gtk_file_filter_add_pattern (filter, "*.tgz"); gtk_file_filter_add_pattern (filter, "*.tar.bz2"); gtk_file_filter_add_pattern (filter, "*.tbz"); gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter); response = gtk_dialog_run (GTK_DIALOG (dialog)); if (response == 1) { gtk_widget_destroy (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; } 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 (path); theme_preferences_populate_gtk3 (ui); } static void theme_preferences_gtk3_remove_cb (GtkWidget *button, gpointer user_data) { theme_preferences_ui *ui = user_data; char *id; GError *error = NULL; (void)button; id = theme_preferences_gtk3_active_id (ui); if (!id) return; if (!zoitechat_gtk3_theme_service_remove_user_theme (id, &error)) theme_preferences_show_message (ui, GTK_MESSAGE_ERROR, error ? error->message : _("Failed to remove GTK3 theme.")); g_clear_error (&error); g_free (id); theme_preferences_populate_gtk3 (ui); } GtkWidget * theme_preferences_create_page (GtkWindow *parent, struct zoitechatprefs *setup_prefs, gboolean *color_change_flag) { theme_preferences_ui *ui; GtkWidget *box; GtkWidget *label; GtkWidget *colors_frame; GtkWidget *colors_box; GtkWidget *manage_colors_button; GtkWidget *gtk3_frame; GtkWidget *gtk3_grid; GtkWidget *gtk3_button; GtkTreeStore *gtk3_store; GtkCellRenderer *renderer; ui = g_new0 (theme_preferences_ui, 1); ui->parent = parent; ui->setup_prefs = setup_prefs; box = gtkutil_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 6); gtk_container_set_border_width (GTK_CONTAINER (box), 6); colors_frame = gtk_frame_new (_("Colors")); gtk_box_pack_start (GTK_BOX (box), colors_frame, FALSE, FALSE, 0); colors_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6); gtk_container_set_border_width (GTK_CONTAINER (colors_box), 6); gtk_container_add (GTK_CONTAINER (colors_frame), colors_box); label = gtk_label_new (_("GTK3 theme colors are used by default. Open the color manager to set custom colors.")); gtk_widget_set_halign (label, GTK_ALIGN_START); gtk_label_set_xalign (GTK_LABEL (label), 0.0f); gtk_box_pack_start (GTK_BOX (colors_box), label, FALSE, FALSE, 0); manage_colors_button = gtk_button_new_with_label (_("Manage all client colors…")); gtk_widget_set_halign (manage_colors_button, GTK_ALIGN_START); gtk_box_pack_start (GTK_BOX (colors_box), manage_colors_button, FALSE, FALSE, 0); g_signal_connect (G_OBJECT (manage_colors_button), "clicked", G_CALLBACK (theme_preferences_manage_colors_cb), color_change_flag); gtk3_frame = gtk_frame_new (_("GTK3 Theme")); gtk_box_pack_start (GTK_BOX (box), gtk3_frame, FALSE, FALSE, 0); gtk3_grid = gtk_grid_new (); gtk_container_set_border_width (GTK_CONTAINER (gtk3_grid), 6); gtk_grid_set_row_spacing (GTK_GRID (gtk3_grid), 6); gtk_grid_set_column_spacing (GTK_GRID (gtk3_grid), 6); gtk_container_add (GTK_CONTAINER (gtk3_frame), gtk3_grid); label = gtk_label_new (_("GTK3 theme:")); gtk_widget_set_halign (label, GTK_ALIGN_START); gtk_grid_attach (GTK_GRID (gtk3_grid), label, 0, 0, 1, 1); gtk3_store = gtk_tree_store_new (GTK3_THEME_COL_COUNT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, GDK_TYPE_PIXBUF); ui->gtk3_combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL (gtk3_store)); g_object_unref (gtk3_store); renderer = gtk_cell_renderer_pixbuf_new (); gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (ui->gtk3_combo), renderer, FALSE); gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (ui->gtk3_combo), renderer, "pixbuf", GTK3_THEME_COL_THUMBNAIL); renderer = gtk_cell_renderer_text_new (); gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (ui->gtk3_combo), renderer, TRUE); gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (ui->gtk3_combo), renderer, "text", GTK3_THEME_COL_LABEL); gtk_grid_attach (GTK_GRID (gtk3_grid), ui->gtk3_combo, 1, 0, 3, 1); g_signal_connect (G_OBJECT (ui->gtk3_combo), "changed", G_CALLBACK (theme_preferences_gtk3_changed_cb), ui); gtk3_button = gtk_button_new_with_mnemonic (_("Import")); gtk_grid_attach (GTK_GRID (gtk3_grid), gtk3_button, 0, 1, 1, 1); g_signal_connect (G_OBJECT (gtk3_button), "clicked", G_CALLBACK (theme_preferences_gtk3_import_cb), ui); ui->gtk3_remove = gtk_button_new_with_mnemonic (_("Remove")); gtk_grid_attach (GTK_GRID (gtk3_grid), ui->gtk3_remove, 1, 1, 1, 1); g_signal_connect (G_OBJECT (ui->gtk3_remove), "clicked", G_CALLBACK (theme_preferences_gtk3_remove_cb), ui); gtk3_button = gtk_button_new_with_mnemonic (_("Open theme folder")); gtk_grid_attach (GTK_GRID (gtk3_grid), gtk3_button, 2, 1, 2, 1); g_signal_connect (G_OBJECT (gtk3_button), "clicked", G_CALLBACK (theme_preferences_open_gtk3_folder_cb), ui); theme_preferences_populate_gtk3 (ui); g_object_set_data_full (G_OBJECT (box), "theme-preferences-ui", ui, g_free); return box; } void theme_preferences_apply_to_session (session_gui *gui, InputStyle *input_style) { if (gui->user_tree) { theme_manager_apply_userlist_style (gui->user_tree, theme_manager_get_userlist_palette_behavior (input_style ? input_style->font_desc : NULL)); } }