home *** CD-ROM | disk | FTP | other *** search
/ Chip 2005 February / CMCD0205.ISO / Linux / gimp-2.2.0.tar.gz / gimp-2.2.0.tar / gimp-2.2.0 / libgimpwidgets / gimppreview.c < prev    next >
C/C++ Source or Header  |  2004-11-29  |  20KB  |  684 lines

  1. /* LIBGIMP - The GIMP Library
  2.  * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
  3.  *
  4.  * gimppreview.c
  5.  *
  6.  * This library is free software; you can redistribute it and/or
  7.  * modify it under the terms of the GNU Lesser General Public
  8.  * License as published by the Free Software Foundation; either
  9.  * version 2 of the License, or (at your option) any later version.
  10.  *
  11.  * This library is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14.  * Lesser General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU Lesser General Public
  17.  * License along with this library; if not, write to the
  18.  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  19.  * Boston, MA 02111-1307, USA.
  20.  */
  21.  
  22. #include "config.h"
  23.  
  24. #include <gtk/gtk.h>
  25.  
  26. #include "libgimpmath/gimpmath.h"
  27.  
  28. #include "gimpwidgets.h"
  29.  
  30. #include "gimppreview.h"
  31.  
  32. #include "libgimp/libgimp-intl.h"
  33.  
  34.  
  35. #define DEFAULT_SIZE     150
  36. #define PREVIEW_TIMEOUT  200
  37.  
  38.  
  39. enum
  40. {
  41.   INVALIDATED,
  42.   LAST_SIGNAL
  43. };
  44.  
  45. enum
  46. {
  47.   PROP_0,
  48.   PROP_UPDATE
  49. };
  50.  
  51.  
  52. static void      gimp_preview_class_init          (GimpPreviewClass *klass);
  53. static void      gimp_preview_init                (GimpPreview      *preview);
  54. static void      gimp_preview_dispose             (GObject          *object);
  55. static void      gimp_preview_get_property        (GObject          *object,
  56.                                                    guint             property_id,
  57.                                                    GValue           *value,
  58.                                                    GParamSpec       *pspec);
  59. static void      gimp_preview_set_property        (GObject          *object,
  60.                                                    guint             property_id,
  61.                                                    const GValue     *value,
  62.                                                    GParamSpec       *pspec);
  63.  
  64. static void      gimp_preview_direction_changed   (GtkWidget        *widget,
  65.                                                    GtkTextDirection  prev_dir);
  66. static gboolean  gimp_preview_popup_menu          (GtkWidget        *widget);
  67.  
  68. static void      gimp_preview_area_realize        (GtkWidget        *widget,
  69.                                                    GimpPreview      *preview);
  70. static void      gimp_preview_area_unrealize      (GtkWidget        *widget,
  71.                                                    GimpPreview      *preview);
  72. static void      gimp_preview_area_size_allocate  (GtkWidget        *widget,
  73.                                                    GtkAllocation    *allocation,
  74.                                                    GimpPreview      *preview);
  75. static gboolean  gimp_preview_area_event          (GtkWidget        *area,
  76.                                                    GdkEvent         *event,
  77.                                                    GimpPreview      *preview);
  78.  
  79. static void      gimp_preview_toggle_callback     (GtkWidget        *toggle,
  80.                                                    GimpPreview      *preview);
  81.  
  82. static void      gimp_preview_notify_checks       (GimpPreview      *preview);
  83.  
  84. static gboolean  gimp_preview_invalidate_now      (GimpPreview      *preview);
  85. static void      gimp_preview_set_cursor          (GimpPreview      *preview);
  86.  
  87.  
  88. static guint preview_signals[LAST_SIGNAL] = { 0 };
  89.  
  90. static GtkVBoxClass *parent_class = NULL;
  91.  
  92.  
  93. GType
  94. gimp_preview_get_type (void)
  95. {
  96.   static GType preview_type = 0;
  97.  
  98.   if (! preview_type)
  99.     {
  100.       static const GTypeInfo preview_info =
  101.       {
  102.         sizeof (GimpPreviewClass),
  103.         (GBaseInitFunc) NULL,
  104.         (GBaseFinalizeFunc) NULL,
  105.         (GClassInitFunc) gimp_preview_class_init,
  106.         NULL,           /* class_finalize */
  107.         NULL,           /* class_data     */
  108.         sizeof (GimpPreview),
  109.         0,              /* n_preallocs    */
  110.         (GInstanceInitFunc) gimp_preview_init,
  111.       };
  112.  
  113.       preview_type = g_type_register_static (GTK_TYPE_VBOX,
  114.                                              "GimpPreview",
  115.                                              &preview_info,
  116.                                              G_TYPE_FLAG_ABSTRACT);
  117.     }
  118.  
  119.   return preview_type;
  120. }
  121.  
  122. static void
  123. gimp_preview_class_init (GimpPreviewClass *klass)
  124. {
  125.   GObjectClass   *object_class = G_OBJECT_CLASS (klass);
  126.   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
  127.  
  128.   parent_class = g_type_class_peek_parent (klass);
  129.  
  130.   preview_signals[INVALIDATED] =
  131.     g_signal_new ("invalidated",
  132.                   G_TYPE_FROM_CLASS (klass),
  133.                   G_SIGNAL_RUN_FIRST,
  134.                   G_STRUCT_OFFSET (GimpPreviewClass, invalidated),
  135.                   NULL, NULL,
  136.                   g_cclosure_marshal_VOID__VOID,
  137.                   G_TYPE_NONE, 0);
  138.  
  139.   object_class->dispose           = gimp_preview_dispose;
  140.   object_class->get_property      = gimp_preview_get_property;
  141.   object_class->set_property      = gimp_preview_set_property;
  142.  
  143.   widget_class->direction_changed = gimp_preview_direction_changed;
  144.   widget_class->popup_menu        = gimp_preview_popup_menu;
  145.  
  146.   klass->draw                     = NULL;
  147.   klass->draw_thumb               = NULL;
  148.   klass->draw_buffer              = NULL;
  149.   klass->set_cursor               = gimp_preview_set_cursor;
  150.  
  151.   g_object_class_install_property (object_class,
  152.                                    PROP_UPDATE,
  153.                                    g_param_spec_boolean ("update",
  154.                                                          NULL, NULL,
  155.                                                          TRUE,
  156.                                                          G_PARAM_READWRITE |
  157.                                                          G_PARAM_CONSTRUCT));
  158.  
  159.   gtk_widget_class_install_style_property (widget_class,
  160.                                            g_param_spec_int ("size",
  161.                                                              NULL, NULL,
  162.                                                              1, 1024,
  163.                                                              DEFAULT_SIZE,
  164.                                                              G_PARAM_READABLE));
  165. }
  166.  
  167. static void
  168. gimp_preview_init (GimpPreview *preview)
  169. {
  170.   GtkWidget *frame;
  171.   gdouble    xalign = 0.0;
  172.  
  173.   gtk_box_set_homogeneous (GTK_BOX (preview), FALSE);
  174.   gtk_box_set_spacing (GTK_BOX (preview), 6);
  175.  
  176.   if (gtk_widget_get_direction (GTK_WIDGET (preview)) == GTK_TEXT_DIR_RTL)
  177.     xalign = 1.0;
  178.  
  179.   preview->frame = gtk_aspect_frame_new (NULL, xalign, 0.0, 1.0, TRUE);
  180.   gtk_frame_set_shadow_type (GTK_FRAME (preview->frame), GTK_SHADOW_NONE);
  181.   gtk_box_pack_start (GTK_BOX (preview), preview->frame, TRUE, TRUE, 0);
  182.   gtk_widget_show (preview->frame);
  183.  
  184.   preview->table = gtk_table_new (3, 2, FALSE);
  185.   gtk_container_add (GTK_CONTAINER (preview->frame), preview->table);
  186.   gtk_widget_show (preview->table);
  187.  
  188.   preview->timeout_id     = 0;
  189.  
  190.   preview->xmin           = preview->ymin = 0;
  191.   preview->xmax           = preview->ymax = 1;
  192.   preview->width          = preview->xmax - preview->xmin;
  193.   preview->height         = preview->ymax - preview->ymin;
  194.  
  195.   preview->xoff           = 0;
  196.   preview->yoff           = 0;
  197.  
  198.   preview->default_cursor = NULL;
  199.  
  200.   /*  preview area  */
  201.   frame = gtk_frame_new (NULL);
  202.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
  203.   gtk_table_attach (GTK_TABLE (preview->table), frame, 0,1, 0,1,
  204.                     GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 0, 0);
  205.   gtk_widget_show (frame);
  206.  
  207.   preview->area = gimp_preview_area_new ();
  208.   gtk_container_add (GTK_CONTAINER (frame), preview->area);
  209.   gtk_widget_show (preview->area);
  210.  
  211.   g_signal_connect_swapped (preview->area, "notify::check-size",
  212.                             G_CALLBACK (gimp_preview_notify_checks),
  213.                             preview);
  214.   g_signal_connect_swapped (preview->area, "notify::check-type",
  215.                             G_CALLBACK (gimp_preview_notify_checks),
  216.                             preview);
  217.  
  218.   gtk_widget_add_events (preview->area,
  219.                          GDK_BUTTON_PRESS_MASK        |
  220.                          GDK_BUTTON_RELEASE_MASK      |
  221.                          GDK_POINTER_MOTION_HINT_MASK |
  222.                          GDK_BUTTON_MOTION_MASK);
  223.  
  224.   g_signal_connect (preview->area, "event",
  225.                     G_CALLBACK (gimp_preview_area_event),
  226.                     preview);
  227.  
  228.   g_signal_connect (preview->area, "realize",
  229.                     G_CALLBACK (gimp_preview_area_realize),
  230.                     preview);
  231.   g_signal_connect (preview->area, "unrealize",
  232.                     G_CALLBACK (gimp_preview_area_unrealize),
  233.                     preview);
  234.  
  235.   g_signal_connect (preview->area, "size_allocate",
  236.                     G_CALLBACK (gimp_preview_area_size_allocate),
  237.                     preview);
  238.  
  239.   /*  toggle button to (des)activate the instant preview  */
  240.   preview->toggle = gtk_check_button_new_with_mnemonic (_("_Preview"));
  241.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (preview->toggle),
  242.                                 preview->update_preview);
  243.   gtk_box_pack_start (GTK_BOX (preview), preview->toggle, FALSE, FALSE, 0);
  244.   gtk_widget_show (preview->toggle);
  245.  
  246.   g_signal_connect (preview->toggle, "toggled",
  247.                     G_CALLBACK (gimp_preview_toggle_callback),
  248.                     preview);
  249. }
  250.  
  251. static void
  252. gimp_preview_dispose (GObject *object)
  253. {
  254.   GimpPreview *preview = GIMP_PREVIEW (object);
  255.  
  256.   if (preview->timeout_id)
  257.     {
  258.       g_source_remove (preview->timeout_id);
  259.       preview->timeout_id = 0;
  260.     }
  261.  
  262.   G_OBJECT_CLASS (parent_class)->dispose (object);
  263. }
  264.  
  265. static void
  266. gimp_preview_get_property (GObject    *object,
  267.                            guint       property_id,
  268.                            GValue     *value,
  269.                            GParamSpec *pspec)
  270. {
  271.   GimpPreview *preview = GIMP_PREVIEW (object);
  272.  
  273.   switch (property_id)
  274.     {
  275.     case PROP_UPDATE:
  276.       g_value_set_boolean (value, preview->update_preview);
  277.       break;
  278.  
  279.     default:
  280.       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
  281.       break;
  282.     }
  283. }
  284.  
  285. static void
  286. gimp_preview_set_property (GObject      *object,
  287.                            guint         property_id,
  288.                            const GValue *value,
  289.                            GParamSpec   *pspec)
  290. {
  291.   GimpPreview *preview = GIMP_PREVIEW (object);
  292.  
  293.   switch (property_id)
  294.     {
  295.     case PROP_UPDATE:
  296.       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (preview->toggle),
  297.                                     g_value_get_boolean (value));
  298.       break;
  299.  
  300.     default:
  301.       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
  302.       break;
  303.     }
  304. }
  305.  
  306. static void
  307. gimp_preview_direction_changed (GtkWidget        *widget,
  308.                                 GtkTextDirection  prev_dir)
  309. {
  310.   GimpPreview *preview = GIMP_PREVIEW (widget);
  311.   gdouble      xalign  = 0.0;
  312.  
  313.   if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
  314.     xalign = 1.0;
  315.  
  316.   gtk_aspect_frame_set (GTK_ASPECT_FRAME (preview->frame),
  317.                         xalign, 0.0, 1.0, TRUE);
  318. }
  319.  
  320. static gboolean
  321. gimp_preview_popup_menu (GtkWidget *widget)
  322. {
  323.   GimpPreview *preview = GIMP_PREVIEW (widget);
  324.  
  325.   gimp_preview_area_menu_popup (GIMP_PREVIEW_AREA (preview->area), NULL);
  326.  
  327.   return TRUE;
  328. }
  329.  
  330. static void
  331. gimp_preview_area_realize (GtkWidget   *widget,
  332.                            GimpPreview *preview)
  333. {
  334.   GdkDisplay *display = gtk_widget_get_display (widget);
  335.  
  336.   g_return_if_fail (preview->cursor_busy == NULL);
  337.  
  338.   preview->cursor_busy = gdk_cursor_new_for_display (display, GDK_WATCH);
  339.  
  340. }
  341.  
  342. static void
  343. gimp_preview_area_unrealize (GtkWidget   *widget,
  344.                              GimpPreview *preview)
  345. {
  346.   if (preview->cursor_busy)
  347.     {
  348.       gdk_cursor_unref (preview->cursor_busy);
  349.       preview->cursor_busy = NULL;
  350.     }
  351. }
  352.  
  353. static void
  354. gimp_preview_area_size_allocate (GtkWidget     *widget,
  355.                                  GtkAllocation *allocation,
  356.                                  GimpPreview   *preview)
  357. {
  358.   gint width  = preview->xmax - preview->xmin;
  359.   gint height = preview->ymax - preview->ymin;
  360.  
  361.   preview->width  = MIN (width,  allocation->width);
  362.   preview->height = MIN (height, allocation->height);
  363.  
  364.   gimp_preview_draw (preview);
  365.   gimp_preview_invalidate (preview);
  366. }
  367.  
  368.  
  369. static gboolean
  370. gimp_preview_area_event (GtkWidget   *area,
  371.                          GdkEvent    *event,
  372.                          GimpPreview *preview)
  373. {
  374.   GdkEventButton *button_event = (GdkEventButton *) event;
  375.  
  376.   switch (event->type)
  377.     {
  378.     case GDK_BUTTON_PRESS:
  379.       switch (button_event->button)
  380.         {
  381.         case 3:
  382.           gimp_preview_area_menu_popup (GIMP_PREVIEW_AREA (area), button_event);
  383.           return TRUE;
  384.         }
  385.       break;
  386.  
  387.     default:
  388.       break;
  389.     }
  390.  
  391.   return FALSE;
  392. }
  393.  
  394. static void
  395. gimp_preview_toggle_callback (GtkWidget   *toggle,
  396.                               GimpPreview *preview)
  397. {
  398.   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (toggle)))
  399.     {
  400.       preview->update_preview = TRUE;
  401.  
  402.       g_object_notify (G_OBJECT (preview), "update");
  403.  
  404.       if (preview->timeout_id)
  405.         g_source_remove (preview->timeout_id);
  406.  
  407.       gimp_preview_invalidate_now (preview);
  408.     }
  409.   else
  410.     {
  411.       preview->update_preview = FALSE;
  412.  
  413.       g_object_notify (G_OBJECT (preview), "update");
  414.  
  415.       gimp_preview_draw (preview);
  416.     }
  417. }
  418.  
  419. static void
  420. gimp_preview_notify_checks (GimpPreview *preview)
  421. {
  422.   gimp_preview_draw (preview);
  423.   gimp_preview_invalidate (preview);
  424. }
  425.  
  426. static gboolean
  427. gimp_preview_invalidate_now (GimpPreview *preview)
  428. {
  429.   GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (preview));
  430.   GimpPreviewClass *class = GIMP_PREVIEW_GET_CLASS (preview);
  431.  
  432.   if (class->draw)
  433.     class->draw (preview);
  434.  
  435.   preview->timeout_id = 0;
  436.  
  437.   if (toplevel && GTK_WIDGET_REALIZED (toplevel))
  438.     {
  439.       gdk_window_set_cursor (toplevel->window, preview->cursor_busy);
  440.       gdk_window_set_cursor (preview->area->window, preview->cursor_busy);
  441.  
  442.       gdk_flush ();
  443.  
  444.       g_signal_emit (preview, preview_signals[INVALIDATED], 0);
  445.  
  446.       class->set_cursor (preview);
  447.       gdk_window_set_cursor (toplevel->window, NULL);
  448.     }
  449.   else
  450.     {
  451.       g_signal_emit (preview, preview_signals[INVALIDATED], 0);
  452.     }
  453.  
  454.   return FALSE;
  455. }
  456.  
  457. static void
  458. gimp_preview_set_cursor (GimpPreview *preview)
  459. {
  460.   gdk_window_set_cursor (preview->area->window,
  461.                          preview->default_cursor);
  462. }
  463.  
  464. /**
  465.  * gimp_preview_set_update:
  466.  * @preview: a #GimpPreview widget
  467.  * @update: %TRUE if the preview should invalidate itself when being
  468.  *          scrolled or when gimp_preview_invalidate() is being called
  469.  *
  470.  * Sets the state of the "Preview" check button.
  471.  *
  472.  * Since: GIMP 2.2
  473.  **/
  474. void
  475. gimp_preview_set_update (GimpPreview *preview,
  476.                          gboolean     update)
  477. {
  478.   g_return_if_fail (GIMP_IS_PREVIEW (preview));
  479.  
  480.   g_object_set (preview,
  481.                 "update", update,
  482.                 NULL);
  483. }
  484.  
  485. /**
  486.  * gimp_preview_get_update:
  487.  * @preview: a #GimpPreview widget
  488.  *
  489.  * Return value: the state of the "Preview" check button.
  490.  *
  491.  * Since: GIMP 2.2
  492.  **/
  493. gboolean
  494. gimp_preview_get_update (GimpPreview *preview)
  495. {
  496.   g_return_val_if_fail (GIMP_IS_PREVIEW (preview), FALSE);
  497.  
  498.   return preview->update_preview;
  499. }
  500.  
  501. /**
  502.  * gimp_preview_set_bounds:
  503.  * @preview: a #GimpPreview widget
  504.  * @xmin:
  505.  * @ymin:
  506.  * @xmax:
  507.  * @ymax:
  508.  *
  509.  * Sets the lower and upper limits for the previewed area. The
  510.  * difference between the upper and lower value is used to set the
  511.  * maximum size of the #GimpPreviewArea used in the @preview.
  512.  *
  513.  * Since: GIMP 2.2
  514.  **/
  515. void
  516. gimp_preview_set_bounds (GimpPreview *preview,
  517.                          gint         xmin,
  518.                          gint         ymin,
  519.                          gint         xmax,
  520.                          gint         ymax)
  521. {
  522.   g_return_if_fail (GIMP_IS_PREVIEW (preview));
  523.   g_return_if_fail (xmax > xmin);
  524.   g_return_if_fail (ymax > ymin);
  525.  
  526.   preview->xmin = xmin;
  527.   preview->ymin = ymin;
  528.   preview->xmax = xmax;
  529.   preview->ymax = ymax;
  530.  
  531.   gimp_preview_area_set_max_size (GIMP_PREVIEW_AREA (preview->area),
  532.                                   xmax - xmin,
  533.                                   ymax - ymin);
  534. }
  535.  
  536. /**
  537.  * gimp_preview_get_size:
  538.  * @preview: a #GimpPreview widget
  539.  * @width:   return location for the preview area width
  540.  * @height:  return location for the preview area height
  541.  *
  542.  * Since: GIMP 2.2
  543.  **/
  544. void
  545. gimp_preview_get_size (GimpPreview *preview,
  546.                        gint        *width,
  547.                        gint        *height)
  548. {
  549.   g_return_if_fail (GIMP_IS_PREVIEW (preview));
  550.  
  551.   if (width)
  552.     *width = preview->width;
  553.  
  554.   if (height)
  555.     *height = preview->height;
  556. }
  557.  
  558. /**
  559.  * gimp_preview_get_position:
  560.  * @preview: a #GimpPreview widget
  561.  * @x:       return location for the horizontal offset
  562.  * @y:       return location for the vertical offset
  563.  *
  564.  * Since: GIMP 2.2
  565.  **/
  566. void
  567. gimp_preview_get_position (GimpPreview *preview,
  568.                            gint        *x,
  569.                            gint        *y)
  570. {
  571.   g_return_if_fail (GIMP_IS_PREVIEW (preview));
  572.  
  573.   if (x)
  574.     *x = preview->xoff + GIMP_PREVIEW (preview)->xmin;
  575.  
  576.   if (y)
  577.     *y = preview->yoff + GIMP_PREVIEW (preview)->ymin;
  578. }
  579.  
  580. /**
  581.  * gimp_preview_draw:
  582.  * @preview: a #GimpPreview widget
  583.  *
  584.  * Calls the GimpPreview::draw method. GimpPreview itself doesn't
  585.  * implement a default draw method so the behaviour is determined by
  586.  * the derived class implementing this method.
  587.  *
  588.  * #GimpDrawablePreview implements gimp_preview_draw() by drawing the
  589.  * original, unmodified drawable to the @preview.
  590.  *
  591.  * Since: GIMP 2.2
  592.  **/
  593. void
  594. gimp_preview_draw (GimpPreview *preview)
  595. {
  596.   GimpPreviewClass *class = GIMP_PREVIEW_GET_CLASS (preview);
  597.  
  598.   if (class->draw)
  599.     class->draw (preview);
  600. }
  601.  
  602. /**
  603.  * gimp_preview_draw_buffer:
  604.  * @preview:   a #GimpPreview widget
  605.  * @buffer:    a pixel buffer the size of the preview
  606.  * @rowstride: the @buffer's rowstride
  607.  *
  608.  * Calls the GimpPreview::draw_buffer method. GimpPreview itself
  609.  * doesn't implement this method so the behaviour is determined by the
  610.  * derived class implementing this method.
  611.  *
  612.  * Since: GIMP 2.2
  613.  **/
  614. void
  615. gimp_preview_draw_buffer (GimpPreview  *preview,
  616.                           const guchar *buffer,
  617.                           gint          rowstride)
  618. {
  619.   GimpPreviewClass *class = GIMP_PREVIEW_GET_CLASS (preview);
  620.  
  621.   if (class->draw_buffer)
  622.     class->draw_buffer (preview, buffer, rowstride);
  623. }
  624.  
  625. /**
  626.  * gimp_preview_invalidate:
  627.  * @preview: a #GimpPreview widget
  628.  *
  629.  * This function starts or renews a short low-priority timeout. When
  630.  * the timeout expires, the GimpPreview::invalidated signal is emitted
  631.  * which will usually cause the @preview to be updated.
  632.  *
  633.  * This function does nothing unless the "Preview" button is checked.
  634.  *
  635.  * During the emission of the signal a busy cursor is set on the
  636.  * toplevel window containing the @preview and on the preview area
  637.  * itself.
  638.  *
  639.  * Since: GIMP 2.2
  640.  **/
  641. void
  642. gimp_preview_invalidate (GimpPreview *preview)
  643. {
  644.   g_return_if_fail (GIMP_IS_PREVIEW (preview));
  645.  
  646.   if (preview->update_preview)
  647.     {
  648.       if (preview->timeout_id)
  649.         g_source_remove (preview->timeout_id);
  650.  
  651.       preview->timeout_id =
  652.         g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE, PREVIEW_TIMEOUT,
  653.                             (GSourceFunc) gimp_preview_invalidate_now,
  654.                             preview, NULL);
  655.     }
  656. }
  657.  
  658. /**
  659.  * gimp_preview_set_default_cursor:
  660.  * @preview: a #GimpPreview widget
  661.  * @cursor:  a #GdkCursor or %NULL
  662.  *
  663.  * Sets the default mouse cursor for the preview.  Note that this will
  664.  * be overriden by a %GDK_FLEUR if the preview has scrollbars, or by a
  665.  * %GDK_WATCH when the preview is invalidated.
  666.  *
  667.  * Since: GIMP 2.2
  668.  **/
  669. void
  670. gimp_preview_set_default_cursor (GimpPreview *preview,
  671.                                  GdkCursor   *cursor)
  672. {
  673.   g_return_if_fail (GIMP_IS_PREVIEW (preview));
  674.  
  675.   if (preview->default_cursor)
  676.     gdk_cursor_unref (preview->default_cursor);
  677.  
  678.   if (cursor)
  679.     gdk_cursor_ref (cursor);
  680.  
  681.   preview->default_cursor = cursor;
  682. }
  683.  
  684.