feat: update to new nheko api
This commit is contained in:
parent
eddd3f8cee
commit
4925fdf2ca
|
@ -43,7 +43,6 @@ const NhdbusGen = struct {
|
|||
}
|
||||
|
||||
fn make(step: *std.build.Step) !void {
|
||||
_ = step;
|
||||
const self = @fieldParentPtr(NhdbusGen, "step", step);
|
||||
const b = self.lib.builder;
|
||||
|
||||
|
|
|
@ -1,65 +1,64 @@
|
|||
<!DOCTYPE
|
||||
node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
||||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
<node>
|
||||
<interface name="im.nheko.Nheko">
|
||||
<method name="apiVersion">
|
||||
<arg type="s" direction="out" />
|
||||
<arg type="s" direction="out"/>
|
||||
</method>
|
||||
<method name="nhekoVersion">
|
||||
<arg type="s" direction="out" />
|
||||
<arg type="s" direction="out"/>
|
||||
</method>
|
||||
<method name="rooms">
|
||||
<arg type="a(sss(iiibiiay)i)" direction="out" />
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0"
|
||||
value="QVector<nheko::dbus::RoomInfoItem>" />
|
||||
<arg type="a(ssssi)" direction="out"/>
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVector<nheko::dbus::RoomInfoItem>"/>
|
||||
</method>
|
||||
<method name="image">
|
||||
<arg type="(iiibiiay)" direction="out"/>
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QImage"/>
|
||||
<arg name="uri" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="activateRoom">
|
||||
<arg name="alias" type="s" direction="in" />
|
||||
<arg name="alias" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="joinRoom">
|
||||
<arg name="alias" type="s" direction="in" />
|
||||
<arg name="alias" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="directChat">
|
||||
<arg name="userId" type="s" direction="in" />
|
||||
<arg name="userId" type="s" direction="in"/>
|
||||
</method>
|
||||
</interface>
|
||||
<interface name="org.freedesktop.DBus.Properties">
|
||||
<method name="Get">
|
||||
<arg name="interface_name" type="s" direction="in" />
|
||||
<arg name="property_name" type="s" direction="in" />
|
||||
<arg name="value" type="v" direction="out" />
|
||||
<arg name="interface_name" type="s" direction="in"/>
|
||||
<arg name="property_name" type="s" direction="in"/>
|
||||
<arg name="value" type="v" direction="out"/>
|
||||
</method>
|
||||
<method name="Set">
|
||||
<arg name="interface_name" type="s" direction="in" />
|
||||
<arg name="property_name" type="s" direction="in" />
|
||||
<arg name="value" type="v" direction="in" />
|
||||
<arg name="interface_name" type="s" direction="in"/>
|
||||
<arg name="property_name" type="s" direction="in"/>
|
||||
<arg name="value" type="v" direction="in"/>
|
||||
</method>
|
||||
<method name="GetAll">
|
||||
<arg name="interface_name" type="s" direction="in" />
|
||||
<arg name="values" type="a{sv}" direction="out" />
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0"
|
||||
value="QVariantMap" />
|
||||
<arg name="interface_name" type="s" direction="in"/>
|
||||
<arg name="values" type="a{sv}" direction="out"/>
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
|
||||
</method>
|
||||
<signal name="PropertiesChanged">
|
||||
<arg name="interface_name" type="s" direction="out" />
|
||||
<arg name="changed_properties" type="a{sv}"
|
||||
direction="out" />
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.Out1"
|
||||
value="QVariantMap" />
|
||||
<arg name="invalidated_properties" type="as"
|
||||
direction="out" />
|
||||
<arg name="interface_name" type="s" direction="out"/>
|
||||
<arg name="changed_properties" type="a{sv}" direction="out"/>
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.Out1" value="QVariantMap"/>
|
||||
<arg name="invalidated_properties" type="as" direction="out"/>
|
||||
</signal>
|
||||
</interface>
|
||||
<interface name="org.freedesktop.DBus.Introspectable">
|
||||
<method name="Introspect">
|
||||
<arg name="xml_data" type="s" direction="out" />
|
||||
<arg name="xml_data" type="s" direction="out"/>
|
||||
</method>
|
||||
</interface>
|
||||
<interface name="org.freedesktop.DBus.Peer">
|
||||
<method name="Ping" />
|
||||
<method name="Ping"/>
|
||||
<method name="GetMachineId">
|
||||
<arg name="machine_uuid" type="s" direction="out" />
|
||||
<arg name="machine_uuid" type="s" direction="out"/>
|
||||
</method>
|
||||
</interface>
|
||||
</node>
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
const std = @import("std");
|
||||
const c = @import("ffi.zig").c;
|
||||
const dbus = @import("dbus.zig");
|
||||
const Image = @import("Image.zig");
|
||||
|
||||
const Entry = union(enum) {
|
||||
loading,
|
||||
cached: Image,
|
||||
};
|
||||
|
||||
data: std.StringHashMap(Entry),
|
||||
|
||||
const Self = @This();
|
||||
|
||||
pub fn init(alloc: std.mem.Allocator) Self {
|
||||
return .{
|
||||
.data = std.StringHashMap(Entry).init(alloc),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Self) void {
|
||||
self.data.deinit();
|
||||
self.* = undefined;
|
||||
}
|
||||
|
||||
/// Will grab the image if its already cached,
|
||||
/// otherwise will start a DBus request to load it, reloading the view
|
||||
/// once the image is received.
|
||||
pub fn get(
|
||||
self: *Self,
|
||||
url: [:0]const u8,
|
||||
proxy: *c.nhdbus,
|
||||
icon_data_alloc: std.mem.Allocator,
|
||||
) !?Image {
|
||||
const result = try self.data.getOrPut(url);
|
||||
if (result.found_existing) {
|
||||
switch (result.value_ptr.*) {
|
||||
.loading => return null,
|
||||
.cached => |img| return img,
|
||||
}
|
||||
}
|
||||
|
||||
std.log.info("Requesting icon `{s}`", .{url});
|
||||
|
||||
try dbus.requestIcon(proxy, self, url, icon_data_alloc);
|
||||
result.value_ptr.* = .loading;
|
||||
return null;
|
||||
}
|
|
@ -1,15 +1,8 @@
|
|||
const c = @import("ffi.zig").c;
|
||||
const Image = @import("Image.zig");
|
||||
|
||||
/// Strings must be deallocated manually
|
||||
id: [:0]c.gchar,
|
||||
alias: [:0]c.gchar,
|
||||
name: [:0]c.gchar,
|
||||
image: Image,
|
||||
icon_url: ?[:0]c.gchar,
|
||||
notifications: c_int,
|
||||
|
||||
const Self = @This();
|
||||
|
||||
pub fn deinit(self: *Self) void {
|
||||
self.image.deinit();
|
||||
}
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
const std = @import("std");
|
||||
const c = @import("ffi.zig").c;
|
||||
const Room = @import("Room.zig");
|
||||
const IconStore = @import("IconStore.zig");
|
||||
|
||||
rooms: std.ArrayList(Room),
|
||||
rooms_lock: std.Thread.Mutex,
|
||||
room_arena: std.heap.ArenaAllocator,
|
||||
icon_store: IconStore,
|
||||
dbus: *c.nhdbus,
|
||||
|
||||
const Self = @This();
|
||||
|
@ -14,6 +16,7 @@ pub fn deinit(self: *Self) void {
|
|||
|
||||
self.room_arena.deinit();
|
||||
self.rooms.deinit();
|
||||
self.icon_store.deinit();
|
||||
c.g_object_unref(self.dbus);
|
||||
|
||||
self.* = undefined;
|
||||
|
|
125
src/dbus.zig
125
src/dbus.zig
|
@ -4,6 +4,7 @@ const c = ffi.c;
|
|||
const State = @import("State.zig");
|
||||
const Room = @import("Room.zig");
|
||||
const Image = @import("Image.zig");
|
||||
const IconStore = @import("IconStore.zig");
|
||||
|
||||
pub fn onRoomsReceived(proxy: *c.nhdbus, res: *c.GAsyncResult, s: *State) void {
|
||||
var rooms: ?*c.GVariant = null;
|
||||
|
@ -41,54 +42,29 @@ fn readRooms(rooms: *c.GVariant, s: *State) void {
|
|||
var room_id: [*c]c.gchar = undefined;
|
||||
var room_alias: [*c]c.gchar = undefined;
|
||||
var room_name: [*c]c.gchar = undefined;
|
||||
var icon_url: [*c]c.gchar = undefined;
|
||||
var room_notifications: c_int = undefined;
|
||||
|
||||
var img_width: c_int = undefined;
|
||||
var img_height: c_int = undefined;
|
||||
var img_stride: c_int = undefined;
|
||||
var img_has_alpha: c_int = undefined;
|
||||
var img_bit_depth: c_int = undefined;
|
||||
|
||||
var data_iter: *c.GVariantIter = undefined;
|
||||
c.g_variant_get(
|
||||
room,
|
||||
"(&s&s&s(iiibiiay)i)",
|
||||
"(&s&s&s&si)",
|
||||
&room_id,
|
||||
&room_alias,
|
||||
&room_name,
|
||||
&img_width,
|
||||
&img_height,
|
||||
&img_stride,
|
||||
&img_has_alpha,
|
||||
&img_bit_depth,
|
||||
@as(?*anyopaque, null), // channel count
|
||||
&data_iter,
|
||||
&icon_url,
|
||||
&room_notifications,
|
||||
);
|
||||
|
||||
const bytes = arena.alloc(
|
||||
u8,
|
||||
@intCast(usize, c.g_variant_iter_n_children(data_iter)),
|
||||
) catch return;
|
||||
var byte: u8 = 0;
|
||||
var i: usize = 0;
|
||||
while (c.g_variant_iter_next(data_iter, "y", &byte) != 0) {
|
||||
bytes[i] = byte;
|
||||
i += 1;
|
||||
}
|
||||
const icon_url_s = std.mem.span(icon_url);
|
||||
|
||||
const r = Room{
|
||||
.id = arena.dupeZ(u8, std.mem.span(room_id)) catch return,
|
||||
.alias = arena.dupeZ(u8, std.mem.span(room_alias)) catch return,
|
||||
.name = arena.dupeZ(u8, std.mem.span(room_name)) catch return,
|
||||
.image = Image.init(
|
||||
img_width,
|
||||
img_height,
|
||||
img_stride,
|
||||
img_has_alpha,
|
||||
img_bit_depth,
|
||||
arena.dupe(u8, bytes) catch return,
|
||||
),
|
||||
.icon_url = if (icon_url_s.len == 0)
|
||||
null
|
||||
else
|
||||
arena.dupeZ(u8, icon_url_s) catch return,
|
||||
.notifications = room_notifications,
|
||||
};
|
||||
|
||||
|
@ -100,6 +76,89 @@ fn readRooms(rooms: *c.GVariant, s: *State) void {
|
|||
std.log.info("Read {} rooms", .{s.rooms.items.len});
|
||||
}
|
||||
|
||||
const IconUdata = struct {
|
||||
url: [:0]u8,
|
||||
store: *IconStore,
|
||||
data_alloc: std.mem.Allocator,
|
||||
};
|
||||
|
||||
pub fn requestIcon(
|
||||
proxy: *c.nhdbus,
|
||||
store: *IconStore,
|
||||
url: [:0]const u8,
|
||||
data_alloc: std.mem.Allocator,
|
||||
) !void {
|
||||
const url_d = try std.heap.c_allocator.dupeZ(u8, url);
|
||||
var udata = try std.heap.c_allocator.create(IconUdata);
|
||||
udata.* = .{
|
||||
.url = url_d,
|
||||
.store = store,
|
||||
.data_alloc = data_alloc,
|
||||
};
|
||||
|
||||
c.nhdbus__call_image(
|
||||
proxy,
|
||||
url.ptr,
|
||||
null,
|
||||
@ptrCast(c.GAsyncReadyCallback, &onIconReceived),
|
||||
udata,
|
||||
);
|
||||
}
|
||||
|
||||
fn onIconReceived(proxy: *c.nhdbus, res: *c.GAsyncResult, udata: *IconUdata) void {
|
||||
defer std.heap.c_allocator.destroy(udata);
|
||||
defer std.heap.c_allocator.free(udata.url);
|
||||
|
||||
var image: ?*c.GVariant = null;
|
||||
var err: ?*c.GError = null;
|
||||
_ = c.nhdbus__call_image_finish(proxy, &image, res, &err);
|
||||
ffi.checkGError(err) catch return;
|
||||
|
||||
defer c.g_variant_unref(image);
|
||||
|
||||
var img_width: c_int = undefined;
|
||||
var img_height: c_int = undefined;
|
||||
var img_stride: c_int = undefined;
|
||||
var img_has_alpha: c_int = undefined;
|
||||
var img_bit_depth: c_int = undefined;
|
||||
var data_iter: *c.GVariantIter = undefined;
|
||||
|
||||
c.g_variant_get(
|
||||
image,
|
||||
"(iiibiiay)",
|
||||
&img_width,
|
||||
&img_height,
|
||||
&img_stride,
|
||||
&img_has_alpha,
|
||||
&img_bit_depth,
|
||||
@as(?*anyopaque, null), // channel count
|
||||
&data_iter,
|
||||
);
|
||||
|
||||
const data = udata.data_alloc.alloc(
|
||||
u8,
|
||||
@intCast(usize, c.g_variant_iter_n_children(data_iter)),
|
||||
) catch return;
|
||||
var byte: u8 = 0;
|
||||
var i: usize = 0;
|
||||
while (c.g_variant_iter_next(data_iter, "y", &byte) != 0) {
|
||||
data[i] = byte;
|
||||
i += 1;
|
||||
}
|
||||
|
||||
const img = Image.init(
|
||||
img_width,
|
||||
img_height,
|
||||
img_stride,
|
||||
img_has_alpha,
|
||||
img_bit_depth,
|
||||
data,
|
||||
);
|
||||
|
||||
(udata.store.data.getOrPut(udata.url) catch return).value_ptr.* = .{ .cached = img };
|
||||
ffi.rofi_view_reload();
|
||||
}
|
||||
|
||||
fn compareRoom(_: void, lhs: Room, rhs: Room) bool {
|
||||
if (lhs.notifications == rhs.notifications) {
|
||||
return std.ascii.lessThanIgnoreCase(
|
||||
|
|
19
src/main.zig
19
src/main.zig
|
@ -6,6 +6,7 @@ const Mode = c.Mode;
|
|||
const Image = @import("Image.zig");
|
||||
const State = @import("State.zig");
|
||||
const Room = @import("Room.zig");
|
||||
const IconStore = @import("IconStore.zig");
|
||||
|
||||
pub const log = @import("glib-log").log(c, "rofi-nheko", 512);
|
||||
// log levels are handled by glib, so zig shouldn't filter
|
||||
|
@ -52,10 +53,6 @@ fn init(m: [*c]Mode) callconv(.C) c_int {
|
|||
|
||||
const state_p = std.heap.c_allocator.create(State) catch return 0;
|
||||
|
||||
state_p.rooms = std.ArrayList(Room).init(std.heap.c_allocator);
|
||||
state_p.rooms_lock = .{};
|
||||
state_p.room_arena = std.heap.ArenaAllocator.init(std.heap.c_allocator);
|
||||
|
||||
var err: ?*c.GError = null;
|
||||
|
||||
const proxy = c.nhdbus__proxy_new_for_bus_sync(
|
||||
|
@ -69,6 +66,14 @@ fn init(m: [*c]Mode) callconv(.C) c_int {
|
|||
ffi.checkGError(err) catch return 0;
|
||||
state_p.dbus = proxy.?;
|
||||
|
||||
state_p.* = .{
|
||||
.dbus = proxy.?,
|
||||
.rooms = std.ArrayList(Room).init(std.heap.c_allocator),
|
||||
.rooms_lock = .{},
|
||||
.room_arena = std.heap.ArenaAllocator.init(std.heap.c_allocator),
|
||||
.icon_store = IconStore.init(std.heap.c_allocator),
|
||||
};
|
||||
|
||||
c.mode_set_private_data(m, state_p);
|
||||
|
||||
c.nhdbus__call_rooms(
|
||||
|
@ -180,7 +185,11 @@ fn getIcon(
|
|||
state(m).rooms_lock.lock();
|
||||
defer state(m).rooms_lock.unlock();
|
||||
|
||||
const img = &state(m).rooms.items[selected_line].image;
|
||||
var img = (state(m).icon_store.get(
|
||||
state(m).rooms.items[selected_line].icon_url orelse return null,
|
||||
state(m).dbus,
|
||||
state(m).room_arena.allocator(),
|
||||
) catch return null) orelse return null;
|
||||
|
||||
const img_surface = (img.createCairoSurface() catch return null) orelse return null;
|
||||
defer c.cairo_surface_destroy(img_surface);
|
||||
|
|
Loading…
Reference in New Issue