1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
3 /* egg-submenu-action widget
5 * Copyright (C) Naba Kumar <naba@gnome.org>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public
18 * License along with this program; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
23 #include <gtk/gtkwidget.h>
24 #include <gtk/gtktoggletoolbutton.h>
25 #include "egg-submenu-action.h"
31 struct _EggSubmenuActionPriv
33 EggSubmenuFactory factory
;
37 static void egg_submenu_action_init (EggSubmenuAction
*action
);
38 static void egg_submenu_action_class_init (EggSubmenuActionClass
*kclass
);
40 static GtkWidget
*create_tool_item (GtkAction
*action
);
41 static GtkWidget
*create_menu_item (GtkAction
*action
);
42 static void connect_proxy (GtkAction
*action
,
44 static void disconnect_proxy (GtkAction
*action
,
46 static void egg_submenu_action_finalize (GObject
*object
);
48 static GObjectClass
*parent_class
= NULL
;
51 egg_submenu_action_get_type (void)
53 static GtkType type
= 0;
57 static const GTypeInfo type_info
=
59 sizeof (EggSubmenuActionClass
),
61 (GBaseFinalizeFunc
) NULL
,
62 (GClassInitFunc
) egg_submenu_action_class_init
,
63 (GClassFinalizeFunc
) NULL
,
66 sizeof (EggSubmenuAction
),
68 (GInstanceInitFunc
) egg_submenu_action_init
,
71 type
= g_type_register_static (GTK_TYPE_ACTION
,
79 egg_submenu_action_class_init (EggSubmenuActionClass
*kclass
)
81 GtkActionClass
*action_class
;
82 GObjectClass
*object_class
;
84 parent_class
= g_type_class_peek_parent (kclass
);
85 action_class
= GTK_ACTION_CLASS (kclass
);
86 object_class
= G_OBJECT_CLASS (kclass
);
88 object_class
->finalize
= egg_submenu_action_finalize
;
90 action_class
->connect_proxy
= connect_proxy
;
91 action_class
->disconnect_proxy
= disconnect_proxy
;
92 action_class
->menu_item_type
= GTK_TYPE_MENU_ITEM
;
93 action_class
->toolbar_item_type
= GTK_TYPE_TOOL_ITEM
;
94 action_class
->create_tool_item
= create_tool_item
;
95 action_class
->create_menu_item
= create_menu_item
;
99 egg_submenu_action_init (EggSubmenuAction
*action
)
101 action
->priv
= g_new0 (EggSubmenuActionPriv
, 1);
102 action
->priv
->factory
= NULL
;
103 action
->priv
->user_data
= NULL
;
107 egg_submenu_action_finalize (GObject
*object
)
109 g_free (EGG_SUBMENU_ACTION (object
)->priv
);
110 if (parent_class
->finalize
)
111 parent_class
->finalize (object
);
115 create_submenu_submenu (EggSubmenuAction
*action
)
119 if (action
->priv
->factory
)
121 submenu
= (*action
->priv
->factory
)(action
->priv
->user_data
);
125 submenu
= gtk_menu_new ();
126 gtk_widget_show (submenu
);
128 gtk_widget_show (submenu
);
133 on_reposition_menu (GtkMenu
*menu
, gint
*x
, gint
*y
, gboolean
*push_in
,
136 gint x1
, y1
, w
, h
, d
;
137 GtkWidget
*button
= GTK_WIDGET (data
);
138 gdk_window_get_origin (button
->window
, x
, y
);
139 gdk_window_get_geometry (button
->window
, &x1
, &y1
, &w
, &h
, &d
);
140 *y
+= button
->allocation
.height
;
141 if (GTK_WIDGET_NO_WINDOW (button
))
143 *x
+= button
->allocation
.x
;
144 *y
+= button
->allocation
.y
;
149 on_selection_done_menu (GtkMenu
*menu
, GtkWidget
*button
)
151 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button
), FALSE
);
155 on_button_pressed (GtkToggleToolButton
*button
, EggSubmenuAction
*action
)
159 /* g_message ("Submenu toolitem toggled"); */
160 submenu
= g_object_get_data (G_OBJECT (button
), "submenu");
163 submenu
= create_submenu_submenu (action
);
164 g_object_set_data_full (G_OBJECT (button
), "submenu", submenu
,
165 (GDestroyNotify
)gtk_widget_destroy
);
166 g_object_set_data (G_OBJECT (submenu
), "thebutton", button
);
167 g_signal_connect (G_OBJECT (submenu
), "selection-done",
168 G_CALLBACK (on_selection_done_menu
), button
);
169 gtk_widget_show (submenu
);
171 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button
)))
173 gtk_menu_popup (GTK_MENU (submenu
), NULL
, NULL
, on_reposition_menu
,
174 button
, 0, gtk_get_current_event_time ());
175 gtk_menu_reposition (GTK_MENU (submenu
));
179 gtk_menu_popdown (GTK_MENU (submenu
));
184 create_tool_item (GtkAction
*action
)
190 g_return_val_if_fail (EGG_IS_SUBMENU_ACTION (action
), NULL
);
191 /* g_message ("Creating submenu toolitem"); */
193 item
= gtk_tool_item_new ();
194 gtk_widget_show(GTK_WIDGET (item
));
195 button
= gtk_toggle_button_new ();
196 gtk_button_set_relief (GTK_BUTTON (button
), GTK_RELIEF_NONE
);
197 gtk_container_add (GTK_CONTAINER (item
), button
);
198 gtk_widget_show(GTK_WIDGET (button
));
199 arrow
= gtk_arrow_new (GTK_ARROW_DOWN
, GTK_SHADOW_NONE
);
200 gtk_widget_show (arrow
);
201 gtk_container_add (GTK_CONTAINER (button
), arrow
);
202 return GTK_WIDGET (item
);
206 create_menu_item (GtkAction
*action
)
208 GtkWidget
*menuitem
, *submenu
;
209 menuitem
= (* GTK_ACTION_CLASS (parent_class
)->create_menu_item
) (action
);
210 submenu
= create_submenu_submenu (EGG_SUBMENU_ACTION (action
));
211 gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem
), submenu
);
216 connect_proxy (GtkAction
*action
, GtkWidget
*proxy
)
218 EggSubmenuAction
*submenu_action
;
220 submenu_action
= EGG_SUBMENU_ACTION (action
);
222 /* do this before hand, so that we don't call the "activate" handler */
223 if (GTK_IS_TOOL_ITEM (proxy
))
225 g_signal_connect (G_OBJECT (gtk_bin_get_child(GTK_BIN (proxy
))),
227 G_CALLBACK (on_button_pressed
), action
);
229 (* GTK_ACTION_CLASS (parent_class
)->connect_proxy
) (action
, proxy
);
233 disconnect_proxy (GtkAction
*action
, GtkWidget
*proxy
)
235 EggSubmenuAction
*submenu_action
;
237 submenu_action
= EGG_SUBMENU_ACTION (action
);
239 /* do this before hand, so that we don't call the "activate" handler */
240 if (GTK_IS_TOOL_ITEM (proxy
))
242 g_signal_handlers_disconnect_by_func (G_OBJECT (gtk_bin_get_child(GTK_BIN (proxy
))),
243 G_CALLBACK (on_button_pressed
),
246 (* GTK_ACTION_CLASS (parent_class
)->connect_proxy
) (action
, proxy
);
250 egg_submenu_action_set_menu_factory (EggSubmenuAction
*action
,
251 EggSubmenuFactory factory
,
254 g_return_if_fail (EGG_IS_SUBMENU_ACTION (action
));
256 action
->priv
->factory
= factory
;
257 action
->priv
->user_data
= user_data
;