Reputation: 201
I want to write a simple image browser in C and then make a bundle for the MacOs.
The problem is that I am encountering a warning when I am trying to open a jpg file from a context menu in Finder.
I compiled my code, I prepared a iViewGtk.app bundle with Info.plist file.
The Info.plist is as follows:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleExecutable</key>
<string>iViewGtk</string>
<key>CFBundleName</key>
<string>iViewGtk</string>
<key>CFBundleGetInfoString</key>
<string>5.0</string>
<key>CFBundleTypeName</key>
<string>3r23rfewfwefwef343f</string>
<key>CFBundleTypeOSTypes</key>
<array>
<string>****</string>
</array>
<key>CFBundleTypeMIMETypes</key>
<string>image/jpeg</string>
<key>CFBundleIconFile</key>
<string>icon.icns</string>
<key>CFBundleIdentifier</key>
<string>net.bean.gtk.iview</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>LSMinimumSystemVersion</key>
<string>10.14</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>CFBundleShortVersionString</key>
<string>5.0</string>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>bmp</string>
<string>cur</string>
<string>gif</string>
<string>icns</string>
<string>ico</string>
<string>jpeg</string>
<string>jpg</string>
<string>jpe</string>
<string>jfi</string>
<string>jfif</string>
<string>pbm</string>
<string>pgm</string>
<string>png</string>
<string>ppm</string>
<string>svg</string>
<string>svgz</string>
<string>tif</string>
<string>tiff</string>
<string>wbmp</string>
<string>webp</string>
<string>xbm</string>
<string>xpm</string>
<string>ani</string>
<string>apng</string>
<string>avif</string>
<string>avifs</string>
<string>bw</string>
<string>exr</string>
<string>hdr</string>
<string>heic</string>
<string>heif</string>
<string>jxl</string>
<string>kra</string>
<string>ora</string>
<string>pcx</string>
<string>pic</string>
<string>psd</string>
<string>ras</string>
<string>rgb</string>
<string>rgba</string>
<string>sgi</string>
<string>tga</string>
<string>xcf</string>
</array>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
</array>
<key>NSSupportsAutomaticGraphicsSwitching</key>
<true />
<key>NSHighResolutionCapable</key>
<true />
</dict>
</plist>
Actually the Info.plist file is a copy of Info.plist file from a working application qView which can be installed using brew install qview
.
In addition to that I am able to click on the bundle and open the application by clicking it.
I copied the app into Application folder and it seems that Finder recognizes it as application which can open image files. It is not grayed out:
Since I don't know how the parameter from Finder is provided to my app, I didn't implement the part which opens and displays the image. I think, that it shouldn't be a problem for MacOS, should be? The main.c looks as follows:
int main(int argc, char **argv)
{
struct ApplicationContext *appContext = malloc(sizeof(appContext));
GtkApplication *app;
int status;
app = gtk_application_new("net.bean.app", G_APPLICATION_HANDLES_OPEN);
g_signal_connect(app, "activate", G_CALLBACK(activate), appContext);
g_signal_connect(app, "open", G_CALLBACK(app_open), appContext);
status = g_application_run(G_APPLICATION(app), argc, argv);
g_object_unref(app);
return status;
}
Could someone tell me why MacOS displays the warning?
Is this somehow related to some MacOs security policies which are forbidding to open a file to an unknown app?
Thank you.
Upvotes: 0
Views: 185
Reputation: 27106
It's not sufficient to have a .plist
file, there is also handling code necessary.
By the way, this is also the case for a regular Cocoa Objective-C applications. If none of the corresponding optional NSApplicationDelegate
methods (such as application:openURLs:
and friends) is implemented there, the dialog shown in the question appears.
Neither from the sample code provided nor from the tags used can one conclude whether the question refers to GTK3 or GTK4 - therefore this answer covers both cases.
GTK4
GTK4 already supports macOS as a backend. Looking for a corresponding NSApplicationDelegate
delegate method in gtkapplication-quartz.c one can see application:openFiles:
, so the support is there.
However in line 164 one can see that the delegate is only set if the boolean register_session
is true, see the check in line 161.
Following that trace backwards via gtk_application_impl_startup
, gtk_application_startup
in gtkapplication.c
etc. one can see that register_session
is a property of the application.
Basically, we need to set this to true to make sure the delegate is set and we are notified of open file attempts.
The property can then be set something like this:
GValue val = G_VALUE_INIT;
g_value_init (&val, G_TYPE_BOOLEAN);
g_value_set_boolean(&val, true);
g_object_set_property(G_OBJECT(app), "register-session", &val);
g_value_unset (&val);
Self-contained GTK4 example
Following on from the above, it could be written something like this:
#include <gtk/gtk.h>
static void
activate (GtkApplication *app) {
GtkWidget *window = gtk_application_window_new (app);
GtkWidget *button = gtk_button_new_with_label ("Close App");
g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_window_close), window);
gtk_window_set_child (GTK_WINDOW (window), button);
gtk_window_present (GTK_WINDOW (window));
}
static void
app_open (GApplication *application, GFile **files, gint n_files, const gchar *hint) {
for (gint i = 0; i < n_files; i++) {
gchar *uri = g_file_get_uri (files[i]);
g_print ("open %s\n", uri);
g_free (uri);
}
}
int main(int argc, char **argv) {
GtkApplication *app = gtk_application_new("net.bean.app", G_APPLICATION_HANDLES_OPEN);
GValue val = G_VALUE_INIT;
g_value_init (&val, G_TYPE_BOOLEAN);
g_value_set_boolean(&val, true);
g_object_set_property(G_OBJECT(app), "register-session", &val);
g_value_unset (&val);
g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
g_signal_connect(app, "open", G_CALLBACK(app_open), NULL);
int status = g_application_run(G_APPLICATION(app), argc, argv);
g_object_unref(app);
return status;
}
CFBundleTypeExtensions is deprecated
This should work with your .plist
file, however CFBundleTypeExtensions
is deprecated since OS X v10.5., see https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
For viewing .jpeg
files, you should rather use something like the following:
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeName</key>
<string>JPEG File</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSHandlerRank</key>
<string>Alternate</string>
<key>LSItemContentTypes</key>
<array>
<string>public.jpeg</string>
</array>
</dict>
</array>
GTK4 Test
After creating the iViewGTK app bundle, you can run a quick test with the above test program - if you run it from the command line, you can even see the output of prinft
on the console:
iViewGTK.app/Contents/MacOS/iViewGTK
When you open a file by right-clicking a .jpeg file in the Finder and choosing Open With
/iViewGTK
from the context menu, the following appears:
open file:///Users/stephan/tmp/gtk/testsuite/gdk/image-data/iamge-cmyk.jpeg
So there is no error dialog and the file path is successfully passed to the GTK application.
GTK3
In the case of a GTK3 application, there are important notes at https://www.gtk.org/docs/installations/macos:
Linking with GTK’s Quartz backend connects your application to the Mac’s native display manager, keyboard, and pointing device. With a little extra code and gtk-mac-integration you can:
...
- Receive open events from Finder.
- ...
Completely self-contained GTK3 example
#include <gtk/gtk.h>
#include <assert.h>
#include <gtkosxapplication.h>
static GtkWidget *
new_window(void) {
GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
assert (window != NULL);
gtk_widget_show_all(window);
return window;
}
static gboolean
app_open_file_cb (GtkosxApplication *app, gchar *path, gpointer user_data) {
printf("open file '%s'\n", path);
//do sth with file
return TRUE;
}
int main(int argc, char **argv) {
gtk_init (&argc, &argv);
GtkApplication *app = g_object_new (GTKOSX_TYPE_APPLICATION, NULL);
GtkWidget *window = new_window();
g_signal_connect (app, "NSApplicationOpenFile",
G_CALLBACK (app_open_file_cb), NULL);
gtkosx_application_ready (app);
gtk_main ();
g_object_unref(app);
return 0;
}
GTK3 Test
The same test as above, if you select Open with
/iViewGTK
in the Finder, the following appears:
So again no error dialog is shown and the file path is successfully passed to the GTK application.
Upvotes: 2