feat: merge GTK3 Theme into Appearance (new Advanced section); fix+scale chat bg image + use FileChooserNative picker

This commit is contained in:
2026-03-08 10:10:59 -06:00
parent f2354a7fa2
commit b47c45d4cc
4 changed files with 203 additions and 33 deletions

View File

@@ -118,11 +118,43 @@ pixmap_load_from_file_real (char *file)
{ {
GdkPixbuf *img; GdkPixbuf *img;
cairo_surface_t *surface; cairo_surface_t *surface;
int width;
int height;
const int max_dimension = 4096;
img = gdk_pixbuf_new_from_file (file, 0); img = gdk_pixbuf_new_from_file (file, 0);
if (!img) if (!img)
return NULL; return NULL;
width = gdk_pixbuf_get_width (img);
height = gdk_pixbuf_get_height (img);
if (width > max_dimension || height > max_dimension)
{
GdkPixbuf *scaled;
double scale;
int target_width;
int target_height;
if (width >= height)
scale = (double)max_dimension / (double)width;
else
scale = (double)max_dimension / (double)height;
target_width = (int)(width * scale);
target_height = (int)(height * scale);
if (target_width < 1)
target_width = 1;
if (target_height < 1)
target_height = 1;
scaled = gdk_pixbuf_scale_simple (img, target_width, target_height, GDK_INTERP_BILINEAR);
if (scaled)
{
g_object_unref (img);
img = scaled;
}
}
surface = pixbuf_to_cairo_surface (img); surface = pixbuf_to_cairo_surface (img);
g_object_unref (img); g_object_unref (img);

View File

@@ -161,10 +161,6 @@ static const setting appearance_settings[] =
{ST_TOGGLE, N_("Colored nick names"), P_OFFINTNL(hex_text_color_nicks), N_("Give each person on IRC a different color"),0,0}, {ST_TOGGLE, N_("Colored nick names"), P_OFFINTNL(hex_text_color_nicks), N_("Give each person on IRC a different color"),0,0},
{ST_TOGGLR, N_("Indent nick names"), P_OFFINTNL(hex_text_indent), N_("Make nick names right-justified"),0,0}, {ST_TOGGLR, N_("Indent nick names"), P_OFFINTNL(hex_text_indent), N_("Make nick names right-justified"),0,0},
{ST_TOGGLE, N_ ("Show marker line"), P_OFFINTNL (hex_text_show_marker), N_ ("Insert a red line after the last read text."), 0, 0}, {ST_TOGGLE, N_ ("Show marker line"), P_OFFINTNL (hex_text_show_marker), N_ ("Insert a red line after the last read text."), 0, 0},
{ST_EFILE, N_ ("Background image:"), P_OFFSETNL (hex_text_background), 0, 0, sizeof prefs.hex_text_background},
{ST_HEADER, N_("Transparency Settings"), 0,0,0},
{ST_HSCALE, N_("Window opacity:"), P_OFFINTNL(hex_gui_transparency),0,0,0},
{ST_HEADER, N_("Timestamps"),0,0,0}, {ST_HEADER, N_("Timestamps"),0,0,0},
{ST_TOGGLE, N_("Enable timestamps"), P_OFFINTNL(hex_stamp_text),0,0,1}, {ST_TOGGLE, N_("Enable timestamps"), P_OFFINTNL(hex_stamp_text),0,0,1},
@@ -183,6 +179,15 @@ static const setting appearance_settings[] =
{ST_END, 0, 0, 0, 0, 0} {ST_END, 0, 0, 0, 0, 0}
}; };
static const setting appearance_advanced_settings[] =
{
{ST_HEADER, N_("Advanced"),0,0,0},
{ST_EFILE, N_ ("Background image:"), P_OFFSETNL (hex_text_background), 0, 0, sizeof prefs.hex_text_background},
{ST_HSCALE, N_("Window opacity:"), P_OFFINTNL(hex_gui_transparency),0,0,0},
{ST_END, 0, 0, 0, 0, 0}
};
static const char *const tabcompmenu[] = static const char *const tabcompmenu[] =
{ {
N_("A-Z"), N_("A-Z"),
@@ -1141,22 +1146,64 @@ setup_filereq_cb (GtkWidget *entry, char *file)
} }
} }
static void
setup_browsefile_response_cb (GtkNativeDialog *dialog, gint response, gpointer user_data)
{
GtkWidget *entry = user_data;
if (response == GTK_RESPONSE_ACCEPT)
{
char *file = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
setup_filereq_cb (entry, file);
g_free (file);
}
g_object_unref (dialog);
}
static void static void
setup_browsefile_cb (GtkWidget *button, GtkWidget *entry) setup_browsefile_cb (GtkWidget *button, GtkWidget *entry)
{ {
/* used for background image only */ GtkFileChooserNative *dialog;
char *filter; GtkFileFilter *filefilter;
int filter_type; const char *current;
char *dirname;
(void)button;
dialog = gtk_file_chooser_native_new (_("Select an Image File"),
GTK_WINDOW (setup_window),
GTK_FILE_CHOOSER_ACTION_OPEN,
_("_Open"),
_("_Cancel"));
gtk_native_dialog_set_modal (GTK_NATIVE_DIALOG (dialog), TRUE);
current = gtk_entry_get_text (GTK_ENTRY (entry));
if (current && current[0])
{
dirname = g_path_get_dirname (current);
if (dirname && dirname[0] && g_file_test (dirname, G_FILE_TEST_IS_DIR))
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), dirname);
else if (g_file_test (current, G_FILE_TEST_IS_DIR))
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), current);
g_free (dirname);
}
filefilter = gtk_file_filter_new ();
#ifdef WIN32 #ifdef WIN32
filter = "*png;*.tiff;*.gif;*.jpeg;*.jpg"; gtk_file_filter_add_pattern (filefilter, "*.png");
filter_type = FRF_EXTENSIONS; gtk_file_filter_add_pattern (filefilter, "*.tiff");
gtk_file_filter_add_pattern (filefilter, "*.gif");
gtk_file_filter_add_pattern (filefilter, "*.jpeg");
gtk_file_filter_add_pattern (filefilter, "*.jpg");
#else #else
filter = "image/*"; gtk_file_filter_add_mime_type (filefilter, "image/*");
filter_type = FRF_MIMETYPES;
#endif #endif
gtkutil_file_req (GTK_WINDOW (setup_window), _("Select an Image File"), setup_filereq_cb, gtk_file_filter_set_name (filefilter, _("Images"));
entry, NULL, filter, filter_type|FRF_RECENTLYUSED|FRF_MODAL); gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dialog), filefilter);
g_signal_connect (G_OBJECT (dialog), "response",
G_CALLBACK (setup_browsefile_response_cb), entry);
gtk_native_dialog_show (GTK_NATIVE_DIALOG (dialog));
} }
@@ -1442,6 +1489,41 @@ setup_create_theme_page (void)
&color_change); &color_change);
} }
static GtkWidget *
setup_create_appearance_page (void)
{
GtkWidget *box;
GtkWidget *appearance_page;
GtkWidget *theme_label;
GtkWidget *theme_page;
GtkWidget *advanced_page;
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
appearance_page = setup_create_page (appearance_settings);
theme_label = gtk_label_new (NULL);
theme_page = setup_create_theme_page ();
advanced_page = setup_create_page (appearance_advanced_settings);
{
char *markup = g_markup_printf_escaped ("<b>%s</b>", _("GTK3 Theme"));
gtk_label_set_markup (GTK_LABEL (theme_label), markup);
g_free (markup);
}
gtk_widget_set_halign (theme_label, GTK_ALIGN_START);
gtk_widget_set_valign (theme_label, GTK_ALIGN_CENTER);
gtk_widget_set_margin_start (theme_label, 2);
gtk_widget_set_margin_end (theme_label, 2);
gtk_widget_set_margin_top (theme_label, 1);
gtk_widget_set_margin_bottom (theme_label, 1);
gtk_box_pack_start (GTK_BOX (box), appearance_page, FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (box), theme_label, FALSE, FALSE, 2);
gtk_box_pack_start (GTK_BOX (box), theme_page, FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (box), advanced_page, FALSE, FALSE, 0);
return box;
}
/* === GLOBALS for sound GUI === */ /* === GLOBALS for sound GUI === */
static GtkWidget *sndfile_entry; static GtkWidget *sndfile_entry;
@@ -1729,7 +1811,6 @@ static const char *const cata_interface[] =
N_("Input box"), N_("Input box"),
N_("User list"), N_("User list"),
N_("Channel switcher"), N_("Channel switcher"),
N_("GTK3 Theme"),
NULL NULL
}; };
@@ -1755,15 +1836,15 @@ static GtkWidget *
setup_create_pages (GtkWidget *box) setup_create_pages (GtkWidget *box)
{ {
GtkWidget *book; GtkWidget *book;
GtkWindow *win = GTK_WINDOW(gtk_widget_get_toplevel (box)); GtkWindow *win = GTK_WINDOW (setup_window);
(void)box;
book = gtk_notebook_new (); book = gtk_notebook_new ();
setup_add_page (cata_interface[0], book, setup_create_page (appearance_settings)); setup_add_page (cata_interface[0], book, setup_create_appearance_page ());
setup_add_page (cata_interface[1], book, setup_create_page (inputbox_settings)); setup_add_page (cata_interface[1], book, setup_create_page (inputbox_settings));
setup_add_page (cata_interface[2], book, setup_create_page (userlist_settings)); setup_add_page (cata_interface[2], book, setup_create_page (userlist_settings));
setup_add_page (cata_interface[3], book, setup_create_page (tabs_settings)); setup_add_page (cata_interface[3], book, setup_create_page (tabs_settings));
setup_add_page (cata_interface[4], book, setup_create_theme_page ());
setup_add_page (cata_chatting[0], book, setup_create_page (general_settings)); setup_add_page (cata_chatting[0], book, setup_create_page (general_settings));
@@ -2124,6 +2205,7 @@ setup_window_open (void)
g_snprintf(buf, sizeof(buf), _("Preferences - %s"), _(DISPLAY_NAME)); g_snprintf(buf, sizeof(buf), _("Preferences - %s"), _(DISPLAY_NAME));
win = gtkutil_window_new (buf, "prefs", 0, 600, 2); win = gtkutil_window_new (buf, "prefs", 0, 600, 2);
setup_window = win;
vbox = gtkutil_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 5); vbox = gtkutil_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 5);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 6); gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);

View File

@@ -689,12 +689,15 @@ settings_apply_from_file (const char *theme_root, const char *css_dir)
for (i = 0; keys && i < n_keys; i++) for (i = 0; keys && i < n_keys; i++)
{ {
char *raw_value; char *raw_value;
char *value;
raw_value = g_key_file_get_value (keyfile, "Settings", keys[i], NULL); raw_value = g_key_file_get_value (keyfile, "Settings", keys[i], NULL);
if (!raw_value) if (!raw_value)
continue; continue;
settings_apply_property (settings, keys[i], raw_value); value = g_strstrip (raw_value);
if (value[0] != '\0')
settings_apply_property (settings, keys[i], value);
g_free (raw_value); g_free (raw_value);
} }

View File

@@ -364,20 +364,30 @@ xtext_draw_bg_offset (GtkXText *xtext, int x, int y, int width, int height, int
if (xtext->background_surface) if (xtext->background_surface)
{ {
int clip_x = xtext->clip_x; GtkAllocation allocation;
int clip_y = xtext->clip_y; int clip_x;
int clip_w = xtext->clip_x2 - xtext->clip_x; int clip_y;
int clip_h = xtext->clip_y2 - xtext->clip_y; int clip_w;
int clip_h;
if (clip_w < 1 || clip_h < 1) if (cairo_surface_status (xtext->background_surface) != CAIRO_STATUS_SUCCESS)
{ {
GtkAllocation allocation; xtext_draw_rectangle (xtext, cr, &xtext->bgc, x, y, width, height);
cairo_destroy (cr);
return;
}
gtk_widget_get_allocation (GTK_WIDGET (xtext), &allocation); gtk_widget_get_allocation (GTK_WIDGET (xtext), &allocation);
clip_x = 0; clip_x = 0;
clip_y = 0; clip_y = 0;
clip_w = allocation.width; clip_w = allocation.width;
clip_h = allocation.height; clip_h = allocation.height;
if (clip_w < 1 || clip_h < 1 || clip_w > 8192 || clip_h > 8192)
{
xtext_draw_rectangle (xtext, cr, &xtext->bgc, x, y, width, height);
cairo_destroy (cr);
return;
} }
if (xtext->background_clip_surface == NULL || if (xtext->background_clip_surface == NULL ||
@@ -396,11 +406,54 @@ xtext_draw_bg_offset (GtkXText *xtext, int x, int y, int width, int height, int
} }
xtext->background_clip_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, clip_w, clip_h); xtext->background_clip_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, clip_w, clip_h);
if (cairo_surface_status (xtext->background_clip_surface) != CAIRO_STATUS_SUCCESS)
{
cairo_surface_destroy (xtext->background_clip_surface);
xtext->background_clip_surface = NULL;
xtext_draw_rectangle (xtext, cr, &xtext->bgc, x, y, width, height);
cairo_destroy (cr);
return;
}
bg_cr = cairo_create (xtext->background_clip_surface); bg_cr = cairo_create (xtext->background_clip_surface);
cairo_set_source_surface (bg_cr, xtext->background_surface, tile_x - clip_x, tile_y - clip_y); if (cairo_surface_get_type (xtext->background_surface) == CAIRO_SURFACE_TYPE_IMAGE)
cairo_pattern_set_extend (cairo_get_source (bg_cr), CAIRO_EXTEND_REPEAT); {
cairo_rectangle (bg_cr, 0.0, 0.0, (double)clip_w, (double)clip_h); int src_w = cairo_image_surface_get_width (xtext->background_surface);
cairo_fill (bg_cr); int src_h = cairo_image_surface_get_height (xtext->background_surface);
if (src_w > 0 && src_h > 0)
{
double scale_x = (double)clip_w / (double)src_w;
double scale_y = (double)clip_h / (double)src_h;
double scale = scale_x < scale_y ? scale_x : scale_y;
double draw_w = src_w * scale;
double draw_h = src_h * scale;
double draw_x = ((double)clip_w - draw_w) / 2.0;
double draw_y = ((double)clip_h - draw_h) / 2.0;
cairo_set_source_rgb (bg_cr, 0.0, 0.0, 0.0);
cairo_paint (bg_cr);
cairo_save (bg_cr);
cairo_translate (bg_cr, draw_x, draw_y);
cairo_scale (bg_cr, scale, scale);
cairo_set_source_surface (bg_cr, xtext->background_surface, 0.0, 0.0);
cairo_pattern_set_extend (cairo_get_source (bg_cr), CAIRO_EXTEND_NONE);
cairo_rectangle (bg_cr, 0.0, 0.0, (double)src_w, (double)src_h);
cairo_fill (bg_cr);
cairo_restore (bg_cr);
}
else
{
cairo_set_source_surface (bg_cr, xtext->background_surface, tile_x - clip_x, tile_y - clip_y);
cairo_pattern_set_extend (cairo_get_source (bg_cr), CAIRO_EXTEND_REPEAT);
cairo_rectangle (bg_cr, 0.0, 0.0, (double)clip_w, (double)clip_h);
cairo_fill (bg_cr);
}
}
else
{
cairo_set_source_surface (bg_cr, xtext->background_surface, tile_x - clip_x, tile_y - clip_y);
cairo_pattern_set_extend (cairo_get_source (bg_cr), CAIRO_EXTEND_REPEAT);
cairo_rectangle (bg_cr, 0.0, 0.0, (double)clip_w, (double)clip_h);
cairo_fill (bg_cr);
}
cairo_destroy (bg_cr); cairo_destroy (bg_cr);
xtext->background_clip_x = clip_x; xtext->background_clip_x = clip_x;