[英]How to open JPG image in application written in C on MacOS
I want to write a simple image browser in C and then make a bundle for the MacOs.我想在 C 中编写一个简单的图像浏览器,然后为 MacO 打包。
The problem is that I am encountering a warning when I am trying to open a jpg file from a context menu in Finder.问题是当我尝试从 Finder 的上下文菜单中打开 jpg 文件时遇到警告。
I compiled my code, I prepared a iViewGtk.app bundle with Info.plist file.我编译了我的代码,我准备了一个带有 Info.plist 文件的 iViewGtk.app 包。
The Info.plist is as follows: Info.plist如下:
<?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
.实际上 Info.plist 文件是来自工作应用程序 qView 的 Info.plist 文件的副本,可以使用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.我将该应用程序复制到应用程序文件夹中,Finder 似乎将其识别为可以打开图像文件的应用程序。 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.因为我不知道 Finder 的参数是如何提供给我的应用程序的,所以我没有实现打开和显示图像的部分。 I think, that it shouldn't be a problem for MacOS, should be?我认为,这对 MacOS 来说应该不是问题,应该是吗? The main.c looks as follows: main.c 如下所示:
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?有人能告诉我为什么 MacOS 会显示警告吗?
Is this somehow related to some MacOs security policies which are forbidding to open a file to an unknown app?这是否与某些禁止将文件打开到未知应用程序的 MacOs 安全策略有关?
Thank you.谢谢你。
It's not sufficient to have a .plist
file, there is also handling code necessary.拥有.plist
文件是不够的,还需要处理代码。
By the way, this is also the case for a regular Cocoa Objective-C applications.顺便说一句,对于常规的 Cocoa Objective-C 应用程序也是如此。 If none of the corresponding optional NSApplicationDelegate
methods (such as application:openURLs:
and friends) is implemented there, the dialog shown in the question appears.如果那里没有实现相应的可选NSApplicationDelegate
方法(例如application:openURLs:
和 friends),则会出现问题中显示的对话框。
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.无论是从提供的示例代码还是从使用的标签中都不能得出问题是指 GTK3 还是 GTK4 - 因此这个答案涵盖了这两种情况。
GTK4 GTK4
GTK4 already supports macOS as a backend. GTK4 已经支持 macOS 作为后端。 Looking for a corresponding NSApplicationDelegate
delegate method in gtkapplication-quartz.c one can see application:openFiles:
, so the support is there.在gtkapplication-quartz.c中寻找相应的NSApplicationDelegate
委托方法可以看到application:openFiles:
,所以支持就在那里。
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 .然而,在第 164 行中,可以看到仅当 boolean register_session
为真时才设置委托,请参见第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.通过gtk_application_impl_startup
、 gtk_application_startup
中的gtkapplication.c
等向后追踪,可以看到register_session
是应用程序的一个属性。
Basically, we need to set this to true to make sure the delegate is set and we are notified of open file attempts.基本上,我们需要将其设置为 true 以确保委托已设置,并且我们会收到打开文件尝试的通知。
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自包含的 GTK4 示例
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 CFBundleTypeExtensions 已弃用
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这应该适用于您的.plist
文件,但是自 OS X v10.5 以来不推荐使用CFBundleTypeExtensions
,请参阅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:要查看.jpeg
文件,您应该使用如下内容:
<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 GTK4 测试
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 应用程序包后,您可以使用上面的测试程序运行快速测试——如果您从命令行运行它,您甚至可以在控制台上看到 prinft 的prinft
:
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:当您通过在 Finder 中右键单击 a.jpeg 文件并从上下文菜单中选择“ Open With
方式”/ iViewGTK
”来打开文件时,将出现以下内容:
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.所以没有错误对话框,文件路径成功传递给 GTK 应用程序。
GTK3 GTK3
In the case of a GTK3 application, there are important notes at https://www.gtk.org/docs/installations/macos :对于 GTK3 应用程序,在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.与 GTK 的 Quartz 后端链接将您的应用程序连接到 Mac 的本机显示管理器、键盘和指点设备。 With a little extra code and gtk-mac-integration you can:通过一些额外的代码和 gtk-mac-integration,您可以:
... ...
- Receive open events from Finder.从 Finder 接收打开的事件。
- ... ...
Completely self-contained GTK3 example完全独立的 GTK3 示例
#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 GTK3 测试
The same test as above, if you select Open with
/ iViewGTK
in the Finder, the following appears:同上测试,如果你在Finder中用/ iViewGTK
Open with
select,出现如下:
So again no error dialog is shown and the file path is successfully passed to the GTK application.因此再次没有显示错误对话框,文件路径已成功传递给 GTK 应用程序。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.