| |
1 /* gaimcombobox.c |
| |
2 * Copyright (C) 2002, 2003 Kristian Rietveld <kris@gtk.org> |
| |
3 * |
| |
4 * This library is free software; you can redistribute it and/or |
| |
5 * modify it under the terms of the GNU Library General Public |
| |
6 * License as published by the Free Software Foundation; either |
| |
7 * version 2 of the License, or (at your option) any later version. |
| |
8 * |
| |
9 * This library is distributed in the hope that it will be useful, |
| |
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| |
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| |
12 * Library General Public License for more details. |
| |
13 * |
| |
14 * You should have received a copy of the GNU Library General Public |
| |
15 * License along with this library; if not, write to the |
| |
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
| |
17 * Boston, MA 02111-1307, USA. |
| |
18 */ |
| |
19 |
| |
20 /* |
| |
21 #include <config.h> |
| |
22 */ |
| |
23 #include <gtk/gtkversion.h> |
| |
24 #if !GTK_CHECK_VERSION(2,6,0) |
| |
25 #include "gaimcombobox.h" |
| |
26 |
| |
27 #if !GTK_CHECK_VERSION(2,4,0) |
| |
28 #include <gtk/gtkarrow.h> |
| |
29 #include <gtk/gtkbindings.h> |
| |
30 #include "gtkcelllayout.h" |
| |
31 #include <gtk/gtkcellrenderertext.h> |
| |
32 #include "gtkcellview.h" |
| |
33 #include "gtkcellviewmenuitem.h" |
| |
34 #include <gtk/gtkeventbox.h> |
| |
35 #include <gtk/gtkframe.h> |
| |
36 #include <gtk/gtkhbox.h> |
| |
37 #include <gtk/gtkliststore.h> |
| |
38 #include <gtk/gtkmain.h> |
| |
39 #include <gtk/gtkmenu.h> |
| |
40 #include <gtk/gtktogglebutton.h> |
| |
41 #include <gtk/gtktreeselection.h> |
| |
42 /* |
| |
43 #include <gtk/gtktreeprivate.h> |
| |
44 */ |
| |
45 #include <gtk/gtkvseparator.h> |
| |
46 #include <gtk/gtkwindow.h> |
| |
47 #include <gtk/gtkversion.h> |
| |
48 |
| |
49 #include <gdk/gdkkeysyms.h> |
| |
50 |
| |
51 #include <gobject/gvaluecollector.h> |
| |
52 |
| |
53 #include <string.h> |
| |
54 #include <stdarg.h> |
| |
55 |
| |
56 #define P_(x) (x) |
| |
57 |
| |
58 /* WELCOME, to THE house of evil code */ |
| |
59 |
| |
60 typedef struct _ComboCellInfo ComboCellInfo; |
| |
61 struct _ComboCellInfo |
| |
62 { |
| |
63 GtkCellRenderer *cell; |
| |
64 GSList *attributes; |
| |
65 |
| |
66 GtkCellLayoutDataFunc func; |
| |
67 gpointer func_data; |
| |
68 GDestroyNotify destroy; |
| |
69 |
| |
70 guint expand : 1; |
| |
71 guint pack : 1; |
| |
72 }; |
| |
73 |
| |
74 struct _GtkComboBoxPrivate |
| |
75 { |
| |
76 GtkTreeModel *model; |
| |
77 |
| |
78 gint col_column; |
| |
79 gint row_column; |
| |
80 |
| |
81 gint wrap_width; |
| |
82 |
| |
83 gint active_item; |
| |
84 |
| |
85 GtkWidget *tree_view; |
| |
86 GtkTreeViewColumn *column; |
| |
87 |
| |
88 GtkWidget *cell_view; |
| |
89 GtkWidget *cell_view_frame; |
| |
90 |
| |
91 GtkWidget *button; |
| |
92 GtkWidget *box; |
| |
93 GtkWidget *arrow; |
| |
94 GtkWidget *separator; |
| |
95 |
| |
96 GtkWidget *popup_widget; |
| |
97 GtkWidget *popup_window; |
| |
98 GtkWidget *popup_frame; |
| |
99 |
| |
100 guint inserted_id; |
| |
101 guint deleted_id; |
| |
102 guint reordered_id; |
| |
103 guint changed_id; |
| |
104 |
| |
105 gint width; |
| |
106 GSList *cells; |
| |
107 |
| |
108 guint popup_in_progress : 1; |
| |
109 guint destroying : 1; |
| |
110 }; |
| |
111 |
| |
112 /* While debugging this evil code, I have learned that |
| |
113 * there are actually 4 modes to this widget, which can |
| |
114 * be characterized as follows |
| |
115 * |
| |
116 * 1) menu mode, no child added |
| |
117 * |
| |
118 * tree_view -> NULL |
| |
119 * cell_view -> GtkCellView, regular child |
| |
120 * cell_view_frame -> NULL |
| |
121 * button -> GtkToggleButton set_parent to combo |
| |
122 * box -> child of button |
| |
123 * arrow -> child of box |
| |
124 * separator -> child of box |
| |
125 * popup_widget -> GtkMenu |
| |
126 * popup_window -> NULL |
| |
127 * popup_frame -> NULL |
| |
128 * |
| |
129 * 2) menu mode, child added |
| |
130 * |
| |
131 * tree_view -> NULL |
| |
132 * cell_view -> NULL |
| |
133 * cell_view_frame -> NULL |
| |
134 * button -> GtkToggleButton set_parent to combo |
| |
135 * box -> NULL |
| |
136 * arrow -> GtkArrow, child of button |
| |
137 * separator -> NULL |
| |
138 * popup_widget -> GtkMenu |
| |
139 * popup_window -> NULL |
| |
140 * popup_frame -> NULL |
| |
141 * |
| |
142 * 3) list mode, no child added |
| |
143 * |
| |
144 * tree_view -> GtkTreeView, child of popup_frame |
| |
145 * cell_view -> GtkCellView, regular child |
| |
146 * cell_view_frame -> GtkFrame, set parent to combo |
| |
147 * button -> GtkToggleButton, set_parent to combo |
| |
148 * box -> NULL |
| |
149 * arrow -> GtkArrow, child of button |
| |
150 * separator -> NULL |
| |
151 * popup_widget -> tree_view |
| |
152 * popup_window -> GtkWindow |
| |
153 * popup_frame -> GtkFrame, child of popup_window |
| |
154 * |
| |
155 * 4) list mode, child added |
| |
156 * |
| |
157 * tree_view -> GtkTreeView, child of popup_frame |
| |
158 * cell_view -> NULL |
| |
159 * cell_view_frame -> NULL |
| |
160 * button -> GtkToggleButton, set_parent to combo |
| |
161 * box -> NULL |
| |
162 * arrow -> GtkArrow, child of button |
| |
163 * separator -> NULL |
| |
164 * popup_widget -> tree_view |
| |
165 * popup_window -> GtkWindow |
| |
166 * popup_frame -> GtkFrame, child of popup_window |
| |
167 * |
| |
168 */ |
| |
169 |
| |
170 enum { |
| |
171 CHANGED, |
| |
172 LAST_SIGNAL |
| |
173 }; |
| |
174 |
| |
175 enum { |
| |
176 PROP_0, |
| |
177 PROP_MODEL, |
| |
178 PROP_WRAP_WIDTH, |
| |
179 PROP_ROW_SPAN_COLUMN, |
| |
180 PROP_COLUMN_SPAN_COLUMN, |
| |
181 PROP_ACTIVE |
| |
182 }; |
| |
183 |
| |
184 static GtkBinClass *parent_class = NULL; |
| |
185 static guint combo_box_signals[LAST_SIGNAL] = {0,}; |
| |
186 |
| |
187 #define BONUS_PADDING 4 |
| |
188 |
| |
189 |
| |
190 /* common */ |
| |
191 static void gtk_combo_box_class_init (GtkComboBoxClass *klass); |
| |
192 static void gtk_combo_box_cell_layout_init (GtkCellLayoutIface *iface); |
| |
193 static void gtk_combo_box_init (GtkComboBox *combo_box); |
| |
194 static void gtk_combo_box_finalize (GObject *object); |
| |
195 static void gtk_combo_box_destroy (GtkObject *object); |
| |
196 |
| |
197 static void gtk_combo_box_set_property (GObject *object, |
| |
198 guint prop_id, |
| |
199 const GValue *value, |
| |
200 GParamSpec *spec); |
| |
201 static void gtk_combo_box_get_property (GObject *object, |
| |
202 guint prop_id, |
| |
203 GValue *value, |
| |
204 GParamSpec *spec); |
| |
205 |
| |
206 static void gtk_combo_box_state_changed (GtkWidget *widget, |
| |
207 GtkStateType previous); |
| |
208 static void gtk_combo_box_style_set (GtkWidget *widget, |
| |
209 GtkStyle *previous); |
| |
210 static void gtk_combo_box_button_toggled (GtkWidget *widget, |
| |
211 gpointer data); |
| |
212 static void gtk_combo_box_add (GtkContainer *container, |
| |
213 GtkWidget *widget); |
| |
214 static void gtk_combo_box_remove (GtkContainer *container, |
| |
215 GtkWidget *widget); |
| |
216 |
| |
217 static ComboCellInfo *gtk_combo_box_get_cell_info (GtkComboBox *combo_box, |
| |
218 GtkCellRenderer *cell); |
| |
219 |
| |
220 static void gtk_combo_box_menu_show (GtkWidget *menu, |
| |
221 gpointer user_data); |
| |
222 static void gtk_combo_box_menu_hide (GtkWidget *menu, |
| |
223 gpointer user_data); |
| |
224 |
| |
225 static void gtk_combo_box_set_popup_widget (GtkComboBox *combo_box, |
| |
226 GtkWidget *popup); |
| |
227 #if GTK_CHECK_VERSION(2,2,0) |
| |
228 static void gtk_combo_box_menu_position_below (GtkMenu *menu, |
| |
229 gint *x, |
| |
230 gint *y, |
| |
231 gint *push_in, |
| |
232 gpointer user_data); |
| |
233 static void gtk_combo_box_menu_position_over (GtkMenu *menu, |
| |
234 gint *x, |
| |
235 gint *y, |
| |
236 gint *push_in, |
| |
237 gpointer user_data); |
| |
238 static void gtk_combo_box_menu_position (GtkMenu *menu, |
| |
239 gint *x, |
| |
240 gint *y, |
| |
241 gint *push_in, |
| |
242 gpointer user_data); |
| |
243 #endif |
| |
244 |
| |
245 static gint gtk_combo_box_calc_requested_width (GtkComboBox *combo_box, |
| |
246 GtkTreePath *path); |
| |
247 static void gtk_combo_box_remeasure (GtkComboBox *combo_box); |
| |
248 |
| |
249 static void gtk_combo_box_unset_model (GtkComboBox *combo_box); |
| |
250 |
| |
251 static void gtk_combo_box_size_request (GtkWidget *widget, |
| |
252 GtkRequisition *requisition); |
| |
253 static void gtk_combo_box_size_allocate (GtkWidget *widget, |
| |
254 GtkAllocation *allocation); |
| |
255 static void gtk_combo_box_forall (GtkContainer *container, |
| |
256 gboolean include_internals, |
| |
257 GtkCallback callback, |
| |
258 gpointer callback_data); |
| |
259 static gboolean gtk_combo_box_expose_event (GtkWidget *widget, |
| |
260 GdkEventExpose *event); |
| |
261 static gboolean gtk_combo_box_scroll_event (GtkWidget *widget, |
| |
262 GdkEventScroll *event); |
| |
263 static void gtk_combo_box_set_active_internal (GtkComboBox *combo_box, |
| |
264 gint index); |
| |
265 static gboolean gtk_combo_box_key_press (GtkWidget *widget, |
| |
266 GdkEventKey *event, |
| |
267 gpointer data); |
| |
268 |
| |
269 /* listening to the model */ |
| |
270 static void gtk_combo_box_model_row_inserted (GtkTreeModel *model, |
| |
271 GtkTreePath *path, |
| |
272 GtkTreeIter *iter, |
| |
273 gpointer user_data); |
| |
274 static void gtk_combo_box_model_row_deleted (GtkTreeModel *model, |
| |
275 GtkTreePath *path, |
| |
276 gpointer user_data); |
| |
277 static void gtk_combo_box_model_rows_reordered (GtkTreeModel *model, |
| |
278 GtkTreePath *path, |
| |
279 GtkTreeIter *iter, |
| |
280 gint *new_order, |
| |
281 gpointer user_data); |
| |
282 static void gtk_combo_box_model_row_changed (GtkTreeModel *model, |
| |
283 GtkTreePath *path, |
| |
284 GtkTreeIter *iter, |
| |
285 gpointer data); |
| |
286 |
| |
287 /* list */ |
| |
288 static void gtk_combo_box_list_position (GtkComboBox *combo_box, |
| |
289 gint *x, |
| |
290 gint *y, |
| |
291 gint *width, |
| |
292 gint *height); |
| |
293 |
| |
294 static void gtk_combo_box_list_setup (GtkComboBox *combo_box); |
| |
295 static void gtk_combo_box_list_destroy (GtkComboBox *combo_box); |
| |
296 |
| |
297 static void gtk_combo_box_list_remove_grabs (GtkComboBox *combo_box); |
| |
298 |
| |
299 static gboolean gtk_combo_box_list_button_released (GtkWidget *widget, |
| |
300 GdkEventButton *event, |
| |
301 gpointer data); |
| |
302 static gboolean gtk_combo_box_list_key_press (GtkWidget *widget, |
| |
303 GdkEventKey *event, |
| |
304 gpointer data); |
| |
305 static gboolean gtk_combo_box_list_button_pressed (GtkWidget *widget, |
| |
306 GdkEventButton *event, |
| |
307 gpointer data); |
| |
308 |
| |
309 static void gtk_combo_box_list_row_changed (GtkTreeModel *model, |
| |
310 GtkTreePath *path, |
| |
311 GtkTreeIter *iter, |
| |
312 gpointer data); |
| |
313 |
| |
314 /* menu */ |
| |
315 static void gtk_combo_box_menu_setup (GtkComboBox *combo_box, |
| |
316 gboolean add_children); |
| |
317 static void gtk_combo_box_menu_fill (GtkComboBox *combo_box); |
| |
318 static void gtk_combo_box_menu_destroy (GtkComboBox *combo_box); |
| |
319 |
| |
320 static void gtk_combo_box_item_get_size (GtkComboBox *combo_box, |
| |
321 gint index, |
| |
322 gint *cols, |
| |
323 gint *rows); |
| |
324 static void gtk_combo_box_relayout_item (GtkComboBox *combo_box, |
| |
325 gint index); |
| |
326 static void gtk_combo_box_relayout (GtkComboBox *combo_box); |
| |
327 |
| |
328 static gboolean gtk_combo_box_menu_button_press (GtkWidget *widget, |
| |
329 GdkEventButton *event, |
| |
330 gpointer user_data); |
| |
331 static void gtk_combo_box_menu_item_activate (GtkWidget *item, |
| |
332 gpointer user_data); |
| |
333 static void gtk_combo_box_menu_row_inserted (GtkTreeModel *model, |
| |
334 GtkTreePath *path, |
| |
335 GtkTreeIter *iter, |
| |
336 gpointer user_data); |
| |
337 static void gtk_combo_box_menu_row_deleted (GtkTreeModel *model, |
| |
338 GtkTreePath *path, |
| |
339 gpointer user_data); |
| |
340 static void gtk_combo_box_menu_rows_reordered (GtkTreeModel *model, |
| |
341 GtkTreePath *path, |
| |
342 GtkTreeIter *iter, |
| |
343 gint *new_order, |
| |
344 gpointer user_data); |
| |
345 static void gtk_combo_box_menu_row_changed (GtkTreeModel *model, |
| |
346 GtkTreePath *path, |
| |
347 GtkTreeIter *iter, |
| |
348 gpointer data); |
| |
349 static gboolean gtk_combo_box_menu_key_press (GtkWidget *widget, |
| |
350 GdkEventKey *event, |
| |
351 gpointer data); |
| |
352 |
| |
353 /* cell layout */ |
| |
354 static void gtk_combo_box_cell_layout_pack_start (GtkCellLayout *layout, |
| |
355 GtkCellRenderer *cell, |
| |
356 gboolean expand); |
| |
357 static void gtk_combo_box_cell_layout_pack_end (GtkCellLayout *layout, |
| |
358 GtkCellRenderer *cell, |
| |
359 gboolean expand); |
| |
360 static void gtk_combo_box_cell_layout_clear (GtkCellLayout *layout); |
| |
361 static void gtk_combo_box_cell_layout_add_attribute (GtkCellLayout *layout, |
| |
362 GtkCellRenderer *cell, |
| |
363 const gchar *attribute, |
| |
364 gint column); |
| |
365 static void gtk_combo_box_cell_layout_set_cell_data_func (GtkCellLayout *layout, |
| |
366 GtkCellRenderer *cell, |
| |
367 GtkCellLayoutDataFunc func, |
| |
368 gpointer func_data, |
| |
369 GDestroyNotify destroy); |
| |
370 static void gtk_combo_box_cell_layout_clear_attributes (GtkCellLayout *layout, |
| |
371 GtkCellRenderer *cell); |
| |
372 static void gtk_combo_box_cell_layout_reorder (GtkCellLayout *layout, |
| |
373 GtkCellRenderer *cell, |
| |
374 gint position); |
| |
375 static gboolean gtk_combo_box_mnemonic_activate (GtkWidget *widget, |
| |
376 gboolean group_cycling); |
| |
377 |
| |
378 static void cell_view_sync_cells (GtkComboBox *combo_box, |
| |
379 GtkCellView *cell_view); |
| |
380 |
| |
381 #if !GTK_CHECK_VERSION(2,4,0) |
| |
382 static void gtk_menu_attach (GtkMenu *menu, |
| |
383 GtkWidget *child, |
| |
384 guint left_attach, |
| |
385 guint right_attach, |
| |
386 guint top_attach, |
| |
387 guint bottom_attach); |
| |
388 #endif |
| |
389 |
| |
390 GType |
| |
391 gtk_combo_box_get_type (void) |
| |
392 { |
| |
393 static GType combo_box_type = 0; |
| |
394 |
| |
395 if (!combo_box_type) |
| |
396 { |
| |
397 static const GTypeInfo combo_box_info = |
| |
398 { |
| |
399 sizeof (GtkComboBoxClass), |
| |
400 NULL, /* base_init */ |
| |
401 NULL, /* base_finalize */ |
| |
402 (GClassInitFunc) gtk_combo_box_class_init, |
| |
403 NULL, /* class_finalize */ |
| |
404 NULL, /* class_data */ |
| |
405 sizeof (GtkComboBox), |
| |
406 0, |
| |
407 (GInstanceInitFunc) gtk_combo_box_init |
| |
408 }; |
| |
409 |
| |
410 static const GInterfaceInfo cell_layout_info = |
| |
411 { |
| |
412 (GInterfaceInitFunc) gtk_combo_box_cell_layout_init, |
| |
413 NULL, |
| |
414 NULL |
| |
415 }; |
| |
416 |
| |
417 combo_box_type = g_type_register_static (GTK_TYPE_BIN, |
| |
418 "GaimGtkComboBox", |
| |
419 &combo_box_info, |
| |
420 0); |
| |
421 |
| |
422 g_type_add_interface_static (combo_box_type, |
| |
423 GTK_TYPE_CELL_LAYOUT, |
| |
424 &cell_layout_info); |
| |
425 } |
| |
426 |
| |
427 return combo_box_type; |
| |
428 } |
| |
429 |
| |
430 /* common */ |
| |
431 static void |
| |
432 gtk_combo_box_class_init (GtkComboBoxClass *klass) |
| |
433 { |
| |
434 GObjectClass *object_class; |
| |
435 GtkBindingSet *binding_set; |
| |
436 GtkObjectClass *gtk_object_class; |
| |
437 GtkContainerClass *container_class; |
| |
438 GtkWidgetClass *widget_class; |
| |
439 |
| |
440 binding_set = gtk_binding_set_by_class (klass); |
| |
441 |
| |
442 container_class = (GtkContainerClass *)klass; |
| |
443 container_class->forall = gtk_combo_box_forall; |
| |
444 container_class->add = gtk_combo_box_add; |
| |
445 container_class->remove = gtk_combo_box_remove; |
| |
446 |
| |
447 widget_class = (GtkWidgetClass *)klass; |
| |
448 widget_class->size_allocate = gtk_combo_box_size_allocate; |
| |
449 widget_class->size_request = gtk_combo_box_size_request; |
| |
450 widget_class->expose_event = gtk_combo_box_expose_event; |
| |
451 widget_class->scroll_event = gtk_combo_box_scroll_event; |
| |
452 widget_class->mnemonic_activate = gtk_combo_box_mnemonic_activate; |
| |
453 widget_class->style_set = gtk_combo_box_style_set; |
| |
454 widget_class->state_changed = gtk_combo_box_state_changed; |
| |
455 |
| |
456 gtk_object_class = (GtkObjectClass *)klass; |
| |
457 gtk_object_class->destroy = gtk_combo_box_destroy; |
| |
458 |
| |
459 object_class = (GObjectClass *)klass; |
| |
460 object_class->finalize = gtk_combo_box_finalize; |
| |
461 object_class->set_property = gtk_combo_box_set_property; |
| |
462 object_class->get_property = gtk_combo_box_get_property; |
| |
463 |
| |
464 parent_class = g_type_class_peek_parent (klass); |
| |
465 |
| |
466 /* signals */ |
| |
467 combo_box_signals[CHANGED] = |
| |
468 g_signal_new ("changed", |
| |
469 G_OBJECT_CLASS_TYPE (klass), |
| |
470 G_SIGNAL_RUN_LAST, |
| |
471 G_STRUCT_OFFSET (GtkComboBoxClass, changed), |
| |
472 NULL, NULL, |
| |
473 g_cclosure_marshal_VOID__VOID, |
| |
474 G_TYPE_NONE, 0); |
| |
475 |
| |
476 /* properties */ |
| |
477 g_object_class_install_property (object_class, |
| |
478 PROP_MODEL, |
| |
479 g_param_spec_object ("model", |
| |
480 P_("ComboBox model"), |
| |
481 P_("The model for the combo box"), |
| |
482 GTK_TYPE_TREE_MODEL, |
| |
483 G_PARAM_READWRITE)); |
| |
484 |
| |
485 g_object_class_install_property (object_class, |
| |
486 PROP_WRAP_WIDTH, |
| |
487 g_param_spec_int ("wrap_width", |
| |
488 P_("Wrap width"), |
| |
489 P_("Wrap width for layouting the items in a grid"), |
| |
490 0, |
| |
491 G_MAXINT, |
| |
492 0, |
| |
493 G_PARAM_READWRITE)); |
| |
494 |
| |
495 g_object_class_install_property (object_class, |
| |
496 PROP_ROW_SPAN_COLUMN, |
| |
497 g_param_spec_int ("row_span_column", |
| |
498 P_("Row span column"), |
| |
499 P_("TreeModel column containing the row span values"), |
| |
500 0, |
| |
501 G_MAXINT, |
| |
502 0, |
| |
503 G_PARAM_READWRITE)); |
| |
504 |
| |
505 g_object_class_install_property (object_class, |
| |
506 PROP_COLUMN_SPAN_COLUMN, |
| |
507 g_param_spec_int ("column_span_column", |
| |
508 P_("Column span column"), |
| |
509 |
| |
510 P_("TreeModel column containing the column span values"), |
| |
511 0, |
| |
512 G_MAXINT, |
| |
513 0, |
| |
514 G_PARAM_READWRITE)); |
| |
515 |
| |
516 g_object_class_install_property (object_class, |
| |
517 PROP_ACTIVE, |
| |
518 g_param_spec_int ("active", |
| |
519 P_("Active item"), |
| |
520 P_("The item which is currently active"), |
| |
521 -1, |
| |
522 G_MAXINT, |
| |
523 -1, |
| |
524 G_PARAM_READWRITE)); |
| |
525 |
| |
526 gtk_widget_class_install_style_property (widget_class, |
| |
527 g_param_spec_boolean ("appears-as-list", |
| |
528 P_("Appears as list"), |
| |
529 P_("Whether combobox dropdowns should look like lists rather than menus"), |
| |
530 FALSE, |
| |
531 G_PARAM_READABLE)); |
| |
532 } |
| |
533 |
| |
534 static void |
| |
535 gtk_combo_box_cell_layout_init (GtkCellLayoutIface *iface) |
| |
536 { |
| |
537 iface->pack_start = gtk_combo_box_cell_layout_pack_start; |
| |
538 iface->pack_end = gtk_combo_box_cell_layout_pack_end; |
| |
539 iface->clear = gtk_combo_box_cell_layout_clear; |
| |
540 iface->add_attribute = gtk_combo_box_cell_layout_add_attribute; |
| |
541 iface->set_cell_data_func = gtk_combo_box_cell_layout_set_cell_data_func; |
| |
542 iface->clear_attributes = gtk_combo_box_cell_layout_clear_attributes; |
| |
543 iface->reorder = gtk_combo_box_cell_layout_reorder; |
| |
544 } |
| |
545 |
| |
546 static void |
| |
547 gtk_combo_box_init (GtkComboBox *combo_box) |
| |
548 { |
| |
549 combo_box->priv = g_new0(GtkComboBoxPrivate,1); |
| |
550 |
| |
551 combo_box->priv->cell_view = gtk_cell_view_new (); |
| |
552 gtk_widget_set_parent (combo_box->priv->cell_view, GTK_WIDGET (combo_box)); |
| |
553 GTK_BIN (combo_box)->child = combo_box->priv->cell_view; |
| |
554 gtk_widget_show (combo_box->priv->cell_view); |
| |
555 |
| |
556 combo_box->priv->width = 0; |
| |
557 combo_box->priv->wrap_width = 0; |
| |
558 |
| |
559 combo_box->priv->active_item = -1; |
| |
560 combo_box->priv->col_column = -1; |
| |
561 combo_box->priv->row_column = -1; |
| |
562 } |
| |
563 |
| |
564 static void |
| |
565 gtk_combo_box_set_property (GObject *object, |
| |
566 guint prop_id, |
| |
567 const GValue *value, |
| |
568 GParamSpec *pspec) |
| |
569 { |
| |
570 GtkComboBox *combo_box = GTK_COMBO_BOX (object); |
| |
571 |
| |
572 switch (prop_id) |
| |
573 { |
| |
574 case PROP_MODEL: |
| |
575 gtk_combo_box_set_model (combo_box, g_value_get_object (value)); |
| |
576 break; |
| |
577 |
| |
578 case PROP_WRAP_WIDTH: |
| |
579 gtk_combo_box_set_wrap_width (combo_box, g_value_get_int (value)); |
| |
580 break; |
| |
581 |
| |
582 case PROP_ROW_SPAN_COLUMN: |
| |
583 gtk_combo_box_set_row_span_column (combo_box, g_value_get_int (value)); |
| |
584 break; |
| |
585 |
| |
586 case PROP_COLUMN_SPAN_COLUMN: |
| |
587 gtk_combo_box_set_column_span_column (combo_box, g_value_get_int (value)); |
| |
588 break; |
| |
589 |
| |
590 case PROP_ACTIVE: |
| |
591 gtk_combo_box_set_active (combo_box, g_value_get_int (value)); |
| |
592 break; |
| |
593 |
| |
594 default: |
| |
595 break; |
| |
596 } |
| |
597 } |
| |
598 |
| |
599 static void |
| |
600 gtk_combo_box_get_property (GObject *object, |
| |
601 guint prop_id, |
| |
602 GValue *value, |
| |
603 GParamSpec *pspec) |
| |
604 { |
| |
605 GtkComboBox *combo_box = GTK_COMBO_BOX (object); |
| |
606 |
| |
607 switch (prop_id) |
| |
608 { |
| |
609 case PROP_MODEL: |
| |
610 g_value_set_object (value, combo_box->priv->model); |
| |
611 break; |
| |
612 |
| |
613 case PROP_WRAP_WIDTH: |
| |
614 g_value_set_int (value, combo_box->priv->wrap_width); |
| |
615 break; |
| |
616 |
| |
617 case PROP_ROW_SPAN_COLUMN: |
| |
618 g_value_set_int (value, combo_box->priv->row_column); |
| |
619 break; |
| |
620 |
| |
621 case PROP_COLUMN_SPAN_COLUMN: |
| |
622 g_value_set_int (value, combo_box->priv->col_column); |
| |
623 break; |
| |
624 |
| |
625 case PROP_ACTIVE: |
| |
626 g_value_set_int (value, gtk_combo_box_get_active (combo_box)); |
| |
627 break; |
| |
628 |
| |
629 default: |
| |
630 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
| |
631 break; |
| |
632 } |
| |
633 } |
| |
634 |
| |
635 static void |
| |
636 gtk_combo_box_state_changed (GtkWidget *widget, |
| |
637 GtkStateType previous) |
| |
638 { |
| |
639 GtkComboBox *combo_box = GTK_COMBO_BOX (widget); |
| |
640 |
| |
641 if (GTK_WIDGET_REALIZED (widget)) |
| |
642 { |
| |
643 if (combo_box->priv->tree_view && combo_box->priv->cell_view) |
| |
644 gtk_cell_view_set_background_color (GTK_CELL_VIEW (combo_box->priv->cell_view), |
| |
645 &widget->style->base[GTK_WIDGET_STATE (widget)]); |
| |
646 } |
| |
647 |
| |
648 gtk_widget_queue_draw (widget); |
| |
649 } |
| |
650 |
| |
651 static void |
| |
652 gtk_combo_box_check_appearance (GtkComboBox *combo_box) |
| |
653 { |
| |
654 gboolean appears_as_list; |
| |
655 |
| |
656 /* if wrap_width > 0, then we are in grid-mode and forced to use |
| |
657 * unix style |
| |
658 */ |
| |
659 if (combo_box->priv->wrap_width) |
| |
660 appears_as_list = FALSE; |
| |
661 else |
| |
662 gtk_widget_style_get (GTK_WIDGET (combo_box), |
| |
663 "appears-as-list", &appears_as_list, |
| |
664 NULL); |
| |
665 |
| |
666 if (appears_as_list) |
| |
667 { |
| |
668 /* Destroy all the menu mode widgets, if they exist. */ |
| |
669 if (GTK_IS_MENU (combo_box->priv->popup_widget)) |
| |
670 gtk_combo_box_menu_destroy (combo_box); |
| |
671 |
| |
672 /* Create the list mode widgets, if they don't already exist. */ |
| |
673 if (!GTK_IS_TREE_VIEW (combo_box->priv->tree_view)) |
| |
674 gtk_combo_box_list_setup (combo_box); |
| |
675 } |
| |
676 else |
| |
677 { |
| |
678 /* Destroy all the list mode widgets, if they exist. */ |
| |
679 if (GTK_IS_TREE_VIEW (combo_box->priv->tree_view)) |
| |
680 gtk_combo_box_list_destroy (combo_box); |
| |
681 |
| |
682 /* Create the menu mode widgets, if they don't already exist. */ |
| |
683 if (!GTK_IS_MENU (combo_box->priv->popup_widget)) |
| |
684 gtk_combo_box_menu_setup (combo_box, TRUE); |
| |
685 } |
| |
686 } |
| |
687 |
| |
688 static void |
| |
689 gtk_combo_box_style_set (GtkWidget *widget, |
| |
690 GtkStyle *previous) |
| |
691 { |
| |
692 GtkComboBox *combo_box = GTK_COMBO_BOX (widget); |
| |
693 |
| |
694 gtk_combo_box_check_appearance (combo_box); |
| |
695 |
| |
696 if (combo_box->priv->tree_view && combo_box->priv->cell_view) |
| |
697 gtk_cell_view_set_background_color (GTK_CELL_VIEW (combo_box->priv->cell_view), |
| |
698 &widget->style->base[GTK_WIDGET_STATE (widget)]); |
| |
699 } |
| |
700 |
| |
701 static void |
| |
702 gtk_combo_box_button_toggled (GtkWidget *widget, |
| |
703 gpointer data) |
| |
704 { |
| |
705 GtkComboBox *combo_box = GTK_COMBO_BOX (data); |
| |
706 |
| |
707 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) |
| |
708 { |
| |
709 if (!combo_box->priv->popup_in_progress) |
| |
710 gtk_combo_box_popup (combo_box); |
| |
711 } |
| |
712 else |
| |
713 gtk_combo_box_popdown (combo_box); |
| |
714 } |
| |
715 |
| |
716 static void |
| |
717 gtk_combo_box_add (GtkContainer *container, |
| |
718 GtkWidget *widget) |
| |
719 { |
| |
720 GtkComboBox *combo_box = GTK_COMBO_BOX (container); |
| |
721 |
| |
722 if (combo_box->priv->cell_view && combo_box->priv->cell_view->parent) |
| |
723 { |
| |
724 gtk_widget_unparent (combo_box->priv->cell_view); |
| |
725 GTK_BIN (container)->child = NULL; |
| |
726 gtk_widget_queue_resize (GTK_WIDGET (container)); |
| |
727 } |
| |
728 |
| |
729 gtk_widget_set_parent (widget, GTK_WIDGET (container)); |
| |
730 GTK_BIN (container)->child = widget; |
| |
731 |
| |
732 if (combo_box->priv->cell_view && |
| |
733 widget != combo_box->priv->cell_view) |
| |
734 { |
| |
735 /* since the cell_view was unparented, it's gone now */ |
| |
736 combo_box->priv->cell_view = NULL; |
| |
737 |
| |
738 if (!combo_box->priv->tree_view && combo_box->priv->separator) |
| |
739 { |
| |
740 gtk_container_remove (GTK_CONTAINER (combo_box->priv->separator->parent), |
| |
741 combo_box->priv->separator); |
| |
742 combo_box->priv->separator = NULL; |
| |
743 |
| |
744 gtk_widget_queue_resize (GTK_WIDGET (container)); |
| |
745 } |
| |
746 else if (combo_box->priv->cell_view_frame) |
| |
747 { |
| |
748 gtk_widget_unparent (combo_box->priv->cell_view_frame); |
| |
749 combo_box->priv->cell_view_frame = NULL; |
| |
750 } |
| |
751 } |
| |
752 } |
| |
753 |
| |
754 static void |
| |
755 gtk_combo_box_remove (GtkContainer *container, |
| |
756 GtkWidget *widget) |
| |
757 { |
| |
758 GtkComboBox *combo_box = GTK_COMBO_BOX (container); |
| |
759 gboolean appears_as_list; |
| |
760 |
| |
761 gtk_widget_unparent (widget); |
| |
762 GTK_BIN (container)->child = NULL; |
| |
763 |
| |
764 if (combo_box->priv->destroying) |
| |
765 return; |
| |
766 |
| |
767 gtk_widget_queue_resize (GTK_WIDGET (container)); |
| |
768 |
| |
769 if (!combo_box->priv->tree_view) |
| |
770 appears_as_list = FALSE; |
| |
771 else |
| |
772 appears_as_list = TRUE; |
| |
773 |
| |
774 if (appears_as_list) |
| |
775 gtk_combo_box_list_destroy (combo_box); |
| |
776 else if (GTK_IS_MENU (combo_box->priv->popup_widget)) |
| |
777 { |
| |
778 gtk_combo_box_menu_destroy (combo_box); |
| |
779 gtk_menu_detach (GTK_MENU (combo_box->priv->popup_widget)); |
| |
780 combo_box->priv->popup_widget = NULL; |
| |
781 } |
| |
782 |
| |
783 if (!combo_box->priv->cell_view) |
| |
784 { |
| |
785 combo_box->priv->cell_view = gtk_cell_view_new (); |
| |
786 gtk_widget_set_parent (combo_box->priv->cell_view, GTK_WIDGET (container)); |
| |
787 GTK_BIN (container)->child = combo_box->priv->cell_view; |
| |
788 |
| |
789 gtk_widget_show (combo_box->priv->cell_view); |
| |
790 gtk_cell_view_set_model (GTK_CELL_VIEW (combo_box->priv->cell_view), |
| |
791 combo_box->priv->model); |
| |
792 cell_view_sync_cells (combo_box, GTK_CELL_VIEW (combo_box->priv->cell_view)); |
| |
793 } |
| |
794 |
| |
795 |
| |
796 if (appears_as_list) |
| |
797 gtk_combo_box_list_setup (combo_box); |
| |
798 else |
| |
799 gtk_combo_box_menu_setup (combo_box, TRUE); |
| |
800 |
| |
801 gtk_combo_box_set_active_internal (combo_box, combo_box->priv->active_item); |
| |
802 } |
| |
803 |
| |
804 static ComboCellInfo * |
| |
805 gtk_combo_box_get_cell_info (GtkComboBox *combo_box, |
| |
806 GtkCellRenderer *cell) |
| |
807 { |
| |
808 GSList *i; |
| |
809 |
| |
810 for (i = combo_box->priv->cells; i; i = i->next) |
| |
811 { |
| |
812 ComboCellInfo *info = (ComboCellInfo *)i->data; |
| |
813 |
| |
814 if (info && info->cell == cell) |
| |
815 return info; |
| |
816 } |
| |
817 |
| |
818 return NULL; |
| |
819 } |
| |
820 |
| |
821 static void |
| |
822 gtk_combo_box_menu_show (GtkWidget *menu, |
| |
823 gpointer user_data) |
| |
824 { |
| |
825 GtkComboBox *combo_box = GTK_COMBO_BOX (user_data); |
| |
826 |
| |
827 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo_box->priv->button), |
| |
828 TRUE); |
| |
829 combo_box->priv->popup_in_progress = FALSE; |
| |
830 } |
| |
831 |
| |
832 static void |
| |
833 gtk_combo_box_menu_hide (GtkWidget *menu, |
| |
834 gpointer user_data) |
| |
835 { |
| |
836 GtkComboBox *combo_box = GTK_COMBO_BOX (user_data); |
| |
837 |
| |
838 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo_box->priv->button), |
| |
839 FALSE); |
| |
840 } |
| |
841 |
| |
842 static void |
| |
843 gtk_combo_box_detacher (GtkWidget *widget, |
| |
844 GtkMenu *menu) |
| |
845 { |
| |
846 GtkComboBox *combo_box; |
| |
847 |
| |
848 g_return_if_fail (GTK_IS_COMBO_BOX (widget)); |
| |
849 |
| |
850 combo_box = GTK_COMBO_BOX (widget); |
| |
851 g_return_if_fail (combo_box->priv->popup_widget == (GtkWidget*) menu); |
| |
852 |
| |
853 g_signal_handlers_disconnect_by_func (menu, |
| |
854 gtk_combo_box_menu_show, |
| |
855 combo_box); |
| |
856 g_signal_handlers_disconnect_by_func (menu, |
| |
857 gtk_combo_box_menu_hide, |
| |
858 combo_box); |
| |
859 |
| |
860 combo_box->priv->popup_widget = NULL; |
| |
861 } |
| |
862 |
| |
863 static void |
| |
864 gtk_combo_box_set_popup_widget (GtkComboBox *combo_box, |
| |
865 GtkWidget *popup) |
| |
866 { |
| |
867 if (GTK_IS_MENU (combo_box->priv->popup_widget)) |
| |
868 { |
| |
869 gtk_menu_detach (GTK_MENU (combo_box->priv->popup_widget)); |
| |
870 combo_box->priv->popup_widget = NULL; |
| |
871 } |
| |
872 else if (combo_box->priv->popup_widget) |
| |
873 { |
| |
874 gtk_container_remove (GTK_CONTAINER (combo_box->priv->popup_frame), |
| |
875 combo_box->priv->popup_widget); |
| |
876 g_object_unref (G_OBJECT (combo_box->priv->popup_widget)); |
| |
877 combo_box->priv->popup_widget = NULL; |
| |
878 } |
| |
879 |
| |
880 if (GTK_IS_MENU (popup)) |
| |
881 { |
| |
882 if (combo_box->priv->popup_window) |
| |
883 { |
| |
884 gtk_widget_destroy (combo_box->priv->popup_window); |
| |
885 combo_box->priv->popup_window = NULL; |
| |
886 combo_box->priv->popup_frame = NULL; |
| |
887 } |
| |
888 |
| |
889 combo_box->priv->popup_widget = popup; |
| |
890 |
| |
891 g_signal_connect (popup, "show", |
| |
892 G_CALLBACK (gtk_combo_box_menu_show), combo_box); |
| |
893 g_signal_connect (popup, "hide", |
| |
894 G_CALLBACK (gtk_combo_box_menu_hide), combo_box); |
| |
895 |
| |
896 gtk_menu_attach_to_widget (GTK_MENU (popup), |
| |
897 GTK_WIDGET (combo_box), |
| |
898 gtk_combo_box_detacher); |
| |
899 } |
| |
900 else |
| |
901 { |
| |
902 if (!combo_box->priv->popup_window) |
| |
903 { |
| |
904 combo_box->priv->popup_window = gtk_window_new (GTK_WINDOW_POPUP); |
| |
905 gtk_window_set_resizable (GTK_WINDOW (combo_box->priv->popup_window), FALSE); |
| |
906 #if GTK_CHECK_VERSION(2,2,0) |
| |
907 gtk_window_set_screen (GTK_WINDOW (combo_box->priv->popup_window), |
| |
908 gtk_widget_get_screen (GTK_WIDGET (combo_box))); |
| |
909 #endif |
| |
910 |
| |
911 combo_box->priv->popup_frame = gtk_frame_new (NULL); |
| |
912 gtk_frame_set_shadow_type (GTK_FRAME (combo_box->priv->popup_frame), |
| |
913 GTK_SHADOW_ETCHED_IN); |
| |
914 gtk_container_add (GTK_CONTAINER (combo_box->priv->popup_window), |
| |
915 combo_box->priv->popup_frame); |
| |
916 |
| |
917 gtk_widget_show (combo_box->priv->popup_frame); |
| |
918 } |
| |
919 |
| |
920 gtk_container_add (GTK_CONTAINER (combo_box->priv->popup_frame), |
| |
921 popup); |
| |
922 gtk_widget_show (popup); |
| |
923 g_object_ref (G_OBJECT (popup)); |
| |
924 combo_box->priv->popup_widget = popup; |
| |
925 } |
| |
926 } |
| |
927 |
| |
928 #if GTK_CHECK_VERSION(2,2,0) |
| |
929 static void |
| |
930 gtk_combo_box_menu_position_below (GtkMenu *menu, |
| |
931 gint *x, |
| |
932 gint *y, |
| |
933 gint *push_in, |
| |
934 gpointer user_data) |
| |
935 { |
| |
936 GtkComboBox *combo_box = GTK_COMBO_BOX (user_data); |
| |
937 gint sx, sy; |
| |
938 GtkWidget *child; |
| |
939 GtkRequisition req; |
| |
940 GdkScreen *screen; |
| |
941 gint monitor_num; |
| |
942 GdkRectangle monitor; |
| |
943 |
| |
944 /* FIXME: is using the size request here broken? */ |
| |
945 child = GTK_BIN (combo_box)->child; |
| |
946 |
| |
947 gdk_window_get_origin (child->window, &sx, &sy); |
| |
948 |
| |
949 if (GTK_WIDGET_NO_WINDOW (child)) |
| |
950 { |
| |
951 sx += child->allocation.x; |
| |
952 sy += child->allocation.y; |
| |
953 } |
| |
954 |
| |
955 gtk_widget_size_request (GTK_WIDGET (menu), &req); |
| |
956 |
| |
957 if (gtk_widget_get_direction (GTK_WIDGET (combo_box)) == GTK_TEXT_DIR_LTR) |
| |
958 *x = sx; |
| |
959 else |
| |
960 *x = sx + child->allocation.width - req.width; |
| |
961 *y = sy; |
| |
962 |
| |
963 screen = gtk_widget_get_screen (GTK_WIDGET (combo_box)); |
| |
964 monitor_num = gdk_screen_get_monitor_at_window (screen, |
| |
965 GTK_WIDGET (combo_box)->window); |
| |
966 gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor); |
| |
967 |
| |
968 if (*x < monitor.x) |
| |
969 *x = monitor.x; |
| |
970 else if (*x + req.width > monitor.x + monitor.width) |
| |
971 *x = monitor.x + monitor.width - req.width; |
| |
972 |
| |
973 if (monitor.y + monitor.height - *y - child->allocation.height >= req.height) |
| |
974 *y += child->allocation.height; |
| |
975 else if (*y - monitor.y >= req.height) |
| |
976 *y -= req.height; |
| |
977 else if (monitor.y + monitor.height - *y - child->allocation.height > *y - monitor.y) |
| |
978 *y += child->allocation.height; |
| |
979 else |
| |
980 *y -= req.height; |
| |
981 |
| |
982 *push_in = FALSE; |
| |
983 } |
| |
984 |
| |
985 static void |
| |
986 gtk_combo_box_menu_position_over (GtkMenu *menu, |
| |
987 gint *x, |
| |
988 gint *y, |
| |
989 gboolean *push_in, |
| |
990 gpointer user_data) |
| |
991 { |
| |
992 GtkComboBox *combo_box; |
| |
993 GtkWidget *active; |
| |
994 GtkWidget *child; |
| |
995 GtkWidget *widget; |
| |
996 GtkRequisition requisition; |
| |
997 GList *children; |
| |
998 gint screen_width; |
| |
999 gint menu_xpos; |
| |
1000 gint menu_ypos; |
| |
1001 gint menu_width; |
| |
1002 |
| |
1003 g_return_if_fail (GTK_IS_COMBO_BOX (user_data)); |
| |
1004 |
| |
1005 combo_box = GTK_COMBO_BOX (user_data); |
| |
1006 widget = GTK_WIDGET (combo_box); |
| |
1007 |
| |
1008 gtk_widget_get_child_requisition (GTK_WIDGET (menu), &requisition); |
| |
1009 menu_width = requisition.width; |
| |
1010 |
| |
1011 active = gtk_menu_get_active (GTK_MENU (combo_box->priv->popup_widget)); |
| |
1012 gdk_window_get_origin (widget->window, &menu_xpos, &menu_ypos); |
| |
1013 |
| |
1014 menu_xpos += widget->allocation.x; |
| |
1015 menu_ypos += widget->allocation.y + widget->allocation.height / 2 - 2; |
| |
1016 |
| |
1017 if (active != NULL) |
| |
1018 { |
| |
1019 gtk_widget_get_child_requisition (active, &requisition); |
| |
1020 menu_ypos -= requisition.height / 2; |
| |
1021 } |
| |
1022 |
| |
1023 children = GTK_MENU_SHELL (combo_box->priv->popup_widget)->children; |
| |
1024 while (children) |
| |
1025 { |
| |
1026 child = children->data; |
| |
1027 |
| |
1028 if (active == child) |
| |
1029 break; |
| |
1030 |
| |
1031 if (GTK_WIDGET_VISIBLE (child)) |
| |
1032 { |
| |
1033 gtk_widget_get_child_requisition (child, &requisition); |
| |
1034 menu_ypos -= requisition.height; |
| |
1035 } |
| |
1036 |
| |
1037 children = children->next; |
| |
1038 } |
| |
1039 |
| |
1040 if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) |
| |
1041 menu_xpos = menu_xpos + widget->allocation.width - menu_width; |
| |
1042 |
| |
1043 /* Clamp the position on screen */ |
| |
1044 screen_width = gdk_screen_get_width (gtk_widget_get_screen (widget)); |
| |
1045 |
| |
1046 if (menu_xpos < 0) |
| |
1047 menu_xpos = 0; |
| |
1048 else if ((menu_xpos + menu_width) > screen_width) |
| |
1049 menu_xpos -= ((menu_xpos + menu_width) - screen_width); |
| |
1050 |
| |
1051 *x = menu_xpos; |
| |
1052 *y = menu_ypos; |
| |
1053 |
| |
1054 *push_in = TRUE; |
| |
1055 } |
| |
1056 |
| |
1057 static void |
| |
1058 gtk_combo_box_menu_position (GtkMenu *menu, |
| |
1059 gint *x, |
| |
1060 gint *y, |
| |
1061 gint *push_in, |
| |
1062 gpointer user_data) |
| |
1063 { |
| |
1064 GtkComboBox *combo_box; |
| |
1065 GtkWidget *menu_item; |
| |
1066 |
| |
1067 combo_box = GTK_COMBO_BOX (user_data); |
| |
1068 |
| |
1069 if (combo_box->priv->wrap_width > 0 || combo_box->priv->cell_view == NULL) |
| |
1070 gtk_combo_box_menu_position_below (menu, x, y, push_in, user_data); |
| |
1071 else |
| |
1072 { |
| |
1073 menu_item = gtk_menu_get_active (GTK_MENU (combo_box->priv->popup_widget)); |
| |
1074 if (menu_item) |
| |
1075 gtk_menu_shell_select_item (GTK_MENU_SHELL (combo_box->priv->popup_widget), |
| |
1076 menu_item); |
| |
1077 |
| |
1078 gtk_combo_box_menu_position_over (menu, x, y, push_in, user_data); |
| |
1079 } |
| |
1080 |
| |
1081 } |
| |
1082 #endif /* Gtk 2.2 */ |
| |
1083 |
| |
1084 static void |
| |
1085 gtk_combo_box_list_position (GtkComboBox *combo_box, |
| |
1086 gint *x, |
| |
1087 gint *y, |
| |
1088 gint *width, |
| |
1089 gint *height) |
| |
1090 { |
| |
1091 GtkWidget *sample; |
| |
1092 GtkRequisition popup_req; |
| |
1093 #if GTK_CHECK_VERSION(2,2,0) |
| |
1094 GdkScreen *screen; |
| |
1095 gint monitor_num; |
| |
1096 GdkRectangle monitor; |
| |
1097 #endif |
| |
1098 |
| |
1099 sample = GTK_BIN (combo_box)->child; |
| |
1100 |
| |
1101 *width = sample->allocation.width; |
| |
1102 gtk_widget_size_request (combo_box->priv->popup_window, &popup_req); |
| |
1103 *height = popup_req.height; |
| |
1104 |
| |
1105 gdk_window_get_origin (sample->window, x, y); |
| |
1106 |
| |
1107 if (combo_box->priv->cell_view_frame) |
| |
1108 { |
| |
1109 *x -= GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width + |
| |
1110 GTK_WIDGET (combo_box->priv->cell_view_frame)->style->xthickness; |
| |
1111 *width += 2 * (GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width + |
| |
1112 GTK_WIDGET (combo_box->priv->cell_view_frame)->style->xthickness); |
| |
1113 } |
| |
1114 |
| |
1115 if (GTK_WIDGET_NO_WINDOW (sample)) |
| |
1116 { |
| |
1117 *x += sample->allocation.x; |
| |
1118 *y += sample->allocation.y; |
| |
1119 } |
| |
1120 |
| |
1121 #if GTK_CHECK_VERSION(2,2,0) |
| |
1122 screen = gtk_widget_get_screen (GTK_WIDGET (combo_box)); |
| |
1123 monitor_num = gdk_screen_get_monitor_at_window (screen, |
| |
1124 GTK_WIDGET (combo_box)->window); |
| |
1125 gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor); |
| |
1126 |
| |
1127 if (*x < monitor.x) |
| |
1128 *x = monitor.x; |
| |
1129 else if (*x + *width > monitor.x + monitor.width) |
| |
1130 *x = monitor.x + monitor.width - *width; |
| |
1131 |
| |
1132 if (*y + sample->allocation.height + *height <= monitor.y + monitor.height) |
| |
1133 *y += sample->allocation.height; |
| |
1134 else |
| |
1135 *y -= *height; |
| |
1136 #endif /* Gtk 2.2 */ |
| |
1137 } |
| |
1138 |
| |
1139 /** |
| |
1140 * gtk_combo_box_popup: |
| |
1141 * @combo_box: a #GtkComboBox |
| |
1142 * |
| |
1143 * Pops up the menu or dropdown list of @combo_box. |
| |
1144 * |
| |
1145 * This function is mostly intended for use by accessibility technologies; |
| |
1146 * applications should have little use for it. |
| |
1147 * |
| |
1148 * Since: 2.4 |
| |
1149 **/ |
| |
1150 void |
| |
1151 gtk_combo_box_popup (GtkComboBox *combo_box) |
| |
1152 { |
| |
1153 gint x, y, width, height; |
| |
1154 |
| |
1155 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box)); |
| |
1156 |
| |
1157 if (GTK_WIDGET_MAPPED (combo_box->priv->popup_widget)) |
| |
1158 return; |
| |
1159 |
| |
1160 if (GTK_IS_MENU (combo_box->priv->popup_widget)) |
| |
1161 { |
| |
1162 gtk_menu_set_active (GTK_MENU (combo_box->priv->popup_widget), |
| |
1163 combo_box->priv->active_item); |
| |
1164 |
| |
1165 if (combo_box->priv->wrap_width == 0) |
| |
1166 { |
| |
1167 GtkRequisition requisition; |
| |
1168 |
| |
1169 width = GTK_WIDGET (combo_box)->allocation.width; |
| |
1170 gtk_widget_size_request (combo_box->priv->popup_widget, &requisition); |
| |
1171 |
| |
1172 gtk_widget_set_size_request (combo_box->priv->popup_widget, |
| |
1173 MAX (width, requisition.width), -1); |
| |
1174 } |
| |
1175 |
| |
1176 gtk_menu_popup (GTK_MENU (combo_box->priv->popup_widget), |
| |
1177 NULL, NULL, |
| |
1178 #if GTK_CHECK_VERSION(2,2,0) |
| |
1179 gtk_combo_box_menu_position, |
| |
1180 #else |
| |
1181 NULL, |
| |
1182 #endif |
| |
1183 combo_box, 0, 0); |
| |
1184 return; |
| |
1185 } |
| |
1186 |
| |
1187 gtk_widget_show_all (combo_box->priv->popup_frame); |
| |
1188 gtk_combo_box_list_position (combo_box, &x, &y, &width, &height); |
| |
1189 |
| |
1190 gtk_widget_set_size_request (combo_box->priv->popup_window, width, -1); |
| |
1191 gtk_window_move (GTK_WINDOW (combo_box->priv->popup_window), x, y); |
| |
1192 |
| |
1193 /* popup */ |
| |
1194 gtk_widget_show (combo_box->priv->popup_window); |
| |
1195 |
| |
1196 gtk_widget_grab_focus (combo_box->priv->popup_window); |
| |
1197 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo_box->priv->button), |
| |
1198 TRUE); |
| |
1199 |
| |
1200 if (!GTK_WIDGET_HAS_FOCUS (combo_box->priv->tree_view)) |
| |
1201 { |
| |
1202 gdk_keyboard_grab (combo_box->priv->popup_window->window, |
| |
1203 FALSE, GDK_CURRENT_TIME); |
| |
1204 gtk_widget_grab_focus (combo_box->priv->tree_view); |
| |
1205 } |
| |
1206 |
| |
1207 gtk_grab_add (combo_box->priv->popup_window); |
| |
1208 gdk_pointer_grab (combo_box->priv->popup_window->window, TRUE, |
| |
1209 GDK_BUTTON_PRESS_MASK | |
| |
1210 GDK_BUTTON_RELEASE_MASK | |
| |
1211 GDK_POINTER_MOTION_MASK, |
| |
1212 NULL, NULL, GDK_CURRENT_TIME); |
| |
1213 |
| |
1214 gtk_grab_add (combo_box->priv->tree_view); |
| |
1215 } |
| |
1216 |
| |
1217 /** |
| |
1218 * gtk_combo_box_popdown: |
| |
1219 * @combo_box: a #GtkComboBox |
| |
1220 * |
| |
1221 * Hides the menu or dropdown list of @combo_box. |
| |
1222 * |
| |
1223 * This function is mostly intended for use by accessibility technologies; |
| |
1224 * applications should have little use for it. |
| |
1225 * |
| |
1226 * Since: 2.4 |
| |
1227 **/ |
| |
1228 void |
| |
1229 gtk_combo_box_popdown (GtkComboBox *combo_box) |
| |
1230 { |
| |
1231 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box)); |
| |
1232 |
| |
1233 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (combo_box))) |
| |
1234 return; |
| |
1235 |
| |
1236 if (GTK_IS_MENU (combo_box->priv->popup_widget)) |
| |
1237 { |
| |
1238 gtk_menu_popdown (GTK_MENU (combo_box->priv->popup_widget)); |
| |
1239 return; |
| |
1240 } |
| |
1241 |
| |
1242 gtk_combo_box_list_remove_grabs (combo_box); |
| |
1243 gtk_widget_hide_all (combo_box->priv->popup_window); |
| |
1244 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo_box->priv->button), |
| |
1245 FALSE); |
| |
1246 } |
| |
1247 |
| |
1248 static gint |
| |
1249 gtk_combo_box_calc_requested_width (GtkComboBox *combo_box, |
| |
1250 GtkTreePath *path) |
| |
1251 { |
| |
1252 gint padding; |
| |
1253 GtkRequisition req; |
| |
1254 |
| |
1255 if (combo_box->priv->cell_view) |
| |
1256 gtk_widget_style_get (combo_box->priv->cell_view, |
| |
1257 "focus-line-width", &padding, |
| |
1258 NULL); |
| |
1259 else |
| |
1260 padding = 0; |
| |
1261 |
| |
1262 /* add some pixels for good measure */ |
| |
1263 padding += BONUS_PADDING; |
| |
1264 |
| |
1265 if (combo_box->priv->cell_view) |
| |
1266 gtk_cell_view_get_size_of_row (GTK_CELL_VIEW (combo_box->priv->cell_view), |
| |
1267 path, &req); |
| |
1268 else |
| |
1269 req.width = 0; |
| |
1270 |
| |
1271 return req.width + padding; |
| |
1272 } |
| |
1273 |
| |
1274 static void |
| |
1275 gtk_combo_box_remeasure (GtkComboBox *combo_box) |
| |
1276 { |
| |
1277 GtkTreeIter iter; |
| |
1278 GtkTreePath *path; |
| |
1279 gint padding = 0; |
| |
1280 |
| |
1281 if (!combo_box->priv->model || |
| |
1282 !gtk_tree_model_get_iter_first (combo_box->priv->model, &iter)) |
| |
1283 return; |
| |
1284 |
| |
1285 combo_box->priv->width = 0; |
| |
1286 |
| |
1287 #if GTK_CHECK_VERSION(2,2,0) |
| |
1288 path = gtk_tree_path_new_from_indices (0, -1); |
| |
1289 #else |
| |
1290 path = gtk_tree_path_new_first(); |
| |
1291 #endif |
| |
1292 |
| |
1293 if (combo_box->priv->cell_view) |
| |
1294 gtk_widget_style_get (combo_box->priv->cell_view, |
| |
1295 "focus-line-width", &padding, |
| |
1296 NULL); |
| |
1297 else |
| |
1298 padding = 0; |
| |
1299 |
| |
1300 /* add some pixels for good measure */ |
| |
1301 padding += BONUS_PADDING; |
| |
1302 |
| |
1303 do |
| |
1304 { |
| |
1305 GtkRequisition req; |
| |
1306 |
| |
1307 if (combo_box->priv->cell_view) |
| |
1308 gtk_cell_view_get_size_of_row (GTK_CELL_VIEW (combo_box->priv->cell_view), |
| |
1309 path, &req); |
| |
1310 else |
| |
1311 req.width = 0; |
| |
1312 |
| |
1313 combo_box->priv->width = MAX (combo_box->priv->width, |
| |
1314 req.width + padding); |
| |
1315 |
| |
1316 gtk_tree_path_next (path); |
| |
1317 } |
| |
1318 while (gtk_tree_model_iter_next (combo_box->priv->model, &iter)); |
| |
1319 |
| |
1320 gtk_tree_path_free (path); |
| |
1321 } |
| |
1322 |
| |
1323 static void |
| |
1324 gtk_combo_box_size_request (GtkWidget *widget, |
| |
1325 GtkRequisition *requisition) |
| |
1326 { |
| |
1327 gint width, height; |
| |
1328 GtkRequisition bin_req; |
| |
1329 |
| |
1330 GtkComboBox *combo_box = GTK_COMBO_BOX (widget); |
| |
1331 |
| |
1332 /* common */ |
| |
1333 gtk_widget_size_request (GTK_BIN (widget)->child, &bin_req); |
| |
1334 gtk_combo_box_remeasure (combo_box); |
| |
1335 bin_req.width = MAX (bin_req.width, combo_box->priv->width); |
| |
1336 |
| |
1337 gtk_combo_box_check_appearance (combo_box); |
| |
1338 |
| |
1339 if (!combo_box->priv->tree_view) |
| |
1340 { |
| |
1341 /* menu mode */ |
| |
1342 |
| |
1343 if (combo_box->priv->cell_view) |
| |
1344 { |
| |
1345 GtkRequisition button_req, sep_req, arrow_req; |
| |
1346 gint border_width, xthickness, ythickness; |
| |
1347 |
| |
1348 gtk_widget_size_request (combo_box->priv->button, &button_req); |
| |
1349 border_width = GTK_CONTAINER (combo_box->priv->button)->border_width; |
| |
1350 xthickness = combo_box->priv->button->style->xthickness; |
| |
1351 ythickness = combo_box->priv->button->style->ythickness; |
| |
1352 |
| |
1353 bin_req.width = MAX (bin_req.width, combo_box->priv->width); |
| |
1354 |
| |
1355 gtk_widget_size_request (combo_box->priv->separator, &sep_req); |
| |
1356 gtk_widget_size_request (combo_box->priv->arrow, &arrow_req); |
| |
1357 |
| |
1358 height = MAX (sep_req.height, arrow_req.height); |
| |
1359 height = MAX (height, bin_req.height); |
| |
1360 |
| |
1361 width = bin_req.width + sep_req.width + arrow_req.width; |
| |
1362 |
| |
1363 height += border_width + 1 + ythickness * 2 + 4; |
| |
1364 width += border_width + 1 + xthickness * 2 + 4; |
| |
1365 |
| |
1366 requisition->width = width; |
| |
1367 requisition->height = height; |
| |
1368 } |
| |
1369 else |
| |
1370 { |
| |
1371 GtkRequisition but_req; |
| |
1372 |
| |
1373 gtk_widget_size_request (combo_box->priv->button, &but_req); |
| |
1374 |
| |
1375 requisition->width = bin_req.width + but_req.width; |
| |
1376 requisition->height = MAX (bin_req.height, but_req.height); |
| |
1377 } |
| |
1378 } |
| |
1379 else |
| |
1380 { |
| |
1381 /* list mode */ |
| |
1382 GtkRequisition button_req, frame_req; |
| |
1383 |
| |
1384 /* sample + frame */ |
| |
1385 *requisition = bin_req; |
| |
1386 |
| |
1387 if (combo_box->priv->cell_view_frame) |
| |
1388 { |
| |
1389 gtk_widget_size_request (combo_box->priv->cell_view_frame, &frame_req); |
| |
1390 requisition->width += 2 * |
| |
1391 (GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width + |
| |
1392 GTK_WIDGET (combo_box->priv->cell_view_frame)->style->xthickness); |
| |
1393 requisition->height += 2 * |
| |
1394 (GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width + |
| |
1395 GTK_WIDGET (combo_box->priv->cell_view_frame)->style->ythickness); |
| |
1396 } |
| |
1397 |
| |
1398 /* the button */ |
| |
1399 gtk_widget_size_request (combo_box->priv->button, &button_req); |
| |
1400 |
| |
1401 requisition->height = MAX (requisition->height, button_req.height); |
| |
1402 requisition->width += button_req.width; |
| |
1403 } |
| |
1404 } |
| |
1405 |
| |
1406 static void |
| |
1407 gtk_combo_box_size_allocate (GtkWidget *widget, |
| |
1408 GtkAllocation *allocation) |
| |
1409 { |
| |
1410 GtkComboBox *combo_box = GTK_COMBO_BOX (widget); |
| |
1411 GtkAllocation child; |
| |
1412 GtkRequisition req; |
| |
1413 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL; |
| |
1414 |
| |
1415 widget->allocation = *allocation; |
| |
1416 |
| |
1417 gtk_combo_box_check_appearance (combo_box); |
| |
1418 |
| |
1419 if (!combo_box->priv->tree_view) |
| |
1420 { |
| |
1421 if (combo_box->priv->cell_view) |
| |
1422 { |
| |
1423 gint border_width, xthickness, ythickness; |
| |
1424 gint width; |
| |
1425 |
| |
1426 /* menu mode */ |
| |
1427 gtk_widget_size_allocate (combo_box->priv->button, allocation); |
| |
1428 |
| |
1429 /* set some things ready */ |
| |
1430 border_width = GTK_CONTAINER (combo_box->priv->button)->border_width; |
| |
1431 xthickness = combo_box->priv->button->style->xthickness; |
| |
1432 ythickness = combo_box->priv->button->style->ythickness; |
| |
1433 |
| |
1434 child.x = allocation->x + border_width + 1 + xthickness + 2; |
| |
1435 child.y = allocation->y + border_width + 1 + ythickness + 2; |
| |
1436 |
| |
1437 width = MAX(1, allocation->width - (border_width + 1 + xthickness * 2 + 4)); |
| |
1438 |
| |
1439 /* handle the children */ |
| |
1440 gtk_widget_size_request (combo_box->priv->arrow, &req); |
| |
1441 child.width = req.width; |
| |
1442 child.height = MAX(1, allocation->height - 2 * (child.y - allocation->y)); |
| |
1443 if (!is_rtl) |
| |
1444 child.x += width - req.width; |
| |
1445 gtk_widget_size_allocate (combo_box->priv->arrow, &child); |
| |
1446 if (is_rtl) |
| |
1447 child.x += req.width; |
| |
1448 gtk_widget_size_request (combo_box->priv->separator, &req); |
| |
1449 child.width = req.width; |
| |
1450 if (!is_rtl) |
| |
1451 child.x -= req.width; |
| |
1452 gtk_widget_size_allocate (combo_box->priv->separator, &child); |
| |
1453 |
| |
1454 if (is_rtl) |
| |
1455 { |
| |
1456 child.x += req.width; |
| |
1457 child.width = MAX(1, allocation->x + allocation->width |
| |
1458 - (border_width + 1 + xthickness + 2) - child.x); |
| |
1459 } |
| |
1460 else |
| |
1461 { |
| |
1462 child.width = child.x; |
| |
1463 child.x = allocation->x + border_width + 1 + xthickness + 2; |
| |
1464 child.width = MAX(1, child.width - child.x); |
| |
1465 } |
| |
1466 |
| |
1467 gtk_widget_size_allocate (GTK_BIN (widget)->child, &child); |
| |
1468 } |
| |
1469 else |
| |
1470 { |
| |
1471 gtk_widget_size_request (combo_box->priv->button, &req); |
| |
1472 if (is_rtl) |
| |
1473 child.x = allocation->x; |
| |
1474 else |
| |
1475 child.x = allocation->x + allocation->width - req.width; |
| |
1476 child.y = allocation->y; |
| |
1477 child.width = req.width; |
| |
1478 child.height = allocation->height; |
| |
1479 gtk_widget_size_allocate (combo_box->priv->button, &child); |
| |
1480 |
| |
1481 if (is_rtl) |
| |
1482 child.x = allocation->x + req.width; |
| |
1483 else |
| |
1484 child.x = allocation->x; |
| |
1485 child.y = allocation->y; |
| |
1486 child.width = MAX(1, allocation->width - req.width); |
| |
1487 gtk_widget_size_allocate (GTK_BIN (widget)->child, &child); |
| |
1488 } |
| |
1489 } |
| |
1490 else |
| |
1491 { |
| |
1492 /* list mode */ |
| |
1493 |
| |
1494 /* button */ |
| |
1495 gtk_widget_size_request (combo_box->priv->button, &req); |
| |
1496 if (is_rtl) |
| |
1497 child.x = allocation->x; |
| |
1498 else |
| |
1499 child.x = allocation->x + allocation->width - req.width; |
| |
1500 child.y = allocation->y; |
| |
1501 child.width = req.width; |
| |
1502 child.height = allocation->height; |
| |
1503 gtk_widget_size_allocate (combo_box->priv->button, &child); |
| |
1504 |
| |
1505 /* frame */ |
| |
1506 if (is_rtl) |
| |
1507 child.x = allocation->x + req.width; |
| |
1508 else |
| |
1509 child.x = allocation->x; |
| |
1510 child.y = allocation->y; |
| |
1511 child.width = MAX (1, allocation->width - req.width); |
| |
1512 child.height = allocation->height; |
| |
1513 |
| |
1514 if (combo_box->priv->cell_view_frame) |
| |
1515 { |
| |
1516 gtk_widget_size_allocate (combo_box->priv->cell_view_frame, &child); |
| |
1517 |
| |
1518 /* the sample */ |
| |
1519 child.x += |
| |
1520 GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width + |
| |
1521 GTK_WIDGET (combo_box->priv->cell_view_frame)->style->xthickness; |
| |
1522 child.y += |
| |
1523 GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width + |
| |
1524 GTK_WIDGET (combo_box->priv->cell_view_frame)->style->ythickness; |
| |
1525 child.width -= 2 * ( |
| |
1526 GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width + |
| |
1527 GTK_WIDGET (combo_box->priv->cell_view_frame)->style->xthickness); |
| |
1528 child.width = MAX(1,child.width); |
| |
1529 child.height -= 2 * ( |
| |
1530 GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width + |
| |
1531 GTK_WIDGET (combo_box->priv->cell_view_frame)->style->ythickness); |
| |
1532 child.height = MAX(1,child.height); |
| |
1533 } |
| |
1534 |
| |
1535 gtk_widget_size_allocate (GTK_BIN (combo_box)->child, &child); |
| |
1536 } |
| |
1537 } |
| |
1538 |
| |
1539 static void |
| |
1540 gtk_combo_box_unset_model (GtkComboBox *combo_box) |
| |
1541 { |
| |
1542 if (combo_box->priv->model) |
| |
1543 { |
| |
1544 g_signal_handler_disconnect (combo_box->priv->model, |
| |
1545 combo_box->priv->inserted_id); |
| |
1546 g_signal_handler_disconnect (combo_box->priv->model, |
| |
1547 combo_box->priv->deleted_id); |
| |
1548 g_signal_handler_disconnect (combo_box->priv->model, |
| |
1549 combo_box->priv->reordered_id); |
| |
1550 g_signal_handler_disconnect (combo_box->priv->model, |
| |
1551 combo_box->priv->changed_id); |
| |
1552 } |
| |
1553 |
| |
1554 /* menu mode */ |
| |
1555 if (!combo_box->priv->tree_view) |
| |
1556 { |
| |
1557 if (combo_box->priv->popup_widget) |
| |
1558 gtk_container_foreach (GTK_CONTAINER (combo_box->priv->popup_widget), |
| |
1559 (GtkCallback)gtk_widget_destroy, NULL); |
| |
1560 } |
| |
1561 |
| |
1562 if (combo_box->priv->model) |
| |
1563 { |
| |
1564 g_object_unref (G_OBJECT (combo_box->priv->model)); |
| |
1565 combo_box->priv->model = NULL; |
| |
1566 } |
| |
1567 |
| |
1568 if (combo_box->priv->cell_view) |
| |
1569 gtk_cell_view_set_displayed_row (GTK_CELL_VIEW (combo_box->priv->cell_view), NULL); |
| |
1570 } |
| |
1571 |
| |
1572 static void |
| |
1573 gtk_combo_box_forall (GtkContainer *container, |
| |
1574 gboolean include_internals, |
| |
1575 GtkCallback callback, |
| |
1576 gpointer callback_data) |
| |
1577 { |
| |
1578 GtkComboBox *combo_box = GTK_COMBO_BOX (container); |
| |
1579 |
| |
1580 if (include_internals) |
| |
1581 { |
| |
1582 if (combo_box->priv->button) |
| |
1583 (* callback) (combo_box->priv->button, callback_data); |
| |
1584 if (combo_box->priv->cell_view_frame) |
| |
1585 (* callback) (combo_box->priv->cell_view_frame, callback_data); |
| |
1586 } |
| |
1587 |
| |
1588 if (GTK_BIN (container)->child) |
| |
1589 (* callback) (GTK_BIN (container)->child, callback_data); |
| |
1590 } |
| |
1591 |
| |
1592 static gboolean |
| |
1593 gtk_combo_box_expose_event (GtkWidget *widget, |
| |
1594 GdkEventExpose *event) |
| |
1595 { |
| |
1596 GtkComboBox *combo_box = GTK_COMBO_BOX (widget); |
| |
1597 |
| |
1598 if (!combo_box->priv->tree_view) |
| |
1599 { |
| |
1600 gtk_container_propagate_expose (GTK_CONTAINER (widget), |
| |
1601 combo_box->priv->button, event); |
| |
1602 } |
| |
1603 else |
| |
1604 { |
| |
1605 gtk_container_propagate_expose (GTK_CONTAINER (widget), |
| |
1606 combo_box->priv->button, event); |
| |
1607 |
| |
1608 if (combo_box->priv->cell_view_frame) |
| |
1609 gtk_container_propagate_expose (GTK_CONTAINER (widget), |
| |
1610 combo_box->priv->cell_view_frame, event); |
| |
1611 } |
| |
1612 |
| |
1613 gtk_container_propagate_expose (GTK_CONTAINER (widget), |
| |
1614 GTK_BIN (widget)->child, event); |
| |
1615 |
| |
1616 return FALSE; |
| |
1617 } |
| |
1618 |
| |
1619 static gboolean |
| |
1620 gtk_combo_box_scroll_event (GtkWidget *widget, |
| |
1621 GdkEventScroll *event) |
| |
1622 { |
| |
1623 GtkComboBox *combo_box = GTK_COMBO_BOX (widget); |
| |
1624 gint index; |
| |
1625 gint items; |
| |
1626 |
| |
1627 index = gtk_combo_box_get_active (combo_box); |
| |
1628 |
| |
1629 if (index != -1) |
| |
1630 { |
| |
1631 items = gtk_tree_model_iter_n_children (combo_box->priv->model, NULL); |
| |
1632 |
| |
1633 if (event->direction == GDK_SCROLL_UP) |
| |
1634 index--; |
| |
1635 else |
| |
1636 index++; |
| |
1637 |
| |
1638 gtk_combo_box_set_active (combo_box, CLAMP (index, 0, items - 1)); |
| |
1639 } |
| |
1640 |
| |
1641 return TRUE; |
| |
1642 } |
| |
1643 |
| |
1644 /* |
| |
1645 * menu style |
| |
1646 */ |
| |
1647 |
| |
1648 static void |
| |
1649 cell_view_sync_cells (GtkComboBox *combo_box, |
| |
1650 GtkCellView *cell_view) |
| |
1651 { |
| |
1652 GSList *k; |
| |
1653 |
| |
1654 for (k = combo_box->priv->cells; k; k = k->next) |
| |
1655 { |
| |
1656 GSList *j; |
| |
1657 ComboCellInfo *info = (ComboCellInfo *)k->data; |
| |
1658 |
| |
1659 if (info->pack == GTK_PACK_START) |
| |
1660 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (cell_view), |
| |
1661 info->cell, info->expand); |
| |
1662 else if (info->pack == GTK_PACK_END) |
| |
1663 gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (cell_view), |
| |
1664 info->cell, info->expand); |
| |
1665 |
| |
1666 gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (cell_view), |
| |
1667 info->cell, |
| |
1668 info->func, info->func_data, NULL); |
| |
1669 |
| |
1670 for (j = info->attributes; j; j = j->next->next) |
| |
1671 { |
| |
1672 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (cell_view), |
| |
1673 info->cell, |
| |
1674 j->data, |
| |
1675 GPOINTER_TO_INT (j->next->data)); |
| |
1676 } |
| |
1677 } |
| |
1678 } |
| |
1679 |
| |
1680 static void |
| |
1681 gtk_combo_box_menu_setup (GtkComboBox *combo_box, |
| |
1682 gboolean add_children) |
| |
1683 { |
| |
1684 GtkWidget *menu; |
| |
1685 |
| |
1686 if (combo_box->priv->cell_view) |
| |
1687 { |
| |
1688 combo_box->priv->button = gtk_toggle_button_new (); |
| |
1689 g_signal_connect (combo_box->priv->button, "toggled", |
| |
1690 G_CALLBACK (gtk_combo_box_button_toggled), combo_box); |
| |
1691 g_signal_connect_after (combo_box->priv->button, "key_press_event", |
| |
1692 G_CALLBACK (gtk_combo_box_key_press), combo_box); |
| |
1693 gtk_widget_set_parent (combo_box->priv->button, |
| |
1694 GTK_BIN (combo_box)->child->parent); |
| |
1695 |
| |
1696 combo_box->priv->box = gtk_hbox_new (FALSE, 0); |
| |
1697 gtk_container_add (GTK_CONTAINER (combo_box->priv->button), |
| |
1698 combo_box->priv->box); |
| |
1699 |
| |
1700 combo_box->priv->separator = gtk_vseparator_new (); |
| |
1701 gtk_container_add (GTK_CONTAINER (combo_box->priv->box), |
| |
1702 combo_box->priv->separator); |
| |
1703 |
| |
1704 combo_box->priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE); |
| |
1705 gtk_container_add (GTK_CONTAINER (combo_box->priv->box), |
| |
1706 combo_box->priv->arrow); |
| |
1707 |
| |
1708 gtk_widget_show_all (combo_box->priv->button); |
| |
1709 } |
| |
1710 else |
| |
1711 { |
| |
1712 combo_box->priv->button = gtk_toggle_button_new (); |
| |
1713 g_signal_connect (combo_box->priv->button, "toggled", |
| |
1714 G_CALLBACK (gtk_combo_box_button_toggled), combo_box); |
| |
1715 g_signal_connect_after (combo_box, "key_press_event", |
| |
1716 G_CALLBACK (gtk_combo_box_key_press), combo_box); |
| |
1717 gtk_widget_set_parent (combo_box->priv->button, |
| |
1718 GTK_BIN (combo_box)->child->parent); |
| |
1719 |
| |
1720 combo_box->priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE); |
| |
1721 gtk_container_add (GTK_CONTAINER (combo_box->priv->button), |
| |
1722 combo_box->priv->arrow); |
| |
1723 gtk_widget_show_all (combo_box->priv->button); |
| |
1724 } |
| |
1725 |
| |
1726 g_signal_connect (combo_box->priv->button, "button_press_event", |
| |
1727 G_CALLBACK (gtk_combo_box_menu_button_press), |
| |
1728 combo_box); |
| |
1729 |
| |
1730 /* create our funky menu */ |
| |
1731 menu = gtk_menu_new (); |
| |
1732 g_signal_connect (menu, "key_press_event", |
| |
1733 G_CALLBACK (gtk_combo_box_menu_key_press), combo_box); |
| |
1734 gtk_combo_box_set_popup_widget (combo_box, menu); |
| |
1735 |
| |
1736 /* add items */ |
| |
1737 if (add_children) |
| |
1738 gtk_combo_box_menu_fill (combo_box); |
| |
1739 |
| |
1740 } |
| |
1741 |
| |
1742 static void |
| |
1743 gtk_combo_box_menu_fill (GtkComboBox *combo_box) |
| |
1744 { |
| |
1745 gint i, items; |
| |
1746 GtkWidget *menu; |
| |
1747 GtkWidget *tmp; |
| |
1748 |
| |
1749 if (!combo_box->priv->model) |
| |
1750 return; |
| |
1751 |
| |
1752 items = gtk_tree_model_iter_n_children (combo_box->priv->model, NULL); |
| |
1753 menu = combo_box->priv->popup_widget; |
| |
1754 |
| |
1755 for (i = 0; i < items; i++) |
| |
1756 { |
| |
1757 GtkTreePath *path; |
| |
1758 #if GTK_CHECK_VERSION(2,2,0) |
| |
1759 path = gtk_tree_path_new_from_indices (i, -1); |
| |
1760 #else |
| |
1761 char buf[32]; |
| |
1762 g_snprintf(buf, sizeof(buf), "%d", i); |
| |
1763 path = gtk_tree_path_new_from_string(buf); |
| |
1764 #endif |
| |
1765 tmp = gtk_cell_view_menu_item_new_from_model (combo_box->priv->model, |
| |
1766 path); |
| |
1767 g_signal_connect (tmp, "activate", |
| |
1768 G_CALLBACK (gtk_combo_box_menu_item_activate), |
| |
1769 combo_box); |
| |
1770 |
| |
1771 cell_view_sync_cells (combo_box, |
| |
1772 GTK_CELL_VIEW (GTK_BIN (tmp)->child)); |
| |
1773 |
| |
1774 gtk_menu_shell_append (GTK_MENU_SHELL (menu), tmp); |
| |
1775 |
| |
1776 if (combo_box->priv->wrap_width) |
| |
1777 gtk_combo_box_relayout_item (combo_box, i); |
| |
1778 |
| |
1779 gtk_widget_show (tmp); |
| |
1780 |
| |
1781 gtk_tree_path_free (path); |
| |
1782 } |
| |
1783 } |
| |
1784 |
| |
1785 static void |
| |
1786 gtk_combo_box_menu_destroy (GtkComboBox *combo_box) |
| |
1787 { |
| |
1788 g_signal_handlers_disconnect_matched (combo_box->priv->button, |
| |
1789 G_SIGNAL_MATCH_DATA, |
| |
1790 0, 0, NULL, |
| |
1791 gtk_combo_box_menu_button_press, NULL); |
| |
1792 |
| |
1793 /* unparent will remove our latest ref */ |
| |
1794 gtk_widget_unparent (combo_box->priv->button); |
| |
1795 |
| |
1796 combo_box->priv->box = NULL; |
| |
1797 combo_box->priv->button = NULL; |
| |
1798 combo_box->priv->arrow = NULL; |
| |
1799 combo_box->priv->separator = NULL; |
| |
1800 |
| |
1801 /* changing the popup window will unref the menu and the children */ |
| |
1802 } |
| |
1803 |
| |
1804 /* |
| |
1805 * grid |
| |
1806 */ |
| |
1807 |
| |
1808 static void |
| |
1809 gtk_combo_box_item_get_size (GtkComboBox *combo_box, |
| |
1810 gint index_, |
| |
1811 gint *cols, |
| |
1812 gint *rows) |
| |
1813 { |
| |
1814 GtkTreeIter iter; |
| |
1815 |
| |
1816 gtk_tree_model_iter_nth_child (combo_box->priv->model, &iter, NULL, index_); |
| |
1817 |
| |
1818 if (cols) |
| |
1819 { |
| |
1820 if (combo_box->priv->col_column == -1) |
| |
1821 *cols = 1; |
| |
1822 else |
| |
1823 gtk_tree_model_get (combo_box->priv->model, &iter, |
| |
1824 combo_box->priv->col_column, cols, |
| |
1825 -1); |
| |
1826 } |
| |
1827 |
| |
1828 if (rows) |
| |
1829 { |
| |
1830 if (combo_box->priv->row_column == -1) |
| |
1831 *rows = 1; |
| |
1832 else |
| |
1833 gtk_tree_model_get (combo_box->priv->model, &iter, |
| |
1834 combo_box->priv->row_column, rows, |
| |
1835 -1); |
| |
1836 } |
| |
1837 } |
| |
1838 |
| |
1839 static gboolean |
| |
1840 menu_occupied (GtkMenu *menu, |
| |
1841 guint left_attach, |
| |
1842 guint right_attach, |
| |
1843 guint top_attach, |
| |
1844 guint bottom_attach) |
| |
1845 { |
| |
1846 GList *i; |
| |
1847 |
| |
1848 g_return_val_if_fail (GTK_IS_MENU (menu), TRUE); |
| |
1849 g_return_val_if_fail (left_attach < right_attach, TRUE); |
| |
1850 g_return_val_if_fail (top_attach < bottom_attach, TRUE); |
| |
1851 |
| |
1852 for (i = GTK_MENU_SHELL (menu)->children; i; i = i->next) |
| |
1853 { |
| |
1854 guint l, r, b, t; |
| |
1855 gboolean h_intersect = FALSE; |
| |
1856 gboolean v_intersect = FALSE; |
| |
1857 |
| |
1858 gtk_container_child_get (GTK_CONTAINER (menu), i->data, |
| |
1859 "left_attach", &l, |
| |
1860 "right_attach", &r, |
| |
1861 "bottom_attach", &b, |
| |
1862 "top_attach", &t, |
| |
1863 NULL); |
| |
1864 |
| |
1865 /* look if this item intersects with the given coordinates */ |
| |
1866 h_intersect = left_attach <= l && l <= right_attach; |
| |
1867 h_intersect &= left_attach <= r && r <= right_attach; |
| |
1868 |
| |
1869 v_intersect = top_attach <= t && t <= bottom_attach; |
| |
1870 v_intersect &= top_attach <= b && b <= bottom_attach; |
| |
1871 |
| |
1872 if (h_intersect && v_intersect) |
| |
1873 return TRUE; |
| |
1874 } |
| |
1875 |
| |
1876 return FALSE; |
| |
1877 } |
| |
1878 |
| |
1879 static void |
| |
1880 gtk_combo_box_relayout_item (GtkComboBox *combo_box, |
| |
1881 gint index) |
| |
1882 { |
| |
1883 gint current_col = 0, current_row = 0; |
| |
1884 gint rows, cols; |
| |
1885 GList *list, *nth; |
| |
1886 GtkWidget *item, *last; |
| |
1887 GtkWidget *menu; |
| |
1888 |
| |
1889 menu = combo_box->priv->popup_widget; |
| |
1890 if (!GTK_IS_MENU_SHELL (menu)) |
| |
1891 return; |
| |
1892 |
| |
1893 list = gtk_container_get_children (GTK_CONTAINER (menu)); |
| |
1894 nth = g_list_nth (list, index); |
| |
1895 item = nth->data; |
| |
1896 if (nth->prev) |
| |
1897 last = nth->prev->data; |
| |
1898 else |
| |
1899 last = NULL; |
| |
1900 g_list_free (list); |
| |
1901 |
| |
1902 gtk_combo_box_item_get_size (combo_box, index, &cols, &rows); |
| |
1903 |
| |
1904 if (combo_box->priv->col_column == -1 && |
| |
1905 combo_box->priv->row_column == -1 && |
| |
1906 last) |
| |
1907 { |
| |
1908 gtk_container_child_get (GTK_CONTAINER (menu), |
| |
1909 last, |
| |
1910 "right_attach", ¤t_col, |
| |
1911 "top_attach", ¤t_row, |
| |
1912 NULL); |
| |
1913 if (current_col + cols > combo_box->priv->wrap_width) |
| |
1914 { |
| |
1915 current_col = 0; |
| |
1916 current_row++; |
| |
1917 } |
| |
1918 } |
| |
1919 else |
| |
1920 { |
| |
1921 /* look for a good spot */ |
| |
1922 while (1) |
| |
1923 { |
| |
1924 if (current_col + cols > combo_box->priv->wrap_width) |
| |
1925 { |
| |
1926 current_col = 0; |
| |
1927 current_row++; |
| |
1928 } |
| |
1929 |
| |
1930 if (!menu_occupied (GTK_MENU (menu), |
| |
1931 current_col, current_col + cols, |
| |
1932 current_row, current_row + rows)) |
| |
1933 break; |
| |
1934 |
| |
1935 current_col++; |
| |
1936 } |
| |
1937 } |
| |
1938 |
| |
1939 /* set attach props */ |
| |
1940 gtk_menu_attach (GTK_MENU (menu), item, |
| |
1941 current_col, current_col + cols, |
| |
1942 current_row, current_row + rows); |
| |
1943 } |
| |
1944 |
| |
1945 static void |
| |
1946 gtk_combo_box_relayout (GtkComboBox *combo_box) |
| |
1947 { |
| |
1948 GList *list, *j; |
| |
1949 GtkWidget *menu; |
| |
1950 |
| |
1951 menu = combo_box->priv->popup_widget; |
| |
1952 |
| |
1953 /* do nothing unless we are in menu style and realized */ |
| |
1954 if (combo_box->priv->tree_view || !GTK_IS_MENU_SHELL (menu)) |
| |
1955 return; |
| |
1956 |
| |
1957 /* get rid of all children */ |
| |
1958 list = gtk_container_get_children (GTK_CONTAINER (menu)); |
| |
1959 |
| |
1960 for (j = g_list_last (list); j; j = j->prev) |
| |
1961 gtk_container_remove (GTK_CONTAINER (menu), j->data); |
| |
1962 |
| |
1963 g_list_free (list); |
| |
1964 |
| |
1965 /* and relayout */ |
| |
1966 gtk_combo_box_menu_fill (combo_box); |
| |
1967 } |
| |
1968 |
| |
1969 /* callbacks */ |
| |
1970 static gboolean |
| |
1971 gtk_combo_box_menu_button_press (GtkWidget *widget, |
| |
1972 GdkEventButton *event, |
| |
1973 gpointer user_data) |
| |
1974 { |
| |
1975 GtkComboBox *combo_box = GTK_COMBO_BOX (user_data); |
| |
1976 |
| |
1977 if (! GTK_IS_MENU (combo_box->priv->popup_widget)) |
| |
1978 return FALSE; |
| |
1979 |
| |
1980 if (event->type == GDK_BUTTON_PRESS && event->button == 1) |
| |
1981 { |
| |
1982 combo_box->priv->popup_in_progress = TRUE; |
| |
1983 |
| |
1984 gtk_menu_set_active (GTK_MENU (combo_box->priv->popup_widget), |
| |
1985 combo_box->priv->active_item); |
| |
1986 |
| |
1987 if (combo_box->priv->wrap_width == 0) |
| |
1988 { |
| |
1989 GtkRequisition requisition; |
| |
1990 gint width; |
| |
1991 |
| |
1992 width = GTK_WIDGET (combo_box)->allocation.width; |
| |
1993 gtk_widget_size_request (combo_box->priv->popup_widget, &requisition); |
| |
1994 |
| |
1995 gtk_widget_set_size_request (combo_box->priv->popup_widget, |
| |
1996 MAX (width, requisition.width), -1); |
| |
1997 } |
| |
1998 |
| |
1999 gtk_menu_popup (GTK_MENU (combo_box->priv->popup_widget), |
| |
2000 NULL, NULL, |
| |
2001 #if GTK_CHECK_VERSION(2,2,0) |
| |
2002 gtk_combo_box_menu_position, |
| |
2003 #else |
| |
2004 NULL, |
| |
2005 #endif |
| |
2006 combo_box, event->button, event->time); |
| |
2007 |
| |
2008 return TRUE; |
| |
2009 } |
| |
2010 |
| |
2011 return FALSE; |
| |
2012 } |
| |
2013 |
| |
2014 static void |
| |
2015 gtk_combo_box_menu_item_activate (GtkWidget *item, |
| |
2016 gpointer user_data) |
| |
2017 { |
| |
2018 gint index; |
| |
2019 GtkWidget *menu; |
| |
2020 GtkComboBox *combo_box = GTK_COMBO_BOX (user_data); |
| |
2021 |
| |
2022 menu = combo_box->priv->popup_widget; |
| |
2023 g_return_if_fail (GTK_IS_MENU (menu)); |
| |
2024 |
| |
2025 index = g_list_index (GTK_MENU_SHELL (menu)->children, item); |
| |
2026 |
| |
2027 gtk_combo_box_set_active (combo_box, index); |
| |
2028 } |
| |
2029 |
| |
2030 static void |
| |
2031 gtk_combo_box_model_row_inserted (GtkTreeModel *model, |
| |
2032 GtkTreePath *path, |
| |
2033 GtkTreeIter *iter, |
| |
2034 gpointer user_data) |
| |
2035 { |
| |
2036 GtkComboBox *combo_box = GTK_COMBO_BOX (user_data); |
| |
2037 gint index = gtk_tree_path_get_indices (path)[0]; |
| |
2038 |
| |
2039 if (combo_box->priv->active_item >= index) |
| |
2040 combo_box->priv->active_item++; |
| |
2041 |
| |
2042 if (!combo_box->priv->tree_view) |
| |
2043 gtk_combo_box_menu_row_inserted (model, path, iter, user_data); |
| |
2044 } |
| |
2045 |
| |
2046 static void |
| |
2047 gtk_combo_box_model_row_deleted (GtkTreeModel *model, |
| |
2048 GtkTreePath *path, |
| |
2049 gpointer user_data) |
| |
2050 { |
| |
2051 GtkComboBox *combo_box = GTK_COMBO_BOX (user_data); |
| |
2052 gint index = gtk_tree_path_get_indices (path)[0]; |
| |
2053 |
| |
2054 if (!combo_box->priv->tree_view) |
| |
2055 gtk_combo_box_menu_row_deleted (model, path, user_data); |
| |
2056 |
| |
2057 if (index == combo_box->priv->active_item) |
| |
2058 { |
| |
2059 gint items = gtk_tree_model_iter_n_children (model, NULL); |
| |
2060 |
| |
2061 if (items == 0) |
| |
2062 gtk_combo_box_set_active_internal (combo_box, -1); |
| |
2063 else if (index == items) |
| |
2064 gtk_combo_box_set_active_internal (combo_box, index - 1); |
| |
2065 else |
| |
2066 gtk_combo_box_set_active_internal (combo_box, index); |
| |
2067 } |
| |
2068 else if (combo_box->priv->active_item > index) |
| |
2069 combo_box->priv->active_item--; |
| |
2070 } |
| |
2071 |
| |
2072 static void |
| |
2073 gtk_combo_box_model_rows_reordered (GtkTreeModel *model, |
| |
2074 GtkTreePath *path, |
| |
2075 GtkTreeIter *iter, |
| |
2076 gint *new_order, |
| |
2077 gpointer user_data) |
| |
2078 { |
| |
2079 GtkComboBox *combo_box = GTK_COMBO_BOX (user_data); |
| |
2080 gint items = gtk_tree_model_iter_n_children (model, NULL); |
| |
2081 gint i; |
| |
2082 |
| |
2083 for (i = 0; i < items; i++) |
| |
2084 if (new_order[i] == combo_box->priv->active_item) |
| |
2085 { |
| |
2086 combo_box->priv->active_item = i; |
| |
2087 break; |
| |
2088 } |
| |
2089 |
| |
2090 if (!combo_box->priv->tree_view) |
| |
2091 gtk_combo_box_menu_rows_reordered (model, path, iter, new_order, user_data); |
| |
2092 } |
| |
2093 |
| |
2094 static void |
| |
2095 gtk_combo_box_model_row_changed (GtkTreeModel *model, |
| |
2096 GtkTreePath *path, |
| |
2097 GtkTreeIter *iter, |
| |
2098 gpointer user_data) |
| |
2099 { |
| |
2100 GtkComboBox *combo_box = GTK_COMBO_BOX (user_data); |
| |
2101 gint index = gtk_tree_path_get_indices (path)[0]; |
| |
2102 |
| |
2103 if (index == combo_box->priv->active_item && |
| |
2104 combo_box->priv->cell_view) |
| |
2105 gtk_widget_queue_resize (GTK_WIDGET (combo_box->priv->cell_view)); |
| |
2106 |
| |
2107 if (combo_box->priv->tree_view) |
| |
2108 gtk_combo_box_list_row_changed (model, path, iter, user_data); |
| |
2109 else |
| |
2110 gtk_combo_box_menu_row_changed (model, path, iter, user_data); |
| |
2111 } |
| |
2112 |
| |
2113 |
| |
2114 static void |
| |
2115 gtk_combo_box_menu_row_inserted (GtkTreeModel *model, |
| |
2116 GtkTreePath *path, |
| |
2117 GtkTreeIter *iter, |
| |
2118 gpointer user_data) |
| |
2119 { |
| |
2120 GtkWidget *menu; |
| |
2121 GtkWidget *item; |
| |
2122 GtkComboBox *combo_box = GTK_COMBO_BOX (user_data); |
| |
2123 |
| |
2124 if (!combo_box->priv->popup_widget) |
| |
2125 return; |
| |
2126 |
| |
2127 menu = combo_box->priv->popup_widget; |
| |
2128 g_return_if_fail (GTK_IS_MENU (menu)); |
| |
2129 |
| |
2130 item = gtk_cell_view_menu_item_new_from_model (model, path); |
| |
2131 g_signal_connect (item, "activate", |
| |
2132 G_CALLBACK (gtk_combo_box_menu_item_activate), |
| |
2133 combo_box); |
| |
2134 |
| |
2135 cell_view_sync_cells (combo_box, GTK_CELL_VIEW (GTK_BIN (item)->child)); |
| |
2136 |
| |
2137 gtk_menu_shell_insert (GTK_MENU_SHELL (menu), item, |
| |
2138 gtk_tree_path_get_indices (path)[0]); |
| |
2139 gtk_widget_show (item); |
| |
2140 } |
| |
2141 |
| |
2142 static void |
| |
2143 gtk_combo_box_menu_row_deleted (GtkTreeModel *model, |
| |
2144 GtkTreePath *path, |
| |
2145 gpointer user_data) |
| |
2146 { |
| |
2147 gint index; |
| |
2148 GtkWidget *menu; |
| |
2149 GtkWidget *item; |
| |
2150 GtkComboBox *combo_box = GTK_COMBO_BOX (user_data); |
| |
2151 |
| |
2152 if (!combo_box->priv->popup_widget) |
| |
2153 return; |
| |
2154 |
| |
2155 index = gtk_tree_path_get_indices (path)[0]; |
| |
2156 |
| |
2157 menu = combo_box->priv->popup_widget; |
| |
2158 g_return_if_fail (GTK_IS_MENU (menu)); |
| |
2159 |
| |
2160 item = g_list_nth_data (GTK_MENU_SHELL (menu)->children, index); |
| |
2161 g_return_if_fail (GTK_IS_MENU_ITEM (item)); |
| |
2162 |
| |
2163 gtk_container_remove (GTK_CONTAINER (menu), item); |
| |
2164 } |
| |
2165 |
| |
2166 static void |
| |
2167 gtk_combo_box_menu_rows_reordered (GtkTreeModel *model, |
| |
2168 GtkTreePath *path, |
| |
2169 GtkTreeIter *iter, |
| |
2170 gint *new_order, |
| |
2171 gpointer user_data) |
| |
2172 { |
| |
2173 GtkComboBox *combo_box = GTK_COMBO_BOX (user_data); |
| |
2174 |
| |
2175 gtk_combo_box_relayout (combo_box); |
| |
2176 } |
| |
2177 |
| |
2178 static void |
| |
2179 gtk_combo_box_menu_row_changed (GtkTreeModel *model, |
| |
2180 GtkTreePath *path, |
| |
2181 GtkTreeIter *iter, |
| |
2182 gpointer user_data) |
| |
2183 { |
| |
2184 GtkComboBox *combo_box = GTK_COMBO_BOX (user_data); |
| |
2185 gint width; |
| |
2186 |
| |
2187 if (!combo_box->priv->popup_widget) |
| |
2188 return; |
| |
2189 |
| |
2190 if (combo_box->priv->wrap_width) |
| |
2191 gtk_combo_box_relayout_item (combo_box, |
| |
2192 gtk_tree_path_get_indices (path)[0]); |
| |
2193 |
| |
2194 width = gtk_combo_box_calc_requested_width (combo_box, path); |
| |
2195 |
| |
2196 if (width > combo_box->priv->width) |
| |
2197 { |
| |
2198 if (combo_box->priv->cell_view) |
| |
2199 { |
| |
2200 gtk_widget_set_size_request (combo_box->priv->cell_view, width, -1); |
| |
2201 gtk_widget_queue_resize (combo_box->priv->cell_view); |
| |
2202 } |
| |
2203 combo_box->priv->width = width; |
| |
2204 } |
| |
2205 } |
| |
2206 |
| |
2207 /* |
| |
2208 * list style |
| |
2209 */ |
| |
2210 |
| |
2211 static void |
| |
2212 gtk_combo_box_list_setup (GtkComboBox *combo_box) |
| |
2213 { |
| |
2214 GSList *i; |
| |
2215 GtkTreeSelection *sel; |
| |
2216 |
| |
2217 combo_box->priv->button = gtk_toggle_button_new (); |
| |
2218 gtk_widget_set_parent (combo_box->priv->button, |
| |
2219 GTK_BIN (combo_box)->child->parent); |
| |
2220 g_signal_connect (combo_box->priv->button, "button_press_event", |
| |
2221 G_CALLBACK (gtk_combo_box_list_button_pressed), combo_box); |
| |
2222 g_signal_connect (combo_box->priv->button, "toggled", |
| |
2223 G_CALLBACK (gtk_combo_box_button_toggled), combo_box); |
| |
2224 g_signal_connect_after (combo_box, "key_press_event", |
| |
2225 G_CALLBACK (gtk_combo_box_key_press), combo_box); |
| |
2226 |
| |
2227 combo_box->priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE); |
| |
2228 gtk_container_add (GTK_CONTAINER (combo_box->priv->button), |
| |
2229 combo_box->priv->arrow); |
| |
2230 combo_box->priv->separator = NULL; |
| |
2231 gtk_widget_show_all (combo_box->priv->button); |
| |
2232 |
| |
2233 if (combo_box->priv->cell_view) |
| |
2234 { |
| |
2235 combo_box->priv->cell_view_frame = gtk_frame_new (NULL); |
| |
2236 gtk_widget_set_parent (combo_box->priv->cell_view_frame, |
| |
2237 GTK_BIN (combo_box)->child->parent); |
| |
2238 gtk_frame_set_shadow_type (GTK_FRAME (combo_box->priv->cell_view_frame), |
| |
2239 GTK_SHADOW_IN); |
| |
2240 |
| |
2241 gtk_cell_view_set_background_color (GTK_CELL_VIEW (combo_box->priv->cell_view), |
| |
2242 >K_WIDGET (combo_box)->style->base[GTK_WIDGET_STATE (combo_box)]); |
| |
2243 |
| |
2244 combo_box->priv->box = gtk_event_box_new (); |
| |
2245 /* |
| |
2246 gtk_event_box_set_visible_window (GTK_EVENT_BOX (combo_box->priv->box), |
| |
2247 FALSE); |
| |
2248 */ |
| |
2249 |
| |
2250 gtk_container_add (GTK_CONTAINER (combo_box->priv->cell_view_frame), |
| |
2251 combo_box->priv->box); |
| |
2252 |
| |
2253 gtk_widget_show_all (combo_box->priv->cell_view_frame); |
| |
2254 |
| |
2255 g_signal_connect (combo_box->priv->box, "button_press_event", |
| |
2256 G_CALLBACK (gtk_combo_box_list_button_pressed), |
| |
2257 combo_box); |
| |
2258 } |
| |
2259 |
| |
2260 combo_box->priv->tree_view = gtk_tree_view_new (); |
| |
2261 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (combo_box->priv->tree_view)); |
| |
2262 gtk_tree_selection_set_mode (sel, GTK_SELECTION_BROWSE); |
| |
2263 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (combo_box->priv->tree_view), |
| |
2264 FALSE); |
| |
2265 /* |
| |
2266 _gtk_tree_view_set_hover_selection (GTK_TREE_VIEW (combo_box->priv->tree_view), |
| |
2267 TRUE); |
| |
2268 */ |
| |
2269 if (combo_box->priv->model) |
| |
2270 gtk_tree_view_set_model (GTK_TREE_VIEW (combo_box->priv->tree_view), |
| |
2271 combo_box->priv->model); |
| |
2272 |
| |
2273 g_signal_connect (combo_box->priv->tree_view, "button_press_event", |
| |
2274 G_CALLBACK (gtk_combo_box_list_button_pressed), |
| |
2275 combo_box); |
| |
2276 g_signal_connect (combo_box->priv->tree_view, "button_release_event", |
| |
2277 G_CALLBACK (gtk_combo_box_list_button_released), |
| |
2278 combo_box); |
| |
2279 g_signal_connect (combo_box->priv->tree_view, "key_press_event", |
| |
2280 G_CALLBACK (gtk_combo_box_list_key_press), |
| |
2281 combo_box); |
| |
2282 |
| |
2283 combo_box->priv->column = gtk_tree_view_column_new (); |
| |
2284 gtk_tree_view_append_column (GTK_TREE_VIEW (combo_box->priv->tree_view), |
| |
2285 combo_box->priv->column); |
| |
2286 |
| |
2287 /* sync up */ |
| |
2288 for (i = combo_box->priv->cells; i; i = i->next) |
| |
2289 { |
| |
2290 GSList *j; |
| |
2291 ComboCellInfo *info = (ComboCellInfo *)i->data; |
| |
2292 |
| |
2293 if (info->pack == GTK_PACK_START) |
| |
2294 gtk_tree_view_column_pack_start (combo_box->priv->column, |
| |
2295 info->cell, info->expand); |
| |
2296 else if (info->pack == GTK_PACK_END) |
| |
2297 gtk_tree_view_column_pack_end (combo_box->priv->column, |
| |
2298 info->cell, info->expand); |
| |
2299 |
| |
2300 for (j = info->attributes; j; j = j->next->next) |
| |
2301 { |
| |
2302 gtk_tree_view_column_add_attribute (combo_box->priv->column, |
| |
2303 info->cell, |
| |
2304 j->data, |
| |
2305 GPOINTER_TO_INT (j->next->data)); |
| |
2306 } |
| |
2307 } |
| |
2308 |
| |
2309 if (combo_box->priv->active_item != -1) |
| |
2310 { |
| |
2311 GtkTreePath *path; |
| |
2312 |
| |
2313 #if GTK_CHECK_VERSION(2,2,0) |
| |
2314 path = gtk_tree_path_new_from_indices (combo_box->priv->active_item, -1); |
| |
2315 #else |
| |
2316 char buf[32]; |
| |
2317 g_snprintf(buf, sizeof(buf), "%d", combo_box->priv->active_item); |
| |
2318 path = gtk_tree_path_new_from_string(buf); |
| |
2319 #endif |
| |
2320 if (path) |
| |
2321 { |
| |
2322 gtk_tree_view_set_cursor (GTK_TREE_VIEW (combo_box->priv->tree_view), |
| |
2323 path, NULL, FALSE); |
| |
2324 gtk_tree_path_free (path); |
| |
2325 } |
| |
2326 } |
| |
2327 |
| |
2328 /* set sample/popup widgets */ |
| |
2329 gtk_combo_box_set_popup_widget (combo_box, combo_box->priv->tree_view); |
| |
2330 |
| |
2331 gtk_widget_show (combo_box->priv->tree_view); |
| |
2332 } |
| |
2333 |
| |
2334 static void |
| |
2335 gtk_combo_box_list_destroy (GtkComboBox *combo_box) |
| |
2336 { |
| |
2337 /* disconnect signals */ |
| |
2338 g_signal_handlers_disconnect_matched (combo_box->priv->tree_view, |
| |
2339 G_SIGNAL_MATCH_DATA, |
| |
2340 0, 0, NULL, NULL, combo_box); |
| |
2341 g_signal_handlers_disconnect_matched (combo_box->priv->button, |
| |
2342 G_SIGNAL_MATCH_DATA, |
| |
2343 0, 0, NULL, |
| |
2344 gtk_combo_box_list_button_pressed, |
| |
2345 NULL); |
| |
2346 if (combo_box->priv->box) |
| |
2347 g_signal_handlers_disconnect_matched (combo_box->priv->box, |
| |
2348 G_SIGNAL_MATCH_DATA, |
| |
2349 0, 0, NULL, |
| |
2350 gtk_combo_box_list_button_pressed, |
| |
2351 NULL); |
| |
2352 |
| |
2353 /* destroy things (unparent will kill the latest ref from us) |
| |
2354 * last unref on button will destroy the arrow |
| |
2355 */ |
| |
2356 gtk_widget_unparent (combo_box->priv->button); |
| |
2357 combo_box->priv->button = NULL; |
| |
2358 combo_box->priv->arrow = NULL; |
| |
2359 |
| |
2360 if (combo_box->priv->cell_view) |
| |
2361 { |
| |
2362 g_object_set (G_OBJECT (combo_box->priv->cell_view), |
| |
2363 "background_set", FALSE, |
| |
2364 NULL); |
| |
2365 } |
| |
2366 |
| |
2367 if (combo_box->priv->cell_view_frame) |
| |
2368 { |
| |
2369 gtk_widget_unparent (combo_box->priv->cell_view_frame); |
| |
2370 combo_box->priv->cell_view_frame = NULL; |
| |
2371 combo_box->priv->box = NULL; |
| |
2372 } |
| |
2373 |
| |
2374 gtk_widget_destroy (combo_box->priv->tree_view); |
| |
2375 |
| |
2376 combo_box->priv->tree_view = NULL; |
| |
2377 combo_box->priv->popup_widget = NULL; |
| |
2378 } |
| |
2379 |
| |
2380 /* callbacks */ |
| |
2381 static void |
| |
2382 gtk_combo_box_list_remove_grabs (GtkComboBox *combo_box) |
| |
2383 { |
| |
2384 if (combo_box->priv->tree_view && |
| |
2385 GTK_WIDGET_HAS_GRAB (combo_box->priv->tree_view)) |
| |
2386 { |
| |
2387 gtk_grab_remove (combo_box->priv->tree_view); |
| |
2388 } |
| |
2389 |
| |
2390 if (combo_box->priv->popup_window && |
| |
2391 GTK_WIDGET_HAS_GRAB (combo_box->priv->popup_window)) |
| |
2392 { |
| |
2393 gtk_grab_remove (combo_box->priv->popup_window); |
| |
2394 gdk_keyboard_ungrab (GDK_CURRENT_TIME); |
| |
2395 gdk_pointer_ungrab (GDK_CURRENT_TIME); |
| |
2396 } |
| |
2397 } |
| |
2398 |
| |
2399 static gboolean |
| |
2400 gtk_combo_box_list_button_pressed (GtkWidget *widget, |
| |
2401 GdkEventButton *event, |
| |
2402 gpointer data) |
| |
2403 { |
| |
2404 GtkComboBox *combo_box = GTK_COMBO_BOX (data); |
| |
2405 |
| |
2406 GtkWidget *ewidget = gtk_get_event_widget ((GdkEvent *)event); |
| |
2407 |
| |
2408 if (ewidget == combo_box->priv->tree_view) |
| |
2409 return TRUE; |
| |
2410 |
| |
2411 if ((ewidget != combo_box->priv->button && ewidget != combo_box->priv->box) || |
| |
2412 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (combo_box->priv->button))) |
| |
2413 return FALSE; |
| |
2414 |
| |
2415 gtk_combo_box_popup (combo_box); |
| |
2416 |
| |
2417 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo_box->priv->button), |
| |
2418 TRUE); |
| |
2419 |
| |
2420 combo_box->priv->popup_in_progress = TRUE; |
| |
2421 |
| |
2422 return TRUE; |
| |
2423 } |
| |
2424 |
| |
2425 static gboolean |
| |
2426 gtk_combo_box_list_button_released (GtkWidget *widget, |
| |
2427 GdkEventButton *event, |
| |
2428 gpointer data) |
| |
2429 { |
| |
2430 gboolean ret; |
| |
2431 GtkTreePath *path = NULL; |
| |
2432 |
| |
2433 GtkComboBox *combo_box = GTK_COMBO_BOX (data); |
| |
2434 |
| |
2435 gboolean popup_in_progress = FALSE; |
| |
2436 |
| |
2437 GtkWidget *ewidget = gtk_get_event_widget ((GdkEvent *)event); |
| |
2438 |
| |
2439 if (combo_box->priv->popup_in_progress) |
| |
2440 { |
| |
2441 popup_in_progress = TRUE; |
| |
2442 combo_box->priv->popup_in_progress = FALSE; |
| |
2443 } |
| |
2444 |
| |
2445 if (ewidget != combo_box->priv->tree_view) |
| |
2446 { |
| |
2447 if (ewidget == combo_box->priv->button && |
| |
2448 !popup_in_progress && |
| |
2449 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (combo_box->priv->button))) |
| |
2450 { |
| |
2451 gtk_combo_box_popdown (combo_box); |
| |
2452 return TRUE; |
| |
2453 } |
| |
2454 |
| |
2455 /* released outside treeview */ |
| |
2456 if (ewidget != combo_box->priv->button) |
| |
2457 { |
| |
2458 gtk_combo_box_popdown (combo_box); |
| |
2459 |
| |
2460 return TRUE; |
| |
2461 } |
| |
2462 |
| |
2463 return FALSE; |
| |
2464 } |
| |
2465 |
| |
2466 /* select something cool */ |
| |
2467 ret = gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget), |
| |
2468 event->x, event->y, |
| |
2469 &path, |
| |
2470 NULL, NULL, NULL); |
| |
2471 |
| |
2472 if (!ret) |
| |
2473 return TRUE; /* clicked outside window? */ |
| |
2474 |
| |
2475 gtk_combo_box_set_active (combo_box, gtk_tree_path_get_indices (path)[0]); |
| |
2476 gtk_combo_box_popdown (combo_box); |
| |
2477 |
| |
2478 gtk_tree_path_free (path); |
| |
2479 |
| |
2480 return TRUE; |
| |
2481 } |
| |
2482 |
| |
2483 static gboolean |
| |
2484 gtk_combo_box_key_press (GtkWidget *widget, |
| |
2485 GdkEventKey *event, |
| |
2486 gpointer data) |
| |
2487 { |
| |
2488 GtkComboBox *combo_box = GTK_COMBO_BOX (data); |
| |
2489 guint state = event->state & gtk_accelerator_get_default_mod_mask (); |
| |
2490 gint items = 0; |
| |
2491 gint index = gtk_combo_box_get_active (combo_box); |
| |
2492 gint new_index; |
| |
2493 |
| |
2494 if (combo_box->priv->model) |
| |
2495 items = gtk_tree_model_iter_n_children (combo_box->priv->model, NULL); |
| |
2496 |
| |
2497 if ((event->keyval == GDK_Down || event->keyval == GDK_KP_Down) && |
| |
2498 state == GDK_MOD1_MASK) |
| |
2499 { |
| |
2500 gtk_combo_box_popup (combo_box); |
| |
2501 |
| |
2502 return TRUE; |
| |
2503 } |
| |
2504 |
| |
2505 switch (event->keyval) |
| |
2506 { |
| |
2507 case GDK_Down: |
| |
2508 case GDK_KP_Down: |
| |
2509 new_index = index + 1; |
| |
2510 break; |
| |
2511 case GDK_Up: |
| |
2512 case GDK_KP_Up: |
| |
2513 new_index = index - 1; |
| |
2514 break; |
| |
2515 case GDK_Page_Up: |
| |
2516 case GDK_KP_Page_Up: |
| |
2517 case GDK_Home: |
| |
2518 case GDK_KP_Home: |
| |
2519 new_index = 0; |
| |
2520 break; |
| |
2521 case GDK_Page_Down: |
| |
2522 case GDK_KP_Page_Down: |
| |
2523 case GDK_End: |
| |
2524 case GDK_KP_End: |
| |
2525 new_index = items - 1; |
| |
2526 break; |
| |
2527 default: |
| |
2528 return FALSE; |
| |
2529 } |
| |
2530 |
| |
2531 if (items > 0) |
| |
2532 gtk_combo_box_set_active (combo_box, CLAMP (new_index, 0, items - 1)); |
| |
2533 |
| |
2534 return TRUE; |
| |
2535 } |
| |
2536 |
| |
2537 static gboolean |
| |
2538 gtk_combo_box_menu_key_press (GtkWidget *widget, |
| |
2539 GdkEventKey *event, |
| |
2540 gpointer data) |
| |
2541 { |
| |
2542 GtkComboBox *combo_box = GTK_COMBO_BOX (data); |
| |
2543 guint state = event->state & gtk_accelerator_get_default_mod_mask (); |
| |
2544 |
| |
2545 if ((event->keyval == GDK_Up || event->keyval == GDK_KP_Up) && |
| |
2546 state == GDK_MOD1_MASK) |
| |
2547 { |
| |
2548 gtk_combo_box_popdown (combo_box); |
| |
2549 |
| |
2550 return TRUE; |
| |
2551 } |
| |
2552 |
| |
2553 return FALSE; |
| |
2554 } |
| |
2555 |
| |
2556 static gboolean |
| |
2557 gtk_combo_box_list_key_press (GtkWidget *widget, |
| |
2558 GdkEventKey *event, |
| |
2559 gpointer data) |
| |
2560 { |
| |
2561 GtkComboBox *combo_box = GTK_COMBO_BOX (data); |
| |
2562 guint state = event->state & gtk_accelerator_get_default_mod_mask (); |
| |
2563 |
| |
2564 if (event->keyval == GDK_Escape || |
| |
2565 ((event->keyval == GDK_Up || event->keyval == GDK_KP_Up) && |
| |
2566 state == GDK_MOD1_MASK)) |
| |
2567 { |
| |
2568 /* reset active item -- this is incredibly lame and ugly */ |
| |
2569 gtk_combo_box_set_active (combo_box, |
| |
2570 gtk_combo_box_get_active (combo_box)); |
| |
2571 |
| |
2572 gtk_combo_box_popdown (combo_box); |
| |
2573 |
| |
2574 return TRUE; |
| |
2575 } |
| |
2576 |
| |
2577 if (event->keyval == GDK_Return || event->keyval == GDK_KP_Enter || |
| |
2578 event->keyval == GDK_space || event->keyval == GDK_KP_Space) |
| |
2579 { |
| |
2580 gboolean ret = FALSE; |
| |
2581 GtkTreeIter iter; |
| |
2582 GtkTreeModel *model = NULL; |
| |
2583 |
| |
2584 if (combo_box->priv->model) |
| |
2585 { |
| |
2586 GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (combo_box->priv->tree_view)); |
| |
2587 |
| |
2588 ret = gtk_tree_selection_get_selected (sel, &model, &iter); |
| |
2589 } |
| |
2590 if (ret) |
| |
2591 { |
| |
2592 GtkTreePath *path; |
| |
2593 |
| |
2594 path = gtk_tree_model_get_path (model, &iter); |
| |
2595 if (path) |
| |
2596 { |
| |
2597 gtk_combo_box_set_active (combo_box, gtk_tree_path_get_indices (path)[0]); |
| |
2598 gtk_tree_path_free (path); |
| |
2599 } |
| |
2600 } |
| |
2601 |
| |
2602 gtk_combo_box_popdown (combo_box); |
| |
2603 |
| |
2604 return TRUE; |
| |
2605 } |
| |
2606 |
| |
2607 return FALSE; |
| |
2608 } |
| |
2609 |
| |
2610 static void |
| |
2611 gtk_combo_box_list_row_changed (GtkTreeModel *model, |
| |
2612 GtkTreePath *path, |
| |
2613 GtkTreeIter *iter, |
| |
2614 gpointer data) |
| |
2615 { |
| |
2616 GtkComboBox *combo_box = GTK_COMBO_BOX (data); |
| |
2617 gint width; |
| |
2618 |
| |
2619 width = gtk_combo_box_calc_requested_width (combo_box, path); |
| |
2620 |
| |
2621 if (width > combo_box->priv->width) |
| |
2622 { |
| |
2623 if (combo_box->priv->cell_view) |
| |
2624 { |
| |
2625 gtk_widget_set_size_request (combo_box->priv->cell_view, width, -1); |
| |
2626 gtk_widget_queue_resize (combo_box->priv->cell_view); |
| |
2627 } |
| |
2628 combo_box->priv->width = width; |
| |
2629 } |
| |
2630 } |
| |
2631 |
| |
2632 /* |
| |
2633 * GtkCellLayout implementation |
| |
2634 */ |
| |
2635 static void |
| |
2636 gtk_combo_box_cell_layout_pack_start (GtkCellLayout *layout, |
| |
2637 GtkCellRenderer *cell, |
| |
2638 gboolean expand) |
| |
2639 { |
| |
2640 ComboCellInfo *info; |
| |
2641 GtkComboBox *combo_box; |
| |
2642 GtkWidget *menu; |
| |
2643 |
| |
2644 g_return_if_fail (GTK_IS_COMBO_BOX (layout)); |
| |
2645 g_return_if_fail (GTK_IS_CELL_RENDERER (cell)); |
| |
2646 |
| |
2647 combo_box = GTK_COMBO_BOX (layout); |
| |
2648 |
| |
2649 g_object_ref (G_OBJECT (cell)); |
| |
2650 gtk_object_sink (GTK_OBJECT (cell)); |
| |
2651 |
| |
2652 info = g_new0 (ComboCellInfo, 1); |
| |
2653 info->cell = cell; |
| |
2654 info->expand = expand; |
| |
2655 info->pack = GTK_PACK_START; |
| |
2656 |
| |
2657 combo_box->priv->cells = g_slist_append (combo_box->priv->cells, info); |
| |
2658 |
| |
2659 if (combo_box->priv->cell_view) |
| |
2660 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box->priv->cell_view), |
| |
2661 cell, expand); |
| |
2662 |
| |
2663 if (combo_box->priv->column) |
| |
2664 gtk_tree_view_column_pack_start (combo_box->priv->column, cell, expand); |
| |
2665 |
| |
2666 menu = combo_box->priv->popup_widget; |
| |
2667 if (GTK_IS_MENU (menu)) |
| |
2668 { |
| |
2669 GList *i, *list; |
| |
2670 |
| |
2671 list = gtk_container_get_children (GTK_CONTAINER (menu)); |
| |
2672 for (i = list; i; i = i->next) |
| |
2673 { |
| |
2674 GtkCellView *view; |
| |
2675 |
| |
2676 if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data)) |
| |
2677 view = GTK_CELL_VIEW (GTK_BIN (i->data)->child); |
| |
2678 else |
| |
2679 view = GTK_CELL_VIEW (i->data); |
| |
2680 |
| |
2681 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (view), cell, expand); |
| |
2682 } |
| |
2683 g_list_free (list); |
| |
2684 } |
| |
2685 } |
| |
2686 |
| |
2687 static void |
| |
2688 gtk_combo_box_cell_layout_pack_end (GtkCellLayout *layout, |
| |
2689 GtkCellRenderer *cell, |
| |
2690 gboolean expand) |
| |
2691 { |
| |
2692 ComboCellInfo *info; |
| |
2693 GtkComboBox *combo_box; |
| |
2694 GtkWidget *menu; |
| |
2695 |
| |
2696 g_return_if_fail (GTK_IS_COMBO_BOX (layout)); |
| |
2697 g_return_if_fail (GTK_IS_CELL_RENDERER (cell)); |
| |
2698 |
| |
2699 combo_box = GTK_COMBO_BOX (layout); |
| |
2700 |
| |
2701 g_object_ref (G_OBJECT (cell)); |
| |
2702 gtk_object_sink (GTK_OBJECT (cell)); |
| |
2703 |
| |
2704 info = g_new0 (ComboCellInfo, 1); |
| |
2705 info->cell = cell; |
| |
2706 info->expand = expand; |
| |
2707 info->pack = GTK_PACK_END; |
| |
2708 |
| |
2709 combo_box->priv->cells = g_slist_append (combo_box->priv->cells, info); |
| |
2710 |
| |
2711 if (combo_box->priv->cell_view) |
| |
2712 gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (combo_box->priv->cell_view), |
| |
2713 cell, expand); |
| |
2714 |
| |
2715 if (combo_box->priv->column) |
| |
2716 gtk_tree_view_column_pack_end (combo_box->priv->column, cell, expand); |
| |
2717 |
| |
2718 menu = combo_box->priv->popup_widget; |
| |
2719 if (GTK_IS_MENU (menu)) |
| |
2720 { |
| |
2721 GList *i, *list; |
| |
2722 |
| |
2723 list = gtk_container_get_children (GTK_CONTAINER (menu)); |
| |
2724 for (i = list; i; i = i->next) |
| |
2725 { |
| |
2726 GtkCellView *view; |
| |
2727 |
| |
2728 if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data)) |
| |
2729 view = GTK_CELL_VIEW (GTK_BIN (i->data)->child); |
| |
2730 else |
| |
2731 view = GTK_CELL_VIEW (i->data); |
| |
2732 |
| |
2733 gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (view), cell, expand); |
| |
2734 } |
| |
2735 g_list_free (list); |
| |
2736 } |
| |
2737 } |
| |
2738 |
| |
2739 static void |
| |
2740 gtk_combo_box_cell_layout_clear (GtkCellLayout *layout) |
| |
2741 { |
| |
2742 GtkWidget *menu; |
| |
2743 GtkComboBox *combo_box; |
| |
2744 GSList *i; |
| |
2745 |
| |
2746 g_return_if_fail (GTK_IS_COMBO_BOX (layout)); |
| |
2747 |
| |
2748 combo_box = GTK_COMBO_BOX (layout); |
| |
2749 |
| |
2750 if (combo_box->priv->cell_view) |
| |
2751 gtk_cell_layout_clear (GTK_CELL_LAYOUT (combo_box->priv->cell_view)); |
| |
2752 |
| |
2753 if (combo_box->priv->column) |
| |
2754 gtk_tree_view_column_clear (combo_box->priv->column); |
| |
2755 |
| |
2756 for (i = combo_box->priv->cells; i; i = i->next) |
| |
2757 { |
| |
2758 ComboCellInfo *info = (ComboCellInfo *)i->data; |
| |
2759 |
| |
2760 gtk_combo_box_cell_layout_clear_attributes (layout, info->cell); |
| |
2761 g_object_unref (G_OBJECT (info->cell)); |
| |
2762 g_free (info); |
| |
2763 i->data = NULL; |
| |
2764 } |
| |
2765 g_slist_free (combo_box->priv->cells); |
| |
2766 combo_box->priv->cells = NULL; |
| |
2767 |
| |
2768 menu = combo_box->priv->popup_widget; |
| |
2769 if (GTK_IS_MENU (menu)) |
| |
2770 { |
| |
2771 GList *i, *list; |
| |
2772 |
| |
2773 list = gtk_container_get_children (GTK_CONTAINER (menu)); |
| |
2774 for (i = list; i; i = i->next) |
| |
2775 { |
| |
2776 GtkCellView *view; |
| |
2777 |
| |
2778 if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data)) |
| |
2779 view = GTK_CELL_VIEW (GTK_BIN (i->data)->child); |
| |
2780 else |
| |
2781 view = GTK_CELL_VIEW (i->data); |
| |
2782 |
| |
2783 gtk_cell_layout_clear (GTK_CELL_LAYOUT (view)); |
| |
2784 } |
| |
2785 g_list_free (list); |
| |
2786 } |
| |
2787 } |
| |
2788 |
| |
2789 static void |
| |
2790 gtk_combo_box_cell_layout_add_attribute (GtkCellLayout *layout, |
| |
2791 GtkCellRenderer *cell, |
| |
2792 const gchar *attribute, |
| |
2793 gint column) |
| |
2794 { |
| |
2795 ComboCellInfo *info; |
| |
2796 GtkComboBox *combo_box; |
| |
2797 GtkWidget *menu; |
| |
2798 |
| |
2799 g_return_if_fail (GTK_IS_COMBO_BOX (layout)); |
| |
2800 g_return_if_fail (GTK_IS_CELL_RENDERER (cell)); |
| |
2801 |
| |
2802 combo_box = GTK_COMBO_BOX (layout); |
| |
2803 |
| |
2804 info = gtk_combo_box_get_cell_info (combo_box, cell); |
| |
2805 |
| |
2806 info->attributes = g_slist_prepend (info->attributes, |
| |
2807 GINT_TO_POINTER (column)); |
| |
2808 info->attributes = g_slist_prepend (info->attributes, |
| |
2809 g_strdup (attribute)); |
| |
2810 |
| |
2811 if (combo_box->priv->cell_view) |
| |
2812 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo_box->priv->cell_view), |
| |
2813 cell, attribute, column); |
| |
2814 |
| |
2815 if (combo_box->priv->column) |
| |
2816 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo_box->priv->column), |
| |
2817 cell, attribute, column); |
| |
2818 |
| |
2819 menu = combo_box->priv->popup_widget; |
| |
2820 if (GTK_IS_MENU (menu)) |
| |
2821 { |
| |
2822 GList *i, *list; |
| |
2823 |
| |
2824 list = gtk_container_get_children (GTK_CONTAINER (menu)); |
| |
2825 for (i = list; i; i = i->next) |
| |
2826 { |
| |
2827 GtkCellView *view; |
| |
2828 |
| |
2829 if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data)) |
| |
2830 view = GTK_CELL_VIEW (GTK_BIN (i->data)->child); |
| |
2831 else |
| |
2832 view = GTK_CELL_VIEW (i->data); |
| |
2833 |
| |
2834 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (view), cell, |
| |
2835 attribute, column); |
| |
2836 } |
| |
2837 g_list_free (list); |
| |
2838 } |
| |
2839 |
| |
2840 gtk_widget_queue_resize (GTK_WIDGET (combo_box)); |
| |
2841 } |
| |
2842 |
| |
2843 static void |
| |
2844 gtk_combo_box_cell_layout_set_cell_data_func (GtkCellLayout *layout, |
| |
2845 GtkCellRenderer *cell, |
| |
2846 GtkCellLayoutDataFunc func, |
| |
2847 gpointer func_data, |
| |
2848 GDestroyNotify destroy) |
| |
2849 { |
| |
2850 ComboCellInfo *info; |
| |
2851 GtkComboBox *combo_box; |
| |
2852 GtkWidget *menu; |
| |
2853 |
| |
2854 g_return_if_fail (GTK_IS_COMBO_BOX (layout)); |
| |
2855 |
| |
2856 combo_box = GTK_COMBO_BOX (layout); |
| |
2857 |
| |
2858 info = gtk_combo_box_get_cell_info (combo_box, cell); |
| |
2859 g_return_if_fail (info != NULL); |
| |
2860 |
| |
2861 if (info->destroy) |
| |
2862 { |
| |
2863 GDestroyNotify d = info->destroy; |
| |
2864 |
| |
2865 info->destroy = NULL; |
| |
2866 d (info->func_data); |
| |
2867 } |
| |
2868 |
| |
2869 info->func = func; |
| |
2870 info->func_data = func_data; |
| |
2871 info->destroy = destroy; |
| |
2872 |
| |
2873 if (combo_box->priv->cell_view) |
| |
2874 gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo_box->priv->cell_view), cell, func, func_data, NULL); |
| |
2875 |
| |
2876 if (combo_box->priv->column) |
| |
2877 gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo_box->priv->column), cell, func, func_data, NULL); |
| |
2878 |
| |
2879 menu = combo_box->priv->popup_widget; |
| |
2880 if (GTK_IS_MENU (menu)) |
| |
2881 { |
| |
2882 GList *i, *list; |
| |
2883 |
| |
2884 list = gtk_container_get_children (GTK_CONTAINER (menu)); |
| |
2885 for (i = list; i; i = i->next) |
| |
2886 { |
| |
2887 GtkCellView *view; |
| |
2888 |
| |
2889 if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data)) |
| |
2890 view = GTK_CELL_VIEW (GTK_BIN (i->data)->child); |
| |
2891 else |
| |
2892 view = GTK_CELL_VIEW (i->data); |
| |
2893 |
| |
2894 gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (view), cell, |
| |
2895 func, func_data, NULL); |
| |
2896 } |
| |
2897 g_list_free (list); |
| |
2898 } |
| |
2899 |
| |
2900 gtk_widget_queue_resize (GTK_WIDGET (combo_box)); |
| |
2901 } |
| |
2902 |
| |
2903 static void |
| |
2904 gtk_combo_box_cell_layout_clear_attributes (GtkCellLayout *layout, |
| |
2905 GtkCellRenderer *cell) |
| |
2906 { |
| |
2907 ComboCellInfo *info; |
| |
2908 GtkComboBox *combo_box; |
| |
2909 GtkWidget *menu; |
| |
2910 GSList *list; |
| |
2911 |
| |
2912 g_return_if_fail (GTK_IS_COMBO_BOX (layout)); |
| |
2913 g_return_if_fail (GTK_IS_CELL_RENDERER (cell)); |
| |
2914 |
| |
2915 combo_box = GTK_COMBO_BOX (layout); |
| |
2916 |
| |
2917 info = gtk_combo_box_get_cell_info (combo_box, cell); |
| |
2918 if (info) |
| |
2919 { |
| |
2920 list = info->attributes; |
| |
2921 while (list && list->next) |
| |
2922 { |
| |
2923 g_free (list->data); |
| |
2924 list = list->next->next; |
| |
2925 } |
| |
2926 g_slist_free (info->attributes); |
| |
2927 info->attributes = NULL; |
| |
2928 } |
| |
2929 |
| |
2930 if (combo_box->priv->cell_view) |
| |
2931 gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (combo_box->priv->cell_view), cell); |
| |
2932 |
| |
2933 if (combo_box->priv->column) |
| |
2934 gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (combo_box->priv->column), cell); |
| |
2935 |
| |
2936 menu = combo_box->priv->popup_widget; |
| |
2937 if (GTK_IS_MENU (menu)) |
| |
2938 { |
| |
2939 GList *i, *list; |
| |
2940 |
| |
2941 list = gtk_container_get_children (GTK_CONTAINER (menu)); |
| |
2942 for (i = list; i; i = i->next) |
| |
2943 { |
| |
2944 GtkCellView *view; |
| |
2945 |
| |
2946 if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data)) |
| |
2947 view = GTK_CELL_VIEW (GTK_BIN (i->data)->child); |
| |
2948 else |
| |
2949 view = GTK_CELL_VIEW (i->data); |
| |
2950 |
| |
2951 gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (view), cell); |
| |
2952 } |
| |
2953 g_list_free (list); |
| |
2954 } |
| |
2955 |
| |
2956 gtk_widget_queue_resize (GTK_WIDGET (combo_box)); |
| |
2957 } |
| |
2958 |
| |
2959 static void |
| |
2960 gtk_combo_box_cell_layout_reorder (GtkCellLayout *layout, |
| |
2961 GtkCellRenderer *cell, |
| |
2962 gint position) |
| |
2963 { |
| |
2964 ComboCellInfo *info; |
| |
2965 GtkComboBox *combo_box; |
| |
2966 GtkWidget *menu; |
| |
2967 GSList *link; |
| |
2968 |
| |
2969 g_return_if_fail (GTK_IS_COMBO_BOX (layout)); |
| |
2970 g_return_if_fail (GTK_IS_CELL_RENDERER (cell)); |
| |
2971 |
| |
2972 combo_box = GTK_COMBO_BOX (layout); |
| |
2973 |
| |
2974 info = gtk_combo_box_get_cell_info (combo_box, cell); |
| |
2975 |
| |
2976 g_return_if_fail (info != NULL); |
| |
2977 g_return_if_fail (position >= 0); |
| |
2978 |
| |
2979 link = g_slist_find (combo_box->priv->cells, info); |
| |
2980 |
| |
2981 g_return_if_fail (link != NULL); |
| |
2982 |
| |
2983 combo_box->priv->cells = g_slist_remove_link (combo_box->priv->cells, link); |
| |
2984 combo_box->priv->cells = g_slist_insert (combo_box->priv->cells, info, |
| |
2985 position); |
| |
2986 |
| |
2987 if (combo_box->priv->cell_view) |
| |
2988 gtk_cell_layout_reorder (GTK_CELL_LAYOUT (combo_box->priv->cell_view), |
| |
2989 cell, position); |
| |
2990 |
| |
2991 if (combo_box->priv->column) |
| |
2992 gtk_cell_layout_reorder (GTK_CELL_LAYOUT (combo_box->priv->column), |
| |
2993 cell, position); |
| |
2994 |
| |
2995 menu = combo_box->priv->popup_widget; |
| |
2996 if (GTK_IS_MENU (menu)) |
| |
2997 { |
| |
2998 GList *i, *list; |
| |
2999 |
| |
3000 list = gtk_container_get_children (GTK_CONTAINER (menu)); |
| |
3001 for (i = list; i; i = i->next) |
| |
3002 { |
| |
3003 GtkCellView *view; |
| |
3004 |
| |
3005 if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data)) |
| |
3006 view = GTK_CELL_VIEW (GTK_BIN (i->data)->child); |
| |
3007 else |
| |
3008 view = GTK_CELL_VIEW (i->data); |
| |
3009 |
| |
3010 gtk_cell_layout_reorder (GTK_CELL_LAYOUT (view), cell, position); |
| |
3011 } |
| |
3012 g_list_free (list); |
| |
3013 } |
| |
3014 |
| |
3015 gtk_widget_queue_draw (GTK_WIDGET (combo_box)); |
| |
3016 } |
| |
3017 |
| |
3018 /* |
| |
3019 * public API |
| |
3020 */ |
| |
3021 |
| |
3022 /** |
| |
3023 * gtk_combo_box_new: |
| |
3024 * |
| |
3025 * Creates a new empty #GtkComboBox. |
| |
3026 * |
| |
3027 * Return value: A new #GtkComboBox. |
| |
3028 * |
| |
3029 * Since: 2.4 |
| |
3030 */ |
| |
3031 GtkWidget * |
| |
3032 gtk_combo_box_new (void) |
| |
3033 { |
| |
3034 return GTK_WIDGET (g_object_new (GTK_TYPE_COMBO_BOX, NULL)); |
| |
3035 } |
| |
3036 |
| |
3037 /** |
| |
3038 * gtk_combo_box_new_with_model: |
| |
3039 * @model: A #GtkTreeModel. |
| |
3040 * |
| |
3041 * Creates a new #GtkComboBox with the model initialized to @model. |
| |
3042 * |
| |
3043 * Return value: A new #GtkComboBox. |
| |
3044 * |
| |
3045 * Since: 2.4 |
| |
3046 */ |
| |
3047 GtkWidget * |
| |
3048 gtk_combo_box_new_with_model (GtkTreeModel *model) |
| |
3049 { |
| |
3050 GtkComboBox *combo_box; |
| |
3051 |
| |
3052 g_return_val_if_fail (GTK_IS_TREE_MODEL (model), NULL); |
| |
3053 |
| |
3054 combo_box = GTK_COMBO_BOX (g_object_new (GTK_TYPE_COMBO_BOX, |
| |
3055 "model", model, |
| |
3056 NULL)); |
| |
3057 |
| |
3058 return GTK_WIDGET (combo_box); |
| |
3059 } |
| |
3060 |
| |
3061 /** |
| |
3062 * gtk_combo_box_set_wrap_width: |
| |
3063 * @combo_box: A #GtkComboBox. |
| |
3064 * @width: Preferred number of columns. |
| |
3065 * |
| |
3066 * Sets the wrap width of @combo_box to be @width. The wrap width is basically |
| |
3067 * the preferred number of columns when you want to the popup to be layed out |
| |
3068 * in a table. |
| |
3069 * |
| |
3070 * Since: 2.4 |
| |
3071 */ |
| |
3072 void |
| |
3073 gtk_combo_box_set_wrap_width (GtkComboBox *combo_box, |
| |
3074 gint width) |
| |
3075 { |
| |
3076 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box)); |
| |
3077 g_return_if_fail (width >= 0); |
| |
3078 |
| |
3079 if (width != combo_box->priv->wrap_width) |
| |
3080 { |
| |
3081 combo_box->priv->wrap_width = width; |
| |
3082 |
| |
3083 gtk_combo_box_check_appearance (combo_box); |
| |
3084 gtk_combo_box_relayout (combo_box); |
| |
3085 |
| |
3086 g_object_notify (G_OBJECT (combo_box), "wrap_width"); |
| |
3087 } |
| |
3088 } |
| |
3089 |
| |
3090 /** |
| |
3091 * gtk_combo_box_set_row_span_column: |
| |
3092 * @combo_box: A #GtkComboBox. |
| |
3093 * @row_span: A column in the model passed during construction. |
| |
3094 * |
| |
3095 * Sets the column with row span information for @combo_box to be @row_span. |
| |
3096 * The row span column contains integers which indicate how many rows |
| |
3097 * an item should span. |
| |
3098 * |
| |
3099 * Since: 2.4 |
| |
3100 */ |
| |
3101 void |
| |
3102 gtk_combo_box_set_row_span_column (GtkComboBox *combo_box, |
| |
3103 gint row_span) |
| |
3104 { |
| |
3105 gint col; |
| |
3106 |
| |
3107 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box)); |
| |
3108 |
| |
3109 col = gtk_tree_model_get_n_columns (combo_box->priv->model); |
| |
3110 g_return_if_fail (row_span >= 0 && row_span < col); |
| |
3111 |
| |
3112 if (row_span != combo_box->priv->row_column) |
| |
3113 { |
| |
3114 combo_box->priv->row_column = row_span; |
| |
3115 |
| |
3116 gtk_combo_box_relayout (combo_box); |
| |
3117 |
| |
3118 g_object_notify (G_OBJECT (combo_box), "row_span_column"); |
| |
3119 } |
| |
3120 } |
| |
3121 |
| |
3122 /** |
| |
3123 * gtk_combo_box_set_column_span_column: |
| |
3124 * @combo_box: A #GtkComboBox. |
| |
3125 * @column_span: A column in the model passed during construction. |
| |
3126 * |
| |
3127 * Sets the column with column span information for @combo_box to be |
| |
3128 * @column_span. The column span column contains integers which indicate |
| |
3129 * how many columns an item should span. |
| |
3130 * |
| |
3131 * Since: 2.4 |
| |
3132 */ |
| |
3133 void |
| |
3134 gtk_combo_box_set_column_span_column (GtkComboBox *combo_box, |
| |
3135 gint column_span) |
| |
3136 { |
| |
3137 gint col; |
| |
3138 |
| |
3139 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box)); |
| |
3140 |
| |
3141 col = gtk_tree_model_get_n_columns (combo_box->priv->model); |
| |
3142 g_return_if_fail (column_span >= 0 && column_span < col); |
| |
3143 |
| |
3144 if (column_span != combo_box->priv->col_column) |
| |
3145 { |
| |
3146 combo_box->priv->col_column = column_span; |
| |
3147 |
| |
3148 gtk_combo_box_relayout (combo_box); |
| |
3149 |
| |
3150 g_object_notify (G_OBJECT (combo_box), "column_span_column"); |
| |
3151 } |
| |
3152 } |
| |
3153 |
| |
3154 /** |
| |
3155 * gtk_combo_box_get_active: |
| |
3156 * @combo_box: A #GtkComboBox. |
| |
3157 * |
| |
3158 * Returns the index of the currently active item, or -1 if there's no |
| |
3159 * active item. |
| |
3160 * |
| |
3161 * Return value: An integer which is the index of the currently active item, or |
| |
3162 * -1 if there's no active item. |
| |
3163 * |
| |
3164 * Since: 2.4 |
| |
3165 */ |
| |
3166 gint |
| |
3167 gtk_combo_box_get_active (GtkComboBox *combo_box) |
| |
3168 { |
| |
3169 g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), 0); |
| |
3170 |
| |
3171 return combo_box->priv->active_item; |
| |
3172 } |
| |
3173 |
| |
3174 /** |
| |
3175 * gtk_combo_box_set_active: |
| |
3176 * @combo_box: A #GtkComboBox. |
| |
3177 * @index_: An index in the model passed during construction, or -1 to have |
| |
3178 * no active item. |
| |
3179 * |
| |
3180 * Sets the active item of @combo_box to be the item at @index. |
| |
3181 * |
| |
3182 * Since: 2.4 |
| |
3183 */ |
| |
3184 void |
| |
3185 gtk_combo_box_set_active (GtkComboBox *combo_box, |
| |
3186 gint index_) |
| |
3187 { |
| |
3188 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box)); |
| |
3189 /* -1 means "no item selected" */ |
| |
3190 g_return_if_fail (index_ >= -1); |
| |
3191 |
| |
3192 if (combo_box->priv->active_item == index_) |
| |
3193 return; |
| |
3194 |
| |
3195 gtk_combo_box_set_active_internal (combo_box, index_); |
| |
3196 } |
| |
3197 |
| |
3198 static void |
| |
3199 gtk_combo_box_set_active_internal (GtkComboBox *combo_box, |
| |
3200 gint index) |
| |
3201 { |
| |
3202 GtkTreePath *path; |
| |
3203 |
| |
3204 combo_box->priv->active_item = index; |
| |
3205 |
| |
3206 if (index == -1) |
| |
3207 { |
| |
3208 if (combo_box->priv->tree_view) |
| |
3209 gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (combo_box->priv->tree_view))); |
| |
3210 else |
| |
3211 { |
| |
3212 GtkMenu *menu = GTK_MENU (combo_box->priv->popup_widget); |
| |
3213 |
| |
3214 if (GTK_IS_MENU (menu)) |
| |
3215 gtk_menu_set_active (menu, -1); |
| |
3216 } |
| |
3217 |
| |
3218 if (combo_box->priv->cell_view) |
| |
3219 gtk_cell_view_set_displayed_row (GTK_CELL_VIEW (combo_box->priv->cell_view), NULL); |
| |
3220 } |
| |
3221 else |
| |
3222 { |
| |
3223 #if GTK_CHECK_VERSION(2,2,0) |
| |
3224 path = gtk_tree_path_new_from_indices (index, -1); |
| |
3225 #else |
| |
3226 char buf[32]; |
| |
3227 g_snprintf(buf, sizeof(buf), "%d", index); |
| |
3228 path = gtk_tree_path_new_from_string(buf); |
| |
3229 #endif |
| |
3230 |
| |
3231 if (combo_box->priv->tree_view) |
| |
3232 gtk_tree_view_set_cursor (GTK_TREE_VIEW (combo_box->priv->tree_view), path, NULL, FALSE); |
| |
3233 else |
| |
3234 { |
| |
3235 GtkMenu *menu = GTK_MENU (combo_box->priv->popup_widget); |
| |
3236 |
| |
3237 if (GTK_IS_MENU (menu)) |
| |
3238 gtk_menu_set_active (GTK_MENU (menu), index); |
| |
3239 } |
| |
3240 |
| |
3241 if (combo_box->priv->cell_view) |
| |
3242 gtk_cell_view_set_displayed_row (GTK_CELL_VIEW (combo_box->priv->cell_view), path); |
| |
3243 |
| |
3244 gtk_tree_path_free (path); |
| |
3245 } |
| |
3246 |
| |
3247 g_signal_emit_by_name (combo_box, "changed", NULL, NULL); |
| |
3248 } |
| |
3249 |
| |
3250 |
| |
3251 /** |
| |
3252 * gtk_combo_box_get_active_iter: |
| |
3253 * @combo_box: A #GtkComboBox |
| |
3254 * @iter: The uninitialized #GtkTreeIter. |
| |
3255 * |
| |
3256 * Sets @iter to point to the current active item, if it exists. |
| |
3257 * |
| |
3258 * Return value: %TRUE, if @iter was set |
| |
3259 * |
| |
3260 * Since: 2.4 |
| |
3261 **/ |
| |
3262 gboolean |
| |
3263 gtk_combo_box_get_active_iter (GtkComboBox *combo_box, |
| |
3264 GtkTreeIter *iter) |
| |
3265 { |
| |
3266 GtkTreePath *path; |
| |
3267 gint active; |
| |
3268 gboolean retval; |
| |
3269 #if !GTK_CHECK_VERSION(2,2,0) |
| |
3270 char buf[32]; |
| |
3271 #endif |
| |
3272 |
| |
3273 g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), FALSE); |
| |
3274 |
| |
3275 active = gtk_combo_box_get_active (combo_box); |
| |
3276 if (active < 0) |
| |
3277 return FALSE; |
| |
3278 |
| |
3279 #if GTK_CHECK_VERSION(2,2,0) |
| |
3280 path = gtk_tree_path_new_from_indices (active, -1); |
| |
3281 #else |
| |
3282 g_snprintf(buf, sizeof(buf), "%d", active); |
| |
3283 path = gtk_tree_path_new_from_string(buf); |
| |
3284 #endif |
| |
3285 retval = gtk_tree_model_get_iter (gtk_combo_box_get_model (combo_box), |
| |
3286 iter, path); |
| |
3287 gtk_tree_path_free (path); |
| |
3288 |
| |
3289 return retval; |
| |
3290 } |
| |
3291 |
| |
3292 /** |
| |
3293 * gtk_combo_box_set_active_iter: |
| |
3294 * @combo_box: A #GtkComboBox |
| |
3295 * @iter: The #GtkTreeIter. |
| |
3296 * |
| |
3297 * Sets the current active item to be the one referenced by @iter. |
| |
3298 * @iter must correspond to a path of depth one. |
| |
3299 * |
| |
3300 * Since: 2.4 |
| |
3301 **/ |
| |
3302 void |
| |
3303 gtk_combo_box_set_active_iter (GtkComboBox *combo_box, |
| |
3304 GtkTreeIter *iter) |
| |
3305 { |
| |
3306 GtkTreePath *path; |
| |
3307 |
| |
3308 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box)); |
| |
3309 |
| |
3310 path = gtk_tree_model_get_path (gtk_combo_box_get_model (combo_box), iter); |
| |
3311 g_return_if_fail (path != NULL); |
| |
3312 g_return_if_fail (gtk_tree_path_get_depth (path) == 1); |
| |
3313 |
| |
3314 gtk_combo_box_set_active (combo_box, gtk_tree_path_get_indices (path)[0]); |
| |
3315 gtk_tree_path_free (path); |
| |
3316 } |
| |
3317 |
| |
3318 /** |
| |
3319 * gtk_combo_box_set_model: |
| |
3320 * @combo_box: A #GtkComboBox. |
| |
3321 * @model: A #GtkTreeModel. |
| |
3322 * |
| |
3323 * Sets the model used by @combo_box to be @model. Will unset a previously set |
| |
3324 * model (if applicable). If @model is %NULL, then it will unset the model. |
| |
3325 * |
| |
3326 * Note that this function does not clear the cell renderers, you have to |
| |
3327 * call gtk_combo_box_cell_layout_clear() yourself if you need to set up |
| |
3328 * different cell renderers for the new model. |
| |
3329 * |
| |
3330 * Since: 2.4 |
| |
3331 */ |
| |
3332 void |
| |
3333 gtk_combo_box_set_model (GtkComboBox *combo_box, |
| |
3334 GtkTreeModel *model) |
| |
3335 { |
| |
3336 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box)); |
| |
3337 |
| |
3338 if (!model) |
| |
3339 { |
| |
3340 gtk_combo_box_unset_model (combo_box); |
| |
3341 return; |
| |
3342 } |
| |
3343 |
| |
3344 g_return_if_fail (GTK_IS_TREE_MODEL (model)); |
| |
3345 |
| |
3346 if (model == combo_box->priv->model) |
| |
3347 return; |
| |
3348 |
| |
3349 if (combo_box->priv->model) |
| |
3350 gtk_combo_box_unset_model (combo_box); |
| |
3351 |
| |
3352 combo_box->priv->model = model; |
| |
3353 g_object_ref (G_OBJECT (combo_box->priv->model)); |
| |
3354 |
| |
3355 combo_box->priv->inserted_id = |
| |
3356 g_signal_connect (combo_box->priv->model, "row_inserted", |
| |
3357 G_CALLBACK (gtk_combo_box_model_row_inserted), |
| |
3358 combo_box); |
| |
3359 combo_box->priv->deleted_id = |
| |
3360 g_signal_connect (combo_box->priv->model, "row_deleted", |
| |
3361 G_CALLBACK (gtk_combo_box_model_row_deleted), |
| |
3362 combo_box); |
| |
3363 combo_box->priv->reordered_id = |
| |
3364 g_signal_connect (combo_box->priv->model, "rows_reordered", |
| |
3365 G_CALLBACK (gtk_combo_box_model_rows_reordered), |
| |
3366 combo_box); |
| |
3367 combo_box->priv->changed_id = |
| |
3368 g_signal_connect (combo_box->priv->model, "row_changed", |
| |
3369 G_CALLBACK (gtk_combo_box_model_row_changed), |
| |
3370 combo_box); |
| |
3371 |
| |
3372 if (combo_box->priv->tree_view) |
| |
3373 { |
| |
3374 /* list mode */ |
| |
3375 gtk_tree_view_set_model (GTK_TREE_VIEW (combo_box->priv->tree_view), |
| |
3376 combo_box->priv->model); |
| |
3377 } |
| |
3378 else |
| |
3379 { |
| |
3380 /* menu mode */ |
| |
3381 if (combo_box->priv->popup_widget) |
| |
3382 gtk_combo_box_menu_fill (combo_box); |
| |
3383 |
| |
3384 } |
| |
3385 |
| |
3386 if (combo_box->priv->cell_view) |
| |
3387 gtk_cell_view_set_model (GTK_CELL_VIEW (combo_box->priv->cell_view), |
| |
3388 combo_box->priv->model); |
| |
3389 } |
| |
3390 |
| |
3391 /** |
| |
3392 * gtk_combo_box_get_model |
| |
3393 * @combo_box: A #GtkComboBox. |
| |
3394 * |
| |
3395 * Returns the #GtkTreeModel which is acting as data source for @combo_box. |
| |
3396 * |
| |
3397 * Return value: A #GtkTreeModel which was passed during construction. |
| |
3398 * |
| |
3399 * Since: 2.4 |
| |
3400 */ |
| |
3401 GtkTreeModel * |
| |
3402 gtk_combo_box_get_model (GtkComboBox *combo_box) |
| |
3403 { |
| |
3404 g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), NULL); |
| |
3405 |
| |
3406 return combo_box->priv->model; |
| |
3407 } |
| |
3408 |
| |
3409 |
| |
3410 /* convenience API for simple text combos */ |
| |
3411 |
| |
3412 /** |
| |
3413 * gtk_combo_box_new_text: |
| |
3414 * |
| |
3415 * Convenience function which constructs a new text combo box, which is a |
| |
3416 * #GtkComboBox just displaying strings. If you use this function to create |
| |
3417 * a text combo box, you should only manipulate its data source with the |
| |
3418 * following convenience functions: gtk_combo_box_append_text(), |
| |
3419 * gtk_combo_box_insert_text(), gtk_combo_box_prepend_text() and |
| |
3420 * gtk_combo_box_remove_text(). |
| |
3421 * |
| |
3422 * Return value: A new text combo box. |
| |
3423 * |
| |
3424 * Since: 2.4 |
| |
3425 */ |
| |
3426 GtkWidget * |
| |
3427 gtk_combo_box_new_text (void) |
| |
3428 { |
| |
3429 GtkWidget *combo_box; |
| |
3430 GtkCellRenderer *cell; |
| |
3431 GtkListStore *store; |
| |
3432 |
| |
3433 store = gtk_list_store_new (1, G_TYPE_STRING); |
| |
3434 combo_box = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store)); |
| |
3435 g_object_unref (store); |
| |
3436 |
| |
3437 cell = gtk_cell_renderer_text_new (); |
| |
3438 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), cell, TRUE); |
| |
3439 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), cell, |
| |
3440 "text", 0, |
| |
3441 NULL); |
| |
3442 |
| |
3443 return combo_box; |
| |
3444 } |
| |
3445 |
| |
3446 /** |
| |
3447 * gtk_combo_box_append_text: |
| |
3448 * @combo_box: A #GtkComboBox constructed using gtk_combo_box_new_text(). |
| |
3449 * @text: A string. |
| |
3450 * |
| |
3451 * Appends @string to the list of strings stored in @combo_box. Note that |
| |
3452 * you can only use this function with combo boxes constructed with |
| |
3453 * gtk_combo_box_new_text(). |
| |
3454 * |
| |
3455 * Since: 2.4 |
| |
3456 */ |
| |
3457 void |
| |
3458 gtk_combo_box_append_text (GtkComboBox *combo_box, |
| |
3459 const gchar *text) |
| |
3460 { |
| |
3461 GtkTreeIter iter; |
| |
3462 GtkListStore *store; |
| |
3463 |
| |
3464 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box)); |
| |
3465 g_return_if_fail (GTK_IS_LIST_STORE (combo_box->priv->model)); |
| |
3466 g_return_if_fail (text != NULL); |
| |
3467 |
| |
3468 store = GTK_LIST_STORE (combo_box->priv->model); |
| |
3469 |
| |
3470 gtk_list_store_append (store, &iter); |
| |
3471 gtk_list_store_set (store, &iter, 0, text, -1); |
| |
3472 } |
| |
3473 |
| |
3474 /** |
| |
3475 * gtk_combo_box_insert_text: |
| |
3476 * @combo_box: A #GtkComboBox constructed using gtk_combo_box_new_text(). |
| |
3477 * @position: An index to insert @text. |
| |
3478 * @text: A string. |
| |
3479 * |
| |
3480 * Inserts @string at @position in the list of strings stored in @combo_box. |
| |
3481 * Note that you can only use this function with combo boxes constructed |
| |
3482 * with gtk_combo_box_new_text(). |
| |
3483 * |
| |
3484 * Since: 2.4 |
| |
3485 */ |
| |
3486 void |
| |
3487 gtk_combo_box_insert_text (GtkComboBox *combo_box, |
| |
3488 gint position, |
| |
3489 const gchar *text) |
| |
3490 { |
| |
3491 GtkTreeIter iter; |
| |
3492 GtkListStore *store; |
| |
3493 |
| |
3494 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box)); |
| |
3495 g_return_if_fail (GTK_IS_LIST_STORE (combo_box->priv->model)); |
| |
3496 g_return_if_fail (position >= 0); |
| |
3497 g_return_if_fail (text != NULL); |
| |
3498 |
| |
3499 store = GTK_LIST_STORE (combo_box->priv->model); |
| |
3500 |
| |
3501 gtk_list_store_insert (store, &iter, position); |
| |
3502 gtk_list_store_set (store, &iter, 0, text, -1); |
| |
3503 } |
| |
3504 |
| |
3505 /** |
| |
3506 * gtk_combo_box_prepend_text: |
| |
3507 * @combo_box: A #GtkComboBox constructed with gtk_combo_box_new_text(). |
| |
3508 * @text: A string. |
| |
3509 * |
| |
3510 * Prepends @string to the list of strings stored in @combo_box. Note that |
| |
3511 * you can only use this function with combo boxes constructed with |
| |
3512 * gtk_combo_box_new_text(). |
| |
3513 * |
| |
3514 * Since: 2.4 |
| |
3515 */ |
| |
3516 void |
| |
3517 gtk_combo_box_prepend_text (GtkComboBox *combo_box, |
| |
3518 const gchar *text) |
| |
3519 { |
| |
3520 GtkTreeIter iter; |
| |
3521 GtkListStore *store; |
| |
3522 |
| |
3523 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box)); |
| |
3524 g_return_if_fail (GTK_IS_LIST_STORE (combo_box->priv->model)); |
| |
3525 g_return_if_fail (text != NULL); |
| |
3526 |
| |
3527 store = GTK_LIST_STORE (combo_box->priv->model); |
| |
3528 |
| |
3529 gtk_list_store_prepend (store, &iter); |
| |
3530 gtk_list_store_set (store, &iter, 0, text, -1); |
| |
3531 } |
| |
3532 |
| |
3533 /** |
| |
3534 * gtk_combo_box_remove_text: |
| |
3535 * @combo_box: A #GtkComboBox constructed with gtk_combo_box_new_text(). |
| |
3536 * @position: Index of the item to remove. |
| |
3537 * |
| |
3538 * Removes the string at @position from @combo_box. Note that you can only use |
| |
3539 * this function with combo boxes constructed with gtk_combo_box_new_text(). |
| |
3540 * |
| |
3541 * Since: 2.4 |
| |
3542 */ |
| |
3543 void |
| |
3544 gtk_combo_box_remove_text (GtkComboBox *combo_box, |
| |
3545 gint position) |
| |
3546 { |
| |
3547 GtkTreeIter iter; |
| |
3548 GtkListStore *store; |
| |
3549 |
| |
3550 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box)); |
| |
3551 g_return_if_fail (GTK_IS_LIST_STORE (combo_box->priv->model)); |
| |
3552 g_return_if_fail (position >= 0); |
| |
3553 |
| |
3554 store = GTK_LIST_STORE (combo_box->priv->model); |
| |
3555 |
| |
3556 if (gtk_tree_model_iter_nth_child (combo_box->priv->model, &iter, |
| |
3557 NULL, position)) |
| |
3558 gtk_list_store_remove (store, &iter); |
| |
3559 } |
| |
3560 |
| |
3561 static gboolean |
| |
3562 gtk_combo_box_mnemonic_activate (GtkWidget *widget, |
| |
3563 gboolean group_cycling) |
| |
3564 { |
| |
3565 GtkComboBox *combo_box = GTK_COMBO_BOX (widget); |
| |
3566 |
| |
3567 gtk_widget_grab_focus (combo_box->priv->button); |
| |
3568 |
| |
3569 return TRUE; |
| |
3570 } |
| |
3571 |
| |
3572 static void |
| |
3573 gtk_combo_box_destroy (GtkObject *object) |
| |
3574 { |
| |
3575 GtkComboBox *combo_box = GTK_COMBO_BOX (object); |
| |
3576 |
| |
3577 gtk_combo_box_popdown (combo_box); |
| |
3578 |
| |
3579 combo_box->priv->destroying = 1; |
| |
3580 |
| |
3581 GTK_OBJECT_CLASS (parent_class)->destroy (object); |
| |
3582 combo_box->priv->cell_view = NULL; |
| |
3583 |
| |
3584 combo_box->priv->destroying = 0; |
| |
3585 } |
| |
3586 |
| |
3587 static void |
| |
3588 gtk_combo_box_finalize (GObject *object) |
| |
3589 { |
| |
3590 GtkComboBox *combo_box = GTK_COMBO_BOX (object); |
| |
3591 GSList *i; |
| |
3592 |
| |
3593 if (GTK_IS_MENU (combo_box->priv->popup_widget)) |
| |
3594 { |
| |
3595 gtk_combo_box_menu_destroy (combo_box); |
| |
3596 gtk_menu_detach (GTK_MENU (combo_box->priv->popup_widget)); |
| |
3597 combo_box->priv->popup_widget = NULL; |
| |
3598 } |
| |
3599 |
| |
3600 if (GTK_IS_TREE_VIEW (combo_box->priv->tree_view)) |
| |
3601 gtk_combo_box_list_destroy (combo_box); |
| |
3602 |
| |
3603 if (combo_box->priv->popup_window) |
| |
3604 gtk_widget_destroy (combo_box->priv->popup_window); |
| |
3605 |
| |
3606 gtk_combo_box_unset_model (combo_box); |
| |
3607 |
| |
3608 for (i = combo_box->priv->cells; i; i = i->next) |
| |
3609 { |
| |
3610 ComboCellInfo *info = (ComboCellInfo *)i->data; |
| |
3611 GSList *list = info->attributes; |
| |
3612 |
| |
3613 if (info->destroy) |
| |
3614 info->destroy (info->func_data); |
| |
3615 |
| |
3616 while (list && list->next) |
| |
3617 { |
| |
3618 g_free (list->data); |
| |
3619 list = list->next->next; |
| |
3620 } |
| |
3621 g_slist_free (info->attributes); |
| |
3622 |
| |
3623 g_object_unref (G_OBJECT (info->cell)); |
| |
3624 g_free (info); |
| |
3625 } |
| |
3626 g_slist_free (combo_box->priv->cells); |
| |
3627 |
| |
3628 g_free (combo_box->priv); |
| |
3629 |
| |
3630 G_OBJECT_CLASS (parent_class)->finalize (object); |
| |
3631 } |
| |
3632 |
| |
3633 |
| |
3634 /** |
| |
3635 * Code below this point has been pulled in from gtkmenu.c in 2.4.14 |
| |
3636 * and is needed to provide gtk_menu_attach() |
| |
3637 */ |
| |
3638 |
| |
3639 typedef struct |
| |
3640 { |
| |
3641 gint left_attach; |
| |
3642 gint right_attach; |
| |
3643 gint top_attach; |
| |
3644 gint bottom_attach; |
| |
3645 gint effective_left_attach; |
| |
3646 gint effective_right_attach; |
| |
3647 gint effective_top_attach; |
| |
3648 gint effective_bottom_attach; |
| |
3649 } AttachInfo; |
| |
3650 |
| |
3651 #define ATTACH_INFO_KEY "gtk-menu-child-attach-info-key" |
| |
3652 |
| |
3653 static AttachInfo * |
| |
3654 get_attach_info (GtkWidget *child) |
| |
3655 { |
| |
3656 GObject *object = G_OBJECT (child); |
| |
3657 AttachInfo *ai = g_object_get_data (object, ATTACH_INFO_KEY); |
| |
3658 |
| |
3659 if (!ai) |
| |
3660 { |
| |
3661 ai = g_new0 (AttachInfo, 1); |
| |
3662 g_object_set_data_full (object, ATTACH_INFO_KEY, ai, g_free); |
| |
3663 } |
| |
3664 |
| |
3665 return ai; |
| |
3666 } |
| |
3667 |
| |
3668 /** |
| |
3669 * gtk_menu_attach: |
| |
3670 * @menu: a #GtkMenu. |
| |
3671 * @child: a #GtkMenuItem. |
| |
3672 * @left_attach: The column number to attach the left side of the item to. |
| |
3673 * @right_attach: The column number to attach the right side of the item to. |
| |
3674 * @top_attach: The row number to attach the top of the item to. |
| |
3675 * @bottom_attach: The row number to attach the bottom of the item to. |
| |
3676 * |
| |
3677 * Adds a new #GtkMenuItem to a (table) menu. The number of 'cells' that |
| |
3678 * an item will occupy is specified by @left_attach, @right_attach, |
| |
3679 * @top_attach and @bottom_attach. These each represent the leftmost, |
| |
3680 * rightmost, uppermost and lower column and row numbers of the table. |
| |
3681 * (Columns and rows are indexed from zero). |
| |
3682 * |
| |
3683 * Note that this function is not related to gtk_menu_detach(). |
| |
3684 * |
| |
3685 * Since: 2.4 |
| |
3686 **/ |
| |
3687 static void |
| |
3688 gtk_menu_attach (GtkMenu *menu, |
| |
3689 GtkWidget *child, |
| |
3690 guint left_attach, |
| |
3691 guint right_attach, |
| |
3692 guint top_attach, |
| |
3693 guint bottom_attach) |
| |
3694 { |
| |
3695 GtkMenuShell *menu_shell; |
| |
3696 |
| |
3697 g_return_if_fail (GTK_IS_MENU (menu)); |
| |
3698 g_return_if_fail (GTK_IS_MENU_ITEM (child)); |
| |
3699 g_return_if_fail (child->parent == NULL || |
| |
3700 child->parent == GTK_WIDGET (menu)); |
| |
3701 g_return_if_fail (left_attach < right_attach); |
| |
3702 g_return_if_fail (top_attach < bottom_attach); |
| |
3703 |
| |
3704 menu_shell = GTK_MENU_SHELL (menu); |
| |
3705 |
| |
3706 if (!child->parent) |
| |
3707 { |
| |
3708 AttachInfo *ai = get_attach_info (child); |
| |
3709 |
| |
3710 ai->left_attach = left_attach; |
| |
3711 ai->right_attach = right_attach; |
| |
3712 ai->top_attach = top_attach; |
| |
3713 ai->bottom_attach = bottom_attach; |
| |
3714 |
| |
3715 menu_shell->children = g_list_append (menu_shell->children, child); |
| |
3716 |
| |
3717 gtk_widget_set_parent (child, GTK_WIDGET (menu)); |
| |
3718 |
| |
3719 /* |
| |
3720 menu_queue_resize (menu); |
| |
3721 */ |
| |
3722 } |
| |
3723 else |
| |
3724 { |
| |
3725 gtk_container_child_set (GTK_CONTAINER (child->parent), child, |
| |
3726 "left_attach", left_attach, |
| |
3727 "right_attach", right_attach, |
| |
3728 "top_attach", top_attach, |
| |
3729 "bottom_attach", bottom_attach, |
| |
3730 NULL); |
| |
3731 } |
| |
3732 } |
| |
3733 #endif /* Gtk 2.4 */ |
| |
3734 |
| |
3735 gchar * |
| |
3736 gtk_combo_box_get_active_text (GtkComboBox *combo_box) |
| |
3737 { |
| |
3738 GtkTreeIter iter; |
| |
3739 gchar *text = NULL; |
| |
3740 |
| |
3741 /* g_return_val_if_fail (GTK_IS_LIST_STORE (combo_box->priv->model), NULL); */ |
| |
3742 |
| |
3743 if (gtk_combo_box_get_active_iter (combo_box, &iter)) |
| |
3744 gtk_tree_model_get (gtk_combo_box_get_model(combo_box), &iter, |
| |
3745 0, &text, -1); |
| |
3746 return text; |
| |
3747 } |
| |
3748 |
| |
3749 #endif |