<chapter id="gtk-migrating-checklist">
  <title>Migration Checklist</title>

  <para>
    This chapter includes a checklist of things you need to do to
    ensure that your programs are good citizens in the GTK+ world.  By
    paying attention to the points in the checklist, you ensure that
    many automatic features of GTK+ will work correctly in your
    program.
  </para>

  <section id="checklist-popup-menu">
    <title>Implement GtkWidget::popup_menu</title>

    <formalpara>
      <title>Why</title>
      <para>
	By handling this signal, you let widgets have
	context-sensitive menus that can be invoked with the standard
	key bindings.
      </para>
    </formalpara>

    <para>
      The <link
      linkend="GtkWidget-popup-menu">GtkWidget::popup_menu</link>
      signal instructs the widget for which it is emitted to create a
      context-sensitive popup menu.  By default, the <link
      linkend="gtk-bindings">key binding mechanism</link> is set to
      emit this signal when the
      <keycombo><keycap>Shift</keycap><keycap>F10</keycap></keycombo>
      or <keycap>Menu</keycap> keys are pressed while a widget has the
      focus.  If a widget in your application shows a popup menu when
      you press a mouse button, you can make it work as well through
      the normal key binding mechanism in the following fahion:
    </para>

    <orderedlist>
      <listitem>
	<para>
	  Write a function to create and show a popup menu.  This
	  function needs to know the button number and the event's
	  time to pass them to gtk_menu_popup().  You can implement
	  such a function like this:
	</para>

	<programlisting id="do_popup_menu">
static void
do_popup_menu (GtkWidget *my_widget, GdkEventButton *event)
{
  GtkWidget *menu;
  int button, event_time;

  menu = gtk_menu_new ();
  g_signal_connect (menu, "deactivate", 
                    G_CALLBACK (gtk_widget_destroy), NULL);

  /* ... add menu items ... */

  if (event)
    {
      button = event->button;
      event_time = event->time;
    }
  else
    {
      button = 0;
      event_time = gtk_get_current_event_time ();
    }

  gtk_menu_popup (GTK_MENU (popup), NULL, NULL, NULL, NULL, 
                  button, event_time);
}
	</programlisting>
      </listitem>

      <listitem>
	<para>
	  In your button_press handler, call this function when you
	  need to pop up a menu:
	</para>

	<programlisting>
static gboolean
my_widget_button_press_event_handler (GtkWidget *widget, GdkEventButton *event)
{
  /* Ignore double-clicks and triple-clicks */
  if (event->button == 3 &amp;&amp; event->type == GDK_BUTTON_PRESS)
    {
      do_popup_menu (widget, event);
      return TRUE;
    }

  return FALSE;
}
	</programlisting>
      </listitem>

      <listitem>
	<para>
	  Implement a handler for the popup_menu signal:
	</para>

	<programlisting>
static gboolean
my_widget_popup_menu_handler (GtkWidget *widget)
{
  do_popup_menu (widget, NULL);
  return TRUE;
}
	</programlisting>
      </listitem>
    </orderedlist>

    <note>
      <para>
	If you do not pass a positioning function to gtk_menu_popup(),
	it will show the menu at the mouse position by default.  This
	is what you usually want when the menu is shown as a result of
	pressing a mouse button.  However, if you press the
	<keycombo><keycap>Shift</keycap><keycap>F10</keycap></keycombo>
	or <keycap>Menu</keycap> keys while the widget is focused, the
	mouse cursor may not be near the widget at all.  In the <link
	linkend="do_popup_menu">example above</link>, you may want to
	provide your own <link
	linkend="GtkMenuPositionFunc">menu-positioning function</link>
	in the case where the <parameter>event</parameter> is
	<constant>NULL</constant>.  This function should compute the
	desired position for a menu when it is invoked through the
	keyboard.  For example, <xref linkend="GtkEntry"/> aligns the
	top edge of its popup menu with the bottom edge of the entry.
      </para>
    </note>

    <note>
      <para>
	For the standard key bindings to work, your widget must be
	able to take the keyboard focus.  In general, widgets should
	be fully usable through the keyboard and not just the mouse.
	The very first step of this is to ensure that your widget
	turns on the <link
	linkend="gtkwidgetflags"><constant>GTK_CAN_FOCUS</constant></link>
	FLAG.
      </para>
    </note>
  </section>

  <section id="checklist-gdkeventexpose-region">
    <title>Use GdkEventExpose.region</title>

    <formalpara>
      <title>Why</title>
      <para>
	The <structfield>region</structfield> field of
	<structname>GdkEventExpose</structname> allows you to redraw
	less than the traditional
	<structfield>GdkEventRegion.area</structfield>.
      </para>
    </formalpara>

    <para>
      In GTK+ 1.x, the <structname>GdkEventExpose</structname>
      structure only had an <structfield>area</structfield> field to
      let you determine the region that you needed to redraw.  In GTK+
      2.x, this field exists for compatibility and as a simple
      interface.  However, there is also a
      <structfield>region</structfield> field which contains a
      fine-grained region.  The <structfield>area</structfield> field
      is simply the bounding rectangle of the
      <structfield>region</structfield>.
    </para>

    <para>
      Widgets that are very expensive to re-render, such as an image
      editor, may prefer to use the
      <structfield>GdkEventExpose.region</structfield> field to paint
      as little as possible.  Widgets that just use a few drawing
      primitives, such as labels and buttons, may prefer to use the
      traditional <structfield>GdkEventExpose.area</structfield> field
      for simplicity.
    </para>

    <para>
      Regions have an internal representation that is accessible as a
      list of rectangles.  To turn the
      <structfield>GdkEventExpose.region</structfield> field into such
      a list, use gdk_region_get_rectangles():
    </para>

    <programlisting id="gdkregion-get-rectangles">
static gboolean
my_widget_expose_event_handler (GtkWidget *widget, GdkEventExpose *event)
{
  GdkRectangle *rects;
  int n_rects;
  int i;

  gdk_region_get_rectangles (event-&gt;region, &amp;rects, &amp;n_rects);

  for (i = 0; i &lt; n_rects; i++)
    {
      /* Repaint rectangle: (rects[i].x, rects[i].y), 
       *                    (rects[i].width, rects[i].height)
       */
    }

  g_free (rects);

  return FALSE;
}
    </programlisting>
  </section>

  <section id="checklist-modifiers">
    <title>Test for modifier keys correctly</title>

    <formalpara>
      <title>Why</title>
      <para>
	With
	<function>gtk_accelerator_get_default_mod_mask()</function>
	you can test for modifier keys reliably; this way your key
	event handlers will work correctly even if
	<keycap>NumLock</keycap> or <keycap>CapsLock</keycap> are
	activated.
      </para>
    </formalpara>

    <para>
      In a <structname>GdkEventKey</structname>, the
      <structfield>state</structfield> field is a bit mask which
      indicates the modifier state at the time the key was pressed.
      Modifiers are keys like <keycap>Control</keycap> and
      <keycap>NumLock</keycap>.  When implementing a <link
      linkend="GtkWidget-key-press-event">GtkWidget::key_press_event</link>
      handler, you should use
      <function>gtk_accelerator_get_default_mod_mask()</function> to
      test against modifier keys.  This function returns a bit mask
      which encompasses all the modifiers which the user may be
      actively pressing, such as <keycap>Control</keycap>,
      <keycap>Shift</keycap>, and <keycap>Alt</keycap>, but ignores
      "inocuous" modifiers such as <keycap>NumLock</keycap> and
      <keycap>CapsLock</keycap>.
    </para>

    <para>
      Say you want to see if
      <keycombo><keycap>Control</keycap><keycap>F10</keycap></keycombo>
      was pressed.  Doing a simple test like
      <literal>event-&gt;keysym&nbsp;==&nbsp;GDK_F10 &amp;&amp;
      event->state&nbsp;==&nbsp;GDK_CONTROL_MASK</literal> is not
      enough.  If <keycap>CapsLock</keycap> is pressed, then
      <structfield>event-&gt;state</structfield> will be equal to
      <literal>GDK_CONTROL_MASK | GDK_LOCK_MASK</literal>, and the
      simple test will fail.  By taking the logical-and of
      <structfield>event->state</structfield> and
      <function>gtk_accelerator_get_default_mod_mask()</function>, you
      can ignore the modifiers which are not actively pressed by the
      user at the same time as the base key.
    </para>

    <para>
      The following example correctly tests for
      <keycombo><keycap>Control</keycap><keycap>F10</keycap></keycombo>
      being pressed.
    </para>

    <programlisting id="default-mod-mask">
static gboolean
my_widget_key_press_event_handler (GtkWidget *widget, GdkEventKey *event)
{
  guint modifiers;

  modifiers = gtk_accelerator_get_default_mod_mask ();

  if (event-&gt;keysym == GDK_F10
      &amp;&amp; (event-&gt;state &amp; modifiers) == GDK_CONTROL_MASK)
    {
      g_print ("Control-F10 was pressed\n");
      return TRUE;
    }

  return FALSE;
}
    </programlisting>
  </section>
</chapter>

<!--
Local variables:
mode: sgml
sgml-parent-document: ("gtk-docs.sgml" "book" "part" "chapter")
End:
-->
