home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / app / cursorutil.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-12-17  |  14.4 KB  |  565 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 <gtk/gtk.h>
  22.  
  23. #include "apptypes.h"
  24.  
  25. #include "appenv.h"
  26. #include "cursorutil.h"
  27. #include "dialog_handler.h"
  28. #include "gdisplay.h" /* for gdisplay_*_override_cursor() */
  29. #include "tools.h"
  30.  
  31. #include "cursors/mouse.xbm"
  32. #include "cursors/mouse_mask.xbm"
  33. #include "cursors/crosshair.xbm"
  34. #include "cursors/crosshair_mask.xbm"
  35. #include "cursors/crosshair_small.xbm"
  36. #include "cursors/crosshair_small_mask.xbm"
  37. #include "cursors/bad.xbm"
  38. #include "cursors/bad_mask.xbm"
  39. #include "cursors/zoom.xbm"
  40. #include "cursors/zoom_mask.xbm"
  41. #include "cursors/dropper.xbm"
  42. #include "cursors/dropper_mask.xbm"
  43.  
  44. /* modifiers */
  45. #include "cursors/plus.xbm"
  46. #include "cursors/plus_mask.xbm"
  47. #include "cursors/minus.xbm"
  48. #include "cursors/minus_mask.xbm"
  49. #include "cursors/intersect.xbm"
  50. #include "cursors/intersect_mask.xbm"
  51. #include "cursors/move.xbm"
  52. #include "cursors/move_mask.xbm"
  53. #include "cursors/resize.xbm"
  54. #include "cursors/resize_mask.xbm"
  55. #include "cursors/control.xbm"
  56. #include "cursors/control_mask.xbm"
  57. #include "cursors/anchor.xbm"
  58. #include "cursors/anchor_mask.xbm"
  59. #include "cursors/foreground.xbm"
  60. #include "cursors/foreground_mask.xbm"
  61. #include "cursors/background.xbm"
  62. #include "cursors/background_mask.xbm"
  63. #include "cursors/pattern.xbm"
  64. #include "cursors/pattern_mask.xbm"
  65. #include "cursors/hand.xbm"
  66. #include "cursors/hand_mask.xbm"
  67.  
  68.  
  69. /* FIXME: gimp_busy HACK */
  70. gboolean gimp_busy = FALSE;
  71.  
  72. static BitmapCursor gimp_cursors[] =
  73. /* these have to match up with the enum in cursorutil.h */
  74. {
  75.   {
  76.     mouse_bits, mouse_mask_bits,
  77.     mouse_width, mouse_height,
  78.     mouse_x_hot, mouse_y_hot, NULL, NULL, NULL
  79.   },
  80.   {
  81.     crosshair_bits, crosshair_mask_bits,
  82.     crosshair_width, crosshair_height,
  83.     crosshair_x_hot, crosshair_y_hot, NULL, NULL, NULL
  84.   },
  85.   {
  86.     crosshair_small_bits, crosshair_small_mask_bits,
  87.     crosshair_small_width, crosshair_small_height,
  88.     crosshair_small_x_hot, crosshair_small_y_hot, NULL, NULL, NULL
  89.   },
  90.   {
  91.     bad_bits, bad_mask_bits,
  92.     bad_width, bad_height,
  93.     bad_x_hot, bad_y_hot, NULL, NULL, NULL
  94.   },
  95.   {
  96.     zoom_bits, zoom_mask_bits,
  97.     zoom_width, zoom_height,
  98.     zoom_x_hot, zoom_y_hot, NULL, NULL, NULL
  99.   },
  100.   {
  101.     dropper_bits, dropper_mask_bits,
  102.     dropper_width, dropper_height,
  103.     dropper_x_hot, dropper_y_hot, NULL, NULL, NULL
  104.   }
  105. };
  106.  
  107. enum
  108. {
  109.   GIMP_PLUS_CURSOR = GIMP_LAST_CURSOR_ENTRY + 1,
  110.   GIMP_MINUS_CURSOR,
  111.   GIMP_INTERSECT_CURSOR,
  112.   GIMP_MOVE_CURSOR,
  113.   GIMP_RESIZE_CURSOR,
  114.   GIMP_CONTROL_CURSOR,
  115.   GIMP_ANCHOR_CURSOR,
  116.   GIMP_FOREGROUND_CURSOR,
  117.   GIMP_BACKGROUND_CURSOR,
  118.   GIMP_PATTERN_CURSOR,
  119.   GIMP_HAND_CURSOR
  120. };
  121.  
  122. static BitmapCursor modifier_cursors[] =
  123. /* these have to match up with the enum above */
  124. {
  125.   {
  126.     plus_bits, plus_mask_bits,
  127.     plus_width, plus_height,
  128.     plus_x_hot, plus_y_hot, NULL, NULL, NULL
  129.   },
  130.   {
  131.     minus_bits, minus_mask_bits,
  132.     minus_width, minus_height,
  133.     minus_x_hot, minus_y_hot, NULL, NULL, NULL
  134.   },
  135.   {
  136.     intersect_bits, intersect_mask_bits,
  137.     intersect_width, intersect_height,
  138.     intersect_x_hot, intersect_y_hot, NULL, NULL, NULL
  139.   },
  140.   {
  141.     move_bits, move_mask_bits,
  142.     move_width, move_height,
  143.     move_x_hot, move_y_hot, NULL, NULL, NULL
  144.   },
  145.   {
  146.     resize_bits, resize_mask_bits,
  147.     resize_width, resize_height,
  148.     resize_x_hot, resize_y_hot, NULL, NULL, NULL
  149.   },
  150.   {
  151.     control_bits, control_mask_bits,
  152.     control_width, control_height,
  153.     control_x_hot, control_y_hot, NULL, NULL, NULL
  154.   },
  155.   {
  156.     anchor_bits, anchor_mask_bits,
  157.     anchor_width, anchor_height,
  158.     anchor_x_hot, anchor_y_hot, NULL, NULL, NULL
  159.   },
  160.   {
  161.     foreground_bits, foreground_mask_bits,
  162.     foreground_width, foreground_height,
  163.     foreground_x_hot, foreground_y_hot, NULL, NULL, NULL
  164.   },
  165.   {
  166.     background_bits, background_mask_bits,
  167.     background_width, background_height,
  168.     background_x_hot, background_y_hot, NULL, NULL, NULL
  169.   },
  170.   {
  171.     pattern_bits, pattern_mask_bits,
  172.     pattern_width, pattern_height,
  173.     pattern_x_hot, pattern_y_hot, NULL, NULL, NULL
  174.   },
  175.   {
  176.     hand_bits, hand_mask_bits,
  177.     hand_width, hand_height,
  178.     hand_x_hot, hand_y_hot, NULL, NULL, NULL
  179.   }
  180. };
  181.  
  182.  
  183. extern GSList   *display_list; /* It's in gdisplay.c, FYI */
  184. static gboolean  pending_removebusy = FALSE;
  185.  
  186.  
  187. static void
  188. create_cursor_bitmaps (BitmapCursor *bmcursor)
  189. {
  190.   if (bmcursor->bitmap == NULL)
  191.     bmcursor->bitmap = gdk_bitmap_create_from_data (NULL, bmcursor->bits,
  192.                             bmcursor->width,
  193.                             bmcursor->height);
  194.   g_return_if_fail (bmcursor->bitmap != NULL);
  195.  
  196.   if (bmcursor->mask == NULL)
  197.     bmcursor->mask = gdk_bitmap_create_from_data (NULL, bmcursor->mask_bits,
  198.                           bmcursor->width,
  199.                           bmcursor->height);
  200.   g_return_if_fail (bmcursor->mask != NULL);
  201. }
  202.  
  203. static void
  204. create_cursor (BitmapCursor *bmcursor)
  205. {
  206.   if (bmcursor->bitmap == NULL ||
  207.       bmcursor->mask == NULL)
  208.     create_cursor_bitmaps (bmcursor);
  209.  
  210.   if (bmcursor->cursor == NULL)
  211.     {
  212.       GdkColor fg, bg;
  213.  
  214.       /* should have a way to configure the mouse colors */
  215.       gdk_color_parse ("#FFFFFF", &bg);
  216.       gdk_color_parse ("#000000", &fg);
  217.  
  218.       bmcursor->cursor = gdk_cursor_new_from_pixmap (bmcursor->bitmap,
  219.                              bmcursor->mask,
  220.                              &fg, &bg,
  221.                              bmcursor->x_hot,
  222.                              bmcursor->y_hot);
  223.     }
  224.  
  225.   g_return_if_fail (bmcursor->cursor != NULL);
  226. }
  227.  
  228. static void
  229. gimp_change_win_cursor (GdkWindow      *win,
  230.             GimpCursorType  curtype,
  231.             ToolType        tool_type,
  232.             CursorModifier  modifier,
  233.             gboolean        toggle_cursor)
  234. {
  235.   GdkCursor      *cursor;
  236.   GimpCursorType  modtype = GIMP_PLUS_CURSOR;
  237.  
  238.   GdkBitmap *bitmap;
  239.   GdkBitmap *mask;
  240.  
  241.   GdkColor   color;
  242.   GdkColor   fg, bg;
  243.  
  244.   static GdkGC *gc = NULL;
  245.  
  246.   gint width;
  247.   gint height;
  248.  
  249.   BitmapCursor *bmcursor   = NULL;
  250.   BitmapCursor *bmmodifier = NULL;
  251.   BitmapCursor *bmtool     = NULL;
  252.  
  253.   g_return_if_fail (curtype < GIMP_LAST_CURSOR_ENTRY);
  254.  
  255.   /*  allow the small tool cursor only with the standard mouse,
  256.    *  the small crosshair and the bad cursor
  257.    */
  258.   if (curtype != GIMP_MOUSE_CURSOR &&
  259.       curtype != GIMP_CROSSHAIR_SMALL_CURSOR &&
  260.       curtype != GIMP_BAD_CURSOR)
  261.     tool_type = TOOL_TYPE_NONE;
  262.  
  263.   curtype -= GIMP_MOUSE_CURSOR;
  264.   bmcursor = &gimp_cursors[(int)curtype];
  265.  
  266.   if (modifier  == CURSOR_MODIFIER_NONE &&
  267.       tool_type == TOOL_TYPE_NONE)
  268.     {
  269.       if  (bmcursor->cursor == NULL)
  270.     create_cursor (bmcursor);
  271.  
  272.       gdk_window_set_cursor (win, bmcursor->cursor);
  273.  
  274.       return;
  275.     }
  276.  
  277.   switch (modifier)
  278.     {
  279.     case CURSOR_MODIFIER_PLUS:
  280.       modtype = GIMP_PLUS_CURSOR;
  281.       break;
  282.     case CURSOR_MODIFIER_MINUS:
  283.       modtype = GIMP_MINUS_CURSOR;
  284.       break;
  285.     case CURSOR_MODIFIER_INTERSECT:
  286.       modtype = GIMP_INTERSECT_CURSOR;
  287.       break;
  288.     case CURSOR_MODIFIER_MOVE:
  289.       modtype = GIMP_MOVE_CURSOR;
  290.       break;
  291.     case CURSOR_MODIFIER_RESIZE:
  292.       modtype = GIMP_RESIZE_CURSOR;
  293.       break;
  294.     case CURSOR_MODIFIER_CONTROL:
  295.       modtype = GIMP_CONTROL_CURSOR;
  296.       break;
  297.     case CURSOR_MODIFIER_ANCHOR:
  298.       modtype = GIMP_ANCHOR_CURSOR;
  299.       break;
  300.     case CURSOR_MODIFIER_FOREGROUND:
  301.       modtype = GIMP_FOREGROUND_CURSOR;
  302.       break;
  303.     case CURSOR_MODIFIER_BACKGROUND:
  304.       modtype = GIMP_BACKGROUND_CURSOR;
  305.       break;
  306.     case CURSOR_MODIFIER_PATTERN:
  307.       modtype = GIMP_PATTERN_CURSOR;
  308.       break;
  309.     case CURSOR_MODIFIER_HAND:
  310.       modtype = GIMP_HAND_CURSOR;
  311.       break;
  312.     default:
  313.       break;
  314.     }
  315.  
  316.   if (modifier != CURSOR_MODIFIER_NONE)
  317.     {
  318.       modtype -= GIMP_PLUS_CURSOR;
  319.       bmmodifier = &modifier_cursors[(int)modtype];
  320.     }
  321.  
  322.   if (tool_type != TOOL_TYPE_NONE)
  323.     {
  324.       if (toggle_cursor)
  325.     {
  326.       if (tool_info[(gint) tool_type].toggle_cursor.bits != NULL &&
  327.           tool_info[(gint) tool_type].toggle_cursor.mask_bits != NULL)
  328.         bmtool = &tool_info[(gint) tool_type].toggle_cursor;
  329.     }
  330.       else
  331.     {
  332.       if (tool_info[(gint) tool_type].tool_cursor.bits != NULL &&
  333.           tool_info[(gint) tool_type].tool_cursor.mask_bits != NULL)
  334.         bmtool = &tool_info[(gint) tool_type].tool_cursor;
  335.     }
  336.     }
  337.  
  338.   if (bmcursor->bitmap == NULL ||
  339.       bmcursor->mask == NULL)
  340.     create_cursor_bitmaps (bmcursor);
  341.  
  342.   if (bmmodifier &&
  343.       (bmmodifier->bitmap == NULL ||
  344.        bmmodifier->mask == NULL))
  345.     create_cursor_bitmaps (bmmodifier);
  346.  
  347.  if (bmtool &&
  348.       (bmtool->bitmap == NULL ||
  349.        bmtool->mask == NULL))
  350.     create_cursor_bitmaps (bmtool);
  351.  
  352.   if (gc == NULL)
  353.     gc = gdk_gc_new (bmcursor->bitmap);
  354.  
  355.   gdk_window_get_size (bmcursor->bitmap, &width, &height);
  356.  
  357.   bitmap = gdk_pixmap_new (NULL, width, height, 1);
  358.   mask   = gdk_pixmap_new (NULL, width, height, 1);
  359.  
  360.   color.pixel = 1;
  361.   gdk_gc_set_foreground (gc, &color);
  362.  
  363.   gdk_draw_pixmap (bitmap, gc, bmcursor->bitmap,
  364.                    0, 0, 0, 0, width, height);
  365.  
  366.   if (bmmodifier)
  367.     {
  368.       gdk_gc_set_clip_mask (gc, bmmodifier->bitmap);
  369.       gdk_draw_pixmap (bitmap, gc, bmmodifier->bitmap,
  370.                0, 0, 0, 0, width, height);
  371.       gdk_gc_set_clip_mask (gc, NULL);
  372.     }
  373.  
  374.   if (bmtool)
  375.     {
  376.       gdk_gc_set_clip_mask (gc, bmtool->bitmap);
  377.       gdk_draw_pixmap (bitmap, gc, bmtool->bitmap,
  378.                0, 0, 0, 0, width, height);
  379.       gdk_gc_set_clip_mask (gc, NULL);
  380.     }
  381.  
  382.   gdk_draw_pixmap (mask, gc, bmcursor->mask,
  383.                    0, 0, 0, 0, width, height);
  384.  
  385.   if (bmmodifier)
  386.     {
  387.       gdk_gc_set_clip_mask (gc, bmmodifier->mask);
  388.       gdk_draw_pixmap (mask, gc, bmmodifier->mask,
  389.                0, 0, 0, 0, width, height);
  390.       gdk_gc_set_clip_mask (gc, NULL);
  391.     }
  392.  
  393.   if (bmtool)
  394.     {
  395.       gdk_gc_set_clip_mask (gc, bmtool->mask);
  396.       gdk_draw_pixmap (mask, gc, bmtool->mask,
  397.                0, 0, 0, 0, width, height);
  398.       gdk_gc_set_clip_mask (gc, NULL);
  399.     }
  400.  
  401.   /* should have a way to configure the mouse colors */
  402.   gdk_color_parse ("#FFFFFF", &bg);
  403.   gdk_color_parse ("#000000", &fg);
  404.  
  405.   cursor = gdk_cursor_new_from_pixmap (bitmap, mask,
  406.                        &fg, &bg,
  407.                        bmcursor->x_hot,
  408.                        bmcursor->y_hot);
  409.   gdk_window_set_cursor (win, cursor);
  410.   gdk_cursor_destroy (cursor);
  411.   gdk_bitmap_unref (bitmap);
  412.   gdk_bitmap_unref (mask);
  413. }
  414.  
  415. void
  416. change_win_cursor (GdkWindow      *win,
  417.            GdkCursorType   cursortype,
  418.            ToolType        tool_type,
  419.            CursorModifier  modifier,
  420.            gboolean        toggle_cursor)
  421. {
  422.   GdkCursor *cursor;
  423.   
  424.   if (cursortype > GDK_LAST_CURSOR)
  425.     {
  426.       gimp_change_win_cursor (win, (GimpCursorType) cursortype,
  427.                   tool_type,
  428.                   modifier,
  429.                   toggle_cursor);
  430.       return;
  431.     }
  432.  
  433.   cursor = gdk_cursor_new (cursortype);
  434.   gdk_window_set_cursor (win, cursor);
  435.   gdk_cursor_destroy (cursor);
  436. }
  437.  
  438. void
  439. unset_win_cursor (GdkWindow *win)
  440. {
  441.   gdk_window_set_cursor (win, NULL);
  442. }
  443.      
  444. void
  445. gimp_add_busy_cursors_until_idle (void)
  446. {
  447.   if (!pending_removebusy)
  448.     {
  449.       gimp_add_busy_cursors ();
  450.       gtk_idle_add_priority (GTK_PRIORITY_HIGH,
  451.                  gimp_remove_busy_cursors, NULL);
  452.       pending_removebusy = TRUE;
  453.     }
  454. }
  455.      
  456. void
  457. gimp_add_busy_cursors (void)
  458. {
  459.   GDisplay *gdisp;
  460.   GSList   *list;
  461.  
  462.   /* FIXME: gimp_busy HACK */
  463.   gimp_busy = TRUE;
  464.  
  465.   /* Canvases */
  466.   for (list = display_list; list; list = g_slist_next (list))
  467.     {
  468.       gdisp = (GDisplay *) list->data;
  469.       gdisplay_install_override_cursor (gdisp, GDK_WATCH);
  470.     }
  471.  
  472.   /* Dialogs */
  473.   dialog_idle_all ();
  474.  
  475.   gdk_flush ();
  476. }
  477.  
  478. gint
  479. gimp_remove_busy_cursors (gpointer data)
  480. {
  481.   GDisplay *gdisp;
  482.   GSList   *list;
  483.  
  484.   /* Canvases */
  485.   for (list = display_list; list; list = g_slist_next (list))
  486.     {
  487.       gdisp = (GDisplay *) list->data;
  488.       gdisplay_remove_override_cursor (gdisp);
  489.     }
  490.  
  491.   /* Dialogs */
  492.   dialog_unidle_all ();
  493.  
  494.   pending_removebusy = FALSE;
  495.  
  496.   /* FIXME: gimp_busy HACK */
  497.   gimp_busy = FALSE;
  498.  
  499.   return 0;
  500. }
  501.  
  502.  
  503. /***************************************************************/
  504. /* gtkutil_compress_motion:
  505.  
  506.    This function walks the whole GDK event queue seeking motion events
  507.    corresponding to the widget 'widget'.  If it finds any it will
  508.    remove them from the queue, write the most recent motion offset
  509.    to 'lastmotion_x' and 'lastmotion_y', then return TRUE.  Otherwise
  510.    it will return FALSE and 'lastmotion_x' / 'lastmotion_y' will be
  511.    untouched.
  512.  */
  513. /* The gtkutil_compress_motion function source may be re-used under
  514.    the XFree86-style license. <adam@gimp.org> */
  515. gboolean
  516. gtkutil_compress_motion (GtkWidget *widget,
  517.              gdouble   *lastmotion_x,
  518.              gdouble   *lastmotion_y)
  519. {
  520.   GdkEvent *event;
  521.   GList    *requeued_events = NULL;
  522.   GList    *list;
  523.   gboolean  success = FALSE;
  524.  
  525.   /* Move the entire GDK event queue to a private list, filtering
  526.      out any motion events for the desired widget. */
  527.   while (gdk_events_pending ())
  528.     {
  529.       event = gdk_event_get ();
  530.  
  531.       if (!event)
  532.     {
  533.       /* Do nothing */
  534.     }
  535.       else if ((gtk_get_event_widget (event) == widget) &&
  536.            (event->any.type == GDK_MOTION_NOTIFY))
  537.     {
  538.       *lastmotion_x = event->motion.x;
  539.       *lastmotion_y = event->motion.y;
  540.       
  541.       gdk_event_free (event);
  542.       success = TRUE;
  543.     }
  544.       else
  545.     {
  546.       requeued_events = g_list_prepend (requeued_events, event);
  547.     }
  548.     }
  549.   
  550.   /* Replay the remains of our private event list back into the
  551.      event queue in order. */
  552.  
  553.   requeued_events = g_list_reverse (requeued_events);
  554.  
  555.   for (list = requeued_events; list; list = g_list_next (list))
  556.     {
  557.       gdk_event_put ((GdkEvent*) list->data);
  558.       gdk_event_free ((GdkEvent*) list->data);
  559.     }
  560.   
  561.   g_list_free (requeued_events);
  562.  
  563.   return success;
  564. }
  565.