summaryrefslogtreecommitdiff
path: root/docs/reference/gtk/migrating-checklist.sgml
blob: 04089c4074d092a489ea80ca9b9f4e40ee7edadf (plain)
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
<?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 Details Checklist</title>

  <para>
    This chapter includes a checklist of smaller 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 &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 #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 early GTK+ versions, the <structname>GdkEventExpose</structname>
      structure only had an <structfield>area</structfield> field to
      let you determine the region that you needed to redraw. In current
      GTK+, this field still 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 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-&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
      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)
{
  GdkModifierType 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>

  <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>
      Named icons can be used for window icons (see gtk_window_set_icon_name())
      and images (see gtk_image_set_icon_name()). 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:
-->