1.1.35
by Matthieu Baerts
Import upstream version 3.3.0 |
1 |
/**
|
2 |
* This file is a part of the Cairo-Dock project
|
|
3 |
*
|
|
4 |
* Copyright : (C) see the 'copyright' file.
|
|
5 |
* E-mail : see the 'copyright' file.
|
|
6 |
*
|
|
7 |
* This program is free software; you can redistribute it and/or
|
|
8 |
* modify it under the terms of the GNU General Public License
|
|
9 |
* as published by the Free Software Foundation; either version 3
|
|
10 |
* of the License, or (at your option) any later version.
|
|
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 |
* You should have received a copy of the GNU General Public License
|
|
17 |
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
18 |
*/
|
|
19 |
||
20 |
#include <stdlib.h> |
|
1.1.38
by Matthieu Baerts
Import upstream version 3.3.99.beta1.1~20140219~bzr1717 |
21 |
#include <math.h> // fabs |
1.1.35
by Matthieu Baerts
Import upstream version 3.3.0 |
22 |
|
23 |
#include <cairo.h> |
|
24 |
#include <gtk/gtk.h> |
|
25 |
#if GTK_CHECK_VERSION (3, 10, 0)
|
|
26 |
#include "gtk3imagemenuitem.h" |
|
27 |
#endif
|
|
28 |
||
29 |
#include "cairo-dock-container.h" |
|
30 |
#include "cairo-dock-icon-factory.h" |
|
31 |
#include "cairo-dock-icon-facility.h" // cairo_dock_get_icon_container |
|
32 |
#include "cairo-dock-desktop-manager.h" // gldi_desktop_get_height |
|
33 |
#include "cairo-dock-log.h" |
|
34 |
#include "cairo-dock-draw.h" |
|
1.1.38
by Matthieu Baerts
Import upstream version 3.3.99.beta1.1~20140219~bzr1717 |
35 |
#include "cairo-dock-backends-manager.h" // cairo_dock_get_dialog_decorator |
36 |
#include "cairo-dock-dialog-manager.h" // myDialogsParam |
|
37 |
#include "cairo-dock-style-manager.h" |
|
1.1.35
by Matthieu Baerts
Import upstream version 3.3.0 |
38 |
#include "cairo-dock-menu.h" |
39 |
||
1.1.38
by Matthieu Baerts
Import upstream version 3.3.99.beta1.1~20140219~bzr1717 |
40 |
#if GTK_MAJOR_VERSION > 2
|
41 |
static gboolean _draw_menu_item (GtkWidget *widget, cairo_t *cr, G_GNUC_UNUSED gpointer data); |
|
42 |
static gboolean _on_select_menu_item (GtkWidget* pMenuItem, G_GNUC_UNUSED gpointer data); |
|
43 |
static gboolean _on_deselect_menu_item (GtkWidget* pMenuItem, G_GNUC_UNUSED gpointer data); |
|
44 |
static void _on_destroy_menu_item (GtkWidget* pMenuItem, G_GNUC_UNUSED gpointer data); |
|
45 |
#endif
|
|
1.1.35
by Matthieu Baerts
Import upstream version 3.3.0 |
46 |
|
47 |
////////////
|
|
48 |
/// MENU ///
|
|
49 |
/////////////
|
|
50 |
||
1.1.38
by Matthieu Baerts
Import upstream version 3.3.99.beta1.1~20140219~bzr1717 |
51 |
#if GTK_MAJOR_VERSION > 2
|
52 |
||
53 |
static void _init_menu_style (void) |
|
54 |
{
|
|
55 |
static GtkCssProvider *cssProvider = NULL; |
|
56 |
static int index = 0; |
|
57 |
||
58 |
if (index == gldi_style_colors_get_index()) |
|
59 |
return; |
|
60 |
index = gldi_style_colors_get_index(); |
|
61 |
g_print ("%s (%d)\n", __func__, index); |
|
62 |
||
63 |
if (myDialogsParam.bUseDefaultColors && myStyleParam.bUseSystemColors) |
|
64 |
{
|
|
65 |
if (cssProvider != NULL) |
|
66 |
{
|
|
67 |
gldi_style_colors_freeze (); |
|
68 |
gtk_style_context_remove_provider_for_screen (gdk_screen_get_default(), GTK_STYLE_PROVIDER(cssProvider)); |
|
69 |
gldi_style_colors_freeze (); |
|
70 |
g_object_unref (cssProvider); |
|
71 |
cssProvider = NULL; |
|
72 |
}
|
|
73 |
}
|
|
74 |
else
|
|
75 |
{
|
|
76 |
if (cssProvider == NULL) |
|
77 |
{
|
|
78 |
cssProvider = gtk_css_provider_new (); |
|
79 |
gldi_style_colors_freeze (); |
|
80 |
gtk_style_context_add_provider_for_screen (gdk_screen_get_default(), GTK_STYLE_PROVIDER(cssProvider), GTK_STYLE_PROVIDER_PRIORITY_USER); |
|
81 |
gldi_style_colors_freeze (); |
|
82 |
}
|
|
83 |
||
84 |
double *bg_color = (myDialogsParam.bUseDefaultColors ? myStyleParam.fBgColor : myDialogsParam.fBgColor); |
|
85 |
double *text_color = (myDialogsParam.bUseDefaultColors ? myStyleParam.textDescription.fColorStart : myDialogsParam.dialogTextDescription.fColorStart); |
|
86 |
||
87 |
double rgb[4]; |
|
88 |
gldi_style_color_shade (bg_color, .2, rgb); |
|
89 |
double rgbs[4]; |
|
90 |
gldi_style_color_shade (bg_color, .2, rgbs); |
|
91 |
double rgbb[4]; |
|
92 |
gldi_style_color_shade (bg_color, .3, rgbb); |
|
93 |
||
94 |
gchar *css = g_strdup_printf ("@define-color menuitem_bg_color rgb (%d, %d, %d); \ |
|
95 |
@define-color menuitem_text_color rgb (%d, %d, %d); \
|
|
96 |
@define-color menuitem_insensitive_text_color rgba (%d, %d, %d, .5); \
|
|
97 |
@define-color menuitem_separator_color rgb (%d, %d, %d); \
|
|
98 |
@define-color menuitem_bg_color2 rgb (%d, %d, %d); \
|
|
99 |
@define-color menu_bg_color rgba (%d, %d, %d, %d); \
|
|
100 |
.menuitem2 { \
|
|
101 |
text-shadow: none; \
|
|
102 |
border-image: none; \
|
|
103 |
box-shadow: none; \
|
|
104 |
background: transparent; \
|
|
105 |
color: @menuitem_text_color; \
|
|
106 |
} \
|
|
107 |
.menuitem2 GtkImage { \
|
|
108 |
background: transparent; \
|
|
109 |
} \
|
|
110 |
.menuitem2.separator, \
|
|
111 |
.menuitem2 .separator { \
|
|
112 |
color: @menuitem_separator_color; \
|
|
113 |
border-width: 1px; \
|
|
114 |
border-style: solid; \
|
|
115 |
border-image: none; \
|
|
116 |
border-color: @menuitem_separator_color; \
|
|
117 |
border-bottom-color: alpha (@menuitem_separator_color, 0.6); \
|
|
118 |
border-right-color: alpha (@menuitem_separator_color, 0.6); \
|
|
119 |
} \
|
|
120 |
.menuitem2:hover, \
|
|
121 |
.menuitem2 *:hover { \
|
|
122 |
background: @menuitem_bg_color; \
|
|
123 |
background-image: none; \
|
|
124 |
text-shadow: none; \
|
|
125 |
border-image: none; \
|
|
126 |
box-shadow: none; \
|
|
127 |
color: @menuitem_text_color; \
|
|
128 |
} \
|
|
129 |
.menuitem2 *:insensitive { \
|
|
130 |
text-shadow: none; \
|
|
131 |
color: @menuitem_insensitive_text_color; \
|
|
132 |
} \
|
|
133 |
.menuitem2 .entry, \
|
|
134 |
.menuitem2.entry { \
|
|
135 |
background: @menuitem_bg_color; \
|
|
136 |
border-image: none; \
|
|
137 |
border-color: transparent; \
|
|
138 |
color: @menuitem_text_color; \
|
|
139 |
} \
|
|
140 |
.menuitem2 .button, \
|
|
141 |
.menuitem2.button { \
|
|
142 |
background: @menuitem_bg_color; \
|
|
143 |
background-image: none; \
|
|
144 |
box-shadow: none; \
|
|
145 |
border-color: transparent; \
|
|
146 |
padding: 2px; \
|
|
147 |
} \
|
|
148 |
.menuitem2 .scale, \
|
|
149 |
.menuitem2.scale { \
|
|
150 |
background: @menuitem_bg_color2; \
|
|
151 |
background-image: none; \
|
|
152 |
color: @menuitem_text_color; \
|
|
153 |
border-image: none; \
|
|
154 |
} \
|
|
155 |
.menuitem2 .scale.left, \
|
|
156 |
.menuitem2.scale.left { \
|
|
157 |
background: @menuitem_bg_color; \
|
|
158 |
background-image: none; \
|
|
159 |
border-image: none; \
|
|
160 |
} \
|
|
161 |
.menuitem2 .scale.slider, \
|
|
162 |
.menuitem2.scale.slider { \
|
|
163 |
background: @menuitem_text_color; \
|
|
164 |
background-image: none; \
|
|
165 |
border-image: none; \
|
|
166 |
} \
|
|
167 |
.menuitem2 GtkCalendar, \
|
|
168 |
.menuitem2 GtkCalendar.button, \
|
|
169 |
.menuitem2 GtkCalendar.header, \
|
|
170 |
.menuitem2 GtkCalendar.view { \
|
|
171 |
background-color: @menuitem_bg_color; \
|
|
172 |
background-image: none; \
|
|
173 |
color: @menuitem_text_color; \
|
|
174 |
} \
|
|
175 |
.menuitem2 GtkCalendar { \
|
|
176 |
background-color: @menuitem_bg_color2; \
|
|
177 |
background-image: none; \
|
|
178 |
} \
|
|
179 |
.menuitem2 GtkCalendar:inconsistent { \
|
|
180 |
color: shade (@menuitem_bg_color2, 0.6); \
|
|
181 |
} \
|
|
182 |
.menu2 { \
|
|
183 |
background: @menu_bg_color; \
|
|
184 |
background-image: none; \
|
|
185 |
color: @menuitem_text_color; \
|
|
186 |
}", |
|
187 |
(int)(rgb[0]*255), (int)(rgb[1]*255), (int)(rgb[2]*255), |
|
188 |
(int)(text_color[0]*255), (int)(text_color[1]*255), (int)(text_color[2]*255), |
|
189 |
(int)(text_color[0]*255), (int)(text_color[1]*255), (int)(text_color[2]*255), |
|
190 |
(int)(rgbs[0]*255), (int)(rgbs[1]*255), (int)(rgbs[2]*255), |
|
191 |
(int)(rgbb[0]*255), (int)(rgbb[1]*255), (int)(rgbb[2]*255), |
|
192 |
(int)(bg_color[0]*255), (int)(bg_color[1]*255), (int)(bg_color[2]*255), (int)(bg_color[3]*255)); // we also define ".menu", so that custom widgets (like in the SoundMenu) can get our colors. |
|
193 |
||
194 |
gldi_style_colors_freeze (); |
|
195 |
gtk_css_provider_load_from_data (cssProvider, |
|
196 |
css, -1, NULL); // (should) clear any previously loaded information |
|
197 |
gldi_style_colors_freeze (); |
|
198 |
g_free (css); |
|
199 |
}
|
|
200 |
}
|
|
201 |
||
202 |
static gboolean _draw_menu (GtkWidget *pWidget, |
|
203 |
cairo_t *pCairoContext, |
|
204 |
G_GNUC_UNUSED GtkWidget *menu) |
|
205 |
{
|
|
206 |
// erase the default background
|
|
207 |
cairo_dock_erase_cairo_context (pCairoContext); |
|
208 |
||
209 |
// draw the background/outline and set the clip
|
|
210 |
CairoDialogDecorator *pDecorator = cairo_dock_get_dialog_decorator (myDialogsParam.cDecoratorName); |
|
211 |
if (pDecorator) |
|
212 |
pDecorator->render_menu (pWidget, pCairoContext); |
|
213 |
||
214 |
// draw the items
|
|
215 |
cairo_set_source_rgba (pCairoContext, 0.0, 0.0, 0.0, 1.0); |
|
216 |
||
217 |
GtkWidgetClass *parent_class = g_type_class_peek (g_type_parent (G_TYPE_FROM_INSTANCE (pWidget))); |
|
218 |
parent_class = g_type_class_peek_parent (parent_class); // skip the direct parent (GtkBin, which does anyway nothing usually), because dbusmenu-gtk draws it |
|
219 |
parent_class->draw (pWidget, pCairoContext); |
|
220 |
||
221 |
return TRUE; |
|
222 |
}
|
|
223 |
||
224 |
static void _set_margin_position (GtkWidget *pMenu, GldiMenuParams *pParams) |
|
225 |
{
|
|
226 |
if (pParams == NULL) |
|
227 |
pParams = g_object_get_data (G_OBJECT (pMenu), "gldi-params"); |
|
228 |
g_return_if_fail (pParams); |
|
229 |
Icon *pIcon = pParams->pIcon; |
|
230 |
g_return_if_fail (pIcon); |
|
231 |
GldiContainer *pContainer = cairo_dock_get_icon_container (pIcon); |
|
232 |
g_return_if_fail (pContainer); |
|
233 |
||
234 |
// define where the menu will point
|
|
235 |
int iMarginPosition; // b, t, r, l |
|
236 |
int y0 = pContainer->iWindowPositionY + pIcon->fDrawY; |
|
237 |
if (pContainer->bDirectionUp) |
|
238 |
y0 += pIcon->fHeight * pIcon->fScale - pIcon->image.iHeight; // the icon might not be maximised yet |
|
239 |
int Hs = (pContainer->bIsHorizontal ? gldi_desktop_get_height() : gldi_desktop_get_width()); |
|
240 |
if (pContainer->bIsHorizontal) |
|
241 |
{
|
|
242 |
iMarginPosition = (y0 > Hs/2 ? 0 : 1); |
|
243 |
}
|
|
244 |
else
|
|
245 |
{
|
|
246 |
iMarginPosition = (y0 > Hs/2 ? 2 : 3); |
|
247 |
}
|
|
248 |
||
249 |
// store the result, and allocate some space to draw the arrow
|
|
250 |
if (iMarginPosition != pParams->iMarginPosition) // margin position is now defined or has changed -> update it on the menu |
|
251 |
{
|
|
252 |
g_print ("margin position: %d -> %d\n", pParams->iMarginPosition, iMarginPosition); |
|
253 |
// store the value
|
|
254 |
pParams->iMarginPosition = iMarginPosition; |
|
255 |
||
256 |
// get/add a css (gtk_widget_set_margin_xxx doesn't work as expected :-/)
|
|
257 |
GtkCssProvider *cssProvider = pParams->cssProvider; |
|
258 |
if (cssProvider) // unfortunately, GTK doesn't update correctly a css provider if we load some new data inside (the previous padding values are kept, along with the new ones, although 'gtk_css_provider_load_from_data' is supposed to "clear any previously loaded information"), so we have to remove/add it :-/ |
|
259 |
{
|
|
260 |
gtk_style_context_remove_provider (gtk_widget_get_style_context(pMenu), GTK_STYLE_PROVIDER(cssProvider)); |
|
261 |
g_object_unref (cssProvider); |
|
262 |
cssProvider = NULL; |
|
263 |
pParams->cssProvider = NULL; |
|
264 |
}
|
|
265 |
if (cssProvider == NULL) |
|
266 |
{
|
|
267 |
cssProvider = gtk_css_provider_new (); |
|
268 |
gtk_style_context_add_provider (gtk_widget_get_style_context(pMenu), GTK_STYLE_PROVIDER(cssProvider), GTK_STYLE_PROVIDER_PRIORITY_USER); // this adds a reference on the provider, plus the one we own |
|
269 |
pParams->cssProvider = cssProvider; |
|
270 |
g_print (" + css\n"); |
|
271 |
}
|
|
272 |
||
273 |
// load the new padding rule into the css
|
|
274 |
gchar *css = NULL; |
|
275 |
int ah = pParams->iArrowHeight; |
|
276 |
int b=0, t=0, r=0, l=0; |
|
277 |
switch (iMarginPosition) |
|
278 |
{
|
|
279 |
case 0: b = ah; break; |
|
280 |
case 1: t = ah; break; |
|
281 |
case 2: r = ah; break; |
|
282 |
case 3: l = ah; break; |
|
283 |
default: break; |
|
284 |
}
|
|
285 |
css = g_strdup_printf ("GtkMenu { \ |
|
286 |
padding-bottom: %dpx; \
|
|
287 |
padding-top: %dpx; \
|
|
288 |
padding-right: %dpx; \
|
|
289 |
padding-left: %dpx; \
|
|
290 |
}", b, t, r, l); // we must define all the paddings, else if the margin position changes, clearing the css won't make the padding disappear :-/ |
|
291 |
gtk_css_provider_load_from_data (cssProvider, |
|
292 |
css, -1, NULL); |
|
293 |
g_free (css); |
|
294 |
}
|
|
295 |
}
|
|
296 |
#endif
|
|
297 |
||
1.1.35
by Matthieu Baerts
Import upstream version 3.3.0 |
298 |
GtkWidget *gldi_menu_new (G_GNUC_UNUSED Icon *pIcon) |
299 |
{
|
|
300 |
GtkWidget *pMenu = gtk_menu_new (); |
|
301 |
||
302 |
gldi_menu_init (pMenu, pIcon); |
|
303 |
||
304 |
return pMenu; |
|
305 |
}
|
|
306 |
||
307 |
static gboolean _on_icon_destroyed (GtkWidget *pMenu, G_GNUC_UNUSED Icon *pIcon) |
|
308 |
{
|
|
1.1.38
by Matthieu Baerts
Import upstream version 3.3.99.beta1.1~20140219~bzr1717 |
309 |
GldiMenuParams *pParams = g_object_get_data (G_OBJECT (pMenu), "gldi-params"); |
310 |
if (pParams) |
|
311 |
pParams->pIcon = NULL; |
|
1.1.35
by Matthieu Baerts
Import upstream version 3.3.0 |
312 |
return GLDI_NOTIFICATION_LET_PASS; |
313 |
}
|
|
314 |
||
315 |
static void _on_menu_destroyed (GtkWidget *pMenu, G_GNUC_UNUSED gpointer data) |
|
316 |
{
|
|
1.1.38
by Matthieu Baerts
Import upstream version 3.3.99.beta1.1~20140219~bzr1717 |
317 |
GldiMenuParams *pParams = g_object_get_data (G_OBJECT (pMenu), "gldi-params"); |
318 |
if (!pParams) |
|
319 |
return; |
|
320 |
Icon *pIcon = pParams->pIcon; |
|
1.1.35
by Matthieu Baerts
Import upstream version 3.3.0 |
321 |
if (pIcon) |
322 |
gldi_object_remove_notification (pIcon, |
|
323 |
NOTIFICATION_DESTROY, |
|
324 |
(GldiNotificationFunc) _on_icon_destroyed, |
|
325 |
NULL); |
|
1.1.38
by Matthieu Baerts
Import upstream version 3.3.99.beta1.1~20140219~bzr1717 |
326 |
#if GTK_MAJOR_VERSION > 2
|
327 |
if (pParams->cssProvider) |
|
328 |
{
|
|
329 |
g_object_unref (pParams->cssProvider); /// need to remove the provider from the style context ?... probably not since the style context will be destroyed and will release its reference on the provider |
|
330 |
}
|
|
331 |
g_free (pParams); |
|
332 |
#endif
|
|
333 |
}
|
|
334 |
||
335 |
#if GTK_MAJOR_VERSION > 2
|
|
336 |
static void _on_menu_deactivated (GtkMenuShell *pMenu, G_GNUC_UNUSED gpointer data) |
|
337 |
{
|
|
338 |
GldiMenuParams *pParams = g_object_get_data (G_OBJECT (pMenu), "gldi-params"); |
|
339 |
if (!pParams) |
|
340 |
return; |
|
341 |
Icon *pIcon = pParams->pIcon; |
|
342 |
if (pIcon->iHideLabel > 0) |
|
343 |
{
|
|
344 |
pIcon->iHideLabel --; |
|
345 |
GldiContainer *pContainer = cairo_dock_get_icon_container (pIcon); |
|
346 |
if (pIcon->iHideLabel == 0 && pContainer) |
|
347 |
gtk_widget_queue_draw (pContainer->pWidget); |
|
348 |
}
|
|
349 |
}
|
|
350 |
#endif
|
|
351 |
||
352 |
void gldi_menu_init (G_GNUC_UNUSED GtkWidget *pMenu, Icon *pIcon) |
|
1.1.35
by Matthieu Baerts
Import upstream version 3.3.0 |
353 |
{
|
354 |
#if (CAIRO_DOCK_FORCE_ICON_IN_MENUS == 1)
|
|
355 |
gtk_menu_set_reserve_toggle_size (GTK_MENU(pMenu), TRUE); |
|
356 |
#endif
|
|
357 |
||
1.1.38
by Matthieu Baerts
Import upstream version 3.3.99.beta1.1~20140219~bzr1717 |
358 |
#if GTK_MAJOR_VERSION > 2
|
359 |
// connect to 'draw' event to draw the menu (background and items)
|
|
360 |
GtkWidget *pWindow = gtk_widget_get_toplevel (pMenu); |
|
361 |
cairo_dock_set_default_rgba_visual (pWindow); |
|
362 |
||
363 |
g_signal_connect (G_OBJECT (pMenu), |
|
364 |
"draw", |
|
365 |
G_CALLBACK (_draw_menu), |
|
366 |
pMenu); |
|
367 |
||
368 |
_init_menu_style (); |
|
369 |
||
370 |
gtk_style_context_add_class (gtk_widget_get_style_context (pMenu), "menu2"); |
|
371 |
#endif
|
|
372 |
||
373 |
// set params
|
|
374 |
GldiMenuParams *pParams = g_new0 (GldiMenuParams, 1); |
|
375 |
g_object_set_data (G_OBJECT (pMenu), "gldi-params", pParams); |
|
376 |
g_signal_connect (G_OBJECT (pMenu), |
|
377 |
"destroy", |
|
378 |
G_CALLBACK (_on_menu_destroyed), |
|
379 |
NULL); |
|
380 |
||
381 |
// init a main menu
|
|
1.1.35
by Matthieu Baerts
Import upstream version 3.3.0 |
382 |
if (pIcon != NULL) // the menu points on an icon |
383 |
{
|
|
384 |
// link it to the icon
|
|
385 |
g_object_set_data (G_OBJECT (pMenu), "gldi-icon", pIcon); |
|
1.1.38
by Matthieu Baerts
Import upstream version 3.3.99.beta1.1~20140219~bzr1717 |
386 |
pParams->pIcon = pIcon; |
1.1.35
by Matthieu Baerts
Import upstream version 3.3.0 |
387 |
gldi_object_register_notification (pIcon, |
388 |
NOTIFICATION_DESTROY, |
|
389 |
(GldiNotificationFunc) _on_icon_destroyed, |
|
1.1.38
by Matthieu Baerts
Import upstream version 3.3.99.beta1.1~20140219~bzr1717 |
390 |
GLDI_RUN_AFTER, pMenu); // when the icon is destroyed, unlink the menu from it; when the menu is destroyed, the above notification will be unregistered on the icon in the "destroy" callback |
391 |
||
392 |
GldiContainer *pContainer = cairo_dock_get_icon_container (pIcon); |
|
393 |
if (pContainer != NULL) |
|
394 |
{
|
|
395 |
#if GTK_MAJOR_VERSION > 2
|
|
396 |
// init the rendering --> align, margin-height
|
|
397 |
CairoDialogDecorator *pDecorator = cairo_dock_get_dialog_decorator (myDialogsParam.cDecoratorName); |
|
398 |
if (pDecorator) |
|
399 |
pDecorator->setup_menu (pMenu); |
|
400 |
||
401 |
// define where the menu will point, and allocate some space to draw the arrow
|
|
402 |
pParams->iMarginPosition = -1; |
|
403 |
_set_margin_position (pMenu, pParams); |
|
404 |
||
405 |
// show the icon's label back when the menu is hidden
|
|
406 |
g_signal_connect (G_OBJECT (pMenu), |
|
407 |
"deactivate", |
|
408 |
G_CALLBACK (_on_menu_deactivated), |
|
409 |
NULL); |
|
410 |
||
411 |
gchar *css = NULL; |
|
412 |
const gchar *orientation = ""; |
|
413 |
int ah = pParams->iArrowHeight; |
|
414 |
switch (pParams->iMarginPosition) |
|
415 |
{
|
|
416 |
case 0: orientation = "bottom"; break; |
|
417 |
case 1: orientation = "top"; break; |
|
418 |
case 2: orientation = "right"; break; |
|
419 |
case 3: orientation = "left"; break; |
|
420 |
default: break; |
|
421 |
}
|
|
422 |
||
423 |
GtkCssProvider *cssProvider = gtk_css_provider_new (); |
|
424 |
css = g_strdup_printf ("GtkMenu { \ |
|
425 |
padding-%s: %dpx; \
|
|
426 |
}", orientation, ah); |
|
427 |
gtk_css_provider_load_from_data (cssProvider, |
|
428 |
css, -1, NULL); |
|
429 |
gtk_style_context_add_provider (gtk_widget_get_style_context(pMenu), GTK_STYLE_PROVIDER(cssProvider), GTK_STYLE_PROVIDER_PRIORITY_USER); |
|
430 |
g_free (css); |
|
431 |
#endif
|
|
432 |
}
|
|
1.1.35
by Matthieu Baerts
Import upstream version 3.3.0 |
433 |
}
|
434 |
}
|
|
435 |
||
436 |
static void _place_menu_on_icon (GtkMenu *menu, gint *x, gint *y, gboolean *push_in, G_GNUC_UNUSED gpointer data) |
|
437 |
{
|
|
438 |
*push_in = FALSE; |
|
1.1.38
by Matthieu Baerts
Import upstream version 3.3.99.beta1.1~20140219~bzr1717 |
439 |
GldiMenuParams *pParams = g_object_get_data (G_OBJECT(menu), "gldi-params"); |
440 |
g_return_if_fail (pParams != NULL); |
|
441 |
||
442 |
Icon *pIcon = pParams->pIcon; |
|
1.1.35
by Matthieu Baerts
Import upstream version 3.3.0 |
443 |
GldiContainer *pContainer = (pIcon ? cairo_dock_get_icon_container (pIcon) : NULL); |
444 |
int x0 = pContainer->iWindowPositionX + pIcon->fDrawX; |
|
445 |
int y0 = pContainer->iWindowPositionY + pIcon->fDrawY; |
|
446 |
if (pContainer->bDirectionUp) |
|
447 |
y0 += pIcon->fHeight * pIcon->fScale - pIcon->image.iHeight; // the icon might not be maximised yet |
|
448 |
||
449 |
int w, h; // taille menu |
|
450 |
GtkRequisition requisition; |
|
451 |
#if (GTK_MAJOR_VERSION < 3)
|
|
452 |
gtk_widget_size_request (GTK_WIDGET (menu), &requisition); |
|
453 |
#else
|
|
454 |
gtk_widget_get_preferred_size (GTK_WIDGET (menu), &requisition, NULL); |
|
455 |
#endif
|
|
456 |
w = requisition.width; |
|
457 |
h = requisition.height; |
|
458 |
||
1.1.38
by Matthieu Baerts
Import upstream version 3.3.99.beta1.1~20140219~bzr1717 |
459 |
/// TODO: use iMarginPosition...
|
460 |
#if GTK_MAJOR_VERSION > 2
|
|
461 |
double fAlign = pParams->fAlign; |
|
462 |
int r = pParams->iRadius; |
|
463 |
int ah = pParams->iArrowHeight; |
|
464 |
int w_, h_; |
|
465 |
#endif
|
|
466 |
int iAimedX, iAimedY; |
|
1.1.35
by Matthieu Baerts
Import upstream version 3.3.0 |
467 |
int Hs = (pContainer->bIsHorizontal ? gldi_desktop_get_height() : gldi_desktop_get_width()); |
468 |
if (pContainer->bIsHorizontal) |
|
469 |
{
|
|
1.1.38
by Matthieu Baerts
Import upstream version 3.3.99.beta1.1~20140219~bzr1717 |
470 |
iAimedX = x0 + pIcon->image.iWidth/2; |
471 |
#if GTK_MAJOR_VERSION > 2
|
|
472 |
w_ = w - 2 * r; |
|
473 |
h_ = h - 2 * r - ah; |
|
474 |
*x = MAX (0, iAimedX - fAlign * w_ - r); |
|
475 |
#else
|
|
476 |
*x = iAimedX; |
|
477 |
#endif
|
|
1.1.35
by Matthieu Baerts
Import upstream version 3.3.0 |
478 |
if (y0 > Hs/2) // pContainer->bDirectionUp |
1.1.38
by Matthieu Baerts
Import upstream version 3.3.99.beta1.1~20140219~bzr1717 |
479 |
{
|
1.1.35
by Matthieu Baerts
Import upstream version 3.3.0 |
480 |
*y = y0 - h; |
1.1.38
by Matthieu Baerts
Import upstream version 3.3.99.beta1.1~20140219~bzr1717 |
481 |
iAimedY = y0; |
482 |
}
|
|
1.1.35
by Matthieu Baerts
Import upstream version 3.3.0 |
483 |
else
|
1.1.38
by Matthieu Baerts
Import upstream version 3.3.99.beta1.1~20140219~bzr1717 |
484 |
{
|
1.1.35
by Matthieu Baerts
Import upstream version 3.3.0 |
485 |
*y = y0 + pIcon->fHeight * pIcon->fScale; |
1.1.38
by Matthieu Baerts
Import upstream version 3.3.99.beta1.1~20140219~bzr1717 |
486 |
iAimedY = y0 + pIcon->image.iHeight; |
487 |
}
|
|
1.1.35
by Matthieu Baerts
Import upstream version 3.3.0 |
488 |
}
|
489 |
else
|
|
490 |
{
|
|
1.1.38
by Matthieu Baerts
Import upstream version 3.3.99.beta1.1~20140219~bzr1717 |
491 |
iAimedY = x0 + pIcon->image.iWidth/2; |
492 |
#if GTK_MAJOR_VERSION > 2
|
|
493 |
w_ = w - 2 * r - ah; |
|
494 |
h_ = h - 2 * r; |
|
495 |
*y = MIN (iAimedY - fAlign * h_ - r, gldi_desktop_get_height() - h); |
|
496 |
#else
|
|
497 |
*y = MIN (iAimedY, gldi_desktop_get_height() - h); |
|
498 |
#endif
|
|
1.1.35
by Matthieu Baerts
Import upstream version 3.3.0 |
499 |
if (y0 > Hs/2) // pContainer->bDirectionUp |
1.1.38
by Matthieu Baerts
Import upstream version 3.3.99.beta1.1~20140219~bzr1717 |
500 |
{
|
1.1.35
by Matthieu Baerts
Import upstream version 3.3.0 |
501 |
*x = y0 - w; |
1.1.38
by Matthieu Baerts
Import upstream version 3.3.99.beta1.1~20140219~bzr1717 |
502 |
iAimedX = y0; |
503 |
}
|
|
1.1.35
by Matthieu Baerts
Import upstream version 3.3.0 |
504 |
else
|
1.1.38
by Matthieu Baerts
Import upstream version 3.3.99.beta1.1~20140219~bzr1717 |
505 |
{
|
506 |
*x = y0 + pIcon->image.iHeight; |
|
507 |
iAimedX = y0 + pIcon->image.iHeight; |
|
508 |
}
|
|
509 |
}
|
|
510 |
pParams->iAimedX = iAimedX; |
|
511 |
pParams->iAimedY = iAimedY; |
|
512 |
}
|
|
513 |
||
514 |
#if GTK_MAJOR_VERSION > 2
|
|
515 |
static void _init_menu_item (GtkWidget *pMenuItem) |
|
516 |
{
|
|
517 |
int index = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (pMenuItem), "gldi-text-color")); |
|
518 |
if (index == 0) |
|
519 |
{
|
|
520 |
// the following code is to draw the menu item; this is more like a proof of concept
|
|
521 |
/**g_signal_connect (G_OBJECT (pMenuItem),
|
|
522 |
"draw",
|
|
523 |
G_CALLBACK (_draw_menu_item),
|
|
524 |
NULL);
|
|
525 |
g_signal_connect (G_OBJECT (pMenuItem),
|
|
526 |
"select",
|
|
527 |
G_CALLBACK (_on_select_menu_item),
|
|
528 |
NULL);
|
|
529 |
g_signal_connect (G_OBJECT (pMenuItem),
|
|
530 |
"deselect",
|
|
531 |
G_CALLBACK (_on_deselect_menu_item),
|
|
532 |
NULL);
|
|
533 |
g_signal_connect (G_OBJECT (pMenuItem),
|
|
534 |
"destroy",
|
|
535 |
G_CALLBACK (_on_destroy_menu_item),
|
|
536 |
NULL);*/
|
|
537 |
||
538 |
gtk_style_context_add_class (gtk_widget_get_style_context (pMenuItem), "menuitem2"); |
|
539 |
||
540 |
g_object_set_data (G_OBJECT (pMenuItem), "gldi-text-color", GINT_TO_POINTER(1)); |
|
541 |
}
|
|
542 |
||
543 |
GtkWidget *pSubMenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (pMenuItem)); |
|
544 |
if (pSubMenu != NULL) /// TODO: if it's a sub-menu not made by us (for instance, the NetworkManager indicator), set the drawing callback... |
|
545 |
gtk_container_forall (GTK_CONTAINER (pSubMenu), (GtkCallback) _init_menu_item, NULL); |
|
546 |
}
|
|
547 |
#endif
|
|
548 |
||
1.1.35
by Matthieu Baerts
Import upstream version 3.3.0 |
549 |
static void _popup_menu (GtkWidget *menu, guint32 time) |
550 |
{
|
|
1.1.38
by Matthieu Baerts
Import upstream version 3.3.99.beta1.1~20140219~bzr1717 |
551 |
GldiMenuParams *pParams = g_object_get_data (G_OBJECT(menu), "gldi-params"); |
552 |
g_return_if_fail (pParams != NULL); |
|
553 |
||
554 |
Icon *pIcon = pParams->pIcon; |
|
1.1.35
by Matthieu Baerts
Import upstream version 3.3.0 |
555 |
GldiContainer *pContainer = (pIcon ? cairo_dock_get_icon_container (pIcon) : NULL); |
556 |
||
1.1.37
by Matthieu Baerts
Import upstream version 3.3.2 |
557 |
// setup the menu for the container
|
1.1.38
by Matthieu Baerts
Import upstream version 3.3.99.beta1.1~20140219~bzr1717 |
558 |
if (pContainer && pContainer->iface.setup_menu) |
559 |
pContainer->iface.setup_menu (pContainer, pIcon, menu); |
|
560 |
||
561 |
#if GTK_MAJOR_VERSION > 2
|
|
562 |
{
|
|
563 |
_init_menu_style (); |
|
564 |
}
|
|
565 |
||
566 |
if (pIcon && pContainer) |
|
567 |
{
|
|
568 |
// hide the icon's label, since menus are placed right above the icon (and therefore, the arrow overlaps the label, which makes it hard to see if both colors are similar).
|
|
569 |
if (pIcon->iHideLabel == 0 && pContainer) |
|
570 |
gtk_widget_queue_draw (pContainer->pWidget); |
|
571 |
pIcon->iHideLabel ++; |
|
572 |
||
573 |
// ensure margin position is still correct
|
|
574 |
_set_margin_position (menu, pParams); |
|
575 |
}
|
|
576 |
#endif
|
|
577 |
||
1.1.35
by Matthieu Baerts
Import upstream version 3.3.0 |
578 |
gtk_widget_show_all (GTK_WIDGET (menu)); |
579 |
||
1.1.38
by Matthieu Baerts
Import upstream version 3.3.99.beta1.1~20140219~bzr1717 |
580 |
#if GTK_MAJOR_VERSION > 2
|
581 |
// to draw the items ourselves
|
|
582 |
gtk_container_forall (GTK_CONTAINER (menu), (GtkCallback) _init_menu_item, NULL); |
|
583 |
#endif
|
|
584 |
||
1.1.35
by Matthieu Baerts
Import upstream version 3.3.0 |
585 |
gtk_menu_popup (GTK_MENU (menu), |
586 |
NULL, |
|
587 |
NULL, |
|
588 |
pIcon != NULL && pContainer != NULL ? _place_menu_on_icon : NULL, |
|
589 |
NULL, |
|
590 |
0, |
|
591 |
time); |
|
592 |
}
|
|
593 |
static gboolean _popup_menu_delayed (GtkWidget *menu) |
|
594 |
{
|
|
595 |
_popup_menu (menu, 0); |
|
596 |
return FALSE; |
|
597 |
}
|
|
598 |
void gldi_menu_popup (GtkWidget *menu) |
|
599 |
{
|
|
600 |
if (menu == NULL) |
|
601 |
return; |
|
602 |
||
603 |
guint32 t = gtk_get_current_event_time(); |
|
604 |
cd_debug ("gtk_get_current_event_time: %d", t); |
|
605 |
if (t > 0) |
|
606 |
{
|
|
607 |
_popup_menu (menu, t); |
|
608 |
}
|
|
609 |
else // 'gtk_menu_popup' is buggy and doesn't work if not triggered directly by an X event :-/ so in this case, we run it with a delay (200ms is the minimal value that always works). |
|
610 |
{
|
|
611 |
g_timeout_add (250, (GSourceFunc)_popup_menu_delayed, menu); |
|
612 |
}
|
|
613 |
}
|
|
614 |
||
615 |
||
616 |
/////////////////
|
|
617 |
/// MENU ITEM ///
|
|
618 |
/////////////////
|
|
619 |
||
1.1.38
by Matthieu Baerts
Import upstream version 3.3.99.beta1.1~20140219~bzr1717 |
620 |
#if GTK_MAJOR_VERSION > 2
|
621 |
const int N = 10; |
|
622 |
const int dt1 = 20; |
|
623 |
const int dt2 = 30; |
|
624 |
||
625 |
static void |
|
626 |
get_arrow_size (GtkWidget *widget, |
|
627 |
GtkWidget *child, |
|
628 |
gint *size, |
|
629 |
gint *spacing) |
|
630 |
{
|
|
631 |
PangoContext *context; |
|
632 |
PangoFontMetrics *metrics; |
|
633 |
gfloat arrow_scaling; |
|
634 |
gint arrow_spacing; |
|
635 |
||
636 |
g_assert (size); |
|
637 |
||
638 |
gtk_widget_style_get (widget, |
|
639 |
"arrow-scaling", &arrow_scaling, |
|
640 |
"arrow-spacing", &arrow_spacing, |
|
641 |
NULL); |
|
642 |
||
643 |
if (spacing != NULL) |
|
644 |
*spacing = arrow_spacing; |
|
645 |
||
646 |
context = gtk_widget_get_pango_context (child); |
|
647 |
||
648 |
metrics = pango_context_get_metrics (context, |
|
649 |
pango_context_get_font_description (context), |
|
650 |
pango_context_get_language (context)); |
|
651 |
||
652 |
*size = (PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) + |
|
653 |
pango_font_metrics_get_descent (metrics))); |
|
654 |
||
655 |
pango_font_metrics_unref (metrics); |
|
656 |
||
657 |
*size = *size * arrow_scaling; |
|
658 |
}
|
|
659 |
static gboolean _draw_menu_item (GtkWidget *widget, |
|
660 |
cairo_t *cr, |
|
661 |
G_GNUC_UNUSED gpointer data) |
|
662 |
{
|
|
663 |
//GtkStateFlags state;
|
|
664 |
GtkStyleContext *context; |
|
665 |
GtkWidget *child; |
|
666 |
gint x, y, w, h, width, height; |
|
667 |
guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget)); |
|
668 |
||
669 |
child = gtk_bin_get_child (GTK_BIN (widget)); |
|
670 |
||
671 |
//state = gtk_widget_get_state_flags (widget);
|
|
672 |
context = gtk_widget_get_style_context (widget); |
|
673 |
width = gtk_widget_get_allocated_width (widget); |
|
674 |
height = gtk_widget_get_allocated_height (widget); |
|
675 |
||
676 |
x = border_width; |
|
677 |
y = border_width; |
|
678 |
w = width - border_width * 2; |
|
679 |
h = height - border_width * 2; |
|
680 |
||
681 |
// draw the background
|
|
682 |
int n = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), "gldi-step")); |
|
683 |
if (n != 0) // so we only draw the barkground if the item is or was selected |
|
684 |
{
|
|
685 |
double a = (double)n/N; |
|
686 |
||
687 |
cairo_save (cr); |
|
688 |
||
689 |
int r=6, l=0; |
|
690 |
cairo_dock_draw_rounded_rectangle (cr, r, l, w - 2*r, h); |
|
691 |
cairo_clip (cr); |
|
692 |
||
693 |
gldi_style_colors_set_selected_bg_color (cr); |
|
694 |
cairo_paint_with_alpha (cr, a); |
|
695 |
||
696 |
cairo_restore (cr); |
|
697 |
}
|
|
698 |
||
699 |
// draw the arrow in case of a sub-menu
|
|
700 |
if (gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget))) |
|
701 |
{
|
|
702 |
gint arrow_x, arrow_y; |
|
703 |
gint arrow_size, spacing; |
|
704 |
GtkTextDirection direction; |
|
705 |
gdouble angle; |
|
706 |
||
707 |
direction = gtk_widget_get_direction (widget); |
|
708 |
get_arrow_size (widget, child, &arrow_size, &spacing); |
|
709 |
||
710 |
if (direction == GTK_TEXT_DIR_LTR) |
|
711 |
{
|
|
712 |
arrow_x = x + w - arrow_size - spacing; |
|
713 |
angle = G_PI / 2; |
|
714 |
}
|
|
715 |
else
|
|
716 |
{
|
|
717 |
arrow_x = x + spacing; |
|
718 |
angle = (3 * G_PI) / 2; |
|
719 |
}
|
|
720 |
||
721 |
arrow_y = y + (h - arrow_size) / 2; |
|
722 |
||
723 |
gtk_render_arrow (context, cr, angle, arrow_x, arrow_y, arrow_size); |
|
724 |
}
|
|
725 |
else if (!child) // separator |
|
726 |
{
|
|
727 |
gboolean wide_separators; |
|
728 |
gint separator_height; |
|
729 |
GtkBorder padding; |
|
730 |
||
731 |
g_print ("SEPARATOR\n"); |
|
732 |
gtk_style_context_get_padding (context, 0, &padding); |
|
733 |
gtk_widget_style_get (widget, |
|
734 |
"wide-separators", &wide_separators, |
|
735 |
"separator-height", &separator_height, |
|
736 |
NULL); |
|
737 |
if (wide_separators) |
|
738 |
gtk_render_frame (context, cr, |
|
739 |
x + padding.left, |
|
740 |
y + padding.top, |
|
741 |
w - padding.left - padding.right, |
|
742 |
separator_height); |
|
743 |
else
|
|
744 |
gtk_render_line (context, cr, |
|
745 |
x + padding.left, |
|
746 |
y + padding.top, |
|
747 |
x + w - padding.right - 1, |
|
748 |
y + padding.top); |
|
749 |
}
|
|
750 |
||
751 |
// draw the item's content
|
|
752 |
GtkWidgetClass *parent_class = g_type_class_peek (g_type_parent (G_TYPE_FROM_INSTANCE (widget))); |
|
753 |
parent_class = g_type_class_peek_parent (parent_class); |
|
754 |
||
755 |
cairo_set_source_rgba (cr, 1, 1, 1, 1); |
|
756 |
||
757 |
parent_class->draw (widget, cr); |
|
758 |
return TRUE; // intercept |
|
759 |
}
|
|
760 |
||
761 |
static gboolean _update_menu_item (GtkWidget* pMenuItem, G_GNUC_UNUSED gpointer data) |
|
762 |
{
|
|
763 |
int n = GPOINTER_TO_INT (g_object_get_data (G_OBJECT(pMenuItem), "gldi-step")); |
|
764 |
gboolean bInside = GPOINTER_TO_INT (g_object_get_data (G_OBJECT(pMenuItem), "gldi-inside")); |
|
765 |
||
766 |
if (bInside) |
|
767 |
{
|
|
768 |
if (n < N) |
|
769 |
n ++; |
|
770 |
}
|
|
771 |
else
|
|
772 |
{
|
|
773 |
if (n > 0) |
|
774 |
n --; |
|
775 |
}
|
|
776 |
g_object_set_data (G_OBJECT(pMenuItem), "gldi-step", GINT_TO_POINTER (n)); |
|
777 |
||
778 |
gtk_widget_queue_draw (pMenuItem); |
|
779 |
||
780 |
if (n == 0 || n == N) |
|
781 |
{
|
|
782 |
guint iSidAnimation = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT(pMenuItem), "gldi-animation")); |
|
783 |
if (iSidAnimation != 0) |
|
784 |
{
|
|
785 |
g_source_remove (iSidAnimation); |
|
786 |
g_object_set_data (G_OBJECT(pMenuItem), "gldi-animation", NULL); |
|
787 |
}
|
|
788 |
return FALSE; |
|
789 |
}
|
|
790 |
return TRUE; |
|
791 |
}
|
|
792 |
static gboolean _on_select_menu_item (GtkWidget* pMenuItem, G_GNUC_UNUSED gpointer data) |
|
793 |
{
|
|
794 |
guint iSidAnimation = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT(pMenuItem), "gldi-animation")); |
|
795 |
if (iSidAnimation != 0) |
|
796 |
g_source_remove (iSidAnimation); |
|
797 |
iSidAnimation = g_timeout_add (dt1, (GSourceFunc)_update_menu_item, pMenuItem); |
|
798 |
g_object_set_data (G_OBJECT(pMenuItem), "gldi-animation", GUINT_TO_POINTER (iSidAnimation)); |
|
799 |
||
800 |
g_object_set_data (G_OBJECT(pMenuItem), "gldi-inside", GINT_TO_POINTER (TRUE)); |
|
801 |
||
802 |
return FALSE; |
|
803 |
}
|
|
804 |
static gboolean _on_deselect_menu_item (GtkWidget* pMenuItem, G_GNUC_UNUSED gpointer data) |
|
805 |
{
|
|
806 |
guint iSidAnimation = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT(pMenuItem), "gldi-animation")); |
|
807 |
if (iSidAnimation != 0) |
|
808 |
g_source_remove (iSidAnimation); |
|
809 |
iSidAnimation = g_timeout_add (dt2, (GSourceFunc)_update_menu_item, pMenuItem); |
|
810 |
g_object_set_data (G_OBJECT(pMenuItem), "gldi-animation", GUINT_TO_POINTER (iSidAnimation)); |
|
811 |
||
812 |
g_object_set_data (G_OBJECT(pMenuItem), "gldi-inside", GINT_TO_POINTER (FALSE)); |
|
813 |
||
814 |
return FALSE; |
|
815 |
}
|
|
816 |
static void _on_destroy_menu_item (GtkWidget* pMenuItem, G_GNUC_UNUSED gpointer data) |
|
817 |
{
|
|
818 |
guint iSidAnimation = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT(pMenuItem), "gldi-animation")); |
|
819 |
if (iSidAnimation != 0) |
|
820 |
{
|
|
821 |
g_source_remove (iSidAnimation); |
|
822 |
g_object_set_data (G_OBJECT(pMenuItem), "gldi-animation", NULL); |
|
823 |
}
|
|
824 |
}
|
|
825 |
#endif
|
|
826 |
||
1.1.35
by Matthieu Baerts
Import upstream version 3.3.0 |
827 |
GtkWidget *gldi_menu_item_new_full (const gchar *cLabel, const gchar *cImage, gboolean bUseMnemonic, GtkIconSize iSize) |
828 |
{
|
|
829 |
if (iSize == 0) |
|
830 |
iSize = GTK_ICON_SIZE_MENU; |
|
831 |
||
832 |
GtkWidget *pMenuItem; |
|
833 |
if (! cImage) |
|
834 |
{
|
|
835 |
if (! cLabel) |
|
1.1.38
by Matthieu Baerts
Import upstream version 3.3.99.beta1.1~20140219~bzr1717 |
836 |
pMenuItem = gtk_menu_item_new (); |
1.1.35
by Matthieu Baerts
Import upstream version 3.3.0 |
837 |
else
|
1.1.38
by Matthieu Baerts
Import upstream version 3.3.99.beta1.1~20140219~bzr1717 |
838 |
pMenuItem = (bUseMnemonic ? gtk_menu_item_new_with_mnemonic (cLabel) : gtk_menu_item_new_with_label (cLabel)); |
1.1.35
by Matthieu Baerts
Import upstream version 3.3.0 |
839 |
}
|
1.1.38
by Matthieu Baerts
Import upstream version 3.3.99.beta1.1~20140219~bzr1717 |
840 |
else
|
841 |
{
|
|
842 |
GtkWidget *image = NULL; |
|
1.1.35
by Matthieu Baerts
Import upstream version 3.3.0 |
843 |
#if (! GTK_CHECK_VERSION (3, 10, 0)) || (CAIRO_DOCK_FORCE_ICON_IN_MENUS == 1)
|
1.1.38
by Matthieu Baerts
Import upstream version 3.3.99.beta1.1~20140219~bzr1717 |
844 |
if (*cImage == '/') |
845 |
{
|
|
846 |
int size; |
|
847 |
gtk_icon_size_lookup (iSize, &size, NULL); |
|
848 |
GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file_at_size (cImage, size, size, NULL); |
|
849 |
image = gtk_image_new_from_pixbuf (pixbuf); |
|
850 |
g_object_unref (pixbuf); |
|
851 |
}
|
|
852 |
else if (*cImage != '\0') |
|
853 |
{
|
|
854 |
#if GTK_CHECK_VERSION (3, 10, 0)
|
|
855 |
image = gtk_image_new_from_icon_name (cImage, iSize); /// actually, this will not work until we replace all the gtk-stock names by standard icon names... which is a PITA, and will be done do later |
|
856 |
#else
|
|
857 |
image = gtk_image_new_from_stock (cImage, iSize); |
|
858 |
#endif
|
|
859 |
}
|
|
860 |
#endif
|
|
861 |
||
862 |
#if GTK_CHECK_VERSION (3, 10, 0)
|
|
863 |
#if (CAIRO_DOCK_FORCE_ICON_IN_MENUS == 1)
|
|
864 |
if (! cLabel) |
|
865 |
pMenuItem = gtk3_image_menu_item_new (); |
|
866 |
else
|
|
867 |
pMenuItem = (bUseMnemonic ? gtk3_image_menu_item_new_with_mnemonic (cLabel) : gtk3_image_menu_item_new_with_label (cLabel)); |
|
868 |
gtk3_image_menu_item_set_image (GTK3_IMAGE_MENU_ITEM (pMenuItem), image); |
|
1.1.35
by Matthieu Baerts
Import upstream version 3.3.0 |
869 |
#else
|
1.1.38
by Matthieu Baerts
Import upstream version 3.3.99.beta1.1~20140219~bzr1717 |
870 |
if (! cLabel) |
871 |
pMenuItem = gtk_menu_item_new (); |
|
872 |
else
|
|
873 |
pMenuItem = (bUseMnemonic ? gtk_menu_item_new_with_mnemonic (cLabel) : gtk_menu_item_new_with_label (cLabel)); |
|
1.1.35
by Matthieu Baerts
Import upstream version 3.3.0 |
874 |
#endif
|
875 |
#else
|
|
1.1.38
by Matthieu Baerts
Import upstream version 3.3.99.beta1.1~20140219~bzr1717 |
876 |
if (! cLabel) |
877 |
pMenuItem = gtk_image_menu_item_new (); |
|
878 |
else
|
|
879 |
pMenuItem = (bUseMnemonic ? gtk_image_menu_item_new_with_mnemonic (cLabel) : gtk_image_menu_item_new_with_label (cLabel)); |
|
880 |
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (pMenuItem), image); |
|
881 |
#if ((CAIRO_DOCK_FORCE_ICON_IN_MENUS == 1) && (GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION >= 16))
|
|
882 |
gtk_image_menu_item_set_always_show_image (GTK_IMAGE_MENU_ITEM (pMenuItem), TRUE); |
|
883 |
#endif
|
|
1.1.35
by Matthieu Baerts
Import upstream version 3.3.0 |
884 |
#endif
|
1.1.38
by Matthieu Baerts
Import upstream version 3.3.99.beta1.1~20140219~bzr1717 |
885 |
}
|
1.1.36
by Matthieu Baerts
Import upstream version 3.3.1 |
886 |
gtk_widget_show_all (pMenuItem); // show immediately, so that the menu-item is realized when the menu is popped up |
887 |
||
1.1.35
by Matthieu Baerts
Import upstream version 3.3.0 |
888 |
return pMenuItem; |
889 |
}
|
|
890 |
||
891 |
||
892 |
void gldi_menu_item_set_image (GtkWidget *pMenuItem, GtkWidget *image) |
|
893 |
{
|
|
894 |
#if GTK_CHECK_VERSION (3, 10, 0)
|
|
895 |
#if (CAIRO_DOCK_FORCE_ICON_IN_MENUS == 1)
|
|
896 |
gtk3_image_menu_item_set_image (GTK3_IMAGE_MENU_ITEM (pMenuItem), image); |
|
897 |
#else
|
|
898 |
g_object_unref (image); |
|
899 |
#endif
|
|
900 |
#else
|
|
901 |
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (pMenuItem), image); |
|
902 |
#if ((CAIRO_DOCK_FORCE_ICON_IN_MENUS == 1) && (GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION >= 16))
|
|
903 |
gtk_image_menu_item_set_always_show_image (GTK_IMAGE_MENU_ITEM (pMenuItem), TRUE); |
|
904 |
#endif
|
|
905 |
#endif
|
|
906 |
}
|
|
907 |
||
908 |
GtkWidget *gldi_menu_item_get_image (GtkWidget *pMenuItem) |
|
909 |
{
|
|
910 |
#if GTK_CHECK_VERSION (3, 10, 0)
|
|
911 |
return gtk3_image_menu_item_get_image (GTK3_IMAGE_MENU_ITEM (pMenuItem)); |
|
912 |
#else
|
|
913 |
return gtk_image_menu_item_get_image (GTK_IMAGE_MENU_ITEM (pMenuItem)); |
|
914 |
#endif
|
|
915 |
}
|
|
916 |
||
917 |
GtkWidget *gldi_menu_item_new_with_action (const gchar *cLabel, const gchar *cImage, GCallback pFunction, gpointer pData) |
|
918 |
{
|
|
919 |
GtkWidget *pMenuItem = gldi_menu_item_new (cLabel, cImage); |
|
920 |
if (pFunction) |
|
921 |
g_signal_connect (G_OBJECT (pMenuItem), "activate", G_CALLBACK (pFunction), pData); |
|
922 |
return pMenuItem; |
|
923 |
}
|
|
924 |
||
925 |
GtkWidget *gldi_menu_item_new_with_submenu (const gchar *cLabel, const gchar *cImage, GtkWidget **pSubMenuPtr) |
|
926 |
{
|
|
927 |
GtkIconSize iSize; |
|
928 |
if (cImage && (*cImage == '/' || *cImage == '\0')) // for icons that are not stock-icons, we choose a bigger size; the reason is that these icons usually don't have a 16x16 version, and don't scale very well to such a small size (most of the time, it's the icon of an application, or the cairo-dock or recent-documents icon (note: for these 2, we could make a small version)). it's a workaround and a better solution may exist ^^ |
|
929 |
iSize = GTK_ICON_SIZE_LARGE_TOOLBAR; |
|
930 |
else
|
|
931 |
iSize = 0; |
|
932 |
GtkWidget *pMenuItem = gldi_menu_item_new_full (cLabel, cImage, FALSE, iSize); |
|
933 |
GtkWidget *pSubMenu = gldi_submenu_new (); |
|
934 |
gtk_menu_item_set_submenu (GTK_MENU_ITEM (pMenuItem), pSubMenu); |
|
935 |
||
936 |
*pSubMenuPtr = pSubMenu; |
|
937 |
return pMenuItem; |
|
938 |
}
|
|
939 |
||
940 |
GtkWidget *gldi_menu_add_item (GtkWidget *pMenu, const gchar *cLabel, const gchar *cImage, GCallback pFunction, gpointer pData) |
|
941 |
{
|
|
942 |
GtkWidget *pMenuItem = gldi_menu_item_new_with_action (cLabel, cImage, pFunction, pData); |
|
943 |
gtk_menu_shell_append (GTK_MENU_SHELL (pMenu), pMenuItem); |
|
944 |
return pMenuItem; |
|
945 |
}
|
|
946 |
||
947 |
GtkWidget *gldi_menu_add_sub_menu_full (GtkWidget *pMenu, const gchar *cLabel, const gchar *cImage, GtkWidget **pMenuItemPtr) |
|
948 |
{
|
|
949 |
GtkWidget *pSubMenu; |
|
950 |
GtkWidget *pMenuItem = gldi_menu_item_new_with_submenu (cLabel, cImage, &pSubMenu); |
|
951 |
gtk_menu_shell_append (GTK_MENU_SHELL (pMenu), pMenuItem); |
|
952 |
if (pMenuItemPtr) |
|
953 |
*pMenuItemPtr = pMenuItem; |
|
954 |
return pSubMenu; |
|
955 |
}
|