1 /*
2  *  Off-the-Record Messaging plugin for pidgin
3  *  Copyright (C) 2004-2012  Ian Goldberg, Rob Smits,
4  *                           Chris Alexander, Willy Lew,
5  *                           Nikita Borisov
6  *                           <otr@cypherpunks.ca>
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of version 2 of the GNU General Public License as
10  *  published by the Free Software Foundation.
11  *
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
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 /* This file is based on a copy of gtkkmenutray.c  */
23 
24 
25 /*
26  * Pidgin is the legal property of its developers, whose names are too numerous
27  * to list here.  Please refer to the COPYRIGHT file distributed with this
28  * source distribution.
29  *
30  * This program is free software; you can redistribute it and/or modify
31  * under the terms of the GNU General Public License as published by
32  * the Free Software Foundation; either version 2 of the License, or
33  * (at your option) any later version.
34  *
35  * This program is distributed in the hope that it will be useful,
36  * but WITHOUT ANY WARRANTY; without even the implied warranty of
37  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
38  * GNU General Public License for more details.
39  *
40  * You should have received a copy of the GNU General Public License
41  * along with this program; if not, write to the Free Software
42  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
43  */
44 #include "debug.h"
45 
46 #include "tooltipmenu.h"
47 
48 #include <gtk/gtkeventbox.h>
49 #include <gtk/gtkiconfactory.h>
50 #include <gtk/gtkversion.h>
51 
52 /******************************************************************************
53  * Enums
54  *****************************************************************************/
55 enum {
56 	PROP_ZERO = 0,
57 	PROP_BOX
58 };
59 
60 /******************************************************************************
61  * Globals
62  *****************************************************************************/
63 static GObjectClass *parent_class = NULL;
64 
65 /******************************************************************************
66  * Internal Stuff
67  *****************************************************************************/
68 
69 /******************************************************************************
70  * Item Stuff
71  *****************************************************************************/
72 /*static void
73 tooltip_menu_select(GtkItem *item) {
74 
75 }
76 
77 static void
78 tooltip_menu_deselect(GtkItem *item) {
79 
80 }*/
81 
82 /******************************************************************************
83  * Widget Stuff
84  *****************************************************************************/
85 
86 /******************************************************************************
87  * Object Stuff
88  *****************************************************************************/
89 static void
tooltip_menu_get_property(GObject * obj,guint param_id,GValue * value,GParamSpec * pspec)90 tooltip_menu_get_property(GObject *obj, guint param_id, GValue *value,
91 								GParamSpec *pspec)
92 {
93 	TooltipMenu *tooltip_menu = TOOLTIP_MENU(obj);
94 
95 	switch(param_id) {
96 		case PROP_BOX:
97 			g_value_set_object(value, tooltip_menu_get_box(tooltip_menu));
98 			break;
99 		default:
100 			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
101 			break;
102 	}
103 }
104 
105 static void
tooltip_menu_finalize(GObject * obj)106 tooltip_menu_finalize(GObject *obj) {
107 #if 0
108 	/* This _might_ be leaking, but I have a sneaking suspicion that the widget is
109 	 * getting destroyed in GtkContainer's finalize function.  But if were are
110 	 * leaking here, be sure to figure out why this causes a crash.
111 	 *      -- Gary
112 	 */
113 	TooltipMenu *tray = TOOLTIP_MENU(obj);
114 
115 	if(GTK_IS_WIDGET(tray->tray))
116 		gtk_widget_destroy(GTK_WIDGET(tray->tray));
117 #endif
118 
119 	G_OBJECT_CLASS(parent_class)->finalize(obj);
120 }
121 
122 static void
tooltip_menu_class_init(TooltipMenuClass * klass)123 tooltip_menu_class_init(TooltipMenuClass *klass) {
124 	GObjectClass *object_class = G_OBJECT_CLASS(klass);
125 	GParamSpec *pspec;
126 
127 	parent_class = g_type_class_peek_parent(klass);
128 
129 	object_class->finalize = tooltip_menu_finalize;
130 	object_class->get_property = tooltip_menu_get_property;
131 
132 	pspec = g_param_spec_object("box", "The box",
133 		"The box",
134 		GTK_TYPE_BOX,
135 		G_PARAM_READABLE);
136 	g_object_class_install_property(object_class, PROP_BOX, pspec);
137 }
138 
139 static void
tooltip_menu_init(TooltipMenu * tooltip_menu)140 tooltip_menu_init(TooltipMenu *tooltip_menu) {
141 	GtkWidget *widget = GTK_WIDGET(tooltip_menu);
142 	gtk_menu_item_set_right_justified(GTK_MENU_ITEM(tooltip_menu), TRUE);
143 
144 	if(!GTK_IS_WIDGET(tooltip_menu->tray))
145 		tooltip_menu->tray = gtk_hbox_new(FALSE, 0);
146 
147 	tooltip_menu->tooltips = gtk_tooltips_new();
148 
149 	gtk_widget_set_size_request(widget, -1, -1);
150 
151 	gtk_container_add(GTK_CONTAINER(tooltip_menu), tooltip_menu->tray);
152 
153 	gtk_widget_show(tooltip_menu->tray);
154 }
155 
156 /******************************************************************************
157  * API
158  *****************************************************************************/
159 GType
tooltip_menu_get_gtype(void)160 tooltip_menu_get_gtype(void) {
161 	static GType type = 0;
162 
163 	if(type == 0) {
164 		static const GTypeInfo info = {
165 			sizeof(TooltipMenuClass),
166 			NULL,
167 			NULL,
168 			(GClassInitFunc)tooltip_menu_class_init,
169 			NULL,
170 			NULL,
171 			sizeof(TooltipMenu),
172 			0,
173 			(GInstanceInitFunc)tooltip_menu_init,
174 			NULL
175 		};
176 
177 		type = g_type_register_static(GTK_TYPE_MENU_ITEM,
178 									  "TooltipMenu",
179 									  &info, 0);
180 	}
181 
182 	return type;
183 }
184 
185 GtkWidget *
tooltip_menu_new()186 tooltip_menu_new() {
187 	return g_object_new(TYPE_TOOLTIP_MENU, NULL);
188 }
189 
190 GtkWidget *
tooltip_menu_get_box(TooltipMenu * tooltip_menu)191 tooltip_menu_get_box(TooltipMenu *tooltip_menu) {
192 	g_return_val_if_fail(IS_TOOLTIP_MENU(tooltip_menu), NULL);
193 	return tooltip_menu->tray;
194 }
195 
196 static void
tooltip_menu_add(TooltipMenu * tooltip_menu,GtkWidget * widget,const char * tooltip,gboolean prepend)197 tooltip_menu_add(TooltipMenu *tooltip_menu, GtkWidget *widget,
198 					   const char *tooltip, gboolean prepend)
199 {
200 	g_return_if_fail(IS_TOOLTIP_MENU(tooltip_menu));
201 	g_return_if_fail(GTK_IS_WIDGET(widget));
202 
203 	if (GTK_WIDGET_NO_WINDOW(widget))
204 	{
205 		GtkWidget *event;
206 
207 		event = gtk_event_box_new();
208 		gtk_container_add(GTK_CONTAINER(event), widget);
209 		gtk_widget_show(event);
210 		widget = event;
211 	}
212 
213 	tooltip_menu_set_tooltip(tooltip_menu, widget, tooltip);
214 
215 	if (prepend)
216 		gtk_box_pack_start(GTK_BOX(tooltip_menu->tray), widget, FALSE, FALSE, 0);
217 	else
218 		gtk_box_pack_end(GTK_BOX(tooltip_menu->tray), widget, FALSE, FALSE, 0);
219 }
220 
221 void
tooltip_menu_append(TooltipMenu * tooltip_menu,GtkWidget * widget,const char * tooltip)222 tooltip_menu_append(TooltipMenu *tooltip_menu, GtkWidget *widget, const char *tooltip)
223 {
224 	tooltip_menu_add(tooltip_menu, widget, tooltip, FALSE);
225 }
226 
227 void
tooltip_menu_prepend(TooltipMenu * tooltip_menu,GtkWidget * widget,const char * tooltip)228 tooltip_menu_prepend(TooltipMenu *tooltip_menu, GtkWidget *widget, const char *tooltip)
229 {
230 	tooltip_menu_add(tooltip_menu, widget, tooltip, TRUE);
231 }
232 
233 void
tooltip_menu_set_tooltip(TooltipMenu * tooltip_menu,GtkWidget * widget,const char * tooltip)234 tooltip_menu_set_tooltip(TooltipMenu *tooltip_menu, GtkWidget *widget, const char *tooltip)
235 {
236 	if (!tooltip_menu->tooltips)
237 		return;
238 
239 	/* Should we check whether widget is a child of tooltip_menu? */
240 
241 	/*
242 	 * If the widget does not have it's own window, then it
243 	 * must have automatically been added to an event box
244 	 * when it was added to the menu tray.  If this is the
245 	 * case, we want to set the tooltip on the widget's parent,
246 	 * not on the widget itself.
247 	 */
248 	if (GTK_WIDGET_NO_WINDOW(widget))
249 		widget = widget->parent;
250 
251 	gtk_tooltips_set_tip(tooltip_menu->tooltips, widget, tooltip, NULL);
252 }
253 
254