home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / app / selection.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-12-17  |  18.3 KB  |  742 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  4.  * This program is free software; you can redistribute it and/or modify
  5.  * it under the terms of the GNU General Public License as published by
  6.  * the Free Software Foundation; either version 2 of the License, or
  7.  * (at your option) any later version.
  8.  *
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17.  */
  18.  
  19. #include "config.h"
  20.  
  21. #include <glib.h>
  22.  
  23. #include "apptypes.h"
  24.  
  25. #include "appenv.h"
  26. #include "boundary.h"
  27. #include "colormaps.h"
  28. #include "gdisplay.h"
  29. #include "gdisplay_ops.h"
  30. #include "gimage_mask.h"
  31. #include "gimprc.h"
  32. #include "selection.h"
  33. #include "marching_ants.h"
  34.  
  35. #define USE_XDRAWPOINTS
  36. #undef VERBOSE
  37.  
  38. /*  The possible internal drawing states...  */
  39. #define INVISIBLE         0
  40. #define INTRO             1
  41. #define MARCHING          2
  42.  
  43. #define INITIAL_DELAY     15  /* in milleseconds */
  44.  
  45.  
  46. /* static function prototypes */
  47. static GdkPixmap *create_cycled_ants_pixmap (GdkWindow *, gint);
  48. static void    cycle_ant_colors            (Selection *);
  49.  
  50. static void    selection_draw              (Selection *);
  51. static void    selection_transform_segs    (Selection *, BoundSeg *, GdkSegment *, int);
  52. static void    selection_generate_segs     (Selection *);
  53. static void    selection_free_segs         (Selection *);
  54. static gint    selection_march_ants        (gpointer);
  55. static gint    selection_start_marching    (gpointer);
  56.  
  57. GdkPixmap *marching_ants[9] = { NULL };
  58. GdkPixmap *cycled_ants_pixmap = NULL;
  59.  
  60.  
  61. /*********************************/
  62. /*  Local function definitions   */
  63. /*********************************/
  64.  
  65. static GdkPixmap *
  66. create_cycled_ants_pixmap (GdkWindow *win,
  67.                gint       depth)
  68. {
  69.   GdkPixmap *pixmap;
  70.   GdkGC *gc;
  71.   GdkColor col;
  72.   int i, j;
  73.  
  74.   pixmap = gdk_pixmap_new (win, 8, 8, depth);
  75.   gc = gdk_gc_new (win);
  76.  
  77.   for (i = 0; i < 8; i++)
  78.     for (j = 0; j < 8; j++)
  79.       {
  80.     col.pixel = marching_ants_pixels[((i + j) % 8)];
  81.     gdk_gc_set_foreground (gc, &col);
  82.     gdk_draw_line (pixmap, gc, i, j, i, j);
  83.       }
  84.  
  85.   gdk_gc_destroy (gc);
  86.  
  87.   return pixmap;
  88. }
  89.  
  90.  
  91. static void
  92. cycle_ant_colors (Selection *select)
  93. {
  94.   int i;
  95.   int index;
  96.  
  97.   for (i = 0; i < 8; i++)
  98.     {
  99.       index = (i + (8 - select->index_in)) % 8;
  100.       if (index < 4)
  101.     marching_ants_pixels[i] = get_color (0, 0, 0);
  102.       else
  103.     marching_ants_pixels[i] = get_color (255, 255, 255);
  104.     }
  105. }
  106.  
  107. #define MAX_POINTS_INC 2048
  108.  
  109. static void
  110. selection_add_point (GdkPoint *points[8],
  111.              gint max_npoints[8],
  112.              gint npoints[8],
  113.              gint x, gint y)
  114. {
  115.   gint i, j;
  116.   j = (x - y) & 7;
  117.  
  118.   i = npoints[j]++;
  119.   if (i == max_npoints[j])
  120.     {
  121.       max_npoints[j] += 2048;
  122.       points[j] = g_realloc (points[j], sizeof (GdkPoint) * max_npoints[j]);
  123.     }
  124.   points[j][i].x = x;
  125.   points[j][i].y = y;
  126. }
  127.  
  128.  
  129. /* Render the segs_in array into points_in */
  130. static void
  131. selection_render_points (Selection *select)
  132. {
  133.   gint i, j;
  134.   gint max_npoints[8];
  135.   gint x, y;
  136.   gint dx, dy;
  137.   gint dxa, dya;
  138.   gint r;
  139.  
  140.   if (select->segs_in == NULL)
  141.     return;
  142.  
  143.   for (j = 0; j < 8; j++)
  144.     {
  145.       max_npoints[j] = MAX_POINTS_INC;
  146.       select->points_in[j] = g_new (GdkPoint, max_npoints[j]);
  147.       select->num_points_in[j] = 0;
  148.     }
  149.  
  150.   for (i = 0; i < select->num_segs_in; i++)
  151.     {
  152. #ifdef VERBOSE
  153.       g_print ("%2d: (%d, %d) - (%d, %d)\n", i,
  154.            select->segs_in[i].x1,
  155.            select->segs_in[i].y1,
  156.            select->segs_in[i].x2,
  157.            select->segs_in[i].y2);
  158. #endif
  159.       x = select->segs_in[i].x1;
  160.       dxa = select->segs_in[i].x2 - x;
  161.       if (dxa > 0)
  162.     {
  163.       dx = 1;
  164.     }
  165.       else
  166.     {
  167.       dxa = -dxa;
  168.       dx = -1;
  169.     }
  170.       y = select->segs_in[i].y1;
  171.       dya = select->segs_in[i].y2 - y;
  172.       if (dya > 0)
  173.     {
  174.       dy = 1;
  175.     }
  176.       else
  177.     {
  178.       dya = -dya;
  179.       dy = -1;
  180.     }
  181.       if (dxa > dya)
  182.     {
  183.       r = dya;
  184.       do {
  185.         selection_add_point (select->points_in,
  186.                  max_npoints,
  187.                  select->num_points_in,
  188.                  x, y);
  189.         x += dx;
  190.         r += dya;
  191.         if (r >= (dxa << 1)) {
  192.           y += dy;
  193.           r -= (dxa << 1);
  194.         }
  195.       } while (x != select->segs_in[i].x2);
  196.     }
  197.       else if (dxa < dya)
  198.     {
  199.       r = dxa;
  200.       do {
  201.         selection_add_point (select->points_in,
  202.                  max_npoints,
  203.                  select->num_points_in,
  204.                  x, y);
  205.         y += dy;
  206.         r += dxa;
  207.         if (r >= (dya << 1)) {
  208.           x += dx;
  209.           r -= (dya << 1);
  210.         }
  211.       } while (y != select->segs_in[i].y2);
  212.     }
  213.       else
  214.     selection_add_point (select->points_in,
  215.                  max_npoints,
  216.                  select->num_points_in,
  217.                  x, y);
  218.     }
  219. }
  220.  
  221. static void
  222. selection_draw (Selection *select)
  223. {
  224.   if (select->hidden)
  225.     return;
  226.  
  227.   if (select->segs_layer && select->index_layer == 0)
  228.     gdk_draw_segments (select->win, select->gc_layer,
  229.                select->segs_layer, select->num_segs_layer);
  230. #ifdef USE_XDRAWPOINTS
  231. #ifdef VERBOSE
  232.   {
  233.     gint j, sum;
  234.     sum = 0;
  235.     for (j = 0; j < 8; j++)
  236.       sum += select->num_points_in[j];
  237.  
  238.     g_print ("%d segments, %d points\n", select->num_segs_in, sum);
  239.   }
  240. #endif
  241.   if (select->segs_in)
  242.     {
  243.       gint i;
  244.  
  245.       if (select->index_in == 0)
  246.     {
  247.       for (i = 0; i < 4; i++)
  248.         if (select->num_points_in[i])
  249.           gdk_draw_points (select->win, select->gc_white,
  250.                    select->points_in[i], select->num_points_in[i]);
  251.       for (i = 4; i < 8; i++)
  252.         if (select->num_points_in[i])
  253.           gdk_draw_points (select->win, select->gc_black,
  254.                    select->points_in[i], select->num_points_in[i]);
  255.     }
  256.       else
  257.     {
  258.       i = ((select->index_in + 3) & 7);
  259.       if (select->num_points_in[i])
  260.         gdk_draw_points (select->win, select->gc_white,
  261.                  select->points_in[i], select->num_points_in[i]);
  262.       i = ((select->index_in + 7) & 7);
  263.       if (select->num_points_in[i])
  264.         gdk_draw_points (select->win, select->gc_black,
  265.                  select->points_in[i], select->num_points_in[i]);
  266.     }
  267.     }
  268. #else
  269.   if (select->segs_in)
  270.     gdk_draw_segments (select->win, select->gc_in,
  271.                select->segs_in, select->num_segs_in);
  272. #endif
  273.   if (select->segs_out && select->index_out == 0)
  274.     gdk_draw_segments (select->win, select->gc_out,
  275.                select->segs_out, select->num_segs_out);
  276. }
  277.  
  278.  
  279. static void
  280. selection_transform_segs (Selection  *select,
  281.               BoundSeg   *src_segs,
  282.               GdkSegment *dest_segs,
  283.               int         num_segs)
  284. {
  285.   GDisplay * gdisp;
  286.   int x, y;
  287.   int i;
  288.  
  289.   gdisp = (GDisplay *) select->gdisp;
  290.  
  291.   for (i = 0; i < num_segs; i++)
  292.     {
  293.       gdisplay_transform_coords (gdisp, src_segs[i].x1, src_segs[i].y1,
  294.                  &x, &y, 0);
  295.  
  296.       dest_segs[i].x1 = x;
  297.       dest_segs[i].y1 = y;
  298.  
  299.       gdisplay_transform_coords (gdisp, src_segs[i].x2, src_segs[i].y2,
  300.                  &x, &y, 0);
  301.  
  302.       dest_segs[i].x2 = x;
  303.       dest_segs[i].y2 = y;
  304.  
  305.       /*  If this segment is a closing segment && the segments lie inside
  306.        *  the region, OR if this is an opening segment and the segments
  307.        *  lie outside the region...
  308.        *  we need to transform it by one display pixel
  309.        */
  310.       if (!src_segs[i].open)
  311.     {
  312.       /*  If it is vertical  */
  313.       if (dest_segs[i].x1 == dest_segs[i].x2)
  314.         {
  315.           dest_segs[i].x1 -= 1;
  316.           dest_segs[i].x2 -= 1;
  317.         }
  318.       else
  319.         {
  320.           dest_segs[i].y1 -= 1;
  321.           dest_segs[i].y2 -= 1;
  322.         }
  323.     }
  324.     }
  325. }
  326.  
  327.  
  328. static void
  329. selection_generate_segs (Selection *select)
  330. {
  331.   GDisplay * gdisp;
  332.   BoundSeg *segs_in;
  333.   BoundSeg *segs_out;
  334.   BoundSeg *segs_layer;
  335.  
  336.   gdisp = (GDisplay *) select->gdisp;
  337.  
  338.   /*  Ask the gimage for the boundary of its selected region...
  339.    *  Then transform that information into a new buffer of XSegments
  340.    */
  341.   gimage_mask_boundary (gdisp->gimage, &segs_in, &segs_out,
  342.             &select->num_segs_in, &select->num_segs_out);
  343.   if (select->num_segs_in)
  344.     {
  345.       select->segs_in = (GdkSegment *) g_malloc (sizeof (GdkSegment) * select->num_segs_in);
  346.       selection_transform_segs (select, segs_in, select->segs_in, select->num_segs_in);
  347. #ifdef USE_XDRAWPOINTS
  348.       selection_render_points (select);
  349. #endif
  350.     }
  351.   else
  352.     select->segs_in = NULL;
  353.  
  354.   /*  Possible secondary boundary representation  */
  355.   if (select->num_segs_out)
  356.     {
  357.       select->segs_out = (GdkSegment *) g_malloc (sizeof (GdkSegment) * select->num_segs_out);
  358.       selection_transform_segs (select, segs_out, select->segs_out, select->num_segs_out);
  359.     }
  360.   else
  361.     select->segs_out = NULL;
  362.  
  363.   /*  The active layer's boundary  */
  364.   gimage_layer_boundary (gdisp->gimage, &segs_layer, &select->num_segs_layer);
  365.   if (select->num_segs_layer)
  366.     {
  367.       select->segs_layer = (GdkSegment *) g_malloc (sizeof (GdkSegment) * select->num_segs_layer);
  368.       selection_transform_segs (select, segs_layer, select->segs_layer, select->num_segs_layer);
  369.     }
  370.   else
  371.     select->segs_layer = NULL;
  372.  
  373.   g_free (segs_layer);
  374. }
  375.  
  376.  
  377. static void
  378. selection_free_segs (Selection *select)
  379. {
  380.   gint j;
  381.   if (select->segs_in)
  382.     g_free (select->segs_in);
  383.   if (select->segs_out)
  384.     g_free (select->segs_out);
  385.   if (select->segs_layer)
  386.     g_free (select->segs_layer);
  387.  
  388.   for (j = 0; j < 8; j++)
  389.     {
  390.       if (select->points_in[j])
  391.     g_free (select->points_in[j]);
  392.       select->points_in[j] = NULL;
  393.       select->num_points_in[j] = 0;
  394.     }
  395.  
  396.   select->segs_in        = NULL;
  397.   select->num_segs_in    = 0;
  398.   select->segs_out       = NULL;
  399.   select->num_segs_out   = 0;
  400.   select->segs_layer     = NULL;
  401.   select->num_segs_layer = 0;
  402. }
  403.  
  404.  
  405. static gint
  406. selection_start_marching (gpointer data)
  407. {
  408.   Selection * select;
  409.  
  410.   select = (Selection *) data;
  411.  
  412.   /*  if the RECALC bit is set, reprocess the boundaries  */
  413.   if (select->recalc)
  414.     {
  415.       selection_free_segs (select);
  416.       selection_generate_segs (select);
  417.       /* Toggle the RECALC flag */
  418.       select->recalc = FALSE;
  419.     }
  420.  
  421.   select->index_in = 0;
  422.   select->index_out = 0;
  423.   select->index_layer = 0;
  424.  
  425.   /*  Make sure the state is set to marching  */
  426.   select->state = MARCHING;
  427.  
  428.   /*  Draw the ants  */
  429.   if (select->cycle)
  430.     cycle_ant_colors (select);
  431.   else
  432.     {
  433.       gdk_gc_set_stipple (select->gc_in, marching_ants[select->index_in]);
  434.       gdk_gc_set_stipple (select->gc_out, marching_ants[select->index_out]);
  435.       gdk_gc_set_stipple (select->gc_layer, marching_ants[select->index_layer]);
  436.     }
  437.  
  438.   selection_draw (select);
  439.  
  440.   /*  Reset the timer  */
  441.   select->timer = gtk_timeout_add (select->speed,
  442.                    selection_march_ants,
  443.                    (gpointer) select);
  444.  
  445.   return FALSE;
  446. }
  447.  
  448. static gint
  449. selection_march_ants (gpointer data)
  450. {
  451.   Selection * select;
  452.  
  453.   select = (Selection *) data;
  454.  
  455.   /*  increment stipple index  */
  456.   select->index_in++;
  457. #ifndef USE_XDRAWPOINTS
  458.   if (select->index_in > 7)
  459.     select->index_in = 0;
  460. #endif
  461.  
  462.   /*  outside segments do not march, so index does not cycle  */
  463.   select->index_out++;
  464.  
  465.   /*  layer doesn't march   */
  466.   select->index_layer++;
  467.  
  468.   /*  Draw the ants  */
  469.   if (select->cycle)
  470.     cycle_ant_colors (select);
  471.   else
  472.     {
  473. #ifndef USE_XDRAWPOINTS
  474.       gdk_gc_set_stipple (select->gc_in, marching_ants[select->index_in]);
  475. #endif
  476.  
  477.       selection_draw (select);
  478.     }
  479.  
  480.   return TRUE;
  481. }
  482.  
  483. /*********************************/
  484. /*  Public function definitions  */
  485. /*********************************/
  486.  
  487. Selection *
  488. selection_create (GdkWindow *win,
  489.           gpointer   gdisp_ptr,
  490.           int        size,
  491.           int        width,
  492.           int        speed)
  493. {
  494.   GdkColor fg, bg;
  495.   GDisplay *gdisp;
  496.   Selection * new;
  497.   int base_type;
  498.   int i;
  499.  
  500.   gdisp = (GDisplay *) gdisp_ptr;
  501.  
  502.   new = (Selection *) g_malloc (sizeof (Selection));
  503.   base_type = gimage_base_type (gdisp->gimage);
  504.  
  505.   if (cycled_marching_ants)
  506.     {
  507.       new->cycle = TRUE;
  508.       if (!cycled_ants_pixmap)
  509.     cycled_ants_pixmap = create_cycled_ants_pixmap (win, gdisp->depth);
  510.  
  511.       new->cycle_pix = cycled_ants_pixmap;
  512.     }
  513.   else
  514.     {
  515.       new->cycle = FALSE;
  516.       if (!marching_ants[0])
  517.     for (i = 0; i < 8; i++)
  518.       marching_ants[i] = gdk_bitmap_create_from_data (win, (char*) ant_data[i], 8, 8);
  519.     }
  520.  
  521.   new->win            = win;
  522.   new->gdisp          = gdisp_ptr;
  523.   new->segs_in        = NULL;
  524.   new->segs_out       = NULL;
  525.   new->segs_layer     = NULL;
  526.   new->num_segs_in    = 0;
  527.   new->num_segs_out   = 0;
  528.   new->num_segs_layer = 0;
  529.   new->index_in       = 0;
  530.   new->index_out      = 0;
  531.   new->index_layer    = 0;
  532.   new->state          = INVISIBLE;
  533.   new->paused         = 0;
  534.   new->recalc         = TRUE;
  535.   new->speed          = speed;
  536.   new->hidden         = FALSE;
  537.  
  538.   for (i = 0; i < 8; i++)
  539.     new->points_in[i] = NULL;
  540.  
  541.   /*  create a new graphics context  */
  542.   new->gc_in = gdk_gc_new (new->win);
  543.  
  544.   if (new->cycle)
  545.     {
  546.       gdk_gc_set_fill (new->gc_in, GDK_TILED);
  547.       gdk_gc_set_tile (new->gc_in, new->cycle_pix);
  548.       gdk_gc_set_line_attributes (new->gc_in, 1, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER);
  549.     }
  550.   else
  551.     {
  552.       /*  get black and white pixels for this gdisplay  */
  553.       fg.pixel = gdisplay_black_pixel ((GDisplay *) gdisp_ptr);
  554.       bg.pixel = gdisplay_white_pixel ((GDisplay *) gdisp_ptr);
  555.  
  556.       gdk_gc_set_foreground (new->gc_in, &fg);
  557.       gdk_gc_set_background (new->gc_in, &bg);
  558.       gdk_gc_set_fill (new->gc_in, GDK_OPAQUE_STIPPLED);
  559.       gdk_gc_set_line_attributes (new->gc_in, 1, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER);
  560.     }
  561.  
  562. #ifdef USE_XDRAWPOINTS
  563.   new->gc_white = gdk_gc_new (new->win);
  564.   gdk_gc_set_foreground (new->gc_white, &bg);
  565.  
  566.   new->gc_black = gdk_gc_new (new->win);
  567.   gdk_gc_set_foreground (new->gc_black, &fg);
  568. #endif
  569.  
  570.   /*  Setup 2nd & 3rd GCs  */
  571.   fg.pixel = gdisplay_white_pixel ((GDisplay *) gdisp_ptr);
  572.   bg.pixel = gdisplay_gray_pixel ((GDisplay *) gdisp_ptr);
  573.  
  574.   /*  create a new graphics context  */
  575.   new->gc_out = gdk_gc_new (new->win);
  576.   gdk_gc_set_foreground (new->gc_out, &fg);
  577.   gdk_gc_set_background (new->gc_out, &bg);
  578.   gdk_gc_set_fill (new->gc_out, GDK_OPAQUE_STIPPLED);
  579.   gdk_gc_set_line_attributes (new->gc_out, 1, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER);
  580.  
  581.   /*  get black and color pixels for this gdisplay  */
  582.   fg.pixel = gdisplay_black_pixel ((GDisplay *) gdisp_ptr);
  583.   bg.pixel = gdisplay_color_pixel ((GDisplay *) gdisp_ptr);
  584.  
  585.   /*  create a new graphics context  */
  586.   new->gc_layer = gdk_gc_new (new->win);
  587.   gdk_gc_set_foreground (new->gc_layer, &fg);
  588.   gdk_gc_set_background (new->gc_layer, &bg);
  589.   gdk_gc_set_fill (new->gc_layer, GDK_OPAQUE_STIPPLED);
  590.   gdk_gc_set_line_attributes (new->gc_layer, 1, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER);
  591.  
  592.   return new;
  593. }
  594.  
  595.  
  596. void
  597. selection_pause (Selection *select)
  598. {
  599.   if (select->state != INVISIBLE)
  600.     gtk_timeout_remove (select->timer);
  601.  
  602.   select->paused ++;
  603. }
  604.  
  605.  
  606. void
  607. selection_resume (Selection *select)
  608. {
  609.   if (select->paused == 1)
  610.     {
  611.       select->state = INTRO;
  612.       select->timer = gtk_timeout_add (INITIAL_DELAY, selection_start_marching,
  613.                        (gpointer) select);
  614.     }
  615.  
  616.   select->paused--;
  617. }
  618.  
  619.  
  620. void
  621. selection_start (Selection *select,
  622.          int        recalc)
  623. {
  624.   /*  A call to selection_start with recalc == TRUE means that
  625.    *  we want to recalculate the selection boundary--usually
  626.    *  after scaling or panning the display, or modifying the
  627.    *  selection in some way.  If recalc == FALSE, the already
  628.    *  calculated boundary is simply redrawn.
  629.    */
  630.   if (recalc)
  631.     select->recalc = TRUE;
  632.  
  633.   /*  If this selection is paused, do not start it  */
  634.   if (select->paused > 0)
  635.     return;
  636.  
  637.   if (select->state != INVISIBLE)
  638.     gtk_timeout_remove (select->timer);
  639.  
  640.   select->state = INTRO;  /*  The state before the first draw  */
  641.   select->timer = gtk_timeout_add (INITIAL_DELAY, selection_start_marching,
  642.                    (gpointer) select);
  643. }
  644.  
  645.  
  646. void
  647. selection_invis (Selection *select)
  648. {
  649.   GDisplay * gdisp;
  650.   int x1, y1, x2, y2;
  651.  
  652.   if (select->state != INVISIBLE)
  653.     {
  654.       gtk_timeout_remove (select->timer);
  655.       select->state = INVISIBLE;
  656.     }
  657.  
  658.   gdisp = (GDisplay *) select->gdisp;
  659.  
  660.   /*  Find the bounds of the selection  */
  661.   if (gdisplay_mask_bounds (gdisp, &x1, &y1, &x2, &y2))
  662.     {
  663.       gdisplay_expose_area (gdisp, x1, y1, (x2 - x1), (y2 - y1));
  664.     }
  665.   else
  666.     {
  667.       selection_start (select, TRUE);
  668.     }
  669. }
  670.  
  671.  
  672. void
  673. selection_layer_invis (Selection *select)
  674. {
  675.   GDisplay * gdisp;
  676.   int x1, y1, x2, y2;
  677.   int x3, y3, x4, y4;
  678.  
  679.   if (select->state != INVISIBLE)
  680.     {
  681.       gtk_timeout_remove (select->timer);
  682.       select->state = INVISIBLE;
  683.     }
  684.   gdisp = (GDisplay *) select->gdisp;
  685.  
  686.   if (select->segs_layer != NULL && select->num_segs_layer == 4)
  687.     {
  688.       x1 = select->segs_layer[0].x1 - 1;
  689.       y1 = select->segs_layer[0].y1 - 1;
  690.       x2 = select->segs_layer[3].x2 + 1;
  691.       y2 = select->segs_layer[3].y2 + 1;
  692.  
  693.       x3 = select->segs_layer[0].x1 + 1;
  694.       y3 = select->segs_layer[0].y1 + 1;
  695.       x4 = select->segs_layer[3].x2 - 1;
  696.       y4 = select->segs_layer[3].y2 - 1;
  697.  
  698.       /*  expose the region  */
  699.       gdisplay_expose_area (gdisp, x1, y1, (x2 - x1) + 1, (y3 - y1) + 1);
  700.       gdisplay_expose_area (gdisp, x1, y3, (x3 - x1) + 1, (y4 - y3) + 1);
  701.       gdisplay_expose_area (gdisp, x1, y4, (x2 - x1) + 1, (y2 - y4) + 1);
  702.       gdisplay_expose_area (gdisp, x4, y3, (x2 - x4) + 1, (y4 - y3) + 1);
  703.     }
  704. }
  705.  
  706.  
  707. void
  708. selection_hide (Selection *select,
  709.         void      *gdisp_ptr)
  710. {
  711.   selection_invis (select);
  712.   selection_layer_invis (select);
  713.  
  714.   /*  toggle the visibility  */
  715.   select->hidden = select->hidden ? FALSE : TRUE;
  716.  
  717.   selection_start (select, TRUE);
  718. }
  719.  
  720.  
  721. void
  722. selection_free (Selection *select)
  723. {
  724.   if (select->state != INVISIBLE)
  725.     gtk_timeout_remove (select->timer);
  726.  
  727.   if (select->gc_in)
  728.     gdk_gc_destroy (select->gc_in);
  729.   if (select->gc_out)
  730.     gdk_gc_destroy (select->gc_out);
  731.   if (select->gc_layer)
  732.     gdk_gc_destroy (select->gc_layer);
  733. #ifdef USE_XDRAWPOINTS
  734.   if (select->gc_white)
  735.     gdk_gc_destroy (select->gc_white);
  736.   if (select->gc_black)
  737.     gdk_gc_destroy (select->gc_black);
  738. #endif
  739.   selection_free_segs (select);
  740.   g_free (select);
  741. }
  742.