1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312
|
<?xml version="1.0"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
]>
<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 #GtkWidget::popup-menu 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_attach_to_widget (GTK_MENU (menu), my_widget, NULL);
gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL,
button, event_time);
}
</programlisting>
</listitem>
<listitem>
<para>
In your #GtkWidget::button-press-event 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 && event->type == GDK_BUTTON_PRESS)
{
do_popup_menu (widget, event);
return TRUE;
}
return FALSE;
}
</programlisting>
</listitem>
<listitem>
<para>
Implement a handler for the #GtkWidget::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
%NULL. This function should compute the desired position for
a menu when it is invoked through the keyboard. For example,
#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 %GTK_CAN_FOCUS <link linkend="gtkwidgetflags">flag</link>.
</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->region, &rects, &n_rects);
for (i = 0; i < 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 gtk_accelerator_get_default_mod_mask() 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
#GtkWidget::key-press-event handler, you should use
gtk_accelerator_get_default_mod_mask() 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
"innocuous" 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->keysym == GDK_F10 &&
event->state == GDK_CONTROL_MASK</literal> is not
enough. If <keycap>CapsLock</keycap> is pressed, then
<structfield>event->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
gtk_accelerator_get_default_mod_mask(), 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->keysym == GDK_F10
&& (event->state & modifiers) == GDK_CONTROL_MASK)
{
g_print ("Control-F10 was pressed\n");
return TRUE;
}
return FALSE;
}
</programlisting>
</section>
<section id="checklist-named-icons">
<title>Use named icons</title>
<formalpara>
<title>Why</title>
<para>
Named icons automatically adapt to theme changes, giving your
application a much more integrated appearance.
</para>
</formalpara>
<para>
Since GTK+ 2.6, named icons can be used for window icons (see
gtk_window_set_icon_name()) and images (see gtk_image_set_icon_name()).
In GTK+ 2.8, you can also use named icons for drag-and-drop (see
gtk_drag_source_set_icon_name()) and in treeview cells (see the
#GtkCellRendererPixbuf:icon-name property).
</para>
</section>
</chapter>
<!--
Local variables:
mode: sgml
sgml-parent-document: ("gtk-docs.sgml" "book" "part" "chapter")
End:
-->
|