Swift包管理器:在Linux上创建和使用X11包
现在 Swift 已经开源了,应该有很多感兴趣的用户已经在他们的 Linux 系统上安装把玩过了。然而,目前的 Foundation 框架还在紧锣密鼓地开发中,所以如果你想开发出比命令行更复杂一点的程序,就得链接已有的 Linux 库,如 GTK,Cairo 或者 libpng 以开发出图形界面的程序。 我刚刚实现了一个简单的 Swift 程序,这个程序链接了 Unix 中最基本的 UI 类库1 —— 在开发的过程中,我们也会使用到新的 Swift 包管理器来为 X11 类库创建一个简单并且可重用的包。 下面是程序运行后的截图2:
Swift 包管理器在实际开始开发我们的 X11 应用之前,需要先定义一个 Swift 包用来定义链接到 X11 类库。一旦完成这个步骤,之后我们就可以将这个包分发给其它开发者,或者在别的项目中进行重用。我们必须将定义一个包和使用一个包区分开来。让我们先从定义开始,然后再学习如何使用。 定义一个包新建一个目录用来保存我们的包。由于我们需要链接到 C 语言的库,我遵循了 Swift 包管理器文档的指南,为包名加上一个 C 的前缀,将包命名为 bash mkdir CX11.swift 对我们来说,我们不想写任何的 Swift 包装(wrapper)代码,而是要直接对已有的 C 语言 API 进行链接。要链接到 C 语言类库和头文件需要通过 bash touch CX11.swift/module.modulemap nano CX11.swift/module.modulemap X11 是一个包含了很多功能的大型类库。你可以在 module CX11 [system] { module Xlib { header "/usr/include/X11/Xlib.h" } module X { header "/usr/include/X11/X.h" } link "X11" } 我们将所创建的模块(module)命名为 但是如果我们想链接到不止一个头文件呢?Module maps 允许我们定义一个 umbrella 头文件或指定一个 umbrella 目录。 Umbrella Header 这是一个头文件,里面包含了引用(通过 umbrella header "/usr/include/gtk/gtk.h" Umbrella Directory 有时候你有一个头文件目录但是并没有一个 umbrella header。在这种情况下,你可以告诉 Swift 直接到该目录下查找头文件: umbrella "/usr/include/X11/" 除了 modulemap 文件,我们还需要一个 Package.swift 文件,否则我们的构建将会失败。但是这个文件可以是空的: bash touch CX11.swift/Package.swift Swift 包管理器使用了 Git 和 Git Tags 来对包进行管理。所以我们还需要为我们的包创建一个 Git 仓库,添加所有的文件,然后打上一个版本标签。这是相当容易的: bash cd CX11.swift git init git add . git commit -m "Initial Import" git tag 1.0.0 cd .. 上述命令首先切换到目录中,创建一个 Git 仓库,添加所有的文件到仓库中,提交,最后为这个提交添加一个版本标记( 就是这些,我们的包已经定义完成了,那我们应该如何来使用呢? 包的使用要使用一个包,我们要先定义一个 bash mkdir swift-x11 touch swift-x11/Package.swift touch swift-x11/main.swift 需要注意的是(针对这个特定的示例程序)需要将 bash ls -l CX11.swift swift-x11 在真正着手开始写 Swift 代码与 X11 进行交互之前,我们需要告诉 import PackageDescription let package = Package( dependencies: [ .Package(url: "../CX11.swift",majorVersion: 1) ] ) 这些代码的意思是告诉 Swift 要到
bash import PackageDescription let package = Package( dependencies: [ .Package(url: "https://github.com/terhechte/CX11.swift.git",majorVersion: 1) ] ) 使用X11现在我们已经定义好了 X11 包,并且包管理器也配置完毕,现在就开始动手用 Swift 写第一个 X11 程序吧。 这里有一个问题我没办法解决,那就是定义在 X11 头文件中的宏并没有导入到 Swift 当中。 c #define RootWindow(dpy,src) (ScreenOfDisplay(dpy,src)->root) #define ScreenOfDisplay(dpy,scr)(&((_XPrivDisplay)dpy)->screens[scr]) 因为这些宏都没有被导入,所以我决定将宏所定义的完整代码都写出来。以下所有的代码都是写在 我们先从导入前面定义的 import CX11.Xlib import CX11.X 配置在这之后,我们需要定义一些变量。
变量定义好之后,我们需要打开到 X11 服务器的连接。但是,由于用户有可能在没有安装 X11 服务器(比如,控制台模式)的机器上运行这个应用程序,所以我们需要判断这个连接是否成功: d = XOpenDisplay(nil) if d == nil { fatalError("cannot open display") } 在成功打开连接之后,我们要获取当前的默认显示屏以及当前的根窗口。由于 // Get the default screen s = XDefaultScreenOfDisplay(d) // And the current root window on that screen let rootWindow = s.memory.root 创建一个窗口现在我们有了创建窗口以及将其显示在屏幕中的所有东西。我们将使用 c XCreateSimpleWindow(Display *display,Window parent,int x,int y,unsigned int width,unsigned int height,unsigned int border_width,unsigned long border,unsigned long background);
// Create our window w = XCreateSimpleWindow(d,rootWindow,10,200,100,1,s.memory.black_pixel,s.memory.white_pixel) 这段代码会在 输入事件当然,我们还需要接受从 Xserver 上传来的输入事件。在这个例子中,我们需要知道窗口何时被显示,此时我们可以在上面进行绘制,我们还需要知道用户按下特定键退出程序的事件。第一个是 c XSelectInput(d,w,ExposureMask | KeyPressMask) 窗口创建完成之后,我们就可以显示它了。这是通过 c XMapWindow(d,w) 事件循环(Event Loop)最后,我们需要在窗口的显示期间启动事件循环。在这里,我用一个 loop: while true { // Wait for the next event XNextEvent(d,e) switch e.memory.type { // The window has to be drawn case Expose: // draw a small black rectangle XFillRectangle(d,s.memory.default_gc,20,10) // draw the text XDrawString(d,70,msg,Int32(msg.characters.count)) // The user did press a key case KeyPress: break loop // We never signed up for this event default: fatalError("Unknown Event") } } 这里的 另一个事件, 运行要运行这个程序,只需要 check out 仓库(最好在Linux上进行)并且在目录中运行如下命令: bash swift build 这个命令会 clone 通过如下的命令来运行: bash .build/debug/swift-x11-example 这将会执行二进制文件,一个小小的 X11 窗口将会出现在你的桌面上:
总结这是一个相当的简单的示例,展示了如何在 Linux 下使用 Swift 写一个 X11 应用程序。当然,这些知识同样适用地链接到其它类库的不同类型的应用程序。这个教程同时也通过使用一个简单的 完整的 X11 应用程序代码可以在这里找到。
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |