Integration

Even though regular GTK+ applications work on the Mac, it is nice to be able to integrate with the native desktop and make it feel more like a Mac application. The integration library described here will help you with that.

Gtk-mac-integration/GtkOSXApplication

The integration library libgtkmacintegration.dylib contains two implementations, the original one using Carbon (gtk-mac-integration) and a new one using Cocoa (GtkOSXApplication). Since Apple has deprecated Carbon in OSX 10.6 (Snow Leopard), gtk-mac-integration is also now deprecated and should not be used in new code. Furthermore, maintainers of existing Gtk-OSX ports which use gtk-mac-integration are strongly encouraged to convert to GtkOSXApplication. In addition to being 64-bit compatible, it also fixes some glaring bugs in gtk-mac-menu when using multiple windows.

Naming Note: Gtk-mac-integration is the name of both the project and the deprecated implementation. It was called ige-mac-integration before being moved to Gnome from Github, and you will find older repositories on Github still using that name.

Gtk+-3.4 added built-in quartz menu integration without documentation. This page is not about that feature.

Documentation

GtkOSXApplication is fully documented via gtk-doc. To build the documentation in your installation, pass --enable-gtk-doc to configure. A current copy of the documentation can also be found here.

There is limited documentation for gtk-mac-integration below.

You'll find a test program at src/test-integration.c which exercises most of the features of each interface (depending on macro settings at the top of the file) which you can study.

Localization

GtkOSXApplication adds two menus, the Application menu (the one on the left with the application's name for a title) and optionally the Window menu, which include some standard menu items. Localization of these items is accomplished using the OSX method, with a GtkOSXApplication.strings file in each lang.lproj directory installed in $PREFIX/share/strings. If you install those directories in the Resources directory of your application bundle, the labels will be localized according to the user's language settings in System Preferences. I made the translations using Google Translate on just the labels, so it's likely that the translations are not idiomatic. Bug reports with better translations are most welcome.

Python

Both interfaces have PyGtk bindings which will be installed automatically if pygtk is detected. There are elementary test files in the respective bindings/python directories. GtkOSXApplication will set up pygobject introspection bindings instead if it detects Gtk+-3.

Haskell

Hamish Mackenzie has implemented Haskell bindings for GtkOSXApplication.

Apple Events

Support for Apple Events is not included in gtk-mac-integration. This means that it is not possible to have a GTK-OSX application opening files when clicked from the Finder.

GtkOSXApplication, on the other hand, provides a signal, NSApplicationOpenFile, to which you can connect to allow opening files from Finder.

Gedit has implemented an Application Delegate which handles the OpenFiles message from LaunchServices. This approach handles the file opening directly instead of emitting a signal; on the other hand, it requires more code in the application.

Alternatively, if developing a Python-based Gtk application, Apple Events can be accessed from MacPython, see MacPython Applescript. Be careful with MacPython, and stay away from anything that might start an event loop.

The automatic conversion of control-foo menu accelerators to command-foo has not been carried over to GtkOSXApplication, though a new facility is provided in Gtk+ (as of this writing it is in Git for Gtk+-2.24, and released in Gtk+-3.2.0) to use the <Primary> descriptor in place of <Control> for accelerators and bindings. This will map the accelerator to Command on OSX and to Control for anything else. Otherwise, you can load an accelerator map with the OSX standard key codes. A template map file is provided in data/template_accel_map; you'll need to edit it to match the accel paths in your application. Instructions are in the comments.

It may be easier to insert gtk_accel_map_save("path")} at the point where you would put gtk_accel_map_load("path"), compile, and run once. That will give you a template accel-map file that you can edit (just replace every instance of <ctrl> with <meta> and uncomment the changed lines: The file is Scheme, so the leading ';' is the comment token).

GStreamer

There is also a video sink that works with GTK+ on OS X available on Github.

Theming

The gtk-quartz-engine provided a more mac-like appearance to applications windows, but it had some major holes in what it rendered. Unfortunately, it is based on Carbon's HITheme interface (and parts of it still use the even-more-deprecated AppearanceManager). We can't recommend that you use it, and because of major changes to the theming architecture it doesn't work in Gtk+-3.

Fortunately, there are a great number of themes and engines available. The common engines can be installed by building meta-gtk-osx-themes. Add any themes you want to $PREFIX/share/themes before bundling, and they'll get copied into the bundle's Resources/share/themes directory. Then you (or your user) need only edit Resources/etc/gtk-2.0/gtkrc to include the line gtk-theme-name = "foo", where "foo" is the name of a subdirectory in Resources/share/themes containing the theme that you like.

Building

There's already a module for it, so just

$ jhbuild buildone gtk-quartz-engine

Installation in a Bundle

Add something like this to your bundle file (see [wiki:Bundle]):

  <binary>
    ${prefix}/lib/gtk-2.0/${pkg:gtk+-2.0:gtk_binary_version}/engines/*.so
  </binary>

  <data>
    ${prefix}/share/themes
  </data>

  <data dest='${bundle}/Contents/Resources/etc/gtk-2.0/gtkrc'>
    ${prefix}/share/themes/Quartz/gtk-2.0/gtkrc
  </data>

  <data dest="${bundle}/Contents/Resources">
    ${prefix}/share/strings
  </data>

Everything will be copied into the right places.

If you're not going to bundle the application, you can just copy the gtkrc above to ~/.gtkrc.

Documentation for the Carbon gtk-mac-integration functions

Here is a simple example for setting up the menu bar:

 gtk_widget_hide (menubar);
 gtk_mac_menu_set_menu_bar (GTK_MENU_SHELL (menubar));

This connects the application menubar to the mac menu bar (the one across the top of the screen). So long as you don't hide top-level menus in the menubar, changes to your menus in GTK will automatically be reflected in your Mac menus.

If you do hide and show top level menu items, then you need to call

  gtk_mac_menu_sync(GTK_MENU_SHELL (menubar));

every time you hide or unhide a top-level menu item.

To make the menu structure feel more native, you can rearrange menu items a bit:

 gtk_mac_menu_set_quit_menu_item (GTK_MENU_ITEM (quit_item));

 group = ige_mac_menu_add_app_menu_group ();
 gtk_mac_menu_add_app_menu_item  (group,
                                   GTK_MENU_ITEM (quit_item),
                                   NULL);
 
gtk_mac_menu_add_app_menu_item  (group,
                                   GTK_MENU_ITEM (about_item),
                                   NULL);

 group = gtk_mac_menu_add_app_menu_group ();
 gtk_mac_menu_add_app_menu_item  (group,
                                   GTK_MENU_ITEM (preferences_item),
                                   NULL);

This moves the Quit, About, and Preferences items to the application menu, where most Mac applications put those.

If for some reason you're writing code that's going to run in a non-quartz environment, you may find it useful to wrap the above code with

 #ifdef MAC_INTEGRATION
 ...
 #endif //MAC_INTEGRATION

and to include something like

### --------------------------------------------------------------------------
### Check to see if GDK uses the quartz backend and if we can use 
### MacOSX integration
_gdk_tgt=`$PKG_CONFIG --variable=target gdk-2.0`
AM_CONDITIONAL([GDK_TARGET_QUARTZ], [test x$_gdk_tgt = xquartz])
if test "x$_gdk_tgt" = xquartz; then 
   PKG_CHECK_MODULES(GTK_MAC, gtk-mac-integration)
   AC_SUBST(GTK_MAC_LIBS)
   AC_SUBST(GTK_MAC_CFLAGS)
fi

in your configure.ac and mention ${GTK_MAC_CFLAGS} and ${GTK_MAC_LIBS} in the appropriate locations of the appropriate Makefile.am.

This code won't work on GTK > 3.0; instead, use the macro provided with GTK to check which backends are supported:

GTK_CHECK_BACKEND([quartz], [3.0], [osx=yes], [osx=no])
if test "$os_osx" = "yes"; then
        PKG_CHECK_MODULES(GTK_MAC, gtk-mac-integration)
        AC_SUBST(GTK_MAC_LIBS)
        AC_SUBST(GTK_MAC_CFLAGS)
fi

For more examples, see the code in the source, test-integration.c. In addition the the menu bar integration, the API currently contains some hooks for the dock, and application bundles.

Projects/GTK+/OSX/Integration (last edited 2017-09-29 18:43:51 by jralls)