feat: update to new nheko api

This commit is contained in:
LordMZTE 2022-10-13 00:25:40 +02:00
parent eddd3f8cee
commit 4925fdf2ca
Signed by: LordMZTE
GPG Key ID: B64802DC33A64FF6
7 changed files with 187 additions and 77 deletions

View File

@ -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;

View File

@ -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&lt;nheko::dbus::RoomInfoItem&gt;" />
<arg type="a(ssssi)" direction="out"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVector&lt;nheko::dbus::RoomInfoItem&gt;"/>
</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>

48
src/IconStore.zig Normal file
View File

@ -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;
}

View File

@ -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();
}

View File

@ -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;

View File

@ -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(

View File

@ -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);