Support individual files and folders in log output.
[anjuta-git-plugin.git] / plugins / class-gen / combo-flags.c
blobeb288d3aafe48917f9a4a760eb0c82d56173bda1
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /* combo-flags.c
3 * Copyright (C) 2006 Armin Burgmeier
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Library General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 #include "combo-flags.h"
22 #include <gtk/gtktreeview.h>
23 #include <gtk/gtktreeselection.h>
24 #include <gtk/gtkcelllayout.h>
25 #include <gtk/gtkcellrenderer.h>
26 #include <gtk/gtkscrolledwindow.h>
27 #include <gtk/gtkframe.h>
28 #include <gtk/gtkwindow.h>
29 #include <gtk/gtkmain.h>
31 #include <gdk/gdkkeysyms.h>
33 #include <libanjuta/anjuta-marshal.h>
35 typedef struct _CgComboFlagsCellInfo CgComboFlagsCellInfo;
36 struct _CgComboFlagsCellInfo
38 GtkCellRenderer *cell;
39 GSList *attributes;
41 GtkCellLayoutDataFunc func;
42 gpointer func_data;
43 GDestroyNotify destroy;
45 guint expand : 1;
46 guint pack : 1;
49 typedef struct _CgComboFlagsPrivate CgComboFlagsPrivate;
50 struct _CgComboFlagsPrivate
52 GtkTreeModel* model;
54 GtkWidget* window;
55 GtkWidget* treeview;
56 GtkTreeViewColumn* column;
58 GSList* cells;
60 gboolean editing_started;
61 gboolean editing_canceled;
64 #define CG_COMBO_FLAGS_PRIVATE(o) \
65 (G_TYPE_INSTANCE_GET_PRIVATE( \
66 (o), \
67 CG_TYPE_COMBO_FLAGS, \
68 CgComboFlagsPrivate \
71 enum {
72 PROP_0,
73 PROP_MODEL
76 enum {
77 SELECTED,
78 LAST_SIGNAL
81 static GtkHBoxClass* parent_class = NULL;
82 static guint combo_flags_signals[LAST_SIGNAL];
84 static CgComboFlagsCellInfo *
85 cg_combo_flags_get_cell_info (CgComboFlags *combo,
86 GtkCellRenderer *cell)
88 CgComboFlagsPrivate *priv;
89 GSList *i;
91 priv = CG_COMBO_FLAGS_PRIVATE (combo);
92 for (i = priv->cells; i != NULL; i = i->next)
94 CgComboFlagsCellInfo *info = (CgComboFlagsCellInfo *) i->data;
96 if (info != NULL && info->cell == cell)
97 return info;
100 return NULL;
103 static void
104 cg_combo_flags_cell_layout_pack_start (GtkCellLayout *layout,
105 GtkCellRenderer *cell,
106 gboolean expand)
108 CgComboFlags *combo;
109 CgComboFlagsPrivate *priv;
110 CgComboFlagsCellInfo *info;
112 combo = CG_COMBO_FLAGS (layout);
113 priv = CG_COMBO_FLAGS_PRIVATE (combo);
115 g_object_ref (cell);
116 gtk_object_sink (GTK_OBJECT (cell));
118 info = g_new0 (CgComboFlagsCellInfo, 1);
119 info->cell = cell;
120 info->expand = expand;
121 info->pack = GTK_PACK_START;
123 priv->cells = g_slist_append (priv->cells, info);
125 if (priv->column != NULL)
126 gtk_tree_view_column_pack_start (priv->column, cell, expand);
129 static void
130 cg_combo_flags_cell_layout_pack_end (GtkCellLayout *layout,
131 GtkCellRenderer *cell,
132 gboolean expand)
134 CgComboFlags *combo;
135 CgComboFlagsPrivate *priv;
136 CgComboFlagsCellInfo *info;
138 combo = CG_COMBO_FLAGS (layout);
139 priv = CG_COMBO_FLAGS_PRIVATE (combo);
141 g_object_ref (cell);
142 gtk_object_sink (GTK_OBJECT (cell));
144 info = g_new0 (CgComboFlagsCellInfo, 1);
145 info->cell = cell;
146 info->expand = expand;
147 info->pack = GTK_PACK_END;
149 priv->cells = g_slist_append (priv->cells, info);
151 if (priv->column != NULL)
152 gtk_tree_view_column_pack_end (priv->column, cell, expand);
155 static void
156 cg_combo_flags_cell_layout_clear_attributes (GtkCellLayout *layout,
157 GtkCellRenderer *cell)
159 CgComboFlags *combo;
160 CgComboFlagsPrivate *priv;
161 CgComboFlagsCellInfo *info;
162 GSList *list;
164 combo = CG_COMBO_FLAGS (layout);
165 priv = CG_COMBO_FLAGS_PRIVATE (combo);
167 info = cg_combo_flags_get_cell_info (combo, cell);
168 g_return_if_fail (info != NULL);
170 list = info->attributes;
171 while (list && list->next)
173 g_free (list->data);
174 list = list->next->next;
177 g_slist_free (info->attributes);
178 info->attributes = NULL;
180 if (priv->column != NULL)
182 gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (priv->column),
183 cell);
186 gtk_widget_queue_resize (GTK_WIDGET (combo));
189 static void
190 cg_combo_flags_cell_layout_clear (GtkCellLayout *layout)
192 CgComboFlags *combo;
193 CgComboFlagsPrivate *priv;
194 GSList *i;
196 combo = CG_COMBO_FLAGS (layout);
197 priv = CG_COMBO_FLAGS_PRIVATE (combo);
199 if (priv->column != NULL)
200 gtk_tree_view_column_clear (priv->column);
202 for (i = priv->cells; i; i = i->next)
204 CgComboFlagsCellInfo* info = (CgComboFlagsCellInfo*)i->data;
206 cg_combo_flags_cell_layout_clear_attributes (layout, info->cell);
207 g_object_unref (info->cell);
208 g_free (info);
209 i->data = NULL;
212 g_slist_free (priv->cells);
213 priv->cells = NULL;
216 static void
217 cg_combo_flags_cell_layout_add_attribute (GtkCellLayout *layout,
218 GtkCellRenderer *cell,
219 const gchar *attribute,
220 gint column)
222 CgComboFlags *combo;
223 CgComboFlagsPrivate *priv;
224 CgComboFlagsCellInfo *info;
226 combo = CG_COMBO_FLAGS (layout);
227 priv = CG_COMBO_FLAGS_PRIVATE(combo);
228 info = cg_combo_flags_get_cell_info (combo, cell);
230 info->attributes = g_slist_prepend (info->attributes,
231 GINT_TO_POINTER (column));
232 info->attributes = g_slist_prepend (info->attributes,
233 g_strdup (attribute));
235 if (priv->column != NULL)
237 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (priv->column),
238 cell, attribute, column);
241 gtk_widget_queue_resize (GTK_WIDGET (combo));
244 static void
245 cg_combo_flags_cell_data_func (GtkCellLayout *cell_layout,
246 GtkCellRenderer *cell,
247 GtkTreeModel *tree_model,
248 GtkTreeIter *iter,
249 gpointer data)
251 CgComboFlagsCellInfo *info;
252 info = (CgComboFlagsCellInfo *) data;
254 if (info->func == NULL)
255 return;
257 (*info->func) (cell_layout, cell, tree_model, iter, info->func_data);
260 static void
261 cg_combo_flags_cell_layout_set_cell_data_func (GtkCellLayout *layout,
262 GtkCellRenderer *cell,
263 GtkCellLayoutDataFunc func,
264 gpointer func_data,
265 GDestroyNotify destroy)
267 CgComboFlags *combo;
268 CgComboFlagsPrivate *priv;
269 CgComboFlagsCellInfo *info;
270 GDestroyNotify old_destroy;
272 combo = CG_COMBO_FLAGS (layout);
273 priv = CG_COMBO_FLAGS_PRIVATE (combo);
274 info = cg_combo_flags_get_cell_info (combo, cell);
275 g_return_if_fail (info != NULL);
277 if (info->destroy)
279 old_destroy = info->destroy;
281 info->destroy = NULL;
282 old_destroy (info->func_data);
285 info->func = func;
286 info->func_data = func_data;
287 info->destroy = destroy;
289 if (priv->column != NULL)
291 gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (priv->column),
292 cell, func, func_data, NULL);
295 gtk_widget_queue_resize (GTK_WIDGET (combo));
298 static void
299 cg_combo_flags_cell_layout_reorder (GtkCellLayout *layout,
300 GtkCellRenderer *cell,
301 gint position)
303 CgComboFlags *combo;
304 CgComboFlagsPrivate *priv;
305 CgComboFlagsCellInfo *info;
306 GSList *link;
308 combo = CG_COMBO_FLAGS (layout);
309 priv = CG_COMBO_FLAGS_PRIVATE (combo);
311 info = cg_combo_flags_get_cell_info (combo, cell);
312 g_return_if_fail (info != NULL);
314 link = g_slist_find (priv->cells, info);
315 g_return_if_fail (link != NULL);
317 priv->cells = g_slist_remove_link (priv->cells, link);
318 priv->cells = g_slist_insert (priv->cells, info, position);
320 if (priv->column != NULL)
321 gtk_cell_layout_reorder (GTK_CELL_LAYOUT (priv->column), cell, position);
323 gtk_widget_queue_draw (GTK_WIDGET (combo));
326 static void
327 cg_combo_flags_cell_editable_start_editing (GtkCellEditable *cell_editable,
328 G_GNUC_UNUSED GdkEvent *event)
330 CgComboFlags *combo;
331 CgComboFlagsPrivate *priv;
333 combo = CG_COMBO_FLAGS (cell_editable);
334 priv = CG_COMBO_FLAGS_PRIVATE (combo);
336 priv->editing_started = TRUE;
337 gtk_widget_grab_focus (GTK_WIDGET (combo));
338 cg_combo_flags_popup (combo);
341 static void
342 cg_combo_flags_sync_cells (CgComboFlags *combo,
343 GtkCellLayout *cell_layout)
345 CgComboFlagsPrivate *priv;
346 CgComboFlagsCellInfo *info;
347 GSList *j;
348 GSList *k;
350 priv = CG_COMBO_FLAGS_PRIVATE (combo);
351 for (k = priv->cells; k != NULL; k = k->next)
353 info = (CgComboFlagsCellInfo *) k->data;
355 if (info->pack == GTK_PACK_START)
356 gtk_cell_layout_pack_start (cell_layout, info->cell, info->expand);
357 else if (info->pack == GTK_PACK_END)
358 gtk_cell_layout_pack_end (cell_layout, info->cell, info->expand);
360 gtk_cell_layout_set_cell_data_func (cell_layout, info->cell,
361 cg_combo_flags_cell_data_func,
362 info, NULL);
364 for (j = info->attributes; j != NULL; j = j->next->next)
366 gtk_cell_layout_add_attribute (cell_layout, info->cell, j->data,
367 GPOINTER_TO_INT (j->next->data));
372 static void
373 cg_combo_flags_get_position (CgComboFlags *combo,
374 gint *x,
375 gint *y,
376 gint *width,
377 gint *height)
379 CgComboFlagsPrivate *priv;
380 GdkScreen *screen;
381 gint monitor_num;
382 GdkRectangle monitor;
383 GtkRequisition popup_req;
385 priv = CG_COMBO_FLAGS_PRIVATE (combo);
387 g_assert (priv->window != NULL);
389 gdk_window_get_origin (GTK_WIDGET (combo)->window, x, y);
391 if (GTK_WIDGET_NO_WINDOW (GTK_WIDGET (combo)))
393 *x += GTK_WIDGET (combo)->allocation.x;
394 *y += GTK_WIDGET (combo)->allocation.y;
397 gtk_widget_size_request (priv->window, &popup_req);
399 *width = GTK_WIDGET (combo)->allocation.width;
400 if (popup_req.width > *width) *width = popup_req.width;
401 *height = popup_req.height;
403 screen = gtk_widget_get_screen (GTK_WIDGET(combo));
404 monitor_num =
405 gdk_screen_get_monitor_at_window (screen, GTK_WIDGET (combo)->window);
407 gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
409 if (*x < monitor.x)
411 *x = monitor.x;
413 else if (*x + *width > monitor.x + monitor.width)
415 *x = monitor.x + monitor.width - *width;
418 if (*y + GTK_WIDGET (combo)->allocation.height + *height <=
419 monitor.y + monitor.height)
421 *y += GTK_WIDGET (combo)->allocation.height;
423 else if (*y - *height >= monitor.y)
425 *y -= *height;
427 else if (monitor.y + monitor.height -
428 (*y + GTK_WIDGET (combo)->allocation.height) > *y - monitor.y)
430 *y += GTK_WIDGET (combo)->allocation.height;
431 *height = monitor.y + monitor.height - *y;
433 else
435 *height = *y - monitor.y;
436 *y = monitor.y;
440 static gboolean
441 cg_combo_flags_treeview_button_press_cb (G_GNUC_UNUSED GtkWidget *widget,
442 GdkEventButton *event,
443 gpointer data)
445 CgComboFlags *combo;
446 CgComboFlagsPrivate *priv;
447 GtkTreeSelection *selection;
448 GtkTreeIter iter;
450 combo = CG_COMBO_FLAGS(data);
451 priv = CG_COMBO_FLAGS_PRIVATE(combo);
453 switch (event->button)
455 case 1:
456 selection =
457 gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview));
459 if(gtk_tree_selection_get_selected (selection, NULL, &iter) == TRUE)
461 g_signal_emit (G_OBJECT (combo), combo_flags_signals[SELECTED],
462 0, &iter, CG_COMBO_FLAGS_SELECTION_TOGGLE);
464 return TRUE;
467 return FALSE;
468 break;
469 case 3:
470 priv->editing_canceled = FALSE;
471 cg_combo_flags_popdown (combo);
472 return TRUE;
473 break;
474 default:
475 return FALSE;
476 break;
480 static gboolean
481 cg_combo_flags_treeview_key_press_cb (G_GNUC_UNUSED GtkWidget *widget,
482 GdkEventKey *event,
483 gpointer data)
485 CgComboFlags *combo;
486 CgComboFlagsPrivate *priv;
487 GtkTreeSelection *selection;
488 GtkTreeIter iter;
490 combo = CG_COMBO_FLAGS (data);
491 priv = CG_COMBO_FLAGS_PRIVATE (combo);
493 switch (event->keyval)
495 case GDK_space:
496 case GDK_KP_Space:
497 selection =
498 gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview));
500 if(gtk_tree_selection_get_selected (selection, NULL, &iter) == TRUE)
502 g_signal_emit (G_OBJECT (combo), combo_flags_signals[SELECTED],
503 0, &iter, CG_COMBO_FLAGS_SELECTION_TOGGLE);
505 return TRUE;
508 return FALSE;
509 break;
510 case GDK_Return:
511 case GDK_KP_Enter:
512 selection =
513 gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview));
515 if(gtk_tree_selection_get_selected (selection, NULL, &iter) == TRUE)
517 g_signal_emit (G_OBJECT (combo), combo_flags_signals[SELECTED],
518 0, &iter, CG_COMBO_FLAGS_SELECTION_SELECT);
521 priv->editing_canceled = FALSE;
522 cg_combo_flags_popdown (combo);
523 return TRUE;
524 break;
525 default:
526 return FALSE;
527 break;
531 static gboolean
532 cg_combo_flags_window_button_press_cb (G_GNUC_UNUSED GtkWidget *widget,
533 G_GNUC_UNUSED GdkEventButton *event,
534 gpointer data)
536 /* Probably the mouse clicked somewhere else but not into the window,
537 * otherwise the treeview would have received the event. */
538 CgComboFlags *combo;
539 CgComboFlagsPrivate *priv;
541 combo = CG_COMBO_FLAGS (data);
542 priv = CG_COMBO_FLAGS_PRIVATE (combo);
544 priv->editing_canceled = FALSE;
545 cg_combo_flags_popdown (combo);
547 return TRUE;
550 static gboolean
551 cg_combo_flags_window_key_press_cb (G_GNUC_UNUSED GtkWidget *widget,
552 GdkEventKey *event,
553 gpointer data)
555 CgComboFlags *combo;
556 CgComboFlagsPrivate *priv;
558 combo = CG_COMBO_FLAGS (data);
559 priv = CG_COMBO_FLAGS_PRIVATE (combo);
561 switch (event->keyval)
563 case GDK_Escape:
564 priv->editing_canceled = TRUE;
565 cg_combo_flags_popdown (combo);
566 return TRUE;
567 break;
568 default:
569 return FALSE;
570 break;
574 static void
575 cg_combo_flags_init (CgComboFlags *combo_flags)
577 CgComboFlagsPrivate *priv;
578 priv = CG_COMBO_FLAGS_PRIVATE (combo_flags);
580 priv->model = NULL;
581 priv->window = NULL;
582 priv->treeview = NULL;
583 priv->column = NULL;
584 priv->cells = NULL;
586 priv->editing_started = FALSE;
587 priv->editing_canceled = FALSE;
590 static void
591 cg_combo_flags_finalize (GObject *object)
593 CgComboFlags *combo_flags;
594 CgComboFlagsPrivate *priv;
596 combo_flags = CG_COMBO_FLAGS (object);
597 priv = CG_COMBO_FLAGS_PRIVATE (combo_flags);
599 if (priv->window != NULL)
600 cg_combo_flags_popdown (combo_flags);
602 G_OBJECT_CLASS (parent_class)->finalize (object);
605 static void
606 cg_combo_flags_set_property (GObject *object,
607 guint prop_id,
608 const GValue *value,
609 GParamSpec *pspec)
611 CgComboFlags *combo_flags;
612 CgComboFlagsPrivate *priv;
614 g_return_if_fail(CG_IS_COMBO_FLAGS (object));
616 combo_flags = CG_COMBO_FLAGS (object);
617 priv = CG_COMBO_FLAGS_PRIVATE (combo_flags);
619 switch (prop_id)
621 case PROP_MODEL:
622 if (priv->model != NULL) g_object_unref (G_OBJECT (priv->model));
623 priv->model = GTK_TREE_MODEL (g_value_dup_object (value));
625 if (priv->treeview != NULL)
627 gtk_tree_view_set_model (GTK_TREE_VIEW (priv->treeview),
628 priv->model);
631 break;
632 default:
633 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
634 break;
638 static void
639 cg_combo_flags_get_property (GObject *object,
640 guint prop_id,
641 GValue *value,
642 GParamSpec *pspec)
644 CgComboFlags *combo_flags;
645 CgComboFlagsPrivate *priv;
647 g_return_if_fail (CG_IS_COMBO_FLAGS (object));
649 combo_flags = CG_COMBO_FLAGS (object);
650 priv = CG_COMBO_FLAGS_PRIVATE (combo_flags);
652 switch (prop_id)
654 case PROP_MODEL:
655 g_value_set_object (value, G_OBJECT (priv->model));
656 break;
657 default:
658 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
659 break;
663 static void
664 cg_combo_flags_class_init (CgComboFlagsClass *klass)
666 GObjectClass *object_class = G_OBJECT_CLASS (klass);
667 parent_class = g_type_class_peek_parent (klass);
669 g_type_class_add_private (klass, sizeof (CgComboFlagsPrivate));
671 object_class->finalize = cg_combo_flags_finalize;
672 object_class->set_property = cg_combo_flags_set_property;
673 object_class->get_property = cg_combo_flags_get_property;
675 g_object_class_install_property(object_class,
676 PROP_MODEL,
677 g_param_spec_object("model",
678 "Model",
679 "The model used by the CgComboFlags widget",
680 GTK_TYPE_TREE_MODEL,
681 G_PARAM_READWRITE));
683 combo_flags_signals[SELECTED] =
684 g_signal_new("selected",
685 G_OBJECT_CLASS_TYPE(object_class),
686 G_SIGNAL_RUN_LAST,
687 0, /* no default handler */
688 NULL, NULL,
689 anjuta_cclosure_marshal_VOID__BOXED_ENUM,
690 G_TYPE_NONE,
692 GTK_TYPE_TREE_ITER,
693 CG_TYPE_COMBO_FLAGS_SELECTION_TYPE);
696 static void
697 cg_combo_flags_cell_layout_init (GtkCellLayoutIface *iface)
699 iface->pack_start = cg_combo_flags_cell_layout_pack_start;
700 iface->pack_end = cg_combo_flags_cell_layout_pack_end;
701 iface->reorder = cg_combo_flags_cell_layout_reorder;
702 iface->clear = cg_combo_flags_cell_layout_clear;
703 iface->add_attribute = cg_combo_flags_cell_layout_add_attribute;
704 iface->set_cell_data_func = cg_combo_flags_cell_layout_set_cell_data_func;
705 iface->clear_attributes = cg_combo_flags_cell_layout_clear_attributes;
708 static void
709 cg_combo_flags_cell_editable_init (GtkCellEditableIface *iface)
711 iface->start_editing = cg_combo_flags_cell_editable_start_editing;
714 static gboolean
715 cg_combo_flags_popup_idle (gpointer data)
717 CgComboFlags *combo;
718 CgComboFlagsPrivate *priv;
719 GtkTreeSelection* selection;
720 GtkWidget *toplevel;
721 GtkWidget *scrolled;
722 gint height, width, x, y;
724 combo = CG_COMBO_FLAGS (data);
725 priv = CG_COMBO_FLAGS_PRIVATE (combo);
727 g_assert (priv->window == NULL);
728 priv->window = gtk_window_new (GTK_WINDOW_POPUP);
730 g_object_ref (G_OBJECT (priv->window));
731 gtk_window_set_resizable (GTK_WINDOW (priv->window), FALSE);
733 g_signal_connect (G_OBJECT (priv->window), "key_press_event",
734 G_CALLBACK (cg_combo_flags_window_key_press_cb),
735 combo);
737 g_signal_connect (G_OBJECT (priv->window), "button_press_event",
738 G_CALLBACK (cg_combo_flags_window_button_press_cb),
739 combo);
741 scrolled = gtk_scrolled_window_new (NULL, NULL);
742 gtk_container_add (GTK_CONTAINER (priv->window), scrolled);
744 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled),
745 GTK_SHADOW_ETCHED_IN);
747 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
748 GTK_POLICY_NEVER, GTK_POLICY_NEVER);
750 gtk_widget_show (scrolled);
752 priv->treeview = gtk_tree_view_new_with_model (priv->model);
753 gtk_widget_show (priv->treeview);
754 gtk_container_add (GTK_CONTAINER (scrolled), priv->treeview);
756 g_signal_connect (G_OBJECT (priv->treeview), "key_press_event",
757 G_CALLBACK (cg_combo_flags_treeview_key_press_cb),
758 combo);
760 g_signal_connect (G_OBJECT (priv->treeview), "button_press_event",
761 G_CALLBACK (cg_combo_flags_treeview_button_press_cb),
762 combo);
764 priv->column = gtk_tree_view_column_new ();
765 g_object_ref (G_OBJECT (priv->column));
766 cg_combo_flags_sync_cells (combo, GTK_CELL_LAYOUT (priv->column));
767 gtk_tree_view_append_column (GTK_TREE_VIEW (priv->treeview), priv->column);
769 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview));
770 gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
772 gtk_tree_view_set_enable_search (GTK_TREE_VIEW (priv->treeview), FALSE);
773 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (priv->treeview), FALSE);
774 gtk_tree_view_set_hover_selection (GTK_TREE_VIEW (priv->treeview), TRUE);
776 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (combo));
777 if (GTK_IS_WINDOW (toplevel))
779 gtk_window_group_add_window (gtk_window_get_group (
780 GTK_WINDOW (toplevel)),
781 GTK_WINDOW (priv->window));
783 gtk_window_set_transient_for (GTK_WINDOW (priv->window),
784 GTK_WINDOW (toplevel));
788 gtk_window_set_screen (GTK_WINDOW (priv->window),
789 gtk_widget_get_screen (GTK_WIDGET (combo)));
791 cg_combo_flags_get_position (combo, &x, &y, &width, &height);
792 gtk_widget_set_size_request (priv->window, width, height);
793 gtk_window_move (GTK_WINDOW(priv->window), x, y);
794 gtk_widget_show (priv->window);
796 gtk_widget_grab_focus (priv->window);
797 if (!GTK_WIDGET_HAS_FOCUS (priv->treeview))
798 gtk_widget_grab_focus (priv->treeview);
800 gdk_pointer_grab (priv->window->window, TRUE,
801 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
802 GDK_POINTER_MOTION_MASK,
803 NULL, NULL, GDK_CURRENT_TIME);
805 gtk_grab_add (priv->window);
807 gdk_keyboard_grab (priv->window->window, TRUE, GDK_CURRENT_TIME);
808 return FALSE;
811 static gboolean
812 cg_combo_flags_popdown_idle (gpointer data)
814 gtk_widget_destroy (GTK_WIDGET (data));
815 return FALSE;
818 GType
819 cg_combo_flags_selection_type_get_type (void)
821 static GType our_type = 0;
823 if(our_type == 0)
825 static const GEnumValue values[] =
827 { CG_COMBO_FLAGS_SELECTION_NONE, "CG_COMBO_FLAGS_SELECTION_NONE", "none" },
828 { CG_COMBO_FLAGS_SELECTION_UNSELECT, "CG_COMBO_FLAGS_SELECTION_UNSELECT", "unselect" },
829 { CG_COMBO_FLAGS_SELECTION_SELECT, "CG_COMBO_FLAGS_SELECTION_SELECT", "select" },
830 { CG_COMBO_FLAGS_SELECTION_TOGGLE, "CG_COMBO_FLAGS_SELECTION_TOGGLE", "toggle" },
831 { 0, NULL, NULL }
834 our_type = g_enum_register_static("CgComboFlagsSelectionType", values);
837 return our_type;
840 GType
841 cg_combo_flags_get_type (void)
843 static GType our_type = 0;
845 if(our_type == 0)
847 static const GTypeInfo our_info =
849 sizeof (CgComboFlagsClass),
850 (GBaseInitFunc) NULL,
851 (GBaseFinalizeFunc) NULL,
852 (GClassInitFunc) cg_combo_flags_class_init,
853 NULL,
854 NULL,
855 sizeof (CgComboFlags),
857 (GInstanceInitFunc) cg_combo_flags_init,
858 NULL
861 static const GInterfaceInfo cell_layout_info =
863 (GInterfaceInitFunc) cg_combo_flags_cell_layout_init,
864 NULL,
865 NULL
868 static const GInterfaceInfo cell_editable_info =
870 (GInterfaceInitFunc) cg_combo_flags_cell_editable_init,
871 NULL,
872 NULL
875 our_type = g_type_register_static(GTK_TYPE_HBOX, "CgComboFlags",
876 &our_info, 0);
878 g_type_add_interface_static (our_type, GTK_TYPE_CELL_LAYOUT,
879 &cell_layout_info);
881 g_type_add_interface_static (our_type, GTK_TYPE_CELL_EDITABLE,
882 &cell_editable_info);
885 return our_type;
888 GtkWidget *
889 cg_combo_flags_new (void)
891 GObject *object;
892 object = g_object_new (CG_TYPE_COMBO_FLAGS, NULL);
893 return GTK_WIDGET (object);
896 GtkWidget *
897 cg_combo_flags_new_with_model (GtkTreeModel *model)
899 GObject *object;
900 object = g_object_new (CG_TYPE_COMBO_FLAGS, "model", model, NULL);
901 return GTK_WIDGET (object);
904 void
905 cg_combo_flags_popup(CgComboFlags *combo)
907 g_idle_add(cg_combo_flags_popup_idle, combo);
910 void
911 cg_combo_flags_popdown(CgComboFlags *combo)
913 CgComboFlagsPrivate *priv;
914 priv = CG_COMBO_FLAGS_PRIVATE (combo);
916 if (priv->window != NULL)
918 gtk_grab_remove (priv->window);
919 gdk_pointer_ungrab (GDK_CURRENT_TIME);
920 gdk_keyboard_ungrab (GDK_CURRENT_TIME);
921 gtk_widget_hide (priv->window);
923 g_object_unref (priv->column);
924 g_idle_add (cg_combo_flags_popdown_idle, priv->window);
926 priv->window = NULL;
927 priv->treeview = NULL;
928 priv->column = NULL;
930 if (priv->editing_started)
932 priv->editing_started = FALSE;
933 gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (combo));
935 /* Seems like someone already calls _remove_widget when the
936 * cell renderer emits its edited signal (which we rely on if
937 * the editing was not canceled). */
938 if (priv->editing_canceled)
939 gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (combo));
944 gboolean
945 cg_combo_flags_editing_canceled (CgComboFlags *combo)
947 return CG_COMBO_FLAGS_PRIVATE (combo)->editing_canceled;