/* GIMP - The GNU Image Manipulation Program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "config.h" #include #include #include #include "libgimpwidgets/gimpwidgets.h" #include "libgimpbase/gimpbase.h" #include "display-types.h" #include "config/gimpdisplayconfig.h" #include "core/gimpcontainer.h" #include "core/gimpdrawable.h" #include "core/gimpimage.h" #include "core/gimpitem.h" #include "core/gimpunit.h" #include "file/file-utils.h" #include "file/gimp-file.h" #include "gimpdisplay.h" #include "gimpdisplayshell.h" #include "gimpdisplayshell-title.h" #include "gimpstatusbar.h" #include "about.h" #include "gimp-intl.h" #define MAX_TITLE_BUF 512 static gboolean gimp_display_shell_update_title_idle (gpointer data); static gint gimp_display_shell_format_title (GimpDisplayShell *display, gchar *title, gint title_len, const gchar *format); static gint gimp_display_shell_format_filename (gchar *buf, gint len, gint start, GimpImage *image, const gchar *filename); /* public functions */ void gimp_display_shell_title_init (GimpDisplayShell *shell) { } void gimp_display_shell_title_update (GimpDisplayShell *shell) { g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); if (shell->title_idle_id) g_source_remove (shell->title_idle_id); shell->title_idle_id = g_idle_add (gimp_display_shell_update_title_idle, shell); } /* private functions */ static gboolean gimp_display_shell_update_title_idle (gpointer data) { GimpDisplayShell *shell = GIMP_DISPLAY_SHELL (data); shell->title_idle_id = 0; if (shell->display->image) { GimpDisplayConfig *config = shell->display->config; gchar title[MAX_TITLE_BUF]; gint len; /* format the title */ len = gimp_display_shell_format_title (shell, title, sizeof (title), config->image_title_format); if (len) /* U+2013 EN DASH */ len += g_strlcpy (title + len, " \342\200\223 ", sizeof (title) - len); g_strlcpy (title + len, GIMP_ACRONYM, sizeof (title) - len); gtk_window_set_title (GTK_WINDOW (shell), title); /* format the statusbar */ gimp_display_shell_format_title (shell, title, sizeof (title), config->image_status_format); gimp_statusbar_replace (GIMP_STATUSBAR (shell->statusbar), "title", NULL, "%s", title); } else { gtk_window_set_title (GTK_WINDOW (shell), GIMP_NAME); gimp_statusbar_replace (GIMP_STATUSBAR (shell->statusbar), "title", NULL, " "); } return FALSE; } static const gchar * gimp_display_shell_title_image_type (GimpImage *image) { const gchar *name = ""; gimp_enum_get_value (GIMP_TYPE_IMAGE_BASE_TYPE, gimp_image_base_type (image), NULL, NULL, &name, NULL); return name; } static const gchar * gimp_display_shell_title_drawable_type (GimpDrawable *drawable) { const gchar *name = ""; gimp_enum_get_value (GIMP_TYPE_IMAGE_TYPE, gimp_drawable_type (drawable), NULL, NULL, &name, NULL); return name; } static gint print (gchar *buf, gint len, gint start, const gchar *fmt, ...) G_GNUC_PRINTF (4, 5); static gint print (gchar *buf, gint len, gint start, const gchar *fmt, ...) { va_list args; gint printed; va_start (args, fmt); printed = g_vsnprintf (buf + start, len - start, fmt, args); if (printed < 0) printed = len - start; va_end (args); return printed; } static gint gimp_display_shell_format_title (GimpDisplayShell *shell, gchar *title, gint title_len, const gchar *format) { Gimp *gimp; GimpImage *image; gint num, denom; gint i = 0; g_return_val_if_fail (GIMP_IS_DISPLAY_SHELL (shell), 0); image = shell->display->image; gimp = shell->display->gimp; if (! image) { title[0] = '\n'; return 0; } gimp_zoom_model_get_fraction (shell->zoom, &num, &denom); while (i < title_len && *format) { switch (*format) { case '%': format++; switch (*format) { case 0: /* format string ends within %-sequence, print literal '%' */ case '%': title[i++] = '%'; break; case 'f': /* base filename */ { const gchar *name = gimp_image_get_display_name (image); i += gimp_display_shell_format_filename (title, title_len, i, image, name); } break; case 'F': /* full filename */ { gchar *filename; const gchar *uri = gimp_image_get_uri (image); filename = file_utils_uri_display_name (uri); i += gimp_display_shell_format_filename (title, title_len, i, image, filename); g_free (filename); } break; case 'p': /* PDB id */ i += print (title, title_len, i, "%d", gimp_image_get_ID (image)); break; case 'i': /* instance */ i += print (title, title_len, i, "%d", shell->display->instance); break; case 't': /* image type */ i += print (title, title_len, i, "%s", gimp_display_shell_title_image_type (image)); break; case 'T': /* drawable type */ { GimpDrawable *drawable = gimp_image_get_active_drawable (image); if (drawable) i += print (title, title_len, i, "%s", gimp_display_shell_title_drawable_type (drawable)); } break; case 's': /* user source zoom factor */ i += print (title, title_len, i, "%d", denom); break; case 'd': /* user destination zoom factor */ i += print (title, title_len, i, "%d", num); break; case 'z': /* user zoom factor (percentage) */ { gdouble scale = gimp_zoom_model_get_factor (shell->zoom); i += print (title, title_len, i, scale >= 0.15 ? "%.0f" : "%.2f", 100.0 * scale); } break; case 'D': /* dirty flag */ if (format[1] == 0) { /* format string ends within %D-sequence, print literal '%D' */ i += print (title, title_len, i, "%%D"); break; } if (gimp_image_is_dirty (image)) title[i++] = format[1]; format++; break; case 'C': /* clean flag */ if (format[1] == 0) { /* format string ends within %C-sequence, print literal '%C' */ i += print (title, title_len, i, "%%C"); break; } if (! gimp_image_is_dirty (image)) title[i++] = format[1]; format++; break; case 'B': /* dirty flag (long) */ if (gimp_image_is_dirty (image)) i += print (title, title_len, i, "%s", _("(modified)")); break; case 'A': /* clean flag (long) */ if (! gimp_image_is_dirty (image)) i += print (title, title_len, i, "%s", _("(clean)")); break; case 'm': /* memory used by image */ { GimpObject *object = GIMP_OBJECT (image); gchar *str; str = g_format_size_for_display (gimp_object_get_memsize (object, NULL)); i += print (title, title_len, i, "%s", str); g_free (str); } break; case 'l': /* number of layers */ i += print (title, title_len, i, "%d", gimp_image_get_n_layers (image)); break; case 'L': /* number of layers (long) */ { gint num = gimp_image_get_n_layers (image); i += print (title, title_len, i, ngettext ("%d layer", "%d layers", num), num); } break; case 'n': /* active drawable name */ { GimpDrawable *drawable = gimp_image_get_active_drawable (image); if (drawable) { gchar *desc; desc = gimp_viewable_get_description (GIMP_VIEWABLE (drawable), NULL); i += print (title, title_len, i, "%s", desc); g_free (desc); } else { i += print (title, title_len, i, "%s", _("(none)")); } } break; case 'P': /* active drawable PDB id */ { GimpDrawable *drawable = gimp_image_get_active_drawable (image); if (drawable) i += print (title, title_len, i, "%d", gimp_item_get_ID (GIMP_ITEM (drawable))); else i += print (title, title_len, i, "%s", _("(none)")); } break; case 'W': /* width in real-world units */ if (shell->unit != GIMP_UNIT_PIXEL) { gdouble xres; gdouble yres; gchar unit_format[8]; gimp_image_get_resolution (image, &xres, &yres); g_snprintf (unit_format, sizeof (unit_format), "%%.%df", _gimp_unit_get_digits (gimp, shell->unit) + 1); i += print (title, title_len, i, unit_format, (gimp_image_get_width (image) * _gimp_unit_get_factor (gimp, shell->unit) / xres)); break; } /* else fallthru */ case 'w': /* width in pixels */ i += print (title, title_len, i, "%d", gimp_image_get_width (image)); break; case 'H': /* height in real-world units */ if (shell->unit != GIMP_UNIT_PIXEL) { gdouble xres; gdouble yres; gchar unit_format[8]; gimp_image_get_resolution (image, &xres, &yres); g_snprintf (unit_format, sizeof (unit_format), "%%.%df", _gimp_unit_get_digits (gimp, shell->unit) + 1); i += print (title, title_len, i, unit_format, (gimp_image_get_height (image) * _gimp_unit_get_factor (gimp, shell->unit) / yres)); break; } /* else fallthru */ case 'h': /* height in pixels */ i += print (title, title_len, i, "%d", gimp_image_get_height (image)); break; case 'u': /* unit symbol */ i += print (title, title_len, i, "%s", _gimp_unit_get_symbol (gimp, shell->unit)); break; case 'U': /* unit abbreviation */ i += print (title, title_len, i, "%s", _gimp_unit_get_abbreviation (gimp, shell->unit)); break; /* Other cool things to be added: * %r = xresolution * %R = yresolution * %ø = image's fractal dimension * %þ = the answer to everything */ default: /* format string contains unknown %-sequence, print it literally */ i += print (title, title_len, i, "%%%c", *format); break; } break; default: title[i++] = *format; break; } format++; } title[MIN (i, title_len - 1)] = '\0'; return i; } static gint gimp_display_shell_format_filename (gchar *buf, gint len, gint start, GimpImage *image, const gchar *filename) { const gchar *source = NULL; const gchar *name_format = NULL; const gchar *export_status = NULL; gchar *format_string = NULL; gchar *name = NULL; gboolean is_imported = FALSE; gint incr = 0; source = g_object_get_data (G_OBJECT (image), GIMP_FILE_IMPORT_SOURCE_URI_KEY); /* Note that as soon as the image is saved, it is not considered * imported any longer (GIMP_FILE_IMPORT_SOURCE_URI_KEY is set to * NULL) */ is_imported = (source != NULL); /* Calculate filename and format */ if (! is_imported) { name = g_strdup (filename); name_format = "%s"; } else { gchar *source_no_ext = file_utils_uri_with_new_ext (source, NULL); name = file_utils_uri_display_basename (source_no_ext); g_free (source_no_ext); name_format = "[%s]"; } /* Calculate filename suffix */ if (! gimp_image_is_export_dirty (image)) { gboolean is_exported; is_exported = (g_object_get_data (G_OBJECT (image), GIMP_FILE_EXPORT_TO_URI_KEY) != NULL); if (is_exported) export_status = _(" (exported)"); else if (is_imported) export_status = _(" (overwritten)"); else g_warning ("Unexpected code path, Save+export implementation is buggy!"); } else if (is_imported) { export_status = _(" (imported)"); } /* Merge strings and print the result */ format_string = g_strconcat (name_format, export_status, NULL); incr = print (buf, len, start, format_string, name); g_free (format_string); /* Cleanup */ g_free (name); return incr; }