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 / gimphelpui.c < prev    next >
C/C++ Source or Header  |  2004-10-04  |  12KB  |  428 lines

  1. /* LIBGIMP - The GIMP Library
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  4.  * gimphelpui.c
  5.  * Copyright (C) 2000-2003 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 2 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, write to the
  19.  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  20.  * Boston, MA 02111-1307, USA.
  21.  */
  22.  
  23. #include "config.h"
  24.  
  25. #include <gtk/gtk.h>
  26. #include <gdk/gdkkeysyms.h>
  27.  
  28. #include "gimpwidgetstypes.h"
  29.  
  30. #include "gimpdialog.h"
  31. #include "gimphelpui.h"
  32. #include "gimpwidgets-private.h"
  33.  
  34.  
  35. typedef enum
  36. {
  37.   GIMP_WIDGET_HELP_TYPE_HELP = 0xff
  38. } GimpWidgetHelpType;
  39.  
  40.  
  41. /*  local function prototypes  */
  42.  
  43. static const gchar * gimp_help_get_help_data       (GtkWidget      *widget,
  44.                                                     GtkWidget     **help_widget,
  45.                                                     gpointer       *ret_data);
  46. static gboolean   gimp_help_callback               (GtkWidget      *widget,
  47.                                                     GimpWidgetHelpType help_type,
  48.                                                     GimpHelpFunc    help_func);
  49.  
  50. static gboolean   gimp_context_help_idle_start     (gpointer        widget);
  51. static gboolean   gimp_context_help_button_press   (GtkWidget      *widget,
  52.                                                     GdkEventButton *bevent,
  53.                                                     gpointer        data);
  54. static gboolean   gimp_context_help_idle_show_help (gpointer        data);
  55.  
  56.  
  57. /*  local variables  */
  58.  
  59. static GtkTooltips *tool_tips = NULL;
  60.  
  61.  
  62. /*  public functions  */
  63.  
  64. /**
  65.  * _gimp_help_init:
  66.  *
  67.  * This function initializes GIMP's help system.
  68.  *
  69.  * Currently it only creates a #GtkTooltips object with gtk_tooltips_new()
  70.  * which will be used by gimp_help_set_help_data().
  71.  *
  72.  * Nota that this function is called automatically by gimp_widgets_init().
  73.  **/
  74. void
  75. _gimp_help_init (void)
  76. {
  77.   if (tool_tips)
  78.     {
  79.       g_warning ("_gimp_help_init() must only be called once!");
  80.       return;
  81.     }
  82.  
  83.   tool_tips = gtk_tooltips_new ();
  84.  
  85.   /* take ownership of the tooltips */
  86.   g_object_ref (tool_tips);
  87.   gtk_object_sink (GTK_OBJECT (tool_tips));
  88. }
  89.  
  90. /**
  91.  * gimp_help_enable_tooltips:
  92.  *
  93.  * This function calls gtk_tooltips_enable().
  94.  **/
  95. void
  96. gimp_help_enable_tooltips (void)
  97. {
  98.   gtk_tooltips_enable (tool_tips);
  99. }
  100.  
  101. /**
  102.  * gimp_help_disable_tooltips:
  103.  *
  104.  * This function calls gtk_tooltips_disable().
  105.  **/
  106. void
  107. gimp_help_disable_tooltips (void)
  108. {
  109.   gtk_tooltips_disable (tool_tips);
  110. }
  111.  
  112. /**
  113.  * gimp_standard_help_func:
  114.  * @help_id:   A unique help identifier.
  115.  * @help_data: The @help_data passed to gimp_help_connect().
  116.  *
  117.  * This is the standard GIMP help function which does nothing but calling
  118.  * gimp_help(). It is the right function to use in almost all cases.
  119.  **/
  120. void
  121. gimp_standard_help_func (const gchar *help_id,
  122.                          gpointer     help_data)
  123. {
  124.   if (! _gimp_standard_help_func)
  125.     {
  126.       g_warning ("%s: you must call gimp_widgets_init() before using "
  127.                  "the help system", G_STRFUNC);
  128.       return;
  129.     }
  130.  
  131.   (* _gimp_standard_help_func) (help_id, help_data);
  132. }
  133.  
  134. /**
  135.  * gimp_help_connect:
  136.  * @widget: The widget you want to connect the help accelerator for. Will
  137.  *          be a #GtkWindow in most cases.
  138.  * @help_func: The function which will be called if the user presses "F1".
  139.  * @help_id:   The @help_id which will be passed to @help_func.
  140.  * @help_data: The @help_data pointer which will be passed to @help_func.
  141.  *
  142.  * Note that this function is automatically called by all libgimp dialog
  143.  * constructors. You only have to call it for windows/dialogs you created
  144.  * "manually".
  145.  **/
  146. void
  147. gimp_help_connect (GtkWidget    *widget,
  148.                    GimpHelpFunc  help_func,
  149.                    const gchar  *help_id,
  150.                    gpointer      help_data)
  151. {
  152.   static gboolean initialized = FALSE;
  153.  
  154.   g_return_if_fail (GTK_IS_WIDGET (widget));
  155.   g_return_if_fail (help_func != NULL);
  156.  
  157.   /*  set up the help signals
  158.    */
  159.   if (! initialized)
  160.     {
  161.       GtkBindingSet *binding_set;
  162.  
  163.       binding_set =
  164.         gtk_binding_set_by_class (g_type_class_peek (GTK_TYPE_WIDGET));
  165.  
  166.       gtk_binding_entry_add_signal (binding_set, GDK_F1, 0,
  167.                                     "show_help", 1,
  168.                                     GTK_TYPE_WIDGET_HELP_TYPE,
  169.                                     GIMP_WIDGET_HELP_TYPE_HELP);
  170.       gtk_binding_entry_add_signal (binding_set, GDK_KP_F1, 0,
  171.                                     "show_help", 1,
  172.                                     GTK_TYPE_WIDGET_HELP_TYPE,
  173.                                     GIMP_WIDGET_HELP_TYPE_HELP);
  174.  
  175.       initialized = TRUE;
  176.     }
  177.  
  178.   gimp_help_set_help_data (widget, NULL, help_id);
  179.  
  180.   g_object_set_data (G_OBJECT (widget), "gimp-help-data", help_data);
  181.  
  182.   g_signal_connect (widget, "show_help",
  183.                     G_CALLBACK (gimp_help_callback),
  184.                     help_func);
  185.  
  186.   gtk_widget_add_events (widget, GDK_BUTTON_PRESS_MASK);
  187. }
  188.  
  189. /**
  190.  * gimp_help_set_help_data:
  191.  * @widget:  The #GtkWidget you want to set a @tooltip and/or @help_id for.
  192.  * @tooltip: The text for this widget's tooltip (or %NULL).
  193.  * @help_id: The @help_id for the #GtkTipsQuery tooltips inspector.
  194.  *
  195.  * The reason why we don't use gtk_tooltips_set_tip() is that it's
  196.  * impossible to set a @private_tip (aka @help_id) without a visible
  197.  * @tooltip.
  198.  *
  199.  * This function can be called with #NULL for @tooltip. Use this feature
  200.  * if you want to set a help link for a widget which shouldn't have
  201.  * a visible tooltip.
  202.  **/
  203. void
  204. gimp_help_set_help_data (GtkWidget   *widget,
  205.                          const gchar *tooltip,
  206.                          const gchar *help_id)
  207. {
  208.   g_return_if_fail (GTK_IS_WIDGET (widget));
  209.  
  210.   if (tooltip)
  211.     gtk_tooltips_set_tip (tool_tips, widget, tooltip, help_id);
  212.   else
  213.     g_object_set_qdata (G_OBJECT (widget), GIMP_HELP_ID, (gpointer) help_id);
  214. }
  215.  
  216. /**
  217.  * gimp_context_help:
  218.  * @widget: Any #GtkWidget on the screen.
  219.  *
  220.  * This function invokes the context help inspector.
  221.  *
  222.  * The mouse cursor will turn turn into a question mark and the user can
  223.  * click on any widget of the application which started the inspector.
  224.  *
  225.  * If the widget the user clicked on has a @help_id string attached
  226.  * (see gimp_help_set_help_data()), the corresponding help page will
  227.  * be displayed. Otherwise the help system will ascend the widget hierarchy
  228.  * until it finds an attached @help_id string (which should be the
  229.  * case at least for every window/dialog).
  230.  **/
  231. void
  232. gimp_context_help (GtkWidget *widget)
  233. {
  234.   g_return_if_fail (GTK_IS_WIDGET (widget));
  235.  
  236.   gimp_help_callback (widget, GTK_WIDGET_HELP_WHATS_THIS, NULL);
  237. }
  238.  
  239. /**
  240.  * gimp_help_id_quark:
  241.  *
  242.  * This function returns the #GQuark which should be used as key when
  243.  * attaching help IDs to widgets and objects.
  244.  *
  245.  * Return value: The #GQuark.
  246.  *
  247.  * Since: GIMP 2.2
  248.  **/
  249. GQuark
  250. gimp_help_id_quark (void)
  251. {
  252.   static GQuark quark = 0;
  253.  
  254.   if (! quark)
  255.     quark = g_quark_from_static_string ("gimp-help-id");
  256.  
  257.   return quark;
  258. }
  259.  
  260.  
  261. /*  private functions  */
  262.  
  263. static const gchar *
  264. gimp_help_get_help_data (GtkWidget  *widget,
  265.                          GtkWidget **help_widget,
  266.                          gpointer   *ret_data)
  267. {
  268.   GtkTooltipsData *tooltips_data;
  269.   gchar           *help_id   = NULL;
  270.   gpointer         help_data = NULL;
  271.  
  272.   for (; widget; widget = widget->parent)
  273.     {
  274.       tooltips_data = gtk_tooltips_data_get (widget);
  275.  
  276.       if (tooltips_data && tooltips_data->tip_private)
  277.         help_id = tooltips_data->tip_private;
  278.       else
  279.         help_id = g_object_get_qdata (G_OBJECT (widget), GIMP_HELP_ID);
  280.  
  281.       help_data = g_object_get_data (G_OBJECT (widget), "gimp-help-data");
  282.  
  283.       if (help_id)
  284.         {
  285.           if (help_widget)
  286.             *help_widget = widget;
  287.  
  288.           if (ret_data)
  289.             *ret_data = help_data;
  290.  
  291.           return (const gchar *) help_id;
  292.         }
  293.     }
  294.  
  295.   if (help_widget)
  296.     *help_widget = NULL;
  297.  
  298.   if (ret_data)
  299.     *ret_data = NULL;
  300.  
  301.   return NULL;
  302. }
  303.  
  304. static gboolean
  305. gimp_help_callback (GtkWidget          *widget,
  306.                     GimpWidgetHelpType  help_type,
  307.                     GimpHelpFunc        help_func)
  308. {
  309.   switch (help_type)
  310.     {
  311.     case GIMP_WIDGET_HELP_TYPE_HELP:
  312.       if (help_func)
  313.         {
  314.           GtkTooltipsData *tooltips_data;
  315.           gchar           *help_id   = NULL;
  316.           gpointer         help_data = NULL;
  317.  
  318.           tooltips_data = gtk_tooltips_data_get (widget);
  319.  
  320.           if (tooltips_data && tooltips_data->tip_private)
  321.             help_id = tooltips_data->tip_private;
  322.           else
  323.             help_id = g_object_get_qdata (G_OBJECT (widget), GIMP_HELP_ID);
  324.  
  325.           help_data = g_object_get_data (G_OBJECT (widget), "gimp-help-data");
  326.  
  327.           (* help_func) (help_id, help_data);
  328.         }
  329.       return TRUE;
  330.  
  331.     case GTK_WIDGET_HELP_WHATS_THIS:
  332.       g_idle_add (gimp_context_help_idle_start, widget);
  333.       return TRUE;
  334.  
  335.     default:
  336.       break;
  337.     }
  338.  
  339.   return FALSE;
  340. }
  341.  
  342. /*  Do all the actual context help calls in idle functions and check for
  343.  *  some widget holding a grab before starting the query because strange
  344.  *  things happen if (1) the help browser pops up while the query has
  345.  *  grabbed the pointer or (2) the query grabs the pointer while some
  346.  *  other part of the gimp has grabbed it (e.g. a tool, eek)
  347.  */
  348.  
  349. static gboolean
  350. gimp_context_help_idle_start (gpointer widget)
  351. {
  352.   if (! gtk_grab_get_current ())
  353.     {
  354.       GtkWidget     *invisible;
  355.       GdkCursor     *cursor;
  356.       GdkGrabStatus  status;
  357.  
  358.       invisible = gtk_invisible_new_for_screen (gtk_widget_get_screen (widget));
  359.       gtk_widget_show (invisible);
  360.  
  361.       cursor = gdk_cursor_new_for_display (gtk_widget_get_display (invisible),
  362.                                            GDK_QUESTION_ARROW);
  363.  
  364.       status = gdk_pointer_grab (invisible->window, TRUE,
  365.                                  GDK_BUTTON_PRESS_MASK   |
  366.                                  GDK_BUTTON_RELEASE_MASK |
  367.                                  GDK_ENTER_NOTIFY_MASK   |
  368.                                  GDK_LEAVE_NOTIFY_MASK,
  369.                                  NULL, cursor,
  370.                                  GDK_CURRENT_TIME);
  371.  
  372.       gdk_cursor_unref (cursor);
  373.  
  374.       if (status != GDK_GRAB_SUCCESS)
  375.         {
  376.           gtk_widget_destroy (invisible);
  377.           return FALSE;
  378.         }
  379.  
  380.       gtk_grab_add (invisible);
  381.  
  382.       g_signal_connect (invisible, "button_press_event",
  383.                         G_CALLBACK (gimp_context_help_button_press),
  384.                         NULL);
  385.     }
  386.  
  387.   return FALSE;
  388. }
  389.  
  390. static gboolean
  391. gimp_context_help_button_press (GtkWidget      *widget,
  392.                                 GdkEventButton *bevent,
  393.                                 gpointer        data)
  394. {
  395.   GtkWidget *event_widget;
  396.  
  397.   event_widget = gtk_get_event_widget ((GdkEvent *) bevent);
  398.  
  399.   if (event_widget && bevent->button == 1 && bevent->type == GDK_BUTTON_PRESS)
  400.     {
  401.       gtk_grab_remove (widget);
  402.       gdk_display_pointer_ungrab (gtk_widget_get_display (widget),
  403.                                   bevent->time);
  404.       gtk_widget_destroy (widget);
  405.  
  406.       if (event_widget != widget)
  407.         g_idle_add (gimp_context_help_idle_show_help, event_widget);
  408.     }
  409.  
  410.   return TRUE;
  411. }
  412.  
  413. static gboolean
  414. gimp_context_help_idle_show_help (gpointer data)
  415. {
  416.   GtkWidget   *help_widget;
  417.   const gchar *help_id   = NULL;
  418.   gpointer     help_data = NULL;
  419.  
  420.   help_id = gimp_help_get_help_data (GTK_WIDGET (data), &help_widget,
  421.                                      &help_data);
  422.  
  423.   if (help_id)
  424.     gimp_standard_help_func (help_id, help_data);
  425.  
  426.   return FALSE;
  427. }
  428.