diff --git a/src/fe-gtk/pixmaps.c b/src/fe-gtk/pixmaps.c index f786670b..7b506065 100644 --- a/src/fe-gtk/pixmaps.c +++ b/src/fe-gtk/pixmaps.c @@ -118,11 +118,43 @@ pixmap_load_from_file_real (char *file) { GdkPixbuf *img; cairo_surface_t *surface; + int width; + int height; + const int max_dimension = 4096; img = gdk_pixbuf_new_from_file (file, 0); if (!img) 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); g_object_unref (img); diff --git a/src/fe-gtk/setup.c b/src/fe-gtk/setup.c index 37554c23..9d015e80 100644 --- a/src/fe-gtk/setup.c +++ b/src/fe-gtk/setup.c @@ -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_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_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_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} }; +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[] = { 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 setup_browsefile_cb (GtkWidget *button, GtkWidget *entry) { - /* used for background image only */ - char *filter; - int filter_type; + GtkFileChooserNative *dialog; + GtkFileFilter *filefilter; + 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 - filter = "*png;*.tiff;*.gif;*.jpeg;*.jpg"; - filter_type = FRF_EXTENSIONS; + gtk_file_filter_add_pattern (filefilter, "*.png"); + 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 - filter = "image/*"; - filter_type = FRF_MIMETYPES; + gtk_file_filter_add_mime_type (filefilter, "image/*"); #endif - gtkutil_file_req (GTK_WINDOW (setup_window), _("Select an Image File"), setup_filereq_cb, - entry, NULL, filter, filter_type|FRF_RECENTLYUSED|FRF_MODAL); + gtk_file_filter_set_name (filefilter, _("Images")); + 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); } +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 ("%s", _("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 === */ static GtkWidget *sndfile_entry; @@ -1729,7 +1811,6 @@ static const char *const cata_interface[] = N_("Input box"), N_("User list"), N_("Channel switcher"), - N_("GTK3 Theme"), NULL }; @@ -1755,15 +1836,15 @@ static GtkWidget * setup_create_pages (GtkWidget *box) { GtkWidget *book; - GtkWindow *win = GTK_WINDOW(gtk_widget_get_toplevel (box)); + GtkWindow *win = GTK_WINDOW (setup_window); + (void)box; 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[2], book, setup_create_page (userlist_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)); @@ -2124,6 +2205,7 @@ setup_window_open (void) g_snprintf(buf, sizeof(buf), _("Preferences - %s"), _(DISPLAY_NAME)); win = gtkutil_window_new (buf, "prefs", 0, 600, 2); + setup_window = win; vbox = gtkutil_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 5); gtk_container_set_border_width (GTK_CONTAINER (vbox), 6); diff --git a/src/fe-gtk/theme/theme-gtk3.c b/src/fe-gtk/theme/theme-gtk3.c index 5d31a435..847e7ded 100644 --- a/src/fe-gtk/theme/theme-gtk3.c +++ b/src/fe-gtk/theme/theme-gtk3.c @@ -689,12 +689,15 @@ settings_apply_from_file (const char *theme_root, const char *css_dir) for (i = 0; keys && i < n_keys; i++) { char *raw_value; + char *value; raw_value = g_key_file_get_value (keyfile, "Settings", keys[i], NULL); if (!raw_value) 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); } diff --git a/src/fe-gtk/xtext.c b/src/fe-gtk/xtext.c index 4229651b..448e3ace 100644 --- a/src/fe-gtk/xtext.c +++ b/src/fe-gtk/xtext.c @@ -364,20 +364,30 @@ xtext_draw_bg_offset (GtkXText *xtext, int x, int y, int width, int height, int if (xtext->background_surface) { - int clip_x = xtext->clip_x; - int clip_y = xtext->clip_y; - int clip_w = xtext->clip_x2 - xtext->clip_x; - int clip_h = xtext->clip_y2 - xtext->clip_y; + GtkAllocation allocation; + int clip_x; + int 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); - clip_x = 0; - clip_y = 0; - clip_w = allocation.width; - clip_h = allocation.height; + gtk_widget_get_allocation (GTK_WIDGET (xtext), &allocation); + clip_x = 0; + clip_y = 0; + clip_w = allocation.width; + 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 || @@ -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); + 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); - 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); + if (cairo_surface_get_type (xtext->background_surface) == CAIRO_SURFACE_TYPE_IMAGE) + { + int src_w = cairo_image_surface_get_width (xtext->background_surface); + 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); xtext->background_clip_x = clip_x;