1 | | --- pidgin/gtkblist.c 2007-12-07 15:37:11.000000000 +0100 |
2 | | +++ ../pidgin-2.3.1/pidgin/gtkblist.c 2008-02-11 15:59:25.000000000 +0100 |
3 | | @@ -27,6 +27,9 @@ |
4 | | #include "internal.h" |
5 | | #include "pidgin.h" |
6 | | |
7 | | +#include "ige-mac-menu.h" |
8 | | +#include "ige-mac-dock.h" |
9 | | +#include "ige-mac-bundle.h" |
10 | | #include "account.h" |
11 | | #include "connection.h" |
12 | | #include "core.h" |
13 | | @@ -5311,6 +5314,7 @@ |
14 | | pidgin_blist_restore_position(); |
15 | | gtk_widget_show_all(GTK_WIDGET(gtkblist->vbox)); |
16 | | gtk_widget_realize(GTK_WIDGET(gtkblist->window)); |
17 | | + ige_mac_menu_set_menu_bar(GTK_MENU_SHELL(menu)); |
18 | | purple_blist_set_visible(purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/list_visible")); |
19 | | |
20 | | /* start the refresh timer */ |
21 | | --- pidgin/ige-mac-bundle.c 1970-01-01 01:00:00.000000000 +0100 |
22 | | +++ ../pidgin-2.3.1/pidgin/ige-mac-bundle.c 2008-02-11 14:38:28.000000000 +0100 |
23 | | @@ -0,0 +1,377 @@ |
24 | | +/* GTK+ Integration for app bundles. |
25 | | + * |
26 | | + * Copyright (C) 2007-2008 Imendio AB |
27 | | + * |
28 | | + * This library is free software; you can redistribute it and/or |
29 | | + * modify it under the terms of the GNU Lesser General Public |
30 | | + * License as published by the Free Software Foundation; version 2.1 |
31 | | + * of the License. |
32 | | + * |
33 | | + * This library is distributed in the hope that it will be useful, |
34 | | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
35 | | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
36 | | + * Lesser General Public License for more details. |
37 | | + * |
38 | | + * You should have received a copy of the GNU Lesser General Public |
39 | | + * License along with this library; if not, write to the |
40 | | + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
41 | | + * Boston, MA 02111-1307, USA. |
42 | | + */ |
43 | | + |
44 | | +/* TODO: Add command line parsing and remove any |
45 | | + * -psn_... arguments? |
46 | | + */ |
47 | | + |
48 | | +#include <gtk/gtk.h> |
49 | | +#include <Carbon/Carbon.h> |
50 | | + |
51 | | +#include "ige-mac-bundle.h" |
52 | | + |
53 | | +typedef struct IgeMacBundlePriv IgeMacBundlePriv; |
54 | | + |
55 | | +struct IgeMacBundlePriv { |
56 | | + CFBundleRef cf_bundle; |
57 | | + gchar *path; |
58 | | + gchar *id; |
59 | | + gchar *datadir; |
60 | | + gchar *localedir; |
61 | | + UInt32 type; |
62 | | + UInt32 creator; |
63 | | +}; |
64 | | + |
65 | | +static void mac_bundle_finalize (GObject *object); |
66 | | +static gchar *cf_string_to_utf8 (CFStringRef str); |
67 | | +static void mac_bundle_set_environment_value (IgeMacBundle *bundle, |
68 | | + const gchar *key, |
69 | | + const gchar *value); |
70 | | + |
71 | | +static IgeMacBundle *global_bundle; |
72 | | + |
73 | | +G_DEFINE_TYPE (IgeMacBundle, ige_mac_bundle, G_TYPE_OBJECT) |
74 | | + |
75 | | +#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), IGE_TYPE_MAC_BUNDLE, IgeMacBundlePriv)) |
76 | | + |
77 | | +static void |
78 | | +ige_mac_bundle_class_init (IgeMacBundleClass *class) |
79 | | +{ |
80 | | + GObjectClass *object_class = G_OBJECT_CLASS (class); |
81 | | + |
82 | | + object_class->finalize = mac_bundle_finalize; |
83 | | + |
84 | | + g_type_class_add_private (object_class, sizeof (IgeMacBundlePriv)); |
85 | | +} |
86 | | + |
87 | | +static void |
88 | | +ige_mac_bundle_init (IgeMacBundle *bundle) |
89 | | +{ |
90 | | + IgeMacBundlePriv *priv = GET_PRIV (bundle); |
91 | | + CFURLRef cf_url; |
92 | | + CFStringRef cf_string; |
93 | | + CFDictionaryRef cf_dict; |
94 | | + |
95 | | + priv->cf_bundle = CFBundleGetMainBundle (); |
96 | | + if (!priv->cf_bundle) |
97 | | + return; |
98 | | + |
99 | | + CFRetain (priv->cf_bundle); |
100 | | + |
101 | | + /* Bundle or binary location. */ |
102 | | + cf_url = CFBundleCopyBundleURL (priv->cf_bundle); |
103 | | + cf_string = CFURLCopyFileSystemPath (cf_url, kCFURLPOSIXPathStyle); |
104 | | + priv->path = cf_string_to_utf8 (cf_string); |
105 | | + CFRelease (cf_string); |
106 | | + CFRelease (cf_url); |
107 | | + |
108 | | + /* Package info. */ |
109 | | + CFBundleGetPackageInfo (priv->cf_bundle, &priv->type, &priv->creator); |
110 | | + |
111 | | + /* Identifier. */ |
112 | | + cf_string = CFBundleGetIdentifier (priv->cf_bundle); |
113 | | + if (cf_string) |
114 | | + priv->id = cf_string_to_utf8 (cf_string); |
115 | | + |
116 | | + /* Get non-localized keys. */ |
117 | | + cf_dict = CFBundleGetInfoDictionary (priv->cf_bundle); |
118 | | + if (cf_dict) |
119 | | + { |
120 | | + CFDictionaryRef env_dict; |
121 | | + CFIndex n_keys, i; |
122 | | + const void **keys; |
123 | | + const void **values; |
124 | | + |
125 | | + env_dict = (CFDictionaryRef) CFDictionaryGetValue (cf_dict, CFSTR ("LSEnvironment")); |
126 | | + if (env_dict) |
127 | | + { |
128 | | + n_keys = CFDictionaryGetCount (env_dict); |
129 | | + |
130 | | + keys = (const void **) g_new (void *, n_keys); |
131 | | + values = (const void **) g_new (void *, n_keys); |
132 | | + |
133 | | + CFDictionaryGetKeysAndValues (env_dict, keys, values); |
134 | | + |
135 | | + for (i = 0; i < n_keys; i++) |
136 | | + { |
137 | | + gchar *key; |
138 | | + gchar *value; |
139 | | + |
140 | | + key = cf_string_to_utf8 ((CFStringRef) keys[i]); |
141 | | + value = cf_string_to_utf8 ((CFStringRef) values[i]); |
142 | | + |
143 | | + mac_bundle_set_environment_value (bundle, key, value); |
144 | | + |
145 | | + g_free (key); |
146 | | + g_free (value); |
147 | | + } |
148 | | + |
149 | | + g_free (keys); |
150 | | + g_free (values); |
151 | | + } |
152 | | + } |
153 | | +} |
154 | | + |
155 | | +static void |
156 | | +mac_bundle_finalize (GObject *object) |
157 | | +{ |
158 | | + IgeMacBundlePriv *priv; |
159 | | + |
160 | | + priv = GET_PRIV (object); |
161 | | + |
162 | | + g_free (priv->path); |
163 | | + g_free (priv->id); |
164 | | + g_free (priv->datadir); |
165 | | + g_free (priv->localedir); |
166 | | + |
167 | | + CFRelease (priv->cf_bundle); |
168 | | + |
169 | | + G_OBJECT_CLASS (ige_mac_bundle_parent_class)->finalize (object); |
170 | | +} |
171 | | + |
172 | | +IgeMacBundle * |
173 | | +ige_mac_bundle_new (void) |
174 | | +{ |
175 | | + return g_object_new (IGE_TYPE_MAC_BUNDLE, NULL); |
176 | | +} |
177 | | + |
178 | | +IgeMacBundle * |
179 | | +ige_mac_bundle_get_default (void) |
180 | | +{ |
181 | | + if (!global_bundle) |
182 | | + global_bundle = ige_mac_bundle_new (); |
183 | | + |
184 | | + return global_bundle; |
185 | | +} |
186 | | + |
187 | | +static gchar * |
188 | | +cf_string_to_utf8 (CFStringRef str) |
189 | | +{ |
190 | | + CFIndex len; |
191 | | + gchar *ret; |
192 | | + |
193 | | + len = CFStringGetMaximumSizeForEncoding (CFStringGetLength (str), |
194 | | + kCFStringEncodingUTF8) + 1; |
195 | | + |
196 | | + ret = g_malloc (len); |
197 | | + ret[len] = '\0'; |
198 | | + |
199 | | + if (CFStringGetCString (str, ret, len, kCFStringEncodingUTF8)) |
200 | | + return ret; |
201 | | + |
202 | | + g_free (ret); |
203 | | + return NULL; |
204 | | +} |
205 | | + |
206 | | +static void |
207 | | +mac_bundle_set_environment_value (IgeMacBundle *bundle, |
208 | | + const gchar *key, |
209 | | + const gchar *value) |
210 | | +{ |
211 | | + IgeMacBundlePriv *priv = GET_PRIV (bundle); |
212 | | + GRegex *regex; |
213 | | + gchar *new_value; |
214 | | + |
215 | | + regex = g_regex_new ("@executable_path", 0, 0, NULL); |
216 | | + |
217 | | + new_value = g_regex_replace_literal (regex, |
218 | | + value, |
219 | | + -1, |
220 | | + 0, |
221 | | + priv->path, |
222 | | + 0, NULL); |
223 | | + |
224 | | + g_print ("%s => %s\n", value, new_value); |
225 | | + |
226 | | + if (new_value) |
227 | | + value = new_value; |
228 | | + |
229 | | + |
230 | | + g_setenv (key, value, TRUE); |
231 | | + |
232 | | + g_free (new_value); |
233 | | + g_regex_unref (regex); |
234 | | +} |
235 | | + |
236 | | +const gchar * |
237 | | +ige_mac_bundle_get_id (IgeMacBundle *bundle) |
238 | | +{ |
239 | | + IgeMacBundlePriv *priv = GET_PRIV (bundle); |
240 | | + |
241 | | + return priv->id; |
242 | | +} |
243 | | + |
244 | | +const gchar * |
245 | | +ige_mac_bundle_get_path (IgeMacBundle *bundle) |
246 | | +{ |
247 | | + IgeMacBundlePriv *priv = GET_PRIV (bundle); |
248 | | + |
249 | | + return priv->path; |
250 | | +} |
251 | | + |
252 | | +gboolean |
253 | | +ige_mac_bundle_get_is_app_bundle (IgeMacBundle *bundle) |
254 | | +{ |
255 | | + IgeMacBundlePriv *priv = GET_PRIV (bundle); |
256 | | + |
257 | | + return (priv->type == 'APPL' && priv->id); |
258 | | +} |
259 | | + |
260 | | +const gchar * |
261 | | +ige_mac_bundle_get_datadir (IgeMacBundle *bundle) |
262 | | +{ |
263 | | + IgeMacBundlePriv *priv = GET_PRIV (bundle); |
264 | | + |
265 | | + if (!ige_mac_bundle_get_is_app_bundle (bundle)) |
266 | | + return NULL; |
267 | | + |
268 | | + if (!priv->datadir) |
269 | | + { |
270 | | + priv->datadir = g_build_filename (priv->path, |
271 | | + "Contents", |
272 | | + "Resources", |
273 | | + "share", |
274 | | + NULL); |
275 | | + } |
276 | | + |
277 | | + return priv->datadir; |
278 | | +} |
279 | | + |
280 | | +const gchar * |
281 | | +ige_mac_bundle_get_localedir (IgeMacBundle *bundle) |
282 | | +{ |
283 | | + IgeMacBundlePriv *priv = GET_PRIV (bundle); |
284 | | + |
285 | | + if (!ige_mac_bundle_get_is_app_bundle (bundle)) |
286 | | + return NULL; |
287 | | + |
288 | | + if (!priv->localedir) |
289 | | + { |
290 | | + priv->localedir = g_build_filename (priv->path, |
291 | | + "Contents", |
292 | | + "Resources", |
293 | | + "share", |
294 | | + "locale", |
295 | | + NULL); |
296 | | + } |
297 | | + |
298 | | + return priv->localedir; |
299 | | +} |
300 | | + |
301 | | +void |
302 | | +ige_mac_bundle_setup_environment (IgeMacBundle *bundle) |
303 | | +{ |
304 | | + IgeMacBundlePriv *priv = GET_PRIV (bundle); |
305 | | + gchar *resources; |
306 | | + gchar *share, *lib, *etc; |
307 | | + gchar *etc_xdg, *etc_immodules, *etc_gtkrc; |
308 | | + gchar *etc_pixbuf, *etc_pangorc; |
309 | | + const gchar *rc_files; |
310 | | + |
311 | | + if (!ige_mac_bundle_get_is_app_bundle (bundle)) |
312 | | + return; |
313 | | + |
314 | | + resources = g_build_filename (priv->path, |
315 | | + "Contents", |
316 | | + "Resources", |
317 | | + NULL); |
318 | | + |
319 | | + share = g_build_filename (resources, "share", NULL); |
320 | | + lib = g_build_filename (resources, "lib", NULL); |
321 | | + etc = g_build_filename (resources, "etc", NULL); |
322 | | + etc_xdg = g_build_filename (etc, "xdg", NULL); |
323 | | + etc_immodules = g_build_filename (etc, "gtk-2.0", "gtk.immodules", NULL); |
324 | | + etc_gtkrc = g_build_filename (etc, "gtk-2.0", "gtkrc", NULL); |
325 | | + etc_pixbuf = g_build_filename (etc, "gtk-2.0", "gdk-pixbuf.loaders", NULL); |
326 | | + etc_pangorc = g_build_filename (etc, "pango", "pangorc", NULL); |
327 | | + |
328 | | + g_setenv ("XDG_CONFIG_DIRS", etc_xdg, TRUE); |
329 | | + g_setenv ("XDG_DATA_DIRS", share, TRUE); |
330 | | + g_setenv ("GTK_DATA_PREFIX", share, TRUE); |
331 | | + g_setenv ("GTK_EXE_PREFIX", resources, TRUE); |
332 | | + g_setenv ("GTK_PATH_PREFIX", resources, TRUE); |
333 | | + |
334 | | + /* Append the normal gtkrc path to allow customizing the theme from |
335 | | + * Info.plist. |
336 | | + */ |
337 | | + rc_files = g_getenv ("GTK2_RC_FILES"); |
338 | | + if (rc_files) |
339 | | + { |
340 | | + gchar *tmp; |
341 | | + |
342 | | + tmp = g_strdup_printf ("%s:%s", rc_files, etc_gtkrc); |
343 | | + g_setenv ("GTK2_RC_FILES", tmp, TRUE); |
344 | | + g_free (tmp); |
345 | | + } |
346 | | + else |
347 | | + g_setenv ("GTK2_RC_FILES", etc_gtkrc, TRUE); |
348 | | + |
349 | | + g_setenv ("GTK_IM_MODULE_FILE", etc_immodules, TRUE); |
350 | | + g_setenv ("GDK_PIXBUF_MODULE_FILE", etc_pixbuf, TRUE); |
351 | | + g_setenv ("PANGO_RC_FILE", etc_pangorc, TRUE); |
352 | | + g_setenv ("CHARSETALIASDIR", lib, TRUE); |
353 | | + |
354 | | + // could add FONTCONFIG_FILE |
355 | | + |
356 | | + /*export LANG="\`grep \"\\\`defaults read .GlobalPreferences AppleCollationOrder \ |
357 | | + 2>&1\\\`_\" /usr/share/locale/locale.alias | tail -n1 | sed 's/\./ /' | \ |
358 | | + awk '{print \$2}'\`.UTF-8"*/ |
359 | | + |
360 | | + g_free (share); |
361 | | + g_free (lib); |
362 | | + g_free (etc); |
363 | | + g_free (etc_xdg); |
364 | | + g_free (etc_immodules); |
365 | | + g_free (etc_gtkrc); |
366 | | + g_free (etc_pixbuf); |
367 | | + g_free (etc_pangorc); |
368 | | +} |
369 | | + |
370 | | +gchar * |
371 | | +ige_mac_bundle_get_resource_path (IgeMacBundle *bundle, |
372 | | + const gchar *name, |
373 | | + const gchar *type, |
374 | | + const gchar *subdir) |
375 | | +{ |
376 | | + IgeMacBundlePriv *priv; |
377 | | + CFURLRef cf_url; |
378 | | + CFStringRef cf_string; |
379 | | + gchar *path; |
380 | | + |
381 | | + if (!bundle) |
382 | | + bundle = ige_mac_bundle_get_default (); |
383 | | + |
384 | | + priv = GET_PRIV (bundle); |
385 | | + |
386 | | + if (!priv->cf_bundle) |
387 | | + return NULL; |
388 | | + |
389 | | + // FIXME: Look at using CFURLGetFileSystemRepresentation (urlcf_, true, (UInt8*)outPathName, 256) |
390 | | + |
391 | | + // FIXME: crate real cfstring here... |
392 | | + cf_url = CFBundleCopyResourceURL (priv->cf_bundle, |
393 | | + CFSTR("name"), CFSTR("type"), CFSTR("subdir")); |
394 | | + cf_string = CFURLCopyFileSystemPath (cf_url, kCFURLPOSIXPathStyle); |
395 | | + path = cf_string_to_utf8 (cf_string); |
396 | | + CFRelease (cf_string); |
397 | | + CFRelease (cf_url); |
398 | | + |
399 | | + return path; |
400 | | +} |
401 | | --- pidgin/ige-mac-bundle.h 1970-01-01 01:00:00.000000000 +0100 |
402 | | +++ ../pidgin-2.3.1/pidgin/ige-mac-bundle.h 2008-02-11 14:38:30.000000000 +0100 |
403 | | @@ -0,0 +1,62 @@ |
404 | | +/* GTK+ Integration for app bundles. |
405 | | + * |
406 | | + * Copyright (C) 2007-2008 Imendio AB |
407 | | + * |
408 | | + * This library is free software; you can redistribute it and/or |
409 | | + * modify it under the terms of the GNU Lesser General Public |
410 | | + * License as published by the Free Software Foundation; version 2.1 |
411 | | + * of the License. |
412 | | + * |
413 | | + * This library is distributed in the hope that it will be useful, |
414 | | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
415 | | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
416 | | + * Lesser General Public License for more details. |
417 | | + * |
418 | | + * You should have received a copy of the GNU Lesser General Public |
419 | | + * License along with this library; if not, write to the |
420 | | + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
421 | | + * Boston, MA 02111-1307, USA. |
422 | | + */ |
423 | | + |
424 | | +#ifndef __IGE_MAC_BUNDLE_H__ |
425 | | +#define __IGE_MAC_BUNDLE_H__ |
426 | | + |
427 | | +#include <glib-object.h> |
428 | | + |
429 | | +G_BEGIN_DECLS |
430 | | + |
431 | | +#define IGE_TYPE_MAC_BUNDLE (ige_mac_bundle_get_type ()) |
432 | | +#define IGE_MAC_BUNDLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), IGE_TYPE_MAC_BUNDLE, IgeMacBundle)) |
433 | | +#define IGE_MAC_BUNDLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), IGE_TYPE_MAC_BUNDLE, IgeMacBundleClass)) |
434 | | +#define IGE_IS_MAC_BUNDLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IGE_TYPE_MAC_BUNDLE)) |
435 | | +#define IGE_IS_MAC_BUNDLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), IGE_TYPE_MAC_BUNDLE)) |
436 | | +#define IGE_MAC_BUNDLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), IGE_TYPE_MAC_BUNDLE, IgeMacBundleClass)) |
437 | | + |
438 | | +typedef struct _IgeMacBundle IgeMacBundle; |
439 | | +typedef struct _IgeMacBundleClass IgeMacBundleClass; |
440 | | + |
441 | | +struct _IgeMacBundle { |
442 | | + GObject parent_instance; |
443 | | +}; |
444 | | + |
445 | | +struct _IgeMacBundleClass { |
446 | | + GObjectClass parent_class; |
447 | | +}; |
448 | | + |
449 | | +GType ige_mac_bundle_get_type (void); |
450 | | +IgeMacBundle *ige_mac_bundle_new (void); |
451 | | +IgeMacBundle *ige_mac_bundle_get_default (void); |
452 | | +void ige_mac_bundle_setup_environment (IgeMacBundle *bundle); |
453 | | +const gchar * ige_mac_bundle_get_id (IgeMacBundle *bundle); |
454 | | +const gchar * ige_mac_bundle_get_path (IgeMacBundle *bundle); |
455 | | +gboolean ige_mac_bundle_get_is_app_bundle (IgeMacBundle *bundle); |
456 | | +const gchar * ige_mac_bundle_get_localedir (IgeMacBundle *bundle); |
457 | | +const gchar * ige_mac_bundle_get_datadir (IgeMacBundle *bundle); |
458 | | +gchar * ige_mac_bundle_get_resource_path (IgeMacBundle *bundle, |
459 | | + const gchar *name, |
460 | | + const gchar *type, |
461 | | + const gchar *subdir); |
462 | | + |
463 | | +G_END_DECLS |
464 | | + |
465 | | +#endif /* __IGE_MAC_BUNDLE_H__ */ |
466 | | --- pidgin/ige-mac-dock.c 1970-01-01 01:00:00.000000000 +0100 |
467 | | +++ ../pidgin-2.3.1/pidgin/ige-mac-dock.c 2008-02-11 14:38:28.000000000 +0100 |
468 | | @@ -0,0 +1,449 @@ |
469 | | +/* GTK+ Integration for the Mac OS X Dock. |
470 | | + * |
471 | | + * Copyright (C) 2007-2008 Imendio AB |
472 | | + * |
473 | | + * This library is free software; you can redistribute it and/or |
474 | | + * modify it under the terms of the GNU Lesser General Public |
475 | | + * License as published by the Free Software Foundation; version 2.1 |
476 | | + * of the License. |
477 | | + * |
478 | | + * This library is distributed in the hope that it will be useful, |
479 | | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
480 | | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
481 | | + * Lesser General Public License for more details. |
482 | | + * |
483 | | + * You should have received a copy of the GNU Lesser General Public |
484 | | + * License along with this library; if not, write to the |
485 | | + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
486 | | + * Boston, MA 02111-1307, USA. |
487 | | + */ |
488 | | + |
489 | | +/* FIXME: Add example like this to docs for the open documents stuff: |
490 | | + |
491 | | + <key>CFBundleDocumentTypes</key> |
492 | | + <array> |
493 | | + <dict> |
494 | | + <key>CFBundleTypeExtensions</key> |
495 | | + <array> |
496 | | + <string>txt</string> |
497 | | + </array> |
498 | | + </dict> |
499 | | + </array> |
500 | | + |
501 | | +*/ |
502 | | + |
503 | | +#include <config.h> |
504 | | +#include <Carbon/Carbon.h> |
505 | | +#include <sys/param.h> |
506 | | +#include <gtk/gtk.h> |
507 | | + |
508 | | +#include "ige-mac-dock.h" |
509 | | +#include "ige-mac-bundle.h" |
510 | | +#include "ige-mac-image-utils.h" |
511 | | + |
512 | | +enum { |
513 | | + CLICKED, |
514 | | + QUIT_ACTIVATE, |
515 | | + OPEN_DOCUMENTS, |
516 | | + LAST_SIGNAL |
517 | | +}; |
518 | | + |
519 | | +static guint signals[LAST_SIGNAL] = { 0 }; |
520 | | + |
521 | | +typedef struct IgeMacDockPriv IgeMacDockPriv; |
522 | | + |
523 | | +struct IgeMacDockPriv { |
524 | | + glong id; |
525 | | +}; |
526 | | + |
527 | | +static void mac_dock_finalize (GObject *object); |
528 | | +static OSErr mac_dock_handle_quit (const AppleEvent *inAppleEvent, |
529 | | + AppleEvent *outAppleEvent, |
530 | | + long inHandlerRefcon); |
531 | | +static OSErr mac_dock_handle_open_documents (const AppleEvent *inAppleEvent, |
532 | | + AppleEvent *outAppleEvent, |
533 | | + long inHandlerRefcon); |
534 | | +static OSErr mac_dock_handle_open_application (const AppleEvent *inAppleEvent, |
535 | | + AppleEvent *outAppleEvent, |
536 | | + long inHandlerRefcon); |
537 | | +static OSErr mac_dock_handle_reopen_application (const AppleEvent *inAppleEvent, |
538 | | + AppleEvent *outAppleEvent, |
539 | | + long inHandlerRefcon); |
540 | | + |
541 | | +G_DEFINE_TYPE (IgeMacDock, ige_mac_dock, G_TYPE_OBJECT) |
542 | | + |
543 | | +#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), IGE_TYPE_MAC_DOCK, IgeMacDockPriv)) |
544 | | + |
545 | | +static GList *handlers; |
546 | | +static IgeMacDock *global_dock; |
547 | | + |
548 | | +static void |
549 | | +ige_mac_dock_class_init (IgeMacDockClass *class) |
550 | | +{ |
551 | | + GObjectClass *object_class = G_OBJECT_CLASS (class); |
552 | | + |
553 | | + object_class->finalize = mac_dock_finalize; |
554 | | + |
555 | | + signals[CLICKED] = |
556 | | + g_signal_new ("clicked", |
557 | | + IGE_TYPE_MAC_DOCK, |
558 | | + G_SIGNAL_RUN_LAST, |
559 | | + 0, |
560 | | + NULL, NULL, |
561 | | + g_cclosure_marshal_VOID__VOID, |
562 | | + G_TYPE_NONE, 0); |
563 | | + |
564 | | + /* FIXME: Need marshaller. */ |
565 | | + signals[OPEN_DOCUMENTS] = |
566 | | + g_signal_new ("open-documents", |
567 | | + IGE_TYPE_MAC_DOCK, |
568 | | + G_SIGNAL_RUN_LAST, |
569 | | + 0, |
570 | | + NULL, NULL, |
571 | | + g_cclosure_marshal_VOID__VOID, |
572 | | + G_TYPE_NONE, 0); |
573 | | + |
574 | | + signals[QUIT_ACTIVATE] = |
575 | | + g_signal_new ("quit-activate", |
576 | | + IGE_TYPE_MAC_DOCK, |
577 | | + G_SIGNAL_RUN_LAST, |
578 | | + 0, |
579 | | + NULL, NULL, |
580 | | + g_cclosure_marshal_VOID__VOID, |
581 | | + G_TYPE_NONE, 0); |
582 | | + |
583 | | + g_type_class_add_private (object_class, sizeof (IgeMacDockPriv)); |
584 | | + |
585 | | + /* FIXME: Just testing with triggering Carbon to take control over |
586 | | + * the dock menu events instead of Cocoa (which happens when the |
587 | | + * sharedApplication is created) to get custom dock menu working |
588 | | + * with carbon menu code. However, doing this makes the dock icon |
589 | | + * not get a "running triangle". |
590 | | + */ |
591 | | +#if 0 |
592 | | + EventTypeSpec kFakeEventList[] = { { INT_MAX, INT_MAX } }; |
593 | | + EventRef event; |
594 | | + |
595 | | + ReceiveNextEvent (GetEventTypeCount (kFakeEventList), |
596 | | + kFakeEventList, |
597 | | + kEventDurationNoWait, false, |
598 | | + &event); |
599 | | +#endif |
600 | | +} |
601 | | + |
602 | | +static void |
603 | | +ige_mac_dock_init (IgeMacDock *dock) |
604 | | +{ |
605 | | + IgeMacDockPriv *priv = GET_PRIV (dock); |
606 | | + static glong id; |
607 | | + |
608 | | + priv->id = ++id; |
609 | | + |
610 | | + handlers = g_list_prepend (handlers, dock); |
611 | | + |
612 | | + AEInstallEventHandler (kCoreEventClass, kAEQuitApplication, |
613 | | + mac_dock_handle_quit, |
614 | | + priv->id, true); |
615 | | + AEInstallEventHandler (kCoreEventClass, kAEOpenApplication, |
616 | | + mac_dock_handle_open_application, |
617 | | + priv->id, true); |
618 | | + AEInstallEventHandler (kCoreEventClass, kAEReopenApplication, |
619 | | + mac_dock_handle_reopen_application, |
620 | | + priv->id, true); |
621 | | + AEInstallEventHandler (kCoreEventClass, kAEOpenDocuments, |
622 | | + mac_dock_handle_open_documents, |
623 | | + priv->id, true); |
624 | | +} |
625 | | + |
626 | | +static void |
627 | | +mac_dock_finalize (GObject *object) |
628 | | +{ |
629 | | + IgeMacDockPriv *priv; |
630 | | + |
631 | | + priv = GET_PRIV (object); |
632 | | + |
633 | | + AERemoveEventHandler (kCoreEventClass, kAEQuitApplication, |
634 | | + mac_dock_handle_quit, false); |
635 | | + AERemoveEventHandler (kCoreEventClass, kAEReopenApplication, |
636 | | + mac_dock_handle_reopen_application, false); |
637 | | + AERemoveEventHandler (kCoreEventClass, kAEOpenApplication, |
638 | | + mac_dock_handle_open_application, false); |
639 | | + AERemoveEventHandler (kCoreEventClass, kAEOpenDocuments, |
640 | | + mac_dock_handle_open_documents, false); |
641 | | + |
642 | | + handlers = g_list_remove (handlers, object); |
643 | | + |
644 | | + G_OBJECT_CLASS (ige_mac_dock_parent_class)->finalize (object); |
645 | | +} |
646 | | + |
647 | | +IgeMacDock * |
648 | | +ige_mac_dock_new (void) |
649 | | +{ |
650 | | + return g_object_new (IGE_TYPE_MAC_DOCK, NULL); |
651 | | +} |
652 | | + |
653 | | +IgeMacDock * |
654 | | +ige_mac_dock_get_default (void) |
655 | | +{ |
656 | | + if (!global_dock) |
657 | | + global_dock = g_object_new (IGE_TYPE_MAC_DOCK, NULL); |
658 | | + |
659 | | + return global_dock; |
660 | | +} |
661 | | + |
662 | | +static IgeMacDock * |
663 | | +mac_dock_get_from_id (gulong id) |
664 | | +{ |
665 | | + GList *l; |
666 | | + IgeMacDock *dock = NULL; |
667 | | + |
668 | | + for (l = handlers; l; l = l->next) |
669 | | + { |
670 | | + dock = l->data; |
671 | | + if (GET_PRIV (dock)->id == id) |
672 | | + break; |
673 | | + |
674 | | + dock = NULL; |
675 | | + } |
676 | | + |
677 | | + return dock; |
678 | | +} |
679 | | + |
680 | | +static OSErr |
681 | | +mac_dock_handle_quit (const AppleEvent *inAppleEvent, |
682 | | + AppleEvent *outAppleEvent, |
683 | | + long inHandlerRefcon) |
684 | | +{ |
685 | | + IgeMacDock *dock; |
686 | | + |
687 | | + dock = mac_dock_get_from_id (inHandlerRefcon); |
688 | | + |
689 | | + if (dock) |
690 | | + g_signal_emit (dock, signals[QUIT_ACTIVATE], 0); |
691 | | + |
692 | | + return noErr; |
693 | | +} |
694 | | + |
695 | | +static OSErr |
696 | | +mac_dock_handle_open_application (const AppleEvent *inAppleEvent, |
697 | | + AppleEvent *outAppleEvent, |
698 | | + long inHandlerRefCon) |
699 | | +{ |
700 | | + g_print ("FIXME: mac_dock_handle_open_application\n"); |
701 | | + |
702 | | + return noErr; |
703 | | +} |
704 | | + |
705 | | +static OSErr |
706 | | +mac_dock_handle_reopen_application (const AppleEvent *inAppleEvent, |
707 | | + AppleEvent *outAppleEvent, |
708 | | + long inHandlerRefcon) |
709 | | +{ |
710 | | + IgeMacDock *dock; |
711 | | + |
712 | | + dock = mac_dock_get_from_id (inHandlerRefcon); |
713 | | + |
714 | | + if (dock) |
715 | | + g_signal_emit (dock, signals[CLICKED], 0); |
716 | | + |
717 | | + return noErr; |
718 | | +} |
719 | | + |
720 | | +static OSErr |
721 | | +mac_dock_handle_open_documents (const AppleEvent *inAppleEvent, |
722 | | + AppleEvent *outAppleEvent, |
723 | | + long inHandlerRefCon) |
724 | | +{ |
725 | | + IgeMacDock *dock; |
726 | | + OSStatus status; |
727 | | + AEDescList documents; |
728 | | + gchar path[MAXPATHLEN]; |
729 | | + |
730 | | + g_print ("FIXME: mac_dock_handle_open_documents\n"); |
731 | | + |
732 | | + dock = mac_dock_get_from_id (inHandlerRefCon); |
733 | | + |
734 | | + status = AEGetParamDesc (inAppleEvent, |
735 | | + keyDirectObject, typeAEList, |
736 | | + &documents); |
737 | | + if (status == noErr) |
738 | | + { |
739 | | + long count = 0; |
740 | | + int i; |
741 | | + |
742 | | + AECountItems (&documents, &count); |
743 | | + |
744 | | + for (i = 0; i < count; i++) |
745 | | + { |
746 | | + FSRef ref; |
747 | | + |
748 | | + status = AEGetNthPtr (&documents, i + 1, typeFSRef, |
749 | | + 0, 0, &ref, sizeof (ref), |
750 | | + 0); |
751 | | + if (status != noErr) |
752 | | + continue; |
753 | | + |
754 | | + FSRefMakePath (&ref, path, MAXPATHLEN); |
755 | | + |
756 | | + /* FIXME: Add to a list, then emit the open-documents |
757 | | + * signal. |
758 | | + */ |
759 | | + g_print (" %s\n", path); |
760 | | + } |
761 | | + } |
762 | | + |
763 | | + return status; |
764 | | +} |
765 | | + |
766 | | +void |
767 | | +ige_mac_dock_set_icon_from_pixbuf (IgeMacDock *dock, |
768 | | + GdkPixbuf *pixbuf) |
769 | | +{ |
770 | | + if (!pixbuf) |
771 | | + RestoreApplicationDockTileImage (); |
772 | | + else |
773 | | + { |
774 | | + CGImageRef image; |
775 | | + |
776 | | + image = ige_mac_image_from_pixbuf (pixbuf); |
777 | | + SetApplicationDockTileImage (image); |
778 | | + CGImageRelease (image); |
779 | | + } |
780 | | +} |
781 | | + |
782 | | +void |
783 | | +ige_mac_dock_set_icon_from_resource (IgeMacDock *dock, |
784 | | + IgeMacBundle *bundle, |
785 | | + const gchar *name, |
786 | | + const gchar *type, |
787 | | + const gchar *subdir) |
788 | | +{ |
789 | | + gchar *path; |
790 | | + |
791 | | + g_return_if_fail (IGE_IS_MAC_DOCK (dock)); |
792 | | + g_return_if_fail (name != NULL); |
793 | | + |
794 | | + path = ige_mac_bundle_get_resource_path (bundle, name, type, subdir); |
795 | | + if (path) |
796 | | + { |
797 | | + GdkPixbuf *pixbuf; |
798 | | + |
799 | | + pixbuf = gdk_pixbuf_new_from_file (path, NULL); |
800 | | + if (pixbuf) |
801 | | + { |
802 | | + ige_mac_dock_set_icon_from_pixbuf (dock, pixbuf); |
803 | | + g_object_unref (pixbuf); |
804 | | + } |
805 | | + |
806 | | + g_free (path); |
807 | | + } |
808 | | +} |
809 | | + |
810 | | +void |
811 | | +ige_mac_dock_set_overlay_from_pixbuf (IgeMacDock *dock, |
812 | | + GdkPixbuf *pixbuf) |
813 | | +{ |
814 | | + CGImageRef image; |
815 | | + |
816 | | + g_return_if_fail (IGE_IS_MAC_DOCK (dock)); |
817 | | + g_return_if_fail (GDK_IS_PIXBUF (pixbuf)); |
818 | | + |
819 | | + image = ige_mac_image_from_pixbuf (pixbuf); |
820 | | + OverlayApplicationDockTileImage (image); |
821 | | + CGImageRelease (image); |
822 | | +} |
823 | | + |
824 | | +void |
825 | | +ige_mac_dock_set_overlay_from_resource (IgeMacDock *dock, |
826 | | + IgeMacBundle *bundle, |
827 | | + const gchar *name, |
828 | | + const gchar *type, |
829 | | + const gchar *subdir) |
830 | | +{ |
831 | | + gchar *path; |
832 | | + |
833 | | + g_return_if_fail (IGE_IS_MAC_DOCK (dock)); |
834 | | + g_return_if_fail (name != NULL); |
835 | | + |
836 | | + path = ige_mac_bundle_get_resource_path (bundle, name, type, subdir); |
837 | | + if (path) |
838 | | + { |
839 | | + GdkPixbuf *pixbuf; |
840 | | + |
841 | | + pixbuf = gdk_pixbuf_new_from_file (path, NULL); |
842 | | + if (pixbuf) |
843 | | + { |
844 | | + ige_mac_dock_set_overlay_from_pixbuf (dock, pixbuf); |
845 | | + g_object_unref (pixbuf); |
846 | | + } |
847 | | + |
848 | | + g_free (path); |
849 | | + } |
850 | | +} |
851 | | + |
852 | | +struct _IgeMacAttentionRequest { |
853 | | + NMRec nm_request; |
854 | | + guint timeout_id; |
855 | | + gboolean is_cancelled; |
856 | | +}; |
857 | | + |
858 | | +static gboolean |
859 | | +mac_dock_attention_cb (IgeMacAttentionRequest *request) |
860 | | +{ |
861 | | + request->timeout_id = 0; |
862 | | + request->is_cancelled = TRUE; |
863 | | + |
864 | | + NMRemove (&request->nm_request); |
865 | | + |
866 | | + return FALSE; |
867 | | +} |
868 | | + |
869 | | + |
870 | | +/* FIXME: Add listener for "application activated" and cancel any |
871 | | + * requests. |
872 | | + */ |
873 | | +IgeMacAttentionRequest * |
874 | | +ige_mac_dock_attention_request (IgeMacDock *dock, |
875 | | + IgeMacAttentionType type) |
876 | | +{ |
877 | | + IgeMacAttentionRequest *request; |
878 | | + |
879 | | + request = g_new0 (IgeMacAttentionRequest, 1); |
880 | | + |
881 | | + request->nm_request.nmMark = 1; |
882 | | + request->nm_request.qType = nmType; |
883 | | + |
884 | | + if (NMInstall (&request->nm_request) != noErr) |
885 | | + { |
886 | | + g_free (request); |
887 | | + return NULL; |
888 | | + } |
889 | | + |
890 | | + if (type == IGE_MAC_ATTENTION_INFO) |
891 | | + request->timeout_id = gdk_threads_add_timeout ( |
892 | | + 1000, |
893 | | + (GSourceFunc) mac_dock_attention_cb, |
894 | | + request); |
895 | | + |
896 | | + return request; |
897 | | +} |
898 | | + |
899 | | +void |
900 | | +ige_mac_dock_attention_cancel (IgeMacDock *dock, |
901 | | + IgeMacAttentionRequest *request) |
902 | | +{ |
903 | | + if (request->timeout_id) |
904 | | + g_source_remove (request->timeout_id); |
905 | | + |
906 | | + if (!request->is_cancelled) |
907 | | + NMRemove (&request->nm_request); |
908 | | + |
909 | | + g_free (request); |
910 | | +} |
911 | | + |
912 | | +GType |
913 | | +ige_mac_attention_type_get_type (void) |
914 | | +{ |
915 | | + /* FIXME */ |
916 | | + return 0; |
917 | | +} |
918 | | --- pidgin/ige-mac-dock.h 1970-01-01 01:00:00.000000000 +0100 |
919 | | +++ ../pidgin-2.3.1/pidgin/ige-mac-dock.h 2008-02-11 14:38:30.000000000 +0100 |
920 | | @@ -0,0 +1,83 @@ |
921 | | +/* GTK+ Integration for the Mac OS X Dock. |
922 | | + * |
923 | | + * Copyright (C) 2007-2008 Imendio AB |
924 | | + * |
925 | | + * This library is free software; you can redistribute it and/or |
926 | | + * modify it under the terms of the GNU Lesser General Public |
927 | | + * License as published by the Free Software Foundation; version 2.1 |
928 | | + * of the License. |
929 | | + * |
930 | | + * This library is distributed in the hope that it will be useful, |
931 | | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
932 | | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
933 | | + * Lesser General Public License for more details. |
934 | | + * |
935 | | + * You should have received a copy of the GNU Lesser General Public |
936 | | + * License along with this library; if not, write to the |
937 | | + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
938 | | + * Boston, MA 02111-1307, USA. |
939 | | + */ |
940 | | + |
941 | | +#ifndef __IGE_MAC_DOCK_H__ |
942 | | +#define __IGE_MAC_DOCK_H__ |
943 | | + |
944 | | +#include <gtk/gtk.h> |
945 | | +#include <ige-mac-bundle.h> |
946 | | + |
947 | | +G_BEGIN_DECLS |
948 | | + |
949 | | +#define IGE_TYPE_MAC_DOCK (ige_mac_dock_get_type ()) |
950 | | +#define IGE_MAC_DOCK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), IGE_TYPE_MAC_DOCK, IgeMacDock)) |
951 | | +#define IGE_MAC_DOCK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), IGE_TYPE_MAC_DOCK, IgeMacDockClass)) |
952 | | +#define IGE_IS_MAC_DOCK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IGE_TYPE_MAC_DOCK)) |
953 | | +#define IGE_IS_MAC_DOCK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), IGE_TYPE_MAC_DOCK)) |
954 | | +#define IGE_MAC_DOCK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), IGE_TYPE_MAC_DOCK, IgeMacDockClass)) |
955 | | + |
956 | | +typedef struct _IgeMacDock IgeMacDock; |
957 | | +typedef struct _IgeMacDockClass IgeMacDockClass; |
958 | | + |
959 | | +typedef struct _IgeMacAttentionRequest IgeMacAttentionRequest; |
960 | | + |
961 | | +struct _IgeMacDock |
962 | | +{ |
963 | | + GObject parent_instance; |
964 | | +}; |
965 | | + |
966 | | +struct _IgeMacDockClass |
967 | | +{ |
968 | | + GObjectClass parent_class; |
969 | | +}; |
970 | | + |
971 | | +typedef enum { |
972 | | + IGE_MAC_ATTENTION_CRITICAL, |
973 | | + IGE_MAC_ATTENTION_INFO |
974 | | +} IgeMacAttentionType; |
975 | | + |
976 | | +GType ige_mac_dock_get_type (void); |
977 | | +IgeMacDock * ige_mac_dock_new (void); |
978 | | +IgeMacDock * ige_mac_dock_get_default (void); |
979 | | +void ige_mac_dock_set_icon_from_pixbuf (IgeMacDock *dock, |
980 | | + GdkPixbuf *pixbuf); |
981 | | +void ige_mac_dock_set_icon_from_resource (IgeMacDock *dock, |
982 | | + IgeMacBundle *bundle, |
983 | | + const gchar *name, |
984 | | + const gchar *type, |
985 | | + const gchar *subdir); |
986 | | +void ige_mac_dock_set_overlay_from_pixbuf (IgeMacDock *dock, |
987 | | + GdkPixbuf *pixbuf); |
988 | | +void ige_mac_dock_set_overlay_from_resource (IgeMacDock *dock, |
989 | | + IgeMacBundle *bundle, |
990 | | + const gchar *name, |
991 | | + const gchar *type, |
992 | | + const gchar *subdir); |
993 | | +IgeMacAttentionRequest *ige_mac_dock_attention_request (IgeMacDock *dock, |
994 | | + IgeMacAttentionType type); |
995 | | +void ige_mac_dock_attention_cancel (IgeMacDock *dock, |
996 | | + IgeMacAttentionRequest *request); |
997 | | + |
998 | | +#define IGE_TYPE_MAC_ATTENTION_TYPE (ige_mac_attention_type_get_type()) |
999 | | +GType ige_mac_attention_type_get_type (void); |
1000 | | + |
1001 | | +G_END_DECLS |
1002 | | + |
1003 | | +#endif /* __IGE_MAC_DOCK_H__ */ |
1004 | | --- pidgin/ige-mac-image-utils.c 1970-01-01 01:00:00.000000000 +0100 |
1005 | | +++ ../pidgin-2.3.1/pidgin/ige-mac-image-utils.c 2008-02-11 14:38:28.000000000 +0100 |
1006 | | @@ -0,0 +1,60 @@ |
1007 | | +/* |
1008 | | + * Copyright (C) 2007 Imendio AB |
1009 | | + * |
1010 | | + * This library is free software; you can redistribute it and/or |
1011 | | + * modify it under the terms of the GNU Lesser General Public |
1012 | | + * License as published by the Free Software Foundation; version 2.1 |
1013 | | + * of the License. |
1014 | | + * |
1015 | | + * This library is distributed in the hope that it will be useful, |
1016 | | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1017 | | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
1018 | | + * Lesser General Public License for more details. |
1019 | | + * |
1020 | | + * You should have received a copy of the GNU Lesser General Public |
1021 | | + * License along with this library; if not, write to the |
1022 | | + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
1023 | | + * Boston, MA 02111-1307, USA. |
1024 | | + */ |
1025 | | + |
1026 | | +#include <config.h> |
1027 | | +#include <gtk/gtk.h> |
1028 | | +#include <Carbon/Carbon.h> |
1029 | | + |
1030 | | +#include "ige-mac-image-utils.h" |
1031 | | + |
1032 | | +CGImageRef |
1033 | | +ige_mac_image_from_pixbuf (GdkPixbuf *pixbuf) |
1034 | | +{ |
1035 | | + CGColorSpaceRef colorspace; |
1036 | | + CGDataProviderRef data_provider; |
1037 | | + CGImageRef image; |
1038 | | + void *data; |
1039 | | + gint rowstride; |
1040 | | + gint pixbuf_width, pixbuf_height; |
1041 | | + gboolean has_alpha; |
1042 | | + |
1043 | | + pixbuf_width = gdk_pixbuf_get_width (pixbuf); |
1044 | | + pixbuf_height = gdk_pixbuf_get_height (pixbuf); |
1045 | | + rowstride = gdk_pixbuf_get_rowstride (pixbuf); |
1046 | | + has_alpha = gdk_pixbuf_get_has_alpha (pixbuf); |
1047 | | + |
1048 | | + data = gdk_pixbuf_get_pixels (pixbuf); |
1049 | | + |
1050 | | + colorspace = CGColorSpaceCreateDeviceRGB (); |
1051 | | + data_provider = CGDataProviderCreateWithData (NULL, data, |
1052 | | + pixbuf_height * rowstride, |
1053 | | + NULL); |
1054 | | + |
1055 | | + image = CGImageCreate (pixbuf_width, pixbuf_height, 8, |
1056 | | + has_alpha ? 32 : 24, rowstride, |
1057 | | + colorspace, |
1058 | | + has_alpha ? kCGImageAlphaLast : 0, |
1059 | | + data_provider, NULL, FALSE, |
1060 | | + kCGRenderingIntentDefault); |
1061 | | + |
1062 | | + CGDataProviderRelease (data_provider); |
1063 | | + CGColorSpaceRelease (colorspace); |
1064 | | + |
1065 | | + return image; |
1066 | | +} |
1067 | | --- pidgin/ige-mac-image-utils.h 1970-01-01 01:00:00.000000000 +0100 |
1068 | | +++ ../pidgin-2.3.1/pidgin/ige-mac-image-utils.h 2008-02-11 14:38:30.000000000 +0100 |
1069 | | @@ -0,0 +1,32 @@ |
1070 | | +/* |
1071 | | + * Copyright (C) 2007 Imendio AB |
1072 | | + * |
1073 | | + * This library is free software; you can redistribute it and/or |
1074 | | + * modify it under the terms of the GNU Lesser General Public |
1075 | | + * License as published by the Free Software Foundation; version 2.1 |
1076 | | + * of the License. |
1077 | | + * |
1078 | | + * This library is distributed in the hope that it will be useful, |
1079 | | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1080 | | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
1081 | | + * Lesser General Public License for more details. |
1082 | | + * |
1083 | | + * You should have received a copy of the GNU Lesser General Public |
1084 | | + * License along with this library; if not, write to the |
1085 | | + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
1086 | | + * Boston, MA 02111-1307, USA. |
1087 | | + */ |
1088 | | + |
1089 | | +#ifndef __IGE_MAC_IMAGE_UTILS_H__ |
1090 | | +#define __IGE_MAC_IMAGE_UTILS_H__ |
1091 | | + |
1092 | | +#include <gdk-pixbuf/gdk-pixbuf.h> |
1093 | | +#include <Carbon/Carbon.h> |
1094 | | + |
1095 | | +G_BEGIN_DECLS |
1096 | | + |
1097 | | +CGImageRef ige_mac_image_from_pixbuf (GdkPixbuf *pixbuf); |
1098 | | + |
1099 | | +G_END_DECLS |
1100 | | + |
1101 | | +#endif /* __IGE_MAC_IMAGE_UTILS_H__ */ |
1102 | | --- pidgin/ige-mac-menu.c 1970-01-01 01:00:00.000000000 +0100 |
1103 | | +++ ../pidgin-2.3.1/pidgin/ige-mac-menu.c 2008-02-11 14:38:28.000000000 +0100 |
1104 | | @@ -0,0 +1,936 @@ |
1105 | | +/* GTK+ Integration for the Mac OS X Menubar. |
1106 | | + * |
1107 | | + * Copyright (C) 2007 Pioneer Research Center USA, Inc. |
1108 | | + * Copyright (C) 2007 Imendio AB |
1109 | | + * |
1110 | | + * For further information, see: |
1111 | | + * http://developer.imendio.com/projects/gtk-macosx/menubar |
1112 | | + * |
1113 | | + * This library is free software; you can redistribute it and/or |
1114 | | + * modify it under the terms of the GNU Lesser General Public |
1115 | | + * License as published by the Free Software Foundation; version 2.1 |
1116 | | + * of the License. |
1117 | | + * |
1118 | | + * This library is distributed in the hope that it will be useful, |
1119 | | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1120 | | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
1121 | | + * Lesser General Public License for more details. |
1122 | | + * |
1123 | | + * You should have received a copy of the GNU Lesser General Public |
1124 | | + * License along with this library; if not, write to the |
1125 | | + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
1126 | | + * Boston, MA 02111-1307, USA. |
1127 | | + */ |
1128 | | + |
1129 | | +#include <gtk/gtk.h> |
1130 | | +#include <gdk/gdkkeysyms.h> |
1131 | | +#include <Carbon/Carbon.h> |
1132 | | + |
1133 | | +#include "ige-mac-menu.h" |
1134 | | + |
1135 | | +/* TODO |
1136 | | + * |
1137 | | + * - Adding a standard Window menu (Minimize etc)? |
1138 | | + * - Sync reordering items? Does that work now? |
1139 | | + * - Create on demand? (can this be done with gtk+? ie fill in menu |
1140 | | + items when the menu is opened) |
1141 | | + * - Figure out what to do per app/window... |
1142 | | + * |
1143 | | + */ |
1144 | | + |
1145 | | +#define IGE_QUARTZ_MENU_CREATOR 'IGEC' |
1146 | | +#define IGE_QUARTZ_ITEM_WIDGET 'IWID' |
1147 | | + |
1148 | | + |
1149 | | +static void sync_menu_shell (GtkMenuShell *menu_shell, |
1150 | | + MenuRef carbon_menu, |
1151 | | + gboolean toplevel, |
1152 | | + gboolean debug); |
1153 | | + |
1154 | | + |
1155 | | +/* |
1156 | | + * utility functions |
1157 | | + */ |
1158 | | + |
1159 | | +static GtkWidget * |
1160 | | +find_menu_label (GtkWidget *widget) |
1161 | | +{ |
1162 | | + GtkWidget *label = NULL; |
1163 | | + |
1164 | | + if (GTK_IS_LABEL (widget)) |
1165 | | + return widget; |
1166 | | + |
1167 | | + if (GTK_IS_CONTAINER (widget)) |
1168 | | + { |
1169 | | + GList *children; |
1170 | | + GList *l; |
1171 | | + |
1172 | | + children = gtk_container_get_children (GTK_CONTAINER (widget)); |
1173 | | + |
1174 | | + for (l = children; l; l = l->next) |
1175 | | + { |
1176 | | + label = find_menu_label (l->data); |
1177 | | + if (label) |
1178 | | + break; |
1179 | | + } |
1180 | | + |
1181 | | + g_list_free (children); |
1182 | | + } |
1183 | | + |
1184 | | + return label; |
1185 | | +} |
1186 | | + |
1187 | | +static const gchar * |
1188 | | +get_menu_label_text (GtkWidget *menu_item, |
1189 | | + GtkWidget **label) |
1190 | | +{ |
1191 | | + GtkWidget *my_label; |
1192 | | + |
1193 | | + my_label = find_menu_label (menu_item); |
1194 | | + if (label) |
1195 | | + *label = my_label; |
1196 | | + |
1197 | | + if (my_label) |
1198 | | + return gtk_label_get_text (GTK_LABEL (my_label)); |
1199 | | + |
1200 | | + return NULL; |
1201 | | +} |
1202 | | + |
1203 | | +static gboolean |
1204 | | +accel_find_func (GtkAccelKey *key, |
1205 | | + GClosure *closure, |
1206 | | + gpointer data) |
1207 | | +{ |
1208 | | + return (GClosure *) data == closure; |
1209 | | +} |
1210 | | + |
1211 | | + |
1212 | | +/* |
1213 | | + * CarbonMenu functions |
1214 | | + */ |
1215 | | + |
1216 | | +typedef struct |
1217 | | +{ |
1218 | | + MenuRef menu; |
1219 | | + guint toplevel : 1; |
1220 | | +} CarbonMenu; |
1221 | | + |
1222 | | +static GQuark carbon_menu_quark = 0; |
1223 | | + |
1224 | | +static CarbonMenu * |
1225 | | +carbon_menu_new (void) |
1226 | | +{ |
1227 | | + return g_slice_new0 (CarbonMenu); |
1228 | | +} |
1229 | | + |
1230 | | +static void |
1231 | | +carbon_menu_free (CarbonMenu *menu) |
1232 | | +{ |
1233 | | + g_slice_free (CarbonMenu, menu); |
1234 | | +} |
1235 | | + |
1236 | | +static CarbonMenu * |
1237 | | +carbon_menu_get (GtkWidget *widget) |
1238 | | +{ |
1239 | | + return g_object_get_qdata (G_OBJECT (widget), carbon_menu_quark); |
1240 | | +} |
1241 | | + |
1242 | | +static void |
1243 | | +carbon_menu_connect (GtkWidget *menu, |
1244 | | + MenuRef menuRef, |
1245 | | + gboolean toplevel) |
1246 | | +{ |
1247 | | + CarbonMenu *carbon_menu = carbon_menu_get (menu); |
1248 | | + |
1249 | | + if (!carbon_menu) |
1250 | | + { |
1251 | | + carbon_menu = carbon_menu_new (); |
1252 | | + |
1253 | | + g_object_set_qdata_full (G_OBJECT (menu), carbon_menu_quark, |
1254 | | + carbon_menu, |
1255 | | + (GDestroyNotify) carbon_menu_free); |
1256 | | + } |
1257 | | + |
1258 | | + carbon_menu->menu = menuRef; |
1259 | | + carbon_menu->toplevel = toplevel; |
1260 | | +} |
1261 | | + |
1262 | | + |
1263 | | +/* |
1264 | | + * CarbonMenuItem functions |
1265 | | + */ |
1266 | | + |
1267 | | +typedef struct |
1268 | | +{ |
1269 | | + MenuRef menu; |
1270 | | + MenuItemIndex index; |
1271 | | + MenuRef submenu; |
1272 | | + GClosure *accel_closure; |
1273 | | +} CarbonMenuItem; |
1274 | | + |
1275 | | +static GQuark carbon_menu_item_quark = 0; |
1276 | | + |
1277 | | +static CarbonMenuItem * |
1278 | | +carbon_menu_item_new (void) |
1279 | | +{ |
1280 | | + return g_slice_new0 (CarbonMenuItem); |
1281 | | +} |
1282 | | + |
1283 | | +static void |
1284 | | +carbon_menu_item_free (CarbonMenuItem *menu_item) |
1285 | | +{ |
1286 | | + if (menu_item->accel_closure) |
1287 | | + g_closure_unref (menu_item->accel_closure); |
1288 | | + |
1289 | | + g_slice_free (CarbonMenuItem, menu_item); |
1290 | | +} |
1291 | | + |
1292 | | +static CarbonMenuItem * |
1293 | | +carbon_menu_item_get (GtkWidget *widget) |
1294 | | +{ |
1295 | | + return g_object_get_qdata (G_OBJECT (widget), carbon_menu_item_quark); |
1296 | | +} |
1297 | | + |
1298 | | +static void |
1299 | | +carbon_menu_item_update_state (CarbonMenuItem *carbon_item, |
1300 | | + GtkWidget *widget) |
1301 | | +{ |
1302 | | + gboolean sensitive; |
1303 | | + gboolean visible; |
1304 | | + UInt32 set_attrs = 0; |
1305 | | + UInt32 clear_attrs = 0; |
1306 | | + |
1307 | | + g_object_get (widget, |
1308 | | + "sensitive", &sensitive, |
1309 | | + "visible", &visible, |
1310 | | + NULL); |
1311 | | + |
1312 | | + if (!sensitive) |
1313 | | + set_attrs |= kMenuItemAttrDisabled; |
1314 | | + else |
1315 | | + clear_attrs |= kMenuItemAttrDisabled; |
1316 | | + |
1317 | | + if (!visible) |
1318 | | + set_attrs |= kMenuItemAttrHidden; |
1319 | | + else |
1320 | | + clear_attrs |= kMenuItemAttrHidden; |
1321 | | + |
1322 | | + ChangeMenuItemAttributes (carbon_item->menu, carbon_item->index, |
1323 | | + set_attrs, clear_attrs); |
1324 | | +} |
1325 | | + |
1326 | | +static void |
1327 | | +carbon_menu_item_update_active (CarbonMenuItem *carbon_item, |
1328 | | + GtkWidget *widget) |
1329 | | +{ |
1330 | | + gboolean active; |
1331 | | + |
1332 | | + g_object_get (widget, |
1333 | | + "active", &active, |
1334 | | + NULL); |
1335 | | + |
1336 | | + CheckMenuItem (carbon_item->menu, carbon_item->index, |
1337 | | + active); |
1338 | | +} |
1339 | | + |
1340 | | +static void |
1341 | | +carbon_menu_item_update_submenu (CarbonMenuItem *carbon_item, |
1342 | | + GtkWidget *widget) |
1343 | | +{ |
1344 | | + GtkWidget *submenu; |
1345 | | + |
1346 | | + submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget)); |
1347 | | + |
1348 | | + if (submenu) |
1349 | | + { |
1350 | | + const gchar *label_text; |
1351 | | + CFStringRef cfstr = NULL; |
1352 | | + |
1353 | | + label_text = get_menu_label_text (widget, NULL); |
1354 | | + if (label_text) |
1355 | | + cfstr = CFStringCreateWithCString (NULL, label_text, |
1356 | | + kCFStringEncodingUTF8); |
1357 | | + |
1358 | | + CreateNewMenu (0, 0, &carbon_item->submenu); |
1359 | | + SetMenuTitleWithCFString (carbon_item->submenu, cfstr); |
1360 | | + SetMenuItemHierarchicalMenu (carbon_item->menu, carbon_item->index, |
1361 | | + carbon_item->submenu); |
1362 | | + |
1363 | | + sync_menu_shell (GTK_MENU_SHELL (submenu), carbon_item->submenu, FALSE, FALSE); |
1364 | | + |
1365 | | + if (cfstr) |
1366 | | + CFRelease (cfstr); |
1367 | | + } |
1368 | | + else |
1369 | | + { |
1370 | | + SetMenuItemHierarchicalMenu (carbon_item->menu, carbon_item->index, |
1371 | | + NULL); |
1372 | | + carbon_item->submenu = NULL; |
1373 | | + } |
1374 | | +} |
1375 | | + |
1376 | | +static void |
1377 | | +carbon_menu_item_update_label (CarbonMenuItem *carbon_item, |
1378 | | + GtkWidget *widget) |
1379 | | +{ |
1380 | | + const gchar *label_text; |
1381 | | + CFStringRef cfstr = NULL; |
1382 | | + |
1383 | | + label_text = get_menu_label_text (widget, NULL); |
1384 | | + if (label_text) |
1385 | | + cfstr = CFStringCreateWithCString (NULL, label_text, |
1386 | | + kCFStringEncodingUTF8); |
1387 | | + |
1388 | | + SetMenuItemTextWithCFString (carbon_item->menu, carbon_item->index, |
1389 | | + cfstr); |
1390 | | + |
1391 | | + if (cfstr) |
1392 | | + CFRelease (cfstr); |
1393 | | +} |
1394 | | + |
1395 | | +static void |
1396 | | +carbon_menu_item_update_accelerator (CarbonMenuItem *carbon_item, |
1397 | | + GtkWidget *widget) |
1398 | | +{ |
1399 | | + GtkWidget *label; |
1400 | | + |
1401 | | + get_menu_label_text (widget, &label); |
1402 | | + |
1403 | | + if (GTK_IS_ACCEL_LABEL (label) && |
1404 | | + GTK_ACCEL_LABEL (label)->accel_closure) |
1405 | | + { |
1406 | | + GtkAccelKey *key; |
1407 | | + |
1408 | | + key = gtk_accel_group_find (GTK_ACCEL_LABEL (label)->accel_group, |
1409 | | + accel_find_func, |
1410 | | + GTK_ACCEL_LABEL (label)->accel_closure); |
1411 | | + |
1412 | | + if (key && |
1413 | | + key->accel_key && |
1414 | | + key->accel_flags & GTK_ACCEL_VISIBLE) |
1415 | | + { |
1416 | | + GdkDisplay *display = gtk_widget_get_display (widget); |
1417 | | + GdkKeymap *keymap = gdk_keymap_get_for_display (display); |
1418 | | + GdkKeymapKey *keys; |
1419 | | + gint n_keys; |
1420 | | + |
1421 | | + if (gdk_keymap_get_entries_for_keyval (keymap, key->accel_key, |
1422 | | + &keys, &n_keys)) |
1423 | | + { |
1424 | | + UInt8 modifiers = 0; |
1425 | | + |
1426 | | + SetMenuItemCommandKey (carbon_item->menu, carbon_item->index, |
1427 | | + true, keys[0].keycode); |
1428 | | + |
1429 | | + g_free (keys); |
1430 | | + |
1431 | | + if (key->accel_mods) |
1432 | | + { |
1433 | | + if (key->accel_mods & GDK_SHIFT_MASK) |
1434 | | + modifiers |= kMenuShiftModifier; |
1435 | | + |
1436 | | + if (key->accel_mods & GDK_MOD1_MASK) |
1437 | | + modifiers |= kMenuOptionModifier; |
1438 | | + } |
1439 | | + |
1440 | | + if (!(key->accel_mods & GDK_CONTROL_MASK)) |
1441 | | + { |
1442 | | + modifiers |= kMenuNoCommandModifier; |
1443 | | + } |
1444 | | + |
1445 | | + SetMenuItemModifiers (carbon_item->menu, carbon_item->index, |
1446 | | + modifiers); |
1447 | | + |
1448 | | + return; |
1449 | | + } |
1450 | | + } |
1451 | | + } |
1452 | | + |
1453 | | + /* otherwise, clear the menu shortcut */ |
1454 | | + SetMenuItemModifiers (carbon_item->menu, carbon_item->index, |
1455 | | + kMenuNoModifiers | kMenuNoCommandModifier); |
1456 | | + ChangeMenuItemAttributes (carbon_item->menu, carbon_item->index, |
1457 | | + 0, kMenuItemAttrUseVirtualKey); |
1458 | | + SetMenuItemCommandKey (carbon_item->menu, carbon_item->index, |
1459 | | + false, 0); |
1460 | | +} |
1461 | | + |
1462 | | +static void |
1463 | | +carbon_menu_item_accel_changed (GtkAccelGroup *accel_group, |
1464 | | + guint keyval, |
1465 | | + GdkModifierType modifier, |
1466 | | + GClosure *accel_closure, |
1467 | | + GtkWidget *widget) |
1468 | | +{ |
1469 | | + CarbonMenuItem *carbon_item = carbon_menu_item_get (widget); |
1470 | | + GtkWidget *label; |
1471 | | + |
1472 | | + get_menu_label_text (widget, &label); |
1473 | | + |
1474 | | + if (GTK_IS_ACCEL_LABEL (label) && |
1475 | | + GTK_ACCEL_LABEL (label)->accel_closure == accel_closure) |
1476 | | + carbon_menu_item_update_accelerator (carbon_item, widget); |
1477 | | +} |
1478 | | + |
1479 | | +static void |
1480 | | +carbon_menu_item_update_accel_closure (CarbonMenuItem *carbon_item, |
1481 | | + GtkWidget *widget) |
1482 | | +{ |
1483 | | + GtkAccelGroup *group; |
1484 | | + GtkWidget *label; |
1485 | | + |
1486 | | + get_menu_label_text (widget, &label); |
1487 | | + |
1488 | | + if (carbon_item->accel_closure) |
1489 | | + { |
1490 | | + group = gtk_accel_group_from_accel_closure (carbon_item->accel_closure); |
1491 | | + |
1492 | | + g_signal_handlers_disconnect_by_func (group, |
1493 | | + carbon_menu_item_accel_changed, |
1494 | | + widget); |
1495 | | + |
1496 | | + g_closure_unref (carbon_item->accel_closure); |
1497 | | + carbon_item->accel_closure = NULL; |
1498 | | + } |
1499 | | + |
1500 | | + if (GTK_IS_ACCEL_LABEL (label)) |
1501 | | + carbon_item->accel_closure = GTK_ACCEL_LABEL (label)->accel_closure; |
1502 | | + |
1503 | | + if (carbon_item->accel_closure) |
1504 | | + { |
1505 | | + g_closure_ref (carbon_item->accel_closure); |
1506 | | + |
1507 | | + group = gtk_accel_group_from_accel_closure (carbon_item->accel_closure); |
1508 | | + |
1509 | | + g_signal_connect_object (group, "accel-changed", |
1510 | | + G_CALLBACK (carbon_menu_item_accel_changed), |
1511 | | + widget, 0); |
1512 | | + } |
1513 | | + |
1514 | | + carbon_menu_item_update_accelerator (carbon_item, widget); |
1515 | | +} |
1516 | | + |
1517 | | +static void |
1518 | | +carbon_menu_item_notify (GObject *object, |
1519 | | + GParamSpec *pspec, |
1520 | | + CarbonMenuItem *carbon_item) |
1521 | | +{ |
1522 | | + if (!strcmp (pspec->name, "sensitive") || |
1523 | | + !strcmp (pspec->name, "visible")) |
1524 | | + { |
1525 | | + carbon_menu_item_update_state (carbon_item, GTK_WIDGET (object)); |
1526 | | + } |
1527 | | + else if (!strcmp (pspec->name, "active")) |
1528 | | + { |
1529 | | + carbon_menu_item_update_active (carbon_item, GTK_WIDGET (object)); |
1530 | | + } |
1531 | | + else if (!strcmp (pspec->name, "submenu")) |
1532 | | + { |
1533 | | + carbon_menu_item_update_submenu (carbon_item, GTK_WIDGET (object)); |
1534 | | + } |
1535 | | +} |
1536 | | + |
1537 | | +static void |
1538 | | +carbon_menu_item_notify_label (GObject *object, |
1539 | | + GParamSpec *pspec, |
1540 | | + gpointer data) |
1541 | | +{ |
1542 | | + CarbonMenuItem *carbon_item = carbon_menu_item_get (GTK_WIDGET (object)); |
1543 | | + |
1544 | | + if (!strcmp (pspec->name, "label")) |
1545 | | + { |
1546 | | + carbon_menu_item_update_label (carbon_item, |
1547 | | + GTK_WIDGET (object)); |
1548 | | + } |
1549 | | + else if (!strcmp (pspec->name, "accel-closure")) |
1550 | | + { |
1551 | | + carbon_menu_item_update_accel_closure (carbon_item, |
1552 | | + GTK_WIDGET (object)); |
1553 | | + } |
1554 | | +} |
1555 | | + |
1556 | | +static CarbonMenuItem * |
1557 | | +carbon_menu_item_connect (GtkWidget *menu_item, |
1558 | | + GtkWidget *label, |
1559 | | + MenuRef menu, |
1560 | | + MenuItemIndex index) |
1561 | | +{ |
1562 | | + CarbonMenuItem *carbon_item = carbon_menu_item_get (menu_item); |
1563 | | + |
1564 | | + if (!carbon_item) |
1565 | | + { |
1566 | | + carbon_item = carbon_menu_item_new (); |
1567 | | + |
1568 | | + g_object_set_qdata_full (G_OBJECT (menu_item), carbon_menu_item_quark, |
1569 | | + carbon_item, |
1570 | | + (GDestroyNotify) carbon_menu_item_free); |
1571 | | + |
1572 | | + g_signal_connect (menu_item, "notify", |
1573 | | + G_CALLBACK (carbon_menu_item_notify), |
1574 | | + carbon_item); |
1575 | | + |
1576 | | + if (label) |
1577 | | + g_signal_connect_swapped (label, "notify::label", |
1578 | | + G_CALLBACK (carbon_menu_item_notify_label), |
1579 | | + menu_item); |
1580 | | + } |
1581 | | + |
1582 | | + carbon_item->menu = menu; |
1583 | | + carbon_item->index = index; |
1584 | | + |
1585 | | + return carbon_item; |
1586 | | +} |
1587 | | + |
1588 | | + |
1589 | | +/* |
1590 | | + * carbon event handler |
1591 | | + */ |
1592 | | + |
1593 | | +static OSStatus |
1594 | | +menu_event_handler_func (EventHandlerCallRef event_handler_call_ref, |
1595 | | + EventRef event_ref, |
1596 | | + void *data) |
1597 | | +{ |
1598 | | + UInt32 event_class = GetEventClass (event_ref); |
1599 | | + UInt32 event_kind = GetEventKind (event_ref); |
1600 | | + MenuRef menu_ref; |
1601 | | + |
1602 | | + switch (event_class) |
1603 | | + { |
1604 | | + case kEventClassCommand: |
1605 | | + /* This is called when activating (is that the right GTK+ term?) |
1606 | | + * a menu item. |
1607 | | + */ |
1608 | | + if (event_kind == kEventCommandProcess) |
1609 | | + { |
1610 | | + HICommand command; |
1611 | | + OSStatus err; |
1612 | | + |
1613 | | + /*g_printerr ("Menu: kEventClassCommand/kEventCommandProcess\n");*/ |
1614 | | + |
1615 | | + err = GetEventParameter (event_ref, kEventParamDirectObject, |
1616 | | + typeHICommand, 0, |
1617 | | + sizeof (command), 0, &command); |
1618 | | + |
1619 | | + if (err == noErr) |
1620 | | + { |
1621 | | + GtkWidget *widget = NULL; |
1622 | | + |
1623 | | + /* Get any GtkWidget associated with the item. */ |
1624 | | + err = GetMenuItemProperty (command.menu.menuRef, |
1625 | | + command.menu.menuItemIndex, |
1626 | | + IGE_QUARTZ_MENU_CREATOR, |
1627 | | + IGE_QUARTZ_ITEM_WIDGET, |
1628 | | + sizeof (widget), 0, &widget); |
1629 | | + if (err == noErr && GTK_IS_WIDGET (widget)) |
1630 | | + { |
1631 | | + gtk_menu_item_activate (GTK_MENU_ITEM (widget)); |
1632 | | + return noErr; |
1633 | | + } |
1634 | | + } |
1635 | | + } |
1636 | | + break; |
1637 | | + |
1638 | | + case kEventClassMenu: |
1639 | | + GetEventParameter (event_ref, |
1640 | | + kEventParamDirectObject, |
1641 | | + typeMenuRef, |
1642 | | + NULL, |
1643 | | + sizeof (menu_ref), |
1644 | | + NULL, |
1645 | | + &menu_ref); |
1646 | | + |
1647 | | + switch (event_kind) |
1648 | | + { |
1649 | | + case kEventMenuTargetItem: |
1650 | | + /* This is called when an item is selected (what is the |
1651 | | + * GTK+ term? prelight?) |
1652 | | + */ |
1653 | | + /*g_printerr ("kEventClassMenu/kEventMenuTargetItem\n");*/ |
1654 | | + break; |
1655 | | + |
1656 | | + case kEventMenuOpening: |
1657 | | + /* Is it possible to dynamically build the menu here? We |
1658 | | + * can at least set visibility/sensitivity. |
1659 | | + */ |
1660 | | + /*g_printerr ("kEventClassMenu/kEventMenuOpening\n");*/ |
1661 | | + break; |
1662 | | + |
1663 | | + case kEventMenuClosed: |
1664 | | + /*g_printerr ("kEventClassMenu/kEventMenuClosed\n");*/ |
1665 | | + break; |
1666 | | + |
1667 | | + default: |
1668 | | + break; |
1669 | | + } |
1670 | | + |
1671 | | + break; |
1672 | | + |
1673 | | + default: |
1674 | | + break; |
1675 | | + } |
1676 | | + |
1677 | | + return CallNextEventHandler (event_handler_call_ref, event_ref); |
1678 | | +} |
1679 | | + |
1680 | | +static void |
1681 | | +setup_menu_event_handler (void) |
1682 | | +{ |
1683 | | + static gboolean is_setup; |
1684 | | + EventHandlerUPP menu_event_handler_upp; |
1685 | | + EventHandlerRef menu_event_handler_ref; |
1686 | | + const EventTypeSpec menu_events[] = { |
1687 | | + { kEventClassCommand, kEventCommandProcess }, |
1688 | | + { kEventClassMenu, kEventMenuTargetItem }, |
1689 | | + { kEventClassMenu, kEventMenuOpening }, |
1690 | | + { kEventClassMenu, kEventMenuClosed } |
1691 | | + }; |
1692 | | + |
1693 | | + if (is_setup) |
1694 | | + return; |
1695 | | + |
1696 | | + /* FIXME: We might have to install one per window? */ |
1697 | | + |
1698 | | + menu_event_handler_upp = NewEventHandlerUPP (menu_event_handler_func); |
1699 | | + InstallEventHandler (GetApplicationEventTarget (), menu_event_handler_upp, |
1700 | | + GetEventTypeCount (menu_events), menu_events, 0, |
1701 | | + &menu_event_handler_ref); |
1702 | | + |
1703 | | +#if 0 |
1704 | | + /* FIXME: Remove the handler with: */ |
1705 | | + RemoveEventHandler(menu_event_handler_ref); |
1706 | | + DisposeEventHandlerUPP(menu_event_handler_upp); |
1707 | | +#endif |
1708 | | + is_setup = TRUE; |
1709 | | +} |
1710 | | + |
1711 | | +static void |
1712 | | +sync_menu_shell (GtkMenuShell *menu_shell, |
1713 | | + MenuRef carbon_menu, |
1714 | | + gboolean toplevel, |
1715 | | + gboolean debug) |
1716 | | +{ |
1717 | | + GList *children; |
1718 | | + GList *l; |
1719 | | + MenuItemIndex carbon_index = 1; |
1720 | | + |
1721 | | + if (debug) |
1722 | | + g_printerr ("%s: syncing shell %p\n", G_STRFUNC, menu_shell); |
1723 | | + |
1724 | | + carbon_menu_connect (GTK_WIDGET (menu_shell), carbon_menu, toplevel); |
1725 | | + |
1726 | | + children = gtk_container_get_children (GTK_CONTAINER (menu_shell)); |
1727 | | + |
1728 | | + for (l = children; l; l = l->next) |
1729 | | + { |
1730 | | + GtkWidget *menu_item = l->data; |
1731 | | + CarbonMenuItem *carbon_item; |
1732 | | + |
1733 | | + if (GTK_IS_TEAROFF_MENU_ITEM (menu_item)) |
1734 | | + continue; |
1735 | | + |
1736 | | + if (toplevel && g_object_get_data (G_OBJECT (menu_item), |
1737 | | + "gtk-empty-menu-item")) |
1738 | | + continue; |
1739 | | + |
1740 | | + carbon_item = carbon_menu_item_get (menu_item); |
1741 | | + |
1742 | | + if (debug) |
1743 | | + g_printerr ("%s: carbon_item %d for menu_item %d (%s, %s)\n", |
1744 | | + G_STRFUNC, carbon_item ? carbon_item->index : -1, |
1745 | | + carbon_index, get_menu_label_text (menu_item, NULL), |
1746 | | + g_type_name (G_TYPE_FROM_INSTANCE (menu_item))); |
1747 | | + |
1748 | | + if (carbon_item && carbon_item->index != carbon_index) |
1749 | | + { |
1750 | | + if (debug) |
1751 | | + g_printerr ("%s: -> not matching, deleting\n", G_STRFUNC); |
1752 | | + |
1753 | | + DeleteMenuItem (carbon_item->menu, carbon_index); |
1754 | | + carbon_item = NULL; |
1755 | | + } |
1756 | | + |
1757 | | + if (!carbon_item) |
1758 | | + { |
1759 | | + GtkWidget *label = NULL; |
1760 | | + const gchar *label_text; |
1761 | | + CFStringRef cfstr = NULL; |
1762 | | + MenuItemAttributes attributes = 0; |
1763 | | + |
1764 | | + if (debug) |
1765 | | + g_printerr ("%s: -> creating new\n", G_STRFUNC); |
1766 | | + |
1767 | | + label_text = get_menu_label_text (menu_item, &label); |
1768 | | + if (label_text) |
1769 | | + cfstr = CFStringCreateWithCString (NULL, label_text, |
1770 | | + kCFStringEncodingUTF8); |
1771 | | + |
1772 | | + if (GTK_IS_SEPARATOR_MENU_ITEM (menu_item)) |
1773 | | + attributes |= kMenuItemAttrSeparator; |
1774 | | + |
1775 | | + if (!GTK_WIDGET_IS_SENSITIVE (menu_item)) |
1776 | | + attributes |= kMenuItemAttrDisabled; |
1777 | | + |
1778 | | + if (!GTK_WIDGET_VISIBLE (menu_item)) |
1779 | | + attributes |= kMenuItemAttrHidden; |
1780 | | + |
1781 | | + InsertMenuItemTextWithCFString (carbon_menu, cfstr, |
1782 | | + carbon_index - 1, |
1783 | | + attributes, 0); |
1784 | | + SetMenuItemProperty (carbon_menu, carbon_index, |
1785 | | + IGE_QUARTZ_MENU_CREATOR, |
1786 | | + IGE_QUARTZ_ITEM_WIDGET, |
1787 | | + sizeof (menu_item), &menu_item); |
1788 | | + |
1789 | | + if (cfstr) |
1790 | | + CFRelease (cfstr); |
1791 | | + |
1792 | | + carbon_item = carbon_menu_item_connect (menu_item, label, |
1793 | | + carbon_menu, |
1794 | | + carbon_index); |
1795 | | + |
1796 | | + if (GTK_IS_CHECK_MENU_ITEM (menu_item)) |
1797 | | + carbon_menu_item_update_active (carbon_item, menu_item); |
1798 | | + |
1799 | | + carbon_menu_item_update_accel_closure (carbon_item, menu_item); |
1800 | | + |
1801 | | + if (gtk_menu_item_get_submenu (GTK_MENU_ITEM (menu_item))) |
1802 | | + carbon_menu_item_update_submenu (carbon_item, menu_item); |
1803 | | + } |
1804 | | + |
1805 | | + carbon_index++; |
1806 | | + } |
1807 | | + |
1808 | | + g_list_free (children); |
1809 | | +} |
1810 | | + |
1811 | | +static gulong emission_hook_id = 0; |
1812 | | +static gint emission_hook_count = 0; |
1813 | | + |
1814 | | +static gboolean |
1815 | | +parent_set_emission_hook (GSignalInvocationHint *ihint, |
1816 | | + guint n_param_values, |
1817 | | + const GValue *param_values, |
1818 | | + gpointer data) |
1819 | | +{ |
1820 | | + GtkWidget *instance = g_value_get_object (param_values); |
1821 | | + |
1822 | | + if (GTK_IS_MENU_ITEM (instance)) |
1823 | | + { |
1824 | | + GtkWidget *previous_parent = g_value_get_object (param_values + 1); |
1825 | | + GtkWidget *menu_shell = NULL; |
1826 | | + |
1827 | | + if (GTK_IS_MENU_SHELL (previous_parent)) |
1828 | | + { |
1829 | | + menu_shell = previous_parent; |
1830 | | + } |
1831 | | + else if (GTK_IS_MENU_SHELL (instance->parent)) |
1832 | | + { |
1833 | | + menu_shell = instance->parent; |
1834 | | + } |
1835 | | + |
1836 | | + if (menu_shell) |
1837 | | + { |
1838 | | + CarbonMenu *carbon_menu = carbon_menu_get (menu_shell); |
1839 | | + |
1840 | | + if (carbon_menu) |
1841 | | + { |
1842 | | +#if 0 |
1843 | | + g_printerr ("%s: item %s %p (%s, %s)\n", G_STRFUNC, |
1844 | | + previous_parent ? "removed from" : "added to", |
1845 | | + menu_shell, |
1846 | | + get_menu_label_text (instance, NULL), |
1847 | | + g_type_name (G_TYPE_FROM_INSTANCE (instance))); |
1848 | | +#endif |
1849 | | + |
1850 | | + sync_menu_shell (GTK_MENU_SHELL (menu_shell), |
1851 | | + carbon_menu->menu, |
1852 | | + carbon_menu->toplevel, |
1853 | | + FALSE); |
1854 | | + } |
1855 | | + } |
1856 | | + } |
1857 | | + |
1858 | | + return TRUE; |
1859 | | +} |
1860 | | + |
1861 | | +static void |
1862 | | +parent_set_emission_hook_remove (GtkWidget *widget, |
1863 | | + gpointer data) |
1864 | | +{ |
1865 | | + emission_hook_count--; |
1866 | | + |
1867 | | + if (emission_hook_count > 0) |
1868 | | + return; |
1869 | | + |
1870 | | + g_signal_remove_emission_hook (g_signal_lookup ("parent-set", |
1871 | | + GTK_TYPE_WIDGET), |
1872 | | + emission_hook_id); |
1873 | | + emission_hook_id = 0; |
1874 | | +} |
1875 | | + |
1876 | | + |
1877 | | +/* |
1878 | | + * public functions |
1879 | | + */ |
1880 | | + |
1881 | | +void |
1882 | | +ige_mac_menu_set_menu_bar (GtkMenuShell *menu_shell) |
1883 | | +{ |
1884 | | + MenuRef carbon_menubar; |
1885 | | + |
1886 | | + g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell)); |
1887 | | + |
1888 | | + if (carbon_menu_quark == 0) |
1889 | | + carbon_menu_quark = g_quark_from_static_string ("CarbonMenu"); |
1890 | | + |
1891 | | + if (carbon_menu_item_quark == 0) |
1892 | | + carbon_menu_item_quark = g_quark_from_static_string ("CarbonMenuItem"); |
1893 | | + |
1894 | | + CarbonMenu *current_menu; |
1895 | | + current_menu = carbon_menu_get (GTK_WIDGET (menu_shell)); |
1896 | | + if (current_menu) |
1897 | | + { |
1898 | | + SetRootMenu (current_menu->menu); |
1899 | | + return; |
1900 | | + } |
1901 | | + |
1902 | | + CreateNewMenu (0 /*id*/, 0 /*options*/, &carbon_menubar); |
1903 | | + SetRootMenu (carbon_menubar); |
1904 | | + |
1905 | | + setup_menu_event_handler (); |
1906 | | + |
1907 | | + if (emission_hook_id == 0) |
1908 | | + { |
1909 | | + emission_hook_id = |
1910 | | + g_signal_add_emission_hook (g_signal_lookup ("parent-set", |
1911 | | + GTK_TYPE_WIDGET), |
1912 | | + 0, |
1913 | | + parent_set_emission_hook, |
1914 | | + NULL, NULL); |
1915 | | + } |
1916 | | + |
1917 | | + emission_hook_count++; |
1918 | | + |
1919 | | + g_signal_connect (menu_shell, "destroy", |
1920 | | + G_CALLBACK (parent_set_emission_hook_remove), |
1921 | | + NULL); |
1922 | | + |
1923 | | + sync_menu_shell (menu_shell, carbon_menubar, TRUE, FALSE); |
1924 | | +} |
1925 | | + |
1926 | | +void |
1927 | | +ige_mac_menu_set_quit_menu_item (GtkMenuItem *menu_item) |
1928 | | +{ |
1929 | | + MenuRef appmenu; |
1930 | | + MenuItemIndex index; |
1931 | | + |
1932 | | + g_return_if_fail (GTK_IS_MENU_ITEM (menu_item)); |
1933 | | + |
1934 | | + setup_menu_event_handler (); |
1935 | | + |
1936 | | + if (GetIndMenuItemWithCommandID (NULL, kHICommandQuit, 1, |
1937 | | + &appmenu, &index) == noErr) |
1938 | | + { |
1939 | | + SetMenuItemCommandID (appmenu, index, 0); |
1940 | | + SetMenuItemProperty (appmenu, index, |
1941 | | + IGE_QUARTZ_MENU_CREATOR, |
1942 | | + IGE_QUARTZ_ITEM_WIDGET, |
1943 | | + sizeof (menu_item), &menu_item); |
1944 | | + |
1945 | | + gtk_widget_hide (GTK_WIDGET (menu_item)); |
1946 | | + } |
1947 | | +} |
1948 | | + |
1949 | | + |
1950 | | +struct _IgeMacMenuGroup |
1951 | | +{ |
1952 | | + GList *items; |
1953 | | +}; |
1954 | | + |
1955 | | +static GList *app_menu_groups = NULL; |
1956 | | + |
1957 | | +IgeMacMenuGroup * |
1958 | | +ige_mac_menu_add_app_menu_group (void) |
1959 | | +{ |
1960 | | + IgeMacMenuGroup *group = g_slice_new0 (IgeMacMenuGroup); |
1961 | | + |
1962 | | + app_menu_groups = g_list_append (app_menu_groups, group); |
1963 | | + |
1964 | | + return group; |
1965 | | +} |
1966 | | + |
1967 | | +void |
1968 | | +ige_mac_menu_add_app_menu_item (IgeMacMenuGroup *group, |
1969 | | + GtkMenuItem *menu_item, |
1970 | | + const gchar *label) |
1971 | | +{ |
1972 | | + MenuRef appmenu; |
1973 | | + GList *list; |
1974 | | + gint index = 0; |
1975 | | + |
1976 | | + g_return_if_fail (group != NULL); |
1977 | | + g_return_if_fail (GTK_IS_MENU_ITEM (menu_item)); |
1978 | | + |
1979 | | + setup_menu_event_handler (); |
1980 | | + |
1981 | | + if (GetIndMenuItemWithCommandID (NULL, kHICommandHide, 1, |
1982 | | + &appmenu, NULL) != noErr) |
1983 | | + { |
1984 | | + g_warning ("%s: retrieving app menu failed", |
1985 | | + G_STRFUNC); |
1986 | | + return; |
1987 | | + } |
1988 | | + |
1989 | | + for (list = app_menu_groups; list; list = g_list_next (list)) |
1990 | | + { |
1991 | | + IgeMacMenuGroup *list_group = list->data; |
1992 | | + |
1993 | | + index += g_list_length (list_group->items); |
1994 | | + |
1995 | | + /* adjust index for the separator between groups, but not |
1996 | | + * before the first group |
1997 | | + */ |
1998 | | + if (list_group->items && list->prev) |
1999 | | + index++; |
2000 | | + |
2001 | | + if (group == list_group) |
2002 | | + { |
2003 | | + CFStringRef cfstr; |
2004 | | + |
2005 | | + /* add a separator before adding the first item, but not |
2006 | | + * for the first group |
2007 | | + */ |
2008 | | + if (!group->items && list->prev) |
2009 | | + { |
2010 | | + InsertMenuItemTextWithCFString (appmenu, NULL, index, |
2011 | | + kMenuItemAttrSeparator, 0); |
2012 | | + index++; |
2013 | | + } |
2014 | | + |
2015 | | + if (!label) |
2016 | | + label = get_menu_label_text (GTK_WIDGET (menu_item), NULL); |
2017 | | + |
2018 | | + cfstr = CFStringCreateWithCString (NULL, label, |
2019 | | + kCFStringEncodingUTF8); |
2020 | | + |
2021 | | + InsertMenuItemTextWithCFString (appmenu, cfstr, index, 0, 0); |
2022 | | + SetMenuItemProperty (appmenu, index + 1, |
2023 | | + IGE_QUARTZ_MENU_CREATOR, |
2024 | | + IGE_QUARTZ_ITEM_WIDGET, |
2025 | | + sizeof (menu_item), &menu_item); |
2026 | | + |
2027 | | + CFRelease (cfstr); |
2028 | | + |
2029 | | + gtk_widget_hide (GTK_WIDGET (menu_item)); |
2030 | | + |
2031 | | + group->items = g_list_append (group->items, menu_item); |
2032 | | + |
2033 | | + return; |
2034 | | + } |
2035 | | + } |
2036 | | + |
2037 | | + if (!list) |
2038 | | + g_warning ("%s: app menu group %p does not exist", |
2039 | | + G_STRFUNC, group); |
2040 | | +} |
2041 | | --- pidgin/ige-mac-menu.h 1970-01-01 01:00:00.000000000 +0100 |
2042 | | +++ ../pidgin-2.3.1/pidgin/ige-mac-menu.h 2008-02-11 14:38:30.000000000 +0100 |
2043 | | @@ -0,0 +1,44 @@ |
2044 | | +/* GTK+ Integration for the Mac OS X Menubar. |
2045 | | + * |
2046 | | + * Copyright (C) 2007 Pioneer Research Center USA, Inc. |
2047 | | + * Copyright (C) 2007 Imendio AB |
2048 | | + * |
2049 | | + * For further information, see: |
2050 | | + * http://developer.imendio.com/projects/gtk-macosx/menubar |
2051 | | + * |
2052 | | + * This library is free software; you can redistribute it and/or |
2053 | | + * modify it under the terms of the GNU Lesser General Public |
2054 | | + * License as published by the Free Software Foundation; version 2.1 |
2055 | | + * of the License. |
2056 | | + * |
2057 | | + * This library is distributed in the hope that it will be useful, |
2058 | | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2059 | | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
2060 | | + * Lesser General Public License for more details. |
2061 | | + * |
2062 | | + * You should have received a copy of the GNU Lesser General Public |
2063 | | + * License along with this library; if not, write to the |
2064 | | + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
2065 | | + * Boston, MA 02111-1307, USA. |
2066 | | + */ |
2067 | | + |
2068 | | +#ifndef __IGE_MAC_MENU_H__ |
2069 | | +#define __IGE_MAC_MENU_H__ |
2070 | | + |
2071 | | +#include <gtk/gtk.h> |
2072 | | + |
2073 | | +G_BEGIN_DECLS |
2074 | | + |
2075 | | +typedef struct _IgeMacMenuGroup IgeMacMenuGroup; |
2076 | | + |
2077 | | +void ige_mac_menu_set_menu_bar (GtkMenuShell *menu_shell); |
2078 | | +void ige_mac_menu_set_quit_menu_item (GtkMenuItem *menu_item); |
2079 | | + |
2080 | | +IgeMacMenuGroup * ige_mac_menu_add_app_menu_group (void); |
2081 | | +void ige_mac_menu_add_app_menu_item (IgeMacMenuGroup *group, |
2082 | | + GtkMenuItem *menu_item, |
2083 | | + const gchar *label); |
2084 | | + |
2085 | | +G_END_DECLS |
2086 | | + |
2087 | | +#endif /* __IGE_MAC_MENU_H__ */ |
2088 | | --- pidgin/Makefile.am 2008-02-11 16:07:09.000000000 +0100 |
2089 | | +++ ../pidgin-2.3.1/pidgin/Makefile.am 2008-02-11 16:08:11.000000000 +0100 |
2090 | | @@ -117,7 +117,11 @@ |
2091 | | gtkthemes.c \ |
2092 | | gtkutils.c \ |
2093 | | gtkwhiteboard.c \ |
2094 | | - minidialog.c |
2095 | | + minidialog.c \ |
2096 | | + ige-mac-bundle.c \ |
2097 | | + ige-mac-dock.c \ |
2098 | | + ige-mac-image-utils.c \ |
2099 | | + ige-mac-menu.c |
2100 | | |
2101 | | pidgin_headers = \ |
2102 | | eggtrayicon.h \ |
2103 | | @@ -170,7 +174,11 @@ |
2104 | | gtkutils.h \ |
2105 | | gtkwhiteboard.h \ |
2106 | | minidialog.h \ |
2107 | | - pidgin.h |
2108 | | + pidgin.h \ |
2109 | | + ige-mac-bundle.h \ |
2110 | | + ige-mac-dock.h \ |
2111 | | + ige-mac-image-utils.h \ |
2112 | | + ige-mac-menu.h |
2113 | | |
2114 | | pidginincludedir=$(includedir)/pidgin |
2115 | | pidgininclude_HEADERS = \ |
2116 | | --- configure.ac 2007-12-07 15:36:58.000000000 +0100 |
2117 | | +++ ../pidgin-2.3.1/configure.ac 2008-02-11 16:46:34.000000000 +0100 |
2118 | | @@ -123,6 +123,11 @@ |
2119 | | ], []) |
2120 | | ], []) |
2121 | | |
2122 | | + AC_CHECK_HEADER(Carbon/Carbon.h, [ |
2123 | | + AC_DEFINE(HAVE_CARBON, 1, [Define if we have CARBON]) |
2124 | | + LIBS="$LIBS -framework Carbon" |
2125 | | + ], []) |
2126 | | + |
2127 | | AC_MSG_CHECKING([for fink]) |
2128 | | if test -d /sw; then |
2129 | | AC_MSG_RESULT([found, adding /sw to search paths]) |