1 /* LIBGIMP - The GIMP Library
2  * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
3  *
4  * gimppageselector.c
5  * Copyright (C) 2005 Michael Natterer <mitch@gimp.org>
6  *
7  * This library is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 3 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library.  If not, see
19  * <https://www.gnu.org/licenses/>.
20  */
21 
22 #include "config.h"
23 
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #include <gegl.h>
28 #include <gtk/gtk.h>
29 
30 #include "gimpwidgetstypes.h"
31 
32 #include "gimpicons.h"
33 #include "gimppageselector.h"
34 #include "gimppropwidgets.h"
35 #include "gimpwidgets.h"
36 #include "gimp3migration.h"
37 
38 #include "libgimp/libgimp-intl.h"
39 
40 
41 /**
42  * SECTION: gimppageselector
43  * @title: GimpPageSelector
44  * @short_description: A widget to select pages from multi-page things.
45  *
46  * Use this for example for specifying what pages to import from
47  * a PDF or PS document.
48  **/
49 
50 
51 enum
52 {
53   SELECTION_CHANGED,
54   ACTIVATE,
55   LAST_SIGNAL
56 };
57 
58 enum
59 {
60   PROP_0,
61   PROP_N_PAGES,
62   PROP_TARGET
63 };
64 
65 enum
66 {
67   COLUMN_PAGE_NO,
68   COLUMN_THUMBNAIL,
69   COLUMN_LABEL,
70   COLUMN_LABEL_SET
71 };
72 
73 
74 typedef struct
75 {
76   gint                    n_pages;
77   GimpPageSelectorTarget  target;
78 
79   GtkListStore           *store;
80   GtkWidget              *view;
81 
82   GtkWidget              *count_label;
83   GtkWidget              *range_entry;
84 
85   GdkPixbuf              *default_thumbnail;
86 } GimpPageSelectorPrivate;
87 
88 #define GIMP_PAGE_SELECTOR_GET_PRIVATE(obj) \
89   ((GimpPageSelectorPrivate *) ((GimpPageSelector *) (obj))->priv)
90 
91 
92 static void   gimp_page_selector_finalize          (GObject          *object);
93 static void   gimp_page_selector_get_property      (GObject          *object,
94                                                     guint             property_id,
95                                                     GValue           *value,
96                                                     GParamSpec       *pspec);
97 static void   gimp_page_selector_set_property      (GObject          *object,
98                                                     guint             property_id,
99                                                     const GValue     *value,
100                                                     GParamSpec       *pspec);
101 
102 static void   gimp_page_selector_selection_changed (GtkIconView      *icon_view,
103                                                     GimpPageSelector *selector);
104 static void   gimp_page_selector_item_activated    (GtkIconView      *icon_view,
105                                                     GtkTreePath      *path,
106                                                     GimpPageSelector *selector);
107 static gboolean gimp_page_selector_range_focus_out (GtkEntry         *entry,
108                                                     GdkEventFocus    *fevent,
109                                                     GimpPageSelector *selector);
110 static void   gimp_page_selector_range_activate    (GtkEntry         *entry,
111                                                     GimpPageSelector *selector);
112 static gint   gimp_page_selector_int_compare       (gconstpointer     a,
113                                                     gconstpointer     b);
114 static void   gimp_page_selector_print_range       (GString          *string,
115                                                     gint              start,
116                                                     gint              end);
117 
118 static GdkPixbuf * gimp_page_selector_add_frame    (GtkWidget        *widget,
119                                                     GdkPixbuf        *pixbuf);
120 
121 
122 G_DEFINE_TYPE_WITH_PRIVATE (GimpPageSelector, gimp_page_selector, GTK_TYPE_BOX)
123 
124 #define parent_class gimp_page_selector_parent_class
125 
126 static guint selector_signals[LAST_SIGNAL] = { 0 };
127 
128 
129 static void
gimp_page_selector_class_init(GimpPageSelectorClass * klass)130 gimp_page_selector_class_init (GimpPageSelectorClass *klass)
131 {
132   GObjectClass   *object_class = G_OBJECT_CLASS (klass);
133   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
134 
135   object_class->finalize     = gimp_page_selector_finalize;
136   object_class->get_property = gimp_page_selector_get_property;
137   object_class->set_property = gimp_page_selector_set_property;
138 
139   klass->selection_changed   = NULL;
140   klass->activate            = NULL;
141 
142   /**
143    * GimpPageSelector::selection-changed:
144    * @widget: the object which received the signal.
145    *
146    * This signal is emitted whenever the set of selected pages changes.
147    *
148    * Since: 2.4
149    **/
150   selector_signals[SELECTION_CHANGED] =
151     g_signal_new ("selection-changed",
152                   G_TYPE_FROM_CLASS (klass),
153                   G_SIGNAL_RUN_FIRST,
154                   G_STRUCT_OFFSET (GimpPageSelectorClass, selection_changed),
155                   NULL, NULL,
156                   g_cclosure_marshal_VOID__VOID,
157                   G_TYPE_NONE, 0);
158 
159   /**
160    * GimpPageSelector::activate:
161    * @widget: the object which received the signal.
162    *
163    * The "activate" signal on GimpPageSelector is an action signal. It
164    * is emitted when a user double-clicks an item in the page selection.
165    *
166    * Since: 2.4
167    */
168   selector_signals[ACTIVATE] =
169     g_signal_new ("activate",
170                   G_OBJECT_CLASS_TYPE (object_class),
171                   G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
172                   G_STRUCT_OFFSET (GimpPageSelectorClass, activate),
173                   NULL, NULL,
174                   g_cclosure_marshal_VOID__VOID,
175                   G_TYPE_NONE, 0);
176   widget_class->activate_signal = selector_signals[ACTIVATE];
177 
178   /**
179    * GimpPageSelector:n-pages:
180    *
181    * The number of pages of the document to open.
182    *
183    * Since: 2.4
184    **/
185   g_object_class_install_property (object_class, PROP_N_PAGES,
186                                    g_param_spec_int ("n-pages",
187                                                      "N Pages",
188                                                      "The number of pages to open",
189                                                      0, G_MAXINT, 0,
190                                                      GIMP_PARAM_READWRITE));
191 
192   /**
193    * GimpPageSelector:target:
194    *
195    * The target to open the document to.
196    *
197    * Since: 2.4
198    **/
199   g_object_class_install_property (object_class, PROP_TARGET,
200                                    g_param_spec_enum ("target",
201                                                       "Target",
202                                                       "the target to open to",
203                                                       GIMP_TYPE_PAGE_SELECTOR_TARGET,
204                                                       GIMP_PAGE_SELECTOR_TARGET_LAYERS,
205                                                       GIMP_PARAM_READWRITE));
206 }
207 
208 static void
gimp_page_selector_init(GimpPageSelector * selector)209 gimp_page_selector_init (GimpPageSelector *selector)
210 {
211   GimpPageSelectorPrivate *priv;
212   GtkWidget               *vbox;
213   GtkWidget               *sw;
214   GtkWidget               *hbox;
215   GtkWidget               *hbbox;
216   GtkWidget               *button;
217   GtkWidget               *label;
218   GtkWidget               *combo;
219 
220   selector->priv = gimp_page_selector_get_instance_private (selector);
221 
222   priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
223 
224   priv->n_pages = 0;
225   priv->target  = GIMP_PAGE_SELECTOR_TARGET_LAYERS;
226 
227   gtk_orientable_set_orientation (GTK_ORIENTABLE (selector),
228                                   GTK_ORIENTATION_VERTICAL);
229 
230   gtk_box_set_spacing (GTK_BOX (selector), 12);
231 
232   /*  Pages  */
233 
234   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
235   gtk_box_pack_start (GTK_BOX (selector), vbox, TRUE, TRUE, 0);
236   gtk_widget_show (vbox);
237 
238   sw = gtk_scrolled_window_new (NULL, NULL);
239   gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_IN);
240   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
241                                   GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
242   gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
243   gtk_widget_show (sw);
244 
245   priv->store = gtk_list_store_new (4,
246                                     G_TYPE_INT,
247                                     GDK_TYPE_PIXBUF,
248                                     G_TYPE_STRING,
249                                     G_TYPE_BOOLEAN);
250 
251   priv->view = gtk_icon_view_new_with_model (GTK_TREE_MODEL (priv->store));
252   gtk_icon_view_set_text_column (GTK_ICON_VIEW (priv->view),
253                                  COLUMN_LABEL);
254   gtk_icon_view_set_pixbuf_column (GTK_ICON_VIEW (priv->view),
255                                    COLUMN_THUMBNAIL);
256   gtk_icon_view_set_selection_mode (GTK_ICON_VIEW (priv->view),
257                                     GTK_SELECTION_MULTIPLE);
258   gtk_container_add (GTK_CONTAINER (sw), priv->view);
259   gtk_widget_show (priv->view);
260 
261   g_signal_connect (priv->view, "selection-changed",
262                     G_CALLBACK (gimp_page_selector_selection_changed),
263                     selector);
264   g_signal_connect (priv->view, "item-activated",
265                     G_CALLBACK (gimp_page_selector_item_activated),
266                     selector);
267 
268   /*  Count label  */
269 
270   priv->count_label = gtk_label_new (_("Nothing selected"));
271   gtk_label_set_xalign (GTK_LABEL (priv->count_label), 0.0);
272   gimp_label_set_attributes (GTK_LABEL (priv->count_label),
273                              PANGO_ATTR_STYLE, PANGO_STYLE_ITALIC,
274                              -1);
275   gtk_box_pack_start (GTK_BOX (vbox), priv->count_label, FALSE, FALSE, 0);
276   gtk_widget_show (priv->count_label);
277 
278   /*  Select all button & range entry  */
279 
280   hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
281   gtk_box_pack_start (GTK_BOX (selector), hbox, FALSE, FALSE, 0);
282   gtk_widget_show (hbox);
283 
284   hbbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
285   gtk_box_pack_start (GTK_BOX (hbox), hbbox, FALSE, FALSE, 0);
286   gtk_widget_show (hbbox);
287 
288   button = gtk_button_new_with_mnemonic (_("Select _All"));
289   gtk_box_pack_start (GTK_BOX (hbbox), button, FALSE, FALSE, 0);
290   gtk_widget_show (button);
291 
292   g_signal_connect_swapped (button, "clicked",
293                             G_CALLBACK (gimp_page_selector_select_all),
294                             selector);
295 
296   priv->range_entry = gtk_entry_new ();
297   gtk_widget_set_size_request (priv->range_entry, 80, -1);
298   gtk_box_pack_end (GTK_BOX (hbox), priv->range_entry, TRUE, TRUE, 0);
299   gtk_widget_show (priv->range_entry);
300 
301   g_signal_connect (priv->range_entry, "focus-out-event",
302                     G_CALLBACK (gimp_page_selector_range_focus_out),
303                     selector);
304   g_signal_connect (priv->range_entry, "activate",
305                     G_CALLBACK (gimp_page_selector_range_activate),
306                     selector);
307 
308   label = gtk_label_new_with_mnemonic (_("Select _range:"));
309   gtk_box_pack_end (GTK_BOX (hbox), label, FALSE, FALSE, 0);
310   gtk_widget_show (label);
311 
312   gtk_label_set_mnemonic_widget (GTK_LABEL (label), priv->range_entry);
313 
314   /*  Target combo  */
315 
316   hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
317   gtk_box_pack_start (GTK_BOX (selector), hbox, FALSE, FALSE, 0);
318   gtk_widget_show (hbox);
319 
320   label = gtk_label_new_with_mnemonic (_("Open _pages as"));
321   gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
322   gtk_widget_show (label);
323 
324   combo = gimp_prop_enum_combo_box_new (G_OBJECT (selector), "target", -1, -1);
325   gtk_box_pack_start (GTK_BOX (hbox), combo, FALSE, FALSE, 0);
326   gtk_widget_show (combo);
327 
328   gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
329 
330   priv->default_thumbnail =
331     gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
332                               "text-x-generic", 32, 0, NULL);
333 }
334 
335 static void
gimp_page_selector_finalize(GObject * object)336 gimp_page_selector_finalize (GObject *object)
337 {
338   GimpPageSelectorPrivate *priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (object);
339 
340   g_clear_object (&priv->default_thumbnail);
341 
342   G_OBJECT_CLASS (parent_class)->finalize (object);
343 }
344 
345 static void
gimp_page_selector_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)346 gimp_page_selector_get_property (GObject    *object,
347                                  guint       property_id,
348                                  GValue     *value,
349                                  GParamSpec *pspec)
350 {
351   GimpPageSelectorPrivate *priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (object);
352 
353   switch (property_id)
354     {
355     case PROP_N_PAGES:
356       g_value_set_int (value, priv->n_pages);
357       break;
358     case PROP_TARGET:
359       g_value_set_enum (value, priv->target);
360       break;
361     default:
362       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
363       break;
364     }
365 }
366 
367 static void
gimp_page_selector_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)368 gimp_page_selector_set_property (GObject      *object,
369                                  guint         property_id,
370                                  const GValue *value,
371                                  GParamSpec   *pspec)
372 {
373   GimpPageSelector        *selector = GIMP_PAGE_SELECTOR (object);
374   GimpPageSelectorPrivate *priv     = GIMP_PAGE_SELECTOR_GET_PRIVATE (object);
375 
376   switch (property_id)
377     {
378     case PROP_N_PAGES:
379       gimp_page_selector_set_n_pages (selector, g_value_get_int (value));
380       break;
381     case PROP_TARGET:
382       priv->target = g_value_get_enum (value);
383       break;
384     default:
385       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
386       break;
387     }
388 }
389 
390 
391 /*  public functions  */
392 
393 /**
394  * gimp_page_selector_new:
395  *
396  * Creates a new #GimpPageSelector widget.
397  *
398  * Returns: Pointer to the new #GimpPageSelector widget.
399  *
400  * Since: 2.4
401  **/
402 GtkWidget *
gimp_page_selector_new(void)403 gimp_page_selector_new (void)
404 {
405   return g_object_new (GIMP_TYPE_PAGE_SELECTOR, NULL);
406 }
407 
408 /**
409  * gimp_page_selector_set_n_pages:
410  * @selector: Pointer to a #GimpPageSelector.
411  * @n_pages:  The number of pages.
412  *
413  * Sets the number of pages in the document to open.
414  *
415  * Since: 2.4
416  **/
417 void
gimp_page_selector_set_n_pages(GimpPageSelector * selector,gint n_pages)418 gimp_page_selector_set_n_pages (GimpPageSelector *selector,
419                                 gint              n_pages)
420 {
421   GimpPageSelectorPrivate *priv;
422 
423   g_return_if_fail (GIMP_IS_PAGE_SELECTOR (selector));
424   g_return_if_fail (n_pages >= 0);
425 
426   priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
427 
428   if (n_pages != priv->n_pages)
429     {
430       GtkTreeIter iter;
431       gint        i;
432 
433       if (n_pages < priv->n_pages)
434         {
435           for (i = n_pages; i < priv->n_pages; i++)
436             {
437               gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (priv->store),
438                                              &iter, NULL, n_pages);
439               gtk_list_store_remove (priv->store, &iter);
440             }
441         }
442       else
443         {
444           for (i = priv->n_pages; i < n_pages; i++)
445             {
446               gchar *text;
447 
448               text = g_strdup_printf (_("Page %d"), i + 1);
449 
450               gtk_list_store_append (priv->store, &iter);
451               gtk_list_store_set (priv->store, &iter,
452                                   COLUMN_PAGE_NO,   i,
453                                   COLUMN_THUMBNAIL, priv->default_thumbnail,
454                                   COLUMN_LABEL,     text,
455                                   COLUMN_LABEL_SET, FALSE,
456                                   -1);
457 
458               g_free (text);
459             }
460         }
461 
462       priv->n_pages = n_pages;
463 
464       g_object_notify (G_OBJECT (selector), "n-pages");
465     }
466 }
467 
468 /**
469  * gimp_page_selector_get_n_pages:
470  * @selector: Pointer to a #GimpPageSelector.
471  *
472  * Returns: the number of pages in the document to open.
473  *
474  * Since: 2.4
475  **/
476 gint
gimp_page_selector_get_n_pages(GimpPageSelector * selector)477 gimp_page_selector_get_n_pages (GimpPageSelector *selector)
478 {
479   GimpPageSelectorPrivate *priv;
480 
481   g_return_val_if_fail (GIMP_IS_PAGE_SELECTOR (selector), 0);
482 
483   priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
484 
485   return priv->n_pages;
486 }
487 
488 /**
489  * gimp_page_selector_set_target:
490  * @selector: Pointer to a #GimpPageSelector.
491  * @target:   How to open the selected pages.
492  *
493  * Since: 2.4
494  **/
495 void
gimp_page_selector_set_target(GimpPageSelector * selector,GimpPageSelectorTarget target)496 gimp_page_selector_set_target (GimpPageSelector       *selector,
497                                GimpPageSelectorTarget  target)
498 {
499   GimpPageSelectorPrivate *priv;
500 
501   g_return_if_fail (GIMP_IS_PAGE_SELECTOR (selector));
502   g_return_if_fail (target <= GIMP_PAGE_SELECTOR_TARGET_IMAGES);
503 
504   priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
505 
506   if (target != priv->target)
507     {
508       priv->target = target;
509 
510       g_object_notify (G_OBJECT (selector), "target");
511     }
512 }
513 
514 /**
515  * gimp_page_selector_get_target:
516  * @selector: Pointer to a #GimpPageSelector.
517  *
518  * Returns: How the selected pages should be opened.
519  *
520  * Since: 2.4
521  **/
522 GimpPageSelectorTarget
gimp_page_selector_get_target(GimpPageSelector * selector)523 gimp_page_selector_get_target (GimpPageSelector *selector)
524 {
525   GimpPageSelectorPrivate *priv;
526 
527   g_return_val_if_fail (GIMP_IS_PAGE_SELECTOR (selector),
528                         GIMP_PAGE_SELECTOR_TARGET_LAYERS);
529 
530   priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
531 
532   return priv->target;
533 }
534 
535 /**
536  * gimp_page_selector_set_page_thumbnail:
537  * @selector: Pointer to a #GimpPageSelector.
538  * @page_no: The number of the page to set the thumbnail for.
539  * @thumbnail: The thumbnail pixbuf.
540  *
541  * Sets the thumbnail for given @page_no. A default "page" icon will
542  * be used if no page thumbnail is set.
543  *
544  * Since: 2.4
545  **/
546 void
gimp_page_selector_set_page_thumbnail(GimpPageSelector * selector,gint page_no,GdkPixbuf * thumbnail)547 gimp_page_selector_set_page_thumbnail (GimpPageSelector *selector,
548                                        gint              page_no,
549                                        GdkPixbuf        *thumbnail)
550 {
551   GimpPageSelectorPrivate *priv;
552   GtkTreeIter              iter;
553 
554   g_return_if_fail (GIMP_IS_PAGE_SELECTOR (selector));
555   g_return_if_fail (thumbnail == NULL || GDK_IS_PIXBUF (thumbnail));
556 
557   priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
558 
559   g_return_if_fail (page_no >= 0 && page_no < priv->n_pages);
560 
561   gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (priv->store),
562                                  &iter, NULL, page_no);
563 
564   if (! thumbnail)
565     {
566       thumbnail = g_object_ref (priv->default_thumbnail);
567     }
568   else
569     {
570       thumbnail = gimp_page_selector_add_frame (GTK_WIDGET (selector),
571                                                 thumbnail);
572     }
573 
574   gtk_list_store_set (priv->store, &iter,
575                       COLUMN_THUMBNAIL, thumbnail,
576                       -1);
577   g_clear_object (&thumbnail);
578 }
579 
580 /**
581  * gimp_page_selector_get_page_thumbnail:
582  * @selector: Pointer to a #GimpPageSelector.
583  * @page_no: The number of the page to get the thumbnail for.
584  *
585  * Returns: The page's thumbnail, or %NULL if none is set. The returned
586  *          pixbuf is owned by #GimpPageSelector and must not be
587  *          unref'ed when no longer needed.
588  *
589  * Since: 2.4
590  **/
591 GdkPixbuf *
gimp_page_selector_get_page_thumbnail(GimpPageSelector * selector,gint page_no)592 gimp_page_selector_get_page_thumbnail (GimpPageSelector *selector,
593                                        gint              page_no)
594 {
595   GimpPageSelectorPrivate *priv;
596   GdkPixbuf               *thumbnail;
597   GtkTreeIter              iter;
598 
599   g_return_val_if_fail (GIMP_IS_PAGE_SELECTOR (selector), NULL);
600 
601   priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
602 
603   g_return_val_if_fail (page_no >= 0 && page_no < priv->n_pages, NULL);
604 
605   gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (priv->store),
606                                  &iter, NULL, page_no);
607   gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter,
608                       COLUMN_THUMBNAIL, &thumbnail,
609                       -1);
610 
611   if (thumbnail)
612     g_object_unref (thumbnail);
613 
614   if (thumbnail == priv->default_thumbnail)
615     return NULL;
616 
617   return thumbnail;
618 }
619 
620 /**
621  * gimp_page_selector_set_page_label:
622  * @selector: Pointer to a #GimpPageSelector.
623  * @page_no:  The number of the page to set the label for.
624  * @label:    The label.
625  *
626  * Sets the label of the specified page.
627  *
628  * Since: 2.4
629  **/
630 void
gimp_page_selector_set_page_label(GimpPageSelector * selector,gint page_no,const gchar * label)631 gimp_page_selector_set_page_label (GimpPageSelector *selector,
632                                    gint              page_no,
633                                    const gchar      *label)
634 {
635   GimpPageSelectorPrivate *priv;
636   GtkTreeIter              iter;
637   gchar                   *tmp;
638 
639   g_return_if_fail (GIMP_IS_PAGE_SELECTOR (selector));
640 
641   priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
642 
643   g_return_if_fail (page_no >= 0 && page_no < priv->n_pages);
644 
645   if (! label)
646     tmp = g_strdup_printf (_("Page %d"), page_no + 1);
647   else
648     tmp = (gchar *) label;
649 
650   gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (priv->store),
651                                  &iter, NULL, page_no);
652   gtk_list_store_set (priv->store, &iter,
653                       COLUMN_LABEL,     tmp,
654                       COLUMN_LABEL_SET, label != NULL,
655                       -1);
656 
657   if (! label)
658     g_free (tmp);
659 }
660 
661 /**
662  * gimp_page_selector_get_page_label:
663  * @selector: Pointer to a #GimpPageSelector.
664  * @page_no: The number of the page to get the thumbnail for.
665  *
666  * Returns: The page's label, or %NULL if none is set. This is a newly
667  *          allocated string that should be g_free()'d when no longer
668  *          needed.
669  *
670  * Since: 2.4
671  **/
672 gchar *
gimp_page_selector_get_page_label(GimpPageSelector * selector,gint page_no)673 gimp_page_selector_get_page_label (GimpPageSelector *selector,
674                                    gint              page_no)
675 {
676   GimpPageSelectorPrivate *priv;
677   GtkTreeIter              iter;
678   gchar                   *label;
679   gboolean                 label_set;
680 
681   g_return_val_if_fail (GIMP_IS_PAGE_SELECTOR (selector), NULL);
682 
683   priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
684 
685   g_return_val_if_fail (page_no >= 0 && page_no < priv->n_pages, NULL);
686 
687   gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (priv->store),
688                                  &iter, NULL, page_no);
689   gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter,
690                       COLUMN_LABEL,     &label,
691                       COLUMN_LABEL_SET, &label_set,
692                       -1);
693 
694   if (! label_set)
695     {
696       g_free (label);
697       label = NULL;
698     }
699 
700   return label;
701 }
702 
703 /**
704  * gimp_page_selector_select_all:
705  * @selector: Pointer to a #GimpPageSelector.
706  *
707  * Selects all pages.
708  *
709  * Since: 2.4
710  **/
711 void
gimp_page_selector_select_all(GimpPageSelector * selector)712 gimp_page_selector_select_all (GimpPageSelector *selector)
713 {
714   GimpPageSelectorPrivate *priv;
715 
716   g_return_if_fail (GIMP_IS_PAGE_SELECTOR (selector));
717 
718   priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
719 
720   gtk_icon_view_select_all (GTK_ICON_VIEW (priv->view));
721 }
722 
723 /**
724  * gimp_page_selector_unselect_all:
725  * @selector: Pointer to a #GimpPageSelector.
726  *
727  * Unselects all pages.
728  *
729  * Since: 2.4
730  **/
731 void
gimp_page_selector_unselect_all(GimpPageSelector * selector)732 gimp_page_selector_unselect_all (GimpPageSelector *selector)
733 {
734   GimpPageSelectorPrivate *priv;
735 
736   g_return_if_fail (GIMP_IS_PAGE_SELECTOR (selector));
737 
738   priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
739 
740   gtk_icon_view_unselect_all (GTK_ICON_VIEW (priv->view));
741 }
742 
743 /**
744  * gimp_page_selector_select_page:
745  * @selector: Pointer to a #GimpPageSelector.
746  * @page_no: The number of the page to select.
747  *
748  * Adds a page to the selection.
749  *
750  * Since: 2.4
751  **/
752 void
gimp_page_selector_select_page(GimpPageSelector * selector,gint page_no)753 gimp_page_selector_select_page (GimpPageSelector *selector,
754                                 gint              page_no)
755 {
756   GimpPageSelectorPrivate *priv;
757   GtkTreeIter              iter;
758   GtkTreePath             *path;
759 
760   g_return_if_fail (GIMP_IS_PAGE_SELECTOR (selector));
761 
762   priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
763 
764   g_return_if_fail (page_no >= 0 && page_no < priv->n_pages);
765 
766   gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (priv->store),
767                                  &iter, NULL, page_no);
768   path = gtk_tree_model_get_path (GTK_TREE_MODEL (priv->store), &iter);
769 
770   gtk_icon_view_select_path (GTK_ICON_VIEW (priv->view), path);
771 
772   gtk_tree_path_free (path);
773 }
774 
775 /**
776  * gimp_page_selector_unselect_page:
777  * @selector: Pointer to a #GimpPageSelector.
778  * @page_no: The number of the page to unselect.
779  *
780  * Removes a page from the selection.
781  *
782  * Since: 2.4
783  **/
784 void
gimp_page_selector_unselect_page(GimpPageSelector * selector,gint page_no)785 gimp_page_selector_unselect_page (GimpPageSelector *selector,
786                                   gint              page_no)
787 {
788   GimpPageSelectorPrivate *priv;
789   GtkTreeIter              iter;
790   GtkTreePath             *path;
791 
792   g_return_if_fail (GIMP_IS_PAGE_SELECTOR (selector));
793 
794   priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
795 
796   g_return_if_fail (page_no >= 0 && page_no < priv->n_pages);
797 
798   gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (priv->store),
799                                  &iter, NULL, page_no);
800   path = gtk_tree_model_get_path (GTK_TREE_MODEL (priv->store), &iter);
801 
802   gtk_icon_view_unselect_path (GTK_ICON_VIEW (priv->view), path);
803 
804   gtk_tree_path_free (path);
805 }
806 
807 /**
808  * gimp_page_selector_page_is_selected:
809  * @selector: Pointer to a #GimpPageSelector.
810  * @page_no: The number of the page to check.
811  *
812  * Returns: %TRUE if the page is selected, %FALSE otherwise.
813  *
814  * Since: 2.4
815  **/
816 gboolean
gimp_page_selector_page_is_selected(GimpPageSelector * selector,gint page_no)817 gimp_page_selector_page_is_selected (GimpPageSelector *selector,
818                                      gint              page_no)
819 {
820   GimpPageSelectorPrivate *priv;
821   GtkTreeIter              iter;
822   GtkTreePath             *path;
823   gboolean                 selected;
824 
825   g_return_val_if_fail (GIMP_IS_PAGE_SELECTOR (selector), FALSE);
826 
827   priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
828 
829   g_return_val_if_fail (page_no >= 0 && page_no < priv->n_pages, FALSE);
830 
831   gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (priv->store),
832                                  &iter, NULL, page_no);
833   path = gtk_tree_model_get_path (GTK_TREE_MODEL (priv->store), &iter);
834 
835   selected = gtk_icon_view_path_is_selected (GTK_ICON_VIEW (priv->view),
836                                              path);
837 
838   gtk_tree_path_free (path);
839 
840   return selected;
841 }
842 
843 /**
844  * gimp_page_selector_get_selected_pages:
845  * @selector: Pointer to a #GimpPageSelector.
846  * @n_selected_pages: Returns the number of selected pages.
847  *
848  * Returns: A sorted array of page numbers of selected pages. Use g_free() if
849  *          you don't need the array any longer.
850  *
851  * Since: 2.4
852  **/
853 gint *
gimp_page_selector_get_selected_pages(GimpPageSelector * selector,gint * n_selected_pages)854 gimp_page_selector_get_selected_pages (GimpPageSelector *selector,
855                                        gint             *n_selected_pages)
856 {
857   GimpPageSelectorPrivate *priv;
858   GList                   *selected;
859   GList                   *list;
860   gint                    *array;
861   gint                     i;
862 
863   g_return_val_if_fail (GIMP_IS_PAGE_SELECTOR (selector), NULL);
864   g_return_val_if_fail (n_selected_pages != NULL, NULL);
865 
866   priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
867 
868   selected = gtk_icon_view_get_selected_items (GTK_ICON_VIEW (priv->view));
869 
870   *n_selected_pages = g_list_length (selected);
871   array = g_new0 (gint, *n_selected_pages);
872 
873   for (list = selected, i = 0; list; list = g_list_next (list), i++)
874     {
875       gint *indices = gtk_tree_path_get_indices (list->data);
876 
877       array[i] = indices[0];
878     }
879 
880   qsort (array, *n_selected_pages, sizeof (gint),
881          gimp_page_selector_int_compare);
882 
883   g_list_free_full (selected, (GDestroyNotify) gtk_tree_path_free);
884 
885   return array;
886 }
887 
888 /**
889  * gimp_page_selector_select_range:
890  * @selector: Pointer to a #GimpPageSelector.
891  * @range: A string representing the set of selected pages.
892  *
893  * Selects the pages described by @range. The range string is a
894  * user-editable list of pages and ranges, e.g. "1,3,5-7,9-12,14".
895  * Note that the page numbering in the range string starts with 1,
896  * not 0.
897  *
898  * Invalid pages and ranges will be silently ignored, duplicate and
899  * overlapping pages and ranges will be merged.
900  *
901  * Since: 2.4
902  **/
903 void
gimp_page_selector_select_range(GimpPageSelector * selector,const gchar * range)904 gimp_page_selector_select_range (GimpPageSelector *selector,
905                                  const gchar      *range)
906 {
907   GimpPageSelectorPrivate  *priv;
908   gchar                   **ranges;
909 
910   g_return_if_fail (GIMP_IS_PAGE_SELECTOR (selector));
911 
912   priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
913 
914   if (! range)
915     range = "";
916 
917   g_signal_handlers_block_by_func (priv->view,
918                                    gimp_page_selector_selection_changed,
919                                    selector);
920 
921   gimp_page_selector_unselect_all (selector);
922 
923   ranges = g_strsplit (range, ",", -1);
924 
925   if (ranges)
926     {
927       gint i;
928 
929       for (i = 0; ranges[i] != NULL; i++)
930         {
931           gchar *range = g_strstrip (ranges[i]);
932           gchar *dash;
933 
934           dash = strchr (range, '-');
935 
936           if (dash)
937             {
938               gchar *from;
939               gchar *to;
940               gint   page_from = -1;
941               gint   page_to   = -1;
942 
943               *dash = '\0';
944 
945               from = g_strstrip (range);
946               to   = g_strstrip (dash + 1);
947 
948               if (sscanf (from, "%i", &page_from) != 1 && strlen (from) == 0)
949                 page_from = 1;
950 
951               if (sscanf (to, "%i", &page_to) != 1 && strlen (to) == 0)
952                 page_to = priv->n_pages;
953 
954               if (page_from > 0        &&
955                   page_to   > 0        &&
956                   page_from <= page_to &&
957                   page_from <= priv->n_pages)
958                 {
959                   gint page_no;
960 
961                   page_from = MAX (page_from, 1) - 1;
962                   page_to   = MIN (page_to, priv->n_pages) - 1;
963 
964                   for (page_no = page_from; page_no <= page_to; page_no++)
965                     gimp_page_selector_select_page (selector, page_no);
966                 }
967             }
968           else
969             {
970               gint page_no;
971 
972               if (sscanf (range, "%i", &page_no) == 1 &&
973                   page_no >= 1                        &&
974                   page_no <= priv->n_pages)
975                 {
976                   gimp_page_selector_select_page (selector, page_no - 1);
977                 }
978             }
979         }
980 
981       g_strfreev (ranges);
982     }
983 
984   g_signal_handlers_unblock_by_func (priv->view,
985                                      gimp_page_selector_selection_changed,
986                                      selector);
987 
988   gimp_page_selector_selection_changed (GTK_ICON_VIEW (priv->view), selector);
989 }
990 
991 /**
992  * gimp_page_selector_get_selected_range:
993  * @selector: Pointer to a #GimpPageSelector.
994  *
995  * Returns: A newly allocated string representing the set of selected
996  *          pages. See gimp_page_selector_select_range() for the
997  *          format of the string.
998  *
999  * Since: 2.4
1000  **/
1001 gchar *
gimp_page_selector_get_selected_range(GimpPageSelector * selector)1002 gimp_page_selector_get_selected_range (GimpPageSelector *selector)
1003 {
1004   gint    *pages;
1005   gint     n_pages;
1006   GString *string;
1007 
1008   g_return_val_if_fail (GIMP_IS_PAGE_SELECTOR (selector), NULL);
1009 
1010   string = g_string_new ("");
1011 
1012   pages = gimp_page_selector_get_selected_pages (selector, &n_pages);
1013 
1014   if (pages)
1015     {
1016       gint range_start, range_end;
1017       gint last_printed;
1018       gint i;
1019 
1020       range_start  = pages[0];
1021       range_end    = pages[0];
1022       last_printed = -1;
1023 
1024       for (i = 1; i < n_pages; i++)
1025         {
1026           if (pages[i] > range_end + 1)
1027             {
1028               gimp_page_selector_print_range (string,
1029                                               range_start, range_end);
1030 
1031               last_printed = range_end;
1032               range_start = pages[i];
1033             }
1034 
1035           range_end = pages[i];
1036         }
1037 
1038       if (range_end != last_printed)
1039         gimp_page_selector_print_range (string, range_start, range_end);
1040 
1041       g_free (pages);
1042     }
1043 
1044   return g_string_free (string, FALSE);
1045 }
1046 
1047 
1048 /*  private functions  */
1049 
1050 static void
gimp_page_selector_selection_changed(GtkIconView * icon_view,GimpPageSelector * selector)1051 gimp_page_selector_selection_changed (GtkIconView      *icon_view,
1052                                       GimpPageSelector *selector)
1053 {
1054   GimpPageSelectorPrivate *priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
1055   GList                   *selected;
1056   gint                     n_selected;
1057   gchar                   *range;
1058 
1059   selected = gtk_icon_view_get_selected_items (GTK_ICON_VIEW (priv->view));
1060   n_selected = g_list_length (selected);
1061   g_list_free_full (selected, (GDestroyNotify) gtk_tree_path_free);
1062 
1063   if (n_selected == 0)
1064     {
1065       gtk_label_set_text (GTK_LABEL (priv->count_label),
1066                           _("Nothing selected"));
1067     }
1068   else if (n_selected == 1)
1069     {
1070       gtk_label_set_text (GTK_LABEL (priv->count_label),
1071                           _("One page selected"));
1072     }
1073   else
1074     {
1075       gchar *text;
1076 
1077       if (n_selected == priv->n_pages)
1078         text = g_strdup_printf (ngettext ("%d page selected",
1079                                           "All %d pages selected", n_selected),
1080                                 n_selected);
1081       else
1082         text = g_strdup_printf (ngettext ("%d page selected",
1083                                           "%d pages selected",
1084                                           n_selected),
1085                                 n_selected);
1086 
1087       gtk_label_set_text (GTK_LABEL (priv->count_label), text);
1088       g_free (text);
1089     }
1090 
1091   range = gimp_page_selector_get_selected_range (selector);
1092   gtk_entry_set_text (GTK_ENTRY (priv->range_entry), range);
1093   g_free (range);
1094 
1095   gtk_editable_set_position (GTK_EDITABLE (priv->range_entry), -1);
1096 
1097   g_signal_emit (selector, selector_signals[SELECTION_CHANGED], 0);
1098 }
1099 
1100 static void
gimp_page_selector_item_activated(GtkIconView * icon_view,GtkTreePath * path,GimpPageSelector * selector)1101 gimp_page_selector_item_activated (GtkIconView      *icon_view,
1102                                    GtkTreePath      *path,
1103                                    GimpPageSelector *selector)
1104 {
1105   g_signal_emit (selector, selector_signals[ACTIVATE], 0);
1106 }
1107 
1108 static gboolean
gimp_page_selector_range_focus_out(GtkEntry * entry,GdkEventFocus * fevent,GimpPageSelector * selector)1109 gimp_page_selector_range_focus_out (GtkEntry         *entry,
1110                                     GdkEventFocus    *fevent,
1111                                     GimpPageSelector *selector)
1112 {
1113   gimp_page_selector_range_activate (entry, selector);
1114 
1115   return FALSE;
1116 }
1117 
1118 static void
gimp_page_selector_range_activate(GtkEntry * entry,GimpPageSelector * selector)1119 gimp_page_selector_range_activate (GtkEntry         *entry,
1120                                    GimpPageSelector *selector)
1121 {
1122   gimp_page_selector_select_range (selector, gtk_entry_get_text (entry));
1123 }
1124 
1125 static gint
gimp_page_selector_int_compare(gconstpointer a,gconstpointer b)1126 gimp_page_selector_int_compare (gconstpointer a,
1127                                 gconstpointer b)
1128 {
1129   return *(gint*)a - *(gint*)b;
1130 }
1131 
1132 static void
gimp_page_selector_print_range(GString * string,gint start,gint end)1133 gimp_page_selector_print_range (GString *string,
1134                                 gint     start,
1135                                 gint     end)
1136 {
1137   if (string->len != 0)
1138     g_string_append_c (string, ',');
1139 
1140   if (start == end)
1141     g_string_append_printf (string, "%d", start + 1);
1142   else
1143     g_string_append_printf (string, "%d-%d", start + 1, end + 1);
1144 }
1145 
1146 static void
draw_frame_row(GdkPixbuf * frame_image,gint target_width,gint source_width,gint source_v_position,gint dest_v_position,GdkPixbuf * result_pixbuf,gint left_offset,gint height)1147 draw_frame_row (GdkPixbuf *frame_image,
1148                 gint       target_width,
1149                 gint       source_width,
1150                 gint       source_v_position,
1151                 gint       dest_v_position,
1152                 GdkPixbuf *result_pixbuf,
1153                 gint       left_offset,
1154                 gint       height)
1155 {
1156   gint remaining_width = target_width;
1157   gint h_offset        = 0;
1158 
1159   while (remaining_width > 0)
1160     {
1161       gint slab_width = (remaining_width > source_width ?
1162                          source_width : remaining_width);
1163 
1164       gdk_pixbuf_copy_area (frame_image,
1165                             left_offset, source_v_position,
1166                             slab_width, height,
1167                             result_pixbuf,
1168                             left_offset + h_offset, dest_v_position);
1169 
1170       remaining_width -= slab_width;
1171       h_offset += slab_width;
1172     }
1173 }
1174 
1175 /* utility to draw the middle section of the frame in a loop */
1176 static void
draw_frame_column(GdkPixbuf * frame_image,gint target_height,gint source_height,gint source_h_position,gint dest_h_position,GdkPixbuf * result_pixbuf,gint top_offset,int width)1177 draw_frame_column (GdkPixbuf *frame_image,
1178                    gint       target_height,
1179                    gint       source_height,
1180                    gint       source_h_position,
1181                    gint       dest_h_position,
1182                    GdkPixbuf *result_pixbuf,
1183                    gint       top_offset, int width)
1184 {
1185   gint remaining_height = target_height;
1186   gint v_offset         = 0;
1187 
1188   while (remaining_height > 0)
1189     {
1190       gint slab_height = (remaining_height > source_height ?
1191                           source_height : remaining_height);
1192 
1193       gdk_pixbuf_copy_area (frame_image,
1194                             source_h_position, top_offset,
1195                             width, slab_height,
1196                             result_pixbuf,
1197                             dest_h_position, top_offset + v_offset);
1198 
1199       remaining_height -= slab_height;
1200       v_offset += slab_height;
1201     }
1202 }
1203 
1204 static GdkPixbuf *
stretch_frame_image(GdkPixbuf * frame_image,gint left_offset,gint top_offset,gint right_offset,gint bottom_offset,gint dest_width,gint dest_height)1205 stretch_frame_image (GdkPixbuf *frame_image,
1206                      gint       left_offset,
1207                      gint       top_offset,
1208                      gint       right_offset,
1209                      gint       bottom_offset,
1210                      gint       dest_width,
1211                      gint       dest_height)
1212 {
1213   GdkPixbuf *pixbuf;
1214   gint       frame_width, frame_height;
1215   gint       target_width,  target_frame_width;
1216   gint       target_height, target_frame_height;
1217 
1218   frame_width  = gdk_pixbuf_get_width  (frame_image);
1219   frame_height = gdk_pixbuf_get_height (frame_image );
1220 
1221   pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
1222                            dest_width, dest_height);
1223   gdk_pixbuf_fill (pixbuf, 0);
1224 
1225   target_width = dest_width - left_offset - right_offset;
1226   target_height = dest_height - top_offset - bottom_offset;
1227   target_frame_width  = frame_width - left_offset - right_offset;
1228   target_frame_height = frame_height - top_offset - bottom_offset;
1229 
1230   left_offset   += MIN (target_width / 4, target_frame_width / 4);
1231   right_offset  += MIN (target_width / 4, target_frame_width / 4);
1232   top_offset    += MIN (target_height / 4, target_frame_height / 4);
1233   bottom_offset += MIN (target_height / 4, target_frame_height / 4);
1234 
1235   target_width = dest_width - left_offset - right_offset;
1236   target_height = dest_height - top_offset - bottom_offset;
1237   target_frame_width  = frame_width - left_offset - right_offset;
1238   target_frame_height = frame_height - top_offset - bottom_offset;
1239 
1240   /* draw the left top corner  and top row */
1241   gdk_pixbuf_copy_area (frame_image,
1242                         0, 0, left_offset, top_offset,
1243                         pixbuf, 0,  0);
1244   draw_frame_row (frame_image, target_width, target_frame_width,
1245                   0, 0,
1246                   pixbuf,
1247                   left_offset, top_offset);
1248 
1249   /* draw the right top corner and left column */
1250   gdk_pixbuf_copy_area (frame_image,
1251                         frame_width - right_offset, 0,
1252                         right_offset, top_offset,
1253 
1254                         pixbuf,
1255                         dest_width - right_offset,  0);
1256   draw_frame_column (frame_image, target_height, target_frame_height, 0, 0,
1257                      pixbuf, top_offset, left_offset);
1258 
1259   /* draw the bottom right corner and bottom row */
1260   gdk_pixbuf_copy_area (frame_image,
1261                         frame_width - right_offset, frame_height - bottom_offset,
1262                         right_offset, bottom_offset,
1263                         pixbuf,
1264                         dest_width - right_offset, dest_height - bottom_offset);
1265   draw_frame_row (frame_image, target_width, target_frame_width,
1266                   frame_height - bottom_offset, dest_height - bottom_offset,
1267                   pixbuf, left_offset, bottom_offset);
1268 
1269   /* draw the bottom left corner and the right column */
1270   gdk_pixbuf_copy_area (frame_image,
1271                         0, frame_height - bottom_offset,
1272                         left_offset, bottom_offset,
1273                         pixbuf,
1274                         0,  dest_height - bottom_offset);
1275   draw_frame_column (frame_image, target_height, target_frame_height,
1276                      frame_width - right_offset, dest_width - right_offset,
1277                      pixbuf, top_offset, right_offset);
1278 
1279   return pixbuf;
1280 }
1281 
1282 #define FRAME_LEFT   2
1283 #define FRAME_TOP    2
1284 #define FRAME_RIGHT  4
1285 #define FRAME_BOTTOM 4
1286 
1287 static GdkPixbuf *
gimp_page_selector_add_frame(GtkWidget * widget,GdkPixbuf * pixbuf)1288 gimp_page_selector_add_frame (GtkWidget *widget,
1289                               GdkPixbuf *pixbuf)
1290 {
1291   GdkPixbuf *frame;
1292   gint       width, height;
1293 
1294   width  = gdk_pixbuf_get_width (pixbuf);
1295   height = gdk_pixbuf_get_height (pixbuf);
1296 
1297   frame = g_object_get_data (G_OBJECT (widget), "frame");
1298 
1299   if (! frame)
1300     {
1301       GError *error = NULL;
1302 
1303       frame = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
1304                                         GIMP_ICON_FRAME, 64, 0, &error);
1305       if (error)
1306         {
1307           g_printerr ("%s: %s\n", G_STRFUNC, error->message);
1308           g_error_free (error);
1309         }
1310       g_return_val_if_fail (frame, NULL);
1311       g_object_set_data_full (G_OBJECT (widget), "frame", frame,
1312                               (GDestroyNotify) g_object_unref);
1313     }
1314 
1315   frame = stretch_frame_image (frame,
1316                                FRAME_LEFT,
1317                                FRAME_TOP,
1318                                FRAME_RIGHT,
1319                                FRAME_BOTTOM,
1320                                width  + FRAME_LEFT + FRAME_RIGHT,
1321                                height + FRAME_TOP  + FRAME_BOTTOM);
1322 
1323   gdk_pixbuf_copy_area (pixbuf, 0, 0, width, height,
1324                         frame, FRAME_LEFT, FRAME_TOP);
1325 
1326   return frame;
1327 }
1328