Gio plugins is a system to use third-party plugins similar to Gio features, this package also holds one collection
of plugins for the Gio. All plugins uses the same interface, and just one line of code must be
added in the main-loop, as explained below. Furthermore, some packages can be used as standalone and doesn't require
the plugin
package.
That package also serves as experimentation ground for "plugin system", which may land to Gio in the future.
Gio is a great GUI library, but it lacks some features that are important for some applications. I worked in some extensions before, and I also maintained one fork of Gio, which contains some changes. However, that leads to many issues: keeping the fork updated is problematic. Creating extensions that are similar to Gio is impossible.
I decided to create a plugin system to make it easier to use third-party extensions. I also proposed this idea to the Gio-core .
First, you must download the plugin
package:
go get -u github.com/gioui-plugins/gio-plugins@latest
Now, you need to modify your event-loop, you must include gioplugins.Hijack(window)
in your event-loop, before handling
events:
window := &app.Window{} // Gio window
for {
+ evt := gioplugins.Hijack(window) // Gio main event loop
switch evt := evt.(type) {
// ...
}
}
Each plugin has its own README.md file, explaining how to use it. In general, you can simple
use nameOfPlugin.SomeOp{}.Add(gtx.Ops)
, similar of how you use pointer.PassOp{}.Add(gtx.Ops)
, native
from Gio. Beginning with Gio 0.6, it also introduces Command
, which is executed using gtx.Execute
, you can
also use Commands, if the plugin supports it, for instance gioplugins.Execute(gtx, gioshare.TextCmd{Text: "Hello, World!"})
,
similar to what you are familiar with gtx.Execute(clipboard.WriteCmd{Text: "Hello, World!"})
.
Once gioplugins.Event
is set, you can use the plugins as simple op
operations or cmd
commands. If you are unsure
if the plugin is working, you can use the pingpong
package, which will return on PongEvent
to the given Tag:
pingpong.PingOp{Tag: &something}.Add(gtx.Ops)
gioplugins.Execute(gtx, pingpong.PingCmd{Tag: &something})
Note: It's uses
gioplugins.Execute
and notgtx.Execute
!
You can receive responses using the Tag
, similar Gio-core operations:
for {
evt, ok := gioplugins.Event(pingpong.Filter{Tag: &something})
if !ok {
break
}
if evt, ok := evt.(pingpong.PongEvent); ok {
fmt.Println(evt.Pong)
}
}
Of course, pingpong
has no use in real-world applications, but it can be used to test if the plugin is working.
We have few plugins available:
Name | Description | OS |
---|---|---|
PingPong | Test if the plugin system is working. | Android, iOS, macOS, Windows, WebAssembly, Linux, FreeBSD |
Share | Share text/links using the native share dialog. | Android, iOS, macOS, Windows, WebAssembly |
WebViewer | Display in-app webview using the native webview implementation on each platform. | Android, iOS, macOS, Windows, WebAssembly |
Hyperlink | Open hyperlinks in the default browser. | Android, iOS, macOS, Windows, WebAssembly |
Explorer | Opens the native file-dialog, to read/write files. | Android, iOS, macOS, Windows, WebAssembly |
Safedata | Read/Write files into the secure storage of the device. | Android, iOS, macOS, Windows, WebAssembly |
We have few plugins planned:
Some plugins are planned, but not yet implemented, follow the development at https://github.com/orgs/gioui-plugins/projects/1. Also, consider send some 👍 on issues which mentions features that you like.
If you want to help, please open an issue or a PR! If you want to suggest a plugin, please open an issue.
If you want to create a new plugin, you can check the pingpog
package, which is the simplest plugin available.
Generally, you need implement plugin.Handler
, and call plugin.Register
in your init()
function. Your code will get
specific events and ops, which you define in your Handler
implementation.
- Android: XML/Manifest: There's no direct integration with
gogio
. Consequently, your plugin cannot require any additional XML file or changes in the manifest. That may limit some plugins, but it's a limitation ofgogio
itself. - General: Position: There's no way to get relative position of each operation, or mimic the
paint.PaintOp{}
, so if your plugin is adding views to the screen, you must use absolute positions. This is a limitation of Gio itself, which doesn't easily expose the relative position of each operation.
Most packages are compatible with the latest version of Gio, and only the latest version should be supported. Beware
that internal changes in the Gio API can break the compatibility with plugin
. None of the packages has stable API,
and breaking changes can happen at any time.
Most plugins are compatible with Android 5+, iOS 13+, MacOS 12+, Windows 10+ and WebAssembly. Currently, we consider the Windows and Android as high-priority, and the WebAssembly as medium-priority, MacOS and iOS as low-priority. Furthermore, we don't have any plans to support Linux and FreeBSD due to the low market-share and the lack of API standards.
Priority | OS | Arch |
---|---|---|
High | Windows | AMD64 |
High | Android | ARM64, ARMv7 |
Medium | WebAssembly | WASMv1 |
Low | MacOS | ARM64, AMD64 |
Low | iOS | ARM64 |
Ignored | FreeBSD | - |
Ignored | Linux | - |
Currently, some package might not work on some platforms, and some features might not be available on some platforms.
This package heavily uses unsafe
, and as it suggest: it can be unsafe to use. We are not responsible for any damage
caused by this package. Some plugins also use unsafe
and CGO to interact with the native platform. While we try to
keep the code safe, we can't guarantee that it is safe enough for your use-case. Also, is impossible to verify the
integrity of native-APIs, so we can't guarantee that the native-APIs will have the expected behavior.
Since we have limited resources and devices, we can't test all plugins on all platforms and devices. Currently, we have a few devices available and with limited range of OS versions. Plugins are usually tested on those devices:
- Android: Motorola Droid Max, Motorola E6, Xiaomi A7, Xiaomi Note 9, (+ BrowserStack)
- iOS: iPhone SE 2Gen (2020), (+ BrowserStack)
- WASM: Chrome, Firefox, Safari, (+ BrowserStack)
- Windows: Custom (Ryzen 3900X+RX 5700XT), Proxmox VM (EPYC 7501P)
- MacOS: MacBook Air (M1, 2020)
- Linux: Proxmox VM (EPYC 7501P)
- FreeBSD: Proxmox VM (EPYC 7501P)
Tests are performed manually, since most features interact with the native platform, and automated tests are not easy to implement. We are open to suggestions on how to improve the testing process.
Please, if you find any bug, open an issue or a PR!
Each OS has its own way to interact with the native APIs. For example, on Android, you need to create a Java class and
call it using JNI. On iOS and MacOS you need to write some Objective-C code and call it using CGO. On Windows, you need
to write some code using syscall
to each DLL, which may use COM API, some APIs uses WinRT instead of Win32, which can
be harder to use. On WebAssembly, you need to use syscall/js
to interact with the browser APIs, or use InkWasm, which
is faster. On Linux/FreeBSD you may need to use C and CGO to interact with the native APIs.
This package is licensed under the MIT License, some pre-compiled files may have other license. See the LICENSE file for details.