我在Mac OSX上用纯C创建一个应用程序。 我想要的是创建一个窗口,我的应用程序将存储。
最好我希望它是纯C解决方案,但是如果我必须使用objective-c类来初始化窗口然后将上下文发送到我的C代码那么它就没问题了。
我没有使用xcode,只有简单的文本编辑器,我试图导入cocoa但它只是产生了很多错误。
总而言之,我的问题是: 如何在简单的纯C中生成将显示osx窗口的代码?
答案 0 :(得分:9)
您可以使用Objective-C runtime API 示例(iOS)Creating an iOS app in pure C
在obj-c中替换相同的代码:
echo '#import <Cocoa/Cocoa.h>
int main ()
{
@autoreleasepool{
[NSApplication sharedApplication];
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
id applicationName = [[NSProcessInfo processInfo] processName];
id window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 120, 120)
styleMask:NSTitledWindowMask backing:NSBackingStoreBuffered defer:NO];
[window cascadeTopLeftFromPoint:NSMakePoint(20,20)];
[window setTitle: applicationName];
[window makeKeyAndOrderFront:nil];
[NSApp activateIgnoringOtherApps:YES];
[NSApp run];
}
return 0;
}' | gcc -fobjc-arc -framework Cocoa -x objective-c -o MicroApp - ; ./MicroApp
这将运行带有1个窗口的Cocoa应用程序。比如下面的截图
您实际上可以使用NSMenu
添加菜单 id applicationMenuBar = [NSMenu new];
id appMenuItem = [NSMenuItem new];
[applicationMenuBar addItem:appMenuItem];
[NSApp setMainMenu: applicationMenuBar];
答案 1 :(得分:9)
cmacs_simple_msgSend((id)objc_getClass("NSApplication"), sel_getUid("sharedApplication"));
if (NSApp == NULL) {
fprintf(stderr,"Failed to initialized NSApplication... terminating...\n");
return;
}
id appDelObj = cmacs_simple_msgSend((id)objc_getClass("AppDelegate"), sel_getUid("alloc"));
appDelObj = cmacs_simple_msgSend(appDelObj, sel_getUid("init"));
cmacs_void_msgSend1(NSApp, sel_getUid("setDelegate:"), appDelObj);
cmacs_void_msgSend(NSApp, sel_getUid("run"));
正如您将注意到的,此代码使用Objective-C运行时API来创建虚假的AppDelegate。创建窗口是一个复杂的过程:
self->window = cmacs_simple_msgSend((id)objc_getClass("NSWindow"), sel_getUid("alloc"));
/// Create an instance of the window.
self->window = cmacs_window_init_msgSend(self->window, sel_getUid("initWithContentRect:styleMask:backing:defer:"), (CMRect){0,0,1024,460}, (NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask | NSMiniaturizableWindowMask), 0, false);
/// Create an instance of our view class.
///
/// Relies on the view having declared a constructor that allocates a class pair for it.
id view = cmacs_rect_msgSend1(cmacs_simple_msgSend((id)objc_getClass("View"), sel_getUid("alloc")), sel_getUid("initWithFrame:"), (CMRect){ 0, 0, 320, 480 });
// here we simply add the view to the window.
cmacs_void_msgSend1(self->window, sel_getUid("setContentView:"), view);
cmacs_simple_msgSend(self->window, sel_getUid("becomeFirstResponder"));
// Shows our window in the bottom-left hand corner of the screen.
cmacs_void_msgSend1(self->window, sel_getUid("makeKeyAndOrderFront:"), self);
return YES;
所以,是的。你可以用纯C写一个Cocoa应用程序。但是我不推荐它。 90%的代码可以被xib文件替换,这样做实际上限制了你的应用程序,因为Apple开发堆栈的更多高级功能确实在Objective-C功能上。虽然技术上可以通过这种方式完成所有事情,但是你做得比它应该更难。
答案 2 :(得分:5)
我翻译了接受的Pure C答案:
// based on https://stackoverflow.com/a/30269562
// Minimal Pure C code to create a window in Cocoa
// $ clang minimal.c -framework Cocoa -o minimal.app
#include <objc/runtime.h>
#include <objc/message.h>
#include <Carbon/Carbon.h>
#define cls objc_getClass
#define sel sel_getUid
#define msg ((id (*)(id, SEL, ...))objc_msgSend)
#define cls_msg ((id (*)(Class, SEL, ...))objc_msgSend)
// poor man's bindings!
typedef enum NSApplicationActivationPolicy {
NSApplicationActivationPolicyRegular = 0,
NSApplicationActivationPolicyAccessory = 1,
NSApplicationActivationPolicyERROR = 2,
} NSApplicationActivationPolicy;
typedef enum NSWindowStyleMask {
NSWindowStyleMaskBorderless = 0,
NSWindowStyleMaskTitled = 1 << 0,
NSWindowStyleMaskClosable = 1 << 1,
NSWindowStyleMaskMiniaturizable = 1 << 2,
NSWindowStyleMaskResizable = 1 << 3,
} NSWindowStyleMask;
typedef enum NSBackingStoreType {
NSBackingStoreBuffered = 2,
} NSBackingStoreType;
int main(int argc, char *argv[])
{
// id app = [NSApplication sharedApplication];
id app = cls_msg(cls("NSApplication"), sel("sharedApplication"));
// [app setActivationPolicy:NSApplicationActivationPolicyRegular];
msg(app, sel("setActivationPolicy:"), NSApplicationActivationPolicyRegular);
struct CGRect frameRect = {0, 0, 600, 500};
// id window = [[NSWindow alloc] initWithContentRect:frameRect styleMask:NSWindowStyleMaskTitled|NSWindowStyleMaskClosable|NSWindowStyleMaskResizable backing:NSBackingStoreBuffered defer:NO];
id window = msg(cls_msg(cls("NSWindow"), sel("alloc")),
sel("initWithContentRect:styleMask:backing:defer:"),
frameRect,
NSWindowStyleMaskTitled|NSWindowStyleMaskClosable|NSWindowStyleMaskResizable,
NSBackingStoreBuffered,
false);
msg(window, sel("setTitle:"), cls_msg(cls("NSString"), sel("stringWithUTF8String:"), "Pure C App"));
// [window makeKeyAndOrderFront:nil];
msg(window, sel("makeKeyAndOrderFront:"), nil);
// [app activateIgnoringOtherApps:YES];
msg(app, sel("activateIgnoringOtherApps:"), true);
msg(app, sel("run"));
}
答案 3 :(得分:1)
我在Mac OSX上用纯C创建应用程序。我想要的是创建一个存储我的应用程序的窗口。
您在寻找TTY窗口吗?
如果是,那么您的应用程序是否需要创建窗口?
如果没有,那么您可以简单地编写纯C程序并在终端内执行 - 一个TTY环境,用于&#34;纯C&#34;。
如果您想要一个可双击的应用程序,您可以编写AppleScript,它将打开终端并运行您的C.类似于:
$string = '<p style="position:absolute;top:98px;left:472px;white-space:nowrap">';
$test = str_replace('left:', 'display:none;[', $string );
$test = str_replace('white-space', ']white-space', $test );
$out = delete_all_between('[', ']', $test);
print($out); // output
function delete_all_between($beginning, $end, $string) {
$beginningPos = strpos($string, $beginning);
$endPos = strpos($string, $end);
if ($beginningPos === false || $endPos === false) {
return $string;
}
$textToDelete = substr($string, $beginningPos, ($endPos + strlen($end)) - $beginningPos);
return str_replace($textToDelete, '', $string);
}
这将打开一个终端窗口,显示&#34; ex&#34;当退出时将终止shell进程(因此不能输入其他命令),但它不关闭终端本身 - 为此你必须更加努力。
如果您确实希望应用程序创建窗口本身,您需要编写自己的简单TTY窗口,您可能会找到一些可以使用的类,或者您可以从开源终端应用程序借用代码,例如iterm
HTH
答案 4 :(得分:1)
我记得大约一年前看到这个问题,当时我非常希望我可以打开d ***窗口,谷歌搜索几天,只找到您在这篇文章上方看到的答案类型。
我正在阅读Mac所基于的操作系统-Berkley Software Distribution。 http://codex.cs.yale.edu/avi/os-book/OS9/appendices-dir/a.pdf在第17页上的那句话“ ... X由MIT开发的Windowing System”打在我身上,我想起了我无法打开窗户,以及对此的不满,我以为这可能是终于解决了!
我用Google搜索“ BSD X窗口编程”,偶然发现了最终用纯C语言打开窗口的方法。
我刚刚发现它,所以我还不是一个大师,但请查看此链接https://en.wikibooks.org/wiki/X_Window_Programming/Xlib并转到示例,请确保遵循顶部的注释以了解如何使用X11库进行编译(您可以只要拥有-lX11,就可以忽略-Wall和-O命令。
如果无法编译,如果找不到头文件,则需要帮助它查找头文件。
X11可能在系统上有几个不同的位置。您很有可能会在/opt/X11/include
中找到它,其中将包含您需要的标头的所有定义。
您可以在C程序中包含完整路径,例如:
#include "/opt/X11/include/X11/Xlib.h"
但是我们希望它看起来像这样#include <X11/Xlib.h>
因此,您可以在编译-I /opt/X11/include
或者转到主目录中的.profile
或.bashrc
或.bash_profile
并添加:
export C_INCLUDE_PATH="$C_INCLUDE_PATH:/opt/X11/include"
/*
简单的Xlib应用程序在窗口中绘制一个框。
* /
从Wiki:
#include<X11/Xlib.h>
#include<stdio.h>
#include<stdlib.h> // prevents error for exit on line 18 when compiling with gcc
int main() {
Display *d;
int s;
Window w;
XEvent e;
/* open connection with the server */
d=XOpenDisplay(NULL);
if(d==NULL) {
printf("Cannot open display\n");
exit(1);
}
s=DefaultScreen(d);
/* create window */
w=XCreateSimpleWindow(d, RootWindow(d, s), 10, 10, 100, 100, 1,
BlackPixel(d, s), WhitePixel(d, s));
// Process Window Close Event through event handler so XNextEvent does Not fail
Atom delWindow = XInternAtom( d, "WM_DELETE_WINDOW", 0 );
XSetWMProtocols(d , w, &delWindow, 1);
/* select kind of events we are interested in */
XSelectInput(d, w, ExposureMask | KeyPressMask);
/* map (show) the window */
XMapWindow(d, w);
/* event loop */
while(1) {
XNextEvent(d, &e);
/* draw or redraw the window */
if(e.type==Expose) {
XFillRectangle(d, w, DefaultGC(d, s), 20, 20, 10, 10);
}
/* exit on key press */
if(e.type==KeyPress)
break;
// Handle Windows Close Event
if(e.type==ClientMessage)
break;
}
/* destroy our window */
XDestroyWindow(d, w);
/* close connection to server */
XCloseDisplay(d);
return 0;
}
编译:
gcc -O2 -Wall -o test test.c -L /usr/X11R6/lib -lX11 -lm
答案 5 :(得分:0)
纯C跨平台示例:(Windows/macOS/Linux) https://nappgui.com/en/demo/products.html
关于纯 C 语言的 macOS 可移植性(更新到 BigSur 和 M1 支持): https://nappgui.com/en/start/win_mac_linux.html#h2