]> Pileus Git - ~andy/gtk/blob - docs/reference/gtk/migrating-checklist.sgml
Document im_module_file and settings assignments as toplevel statements.
[~andy/gtk] / docs / reference / gtk / migrating-checklist.sgml
1 <chapter id="gtk-migrating-checklist">
2   <title>Migration Checklist</title>
3
4   <para>
5     This chapter includes a checklist of things you need to do to
6     ensure that your programs are good citizens in the GTK+ world.  By
7     paying attention to the points in the checklist, you ensure that
8     many automatic features of GTK+ will work correctly in your
9     program.
10   </para>
11
12   <section id="checklist-popup-menu">
13     <title>Implement GtkWidget::popup_menu</title>
14
15     <formalpara>
16       <title>Why</title>
17       <para>
18         By handling this signal, you let widgets have
19         context-sensitive menus that can be invoked with the standard
20         key bindings.
21       </para>
22     </formalpara>
23
24     <para>
25       The <link
26       linkend="GtkWidget-popup-menu">GtkWidget::popup_menu</link>
27       signal instructs the widget for which it is emitted to create a
28       context-sensitive popup menu.  By default, the <link
29       linkend="gtk-bindings">key binding mechanism</link> is set to
30       emit this signal when the
31       <keycombo><keycap>Shift</keycap><keycap>F10</keycap></keycombo>
32       or <keycap>Menu</keycap> keys are pressed while a widget has the
33       focus.  If a widget in your application shows a popup menu when
34       you press a mouse button, you can make it work as well through
35       the normal key binding mechanism in the following fahion:
36     </para>
37
38     <orderedlist>
39       <listitem>
40         <para>
41           Write a function to create and show a popup menu.  This
42           function needs to know the button number and the event's
43           time to pass them to gtk_menu_popup().  You can implement
44           such a function like this:
45         </para>
46
47         <programlisting id="do_popup_menu">
48 static void
49 do_popup_menu (GtkWidget *my_widget, GdkEventButton *event)
50 {
51   GtkWidget *menu;
52   int button, event_time;
53
54   menu = gtk_menu_new ();
55   g_signal_connect (menu, "deactivate", 
56                     G_CALLBACK (gtk_widget_destroy), NULL);
57
58   /* ... add menu items ... */
59
60   if (event)
61     {
62       button = event->button;
63       event_time = event->time;
64     }
65   else
66     {
67       button = 0;
68       event_time = gtk_get_current_event_time ();
69     }
70
71   gtk_menu_popup (GTK_MENU (popup), NULL, NULL, NULL, NULL, 
72                   button, event_time);
73 }
74         </programlisting>
75       </listitem>
76
77       <listitem>
78         <para>
79           In your button_press handler, call this function when you
80           need to pop up a menu:
81         </para>
82
83         <programlisting>
84 static gboolean
85 my_widget_button_press_event_handler (GtkWidget *widget, GdkEventButton *event)
86 {
87   /* Ignore double-clicks and triple-clicks */
88   if (event->button == 3 &amp;&amp; event->type == GDK_BUTTON_PRESS)
89     {
90       do_popup_menu (widget, event);
91       return TRUE;
92     }
93
94   return FALSE;
95 }
96         </programlisting>
97       </listitem>
98
99       <listitem>
100         <para>
101           Implement a handler for the popup_menu signal:
102         </para>
103
104         <programlisting>
105 static gboolean
106 my_widget_popup_menu_handler (GtkWidget *widget)
107 {
108   do_popup_menu (widget, NULL);
109   return TRUE;
110 }
111         </programlisting>
112       </listitem>
113     </orderedlist>
114
115     <note>
116       <para>
117         If you do not pass a positioning function to gtk_menu_popup(),
118         it will show the menu at the mouse position by default.  This
119         is what you usually want when the menu is shown as a result of
120         pressing a mouse button.  However, if you press the
121         <keycombo><keycap>Shift</keycap><keycap>F10</keycap></keycombo>
122         or <keycap>Menu</keycap> keys while the widget is focused, the
123         mouse cursor may not be near the widget at all.  In the <link
124         linkend="do_popup_menu">example above</link>, you may want to
125         provide your own <link
126         linkend="GtkMenuPositionFunc">menu-positioning function</link>
127         in the case where the <parameter>event</parameter> is
128         <constant>NULL</constant>.  This function should compute the
129         desired position for a menu when it is invoked through the
130         keyboard.  For example, <xref linkend="GtkEntry"/> aligns the
131         top edge of its popup menu with the bottom edge of the entry.
132       </para>
133     </note>
134
135     <note>
136       <para>
137         For the standard key bindings to work, your widget must be
138         able to take the keyboard focus.  In general, widgets should
139         be fully usable through the keyboard and not just the mouse.
140         The very first step of this is to ensure that your widget
141         turns on the <link
142         linkend="gtkwidgetflags"><constant>GTK_CAN_FOCUS</constant></link>
143         FLAG.
144       </para>
145     </note>
146   </section>
147
148   <section id="checklist-gdkeventexpose-region">
149     <title>Use GdkEventExpose.region</title>
150
151     <formalpara>
152       <title>Why</title>
153       <para>
154         The <structfield>region</structfield> field of
155         <structname>GdkEventExpose</structname> allows you to redraw
156         less than the traditional
157         <structfield>GdkEventRegion.area</structfield>.
158       </para>
159     </formalpara>
160
161     <para>
162       In GTK+ 1.x, the <structname>GdkEventExpose</structname>
163       structure only had an <structfield>area</structfield> field to
164       let you determine the region that you needed to redraw.  In GTK+
165       2.x, this field exists for compatibility and as a simple
166       interface.  However, there is also a
167       <structfield>region</structfield> field which contains a
168       fine-grained region.  The <structfield>area</structfield> field
169       is simply the bounding rectangle of the
170       <structfield>region</structfield>.
171     </para>
172
173     <para>
174       Widgets that are very expensive to re-render, such as an image
175       editor, may prefer to use the
176       <structfield>GdkEventExpose.region</structfield> field to paint
177       as little as possible.  Widgets that just use a few drawing
178       primitives, such as labels and buttons, may prefer to use the
179       traditional <structfield>GdkEventExpose.area</structfield> field
180       for simplicity.
181     </para>
182
183     <para>
184       Regions have an internal representation that is accessible as a
185       list of rectangles.  To turn the
186       <structfield>GdkEventExpose.region</structfield> field into such
187       a list, use gdk_region_get_rectangles():
188     </para>
189
190     <programlisting id="gdkregion-get-rectangles">
191 static gboolean
192 my_widget_expose_event_handler (GtkWidget *widget, GdkEventExpose *event)
193 {
194   GdkRectangle *rects;
195   int n_rects;
196   int i;
197
198   gdk_region_get_rectangles (event-&gt;region, &amp;rects, &amp;n_rects);
199
200   for (i = 0; i &lt; n_rects; i++)
201     {
202       /* Repaint rectangle: (rects[i].x, rects[i].y), 
203        *                    (rects[i].width, rects[i].height)
204        */
205     }
206
207   g_free (rects);
208
209   return FALSE;
210 }
211     </programlisting>
212   </section>
213
214   <section id="checklist-modifiers">
215     <title>Test for modifier keys correctly</title>
216
217     <formalpara>
218       <title>Why</title>
219       <para>
220         With
221         <function>gtk_accelerator_get_default_mod_mask()</function>
222         you can test for modifier keys reliably; this way your key
223         event handlers will work correctly even if
224         <keycap>NumLock</keycap> or <keycap>CapsLock</keycap> are
225         activated.
226       </para>
227     </formalpara>
228
229     <para>
230       In a <structname>GdkEventKey</structname>, the
231       <structfield>state</structfield> field is a bit mask which
232       indicates the modifier state at the time the key was pressed.
233       Modifiers are keys like <keycap>Control</keycap> and
234       <keycap>NumLock</keycap>.  When implementing a <link
235       linkend="GtkWidget-key-press-event">GtkWidget::key_press_event</link>
236       handler, you should use
237       <function>gtk_accelerator_get_default_mod_mask()</function> to
238       test against modifier keys.  This function returns a bit mask
239       which encompasses all the modifiers which the user may be
240       actively pressing, such as <keycap>Control</keycap>,
241       <keycap>Shift</keycap>, and <keycap>Alt</keycap>, but ignores
242       "inocuous" modifiers such as <keycap>NumLock</keycap> and
243       <keycap>CapsLock</keycap>.
244     </para>
245
246     <para>
247       Say you want to see if
248       <keycombo><keycap>Control</keycap><keycap>F10</keycap></keycombo>
249       was pressed.  Doing a simple test like
250       <literal>event-&gt;keysym&nbsp;==&nbsp;GDK_F10 &amp;&amp;
251       event->state&nbsp;==&nbsp;GDK_CONTROL_MASK</literal> is not
252       enough.  If <keycap>CapsLock</keycap> is pressed, then
253       <structfield>event-&gt;state</structfield> will be equal to
254       <literal>GDK_CONTROL_MASK | GDK_LOCK_MASK</literal>, and the
255       simple test will fail.  By taking the logical-and of
256       <structfield>event->state</structfield> and
257       <function>gtk_accelerator_get_default_mod_mask()</function>, you
258       can ignore the modifiers which are not actively pressed by the
259       user at the same time as the base key.
260     </para>
261
262     <para>
263       The following example correctly tests for
264       <keycombo><keycap>Control</keycap><keycap>F10</keycap></keycombo>
265       being pressed.
266     </para>
267
268     <programlisting id="default-mod-mask">
269 static gboolean
270 my_widget_key_press_event_handler (GtkWidget *widget, GdkEventKey *event)
271 {
272   guint modifiers;
273
274   modifiers = gtk_accelerator_get_default_mod_mask ();
275
276   if (event-&gt;keysym == GDK_F10
277       &amp;&amp; (event-&gt;state &amp; modifiers) == GDK_CONTROL_MASK)
278     {
279       g_print ("Control-F10 was pressed\n");
280       return TRUE;
281     }
282
283   return FALSE;
284 }
285     </programlisting>
286   </section>
287 </chapter>
288
289 <!--
290 Local variables:
291 mode: sgml
292 sgml-parent-document: ("gtk-docs.sgml" "book" "part" "chapter")
293 End:
294 -->