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 {
|
fn make(step: *std.build.Step) !void {
|
||||||
_ = step;
|
|
||||||
const self = @fieldParentPtr(NhdbusGen, "step", step);
|
const self = @fieldParentPtr(NhdbusGen, "step", step);
|
||||||
const b = self.lib.builder;
|
const b = self.lib.builder;
|
||||||
|
|
||||||
|
|
|
@ -1,65 +1,64 @@
|
||||||
<!DOCTYPE
|
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
||||||
node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
|
||||||
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||||
<node>
|
<node>
|
||||||
<interface name="im.nheko.Nheko">
|
<interface name="im.nheko.Nheko">
|
||||||
<method name="apiVersion">
|
<method name="apiVersion">
|
||||||
<arg type="s" direction="out" />
|
<arg type="s" direction="out"/>
|
||||||
</method>
|
</method>
|
||||||
<method name="nhekoVersion">
|
<method name="nhekoVersion">
|
||||||
<arg type="s" direction="out" />
|
<arg type="s" direction="out"/>
|
||||||
</method>
|
</method>
|
||||||
<method name="rooms">
|
<method name="rooms">
|
||||||
<arg type="a(sss(iiibiiay)i)" direction="out" />
|
<arg type="a(ssssi)" direction="out"/>
|
||||||
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0"
|
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVector<nheko::dbus::RoomInfoItem>"/>
|
||||||
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>
|
||||||
<method name="activateRoom">
|
<method name="activateRoom">
|
||||||
<arg name="alias" type="s" direction="in" />
|
<arg name="alias" type="s" direction="in"/>
|
||||||
</method>
|
</method>
|
||||||
<method name="joinRoom">
|
<method name="joinRoom">
|
||||||
<arg name="alias" type="s" direction="in" />
|
<arg name="alias" type="s" direction="in"/>
|
||||||
</method>
|
</method>
|
||||||
<method name="directChat">
|
<method name="directChat">
|
||||||
<arg name="userId" type="s" direction="in" />
|
<arg name="userId" type="s" direction="in"/>
|
||||||
</method>
|
</method>
|
||||||
</interface>
|
</interface>
|
||||||
<interface name="org.freedesktop.DBus.Properties">
|
<interface name="org.freedesktop.DBus.Properties">
|
||||||
<method name="Get">
|
<method name="Get">
|
||||||
<arg name="interface_name" type="s" direction="in" />
|
<arg name="interface_name" type="s" direction="in"/>
|
||||||
<arg name="property_name" type="s" direction="in" />
|
<arg name="property_name" type="s" direction="in"/>
|
||||||
<arg name="value" type="v" direction="out" />
|
<arg name="value" type="v" direction="out"/>
|
||||||
</method>
|
</method>
|
||||||
<method name="Set">
|
<method name="Set">
|
||||||
<arg name="interface_name" type="s" direction="in" />
|
<arg name="interface_name" type="s" direction="in"/>
|
||||||
<arg name="property_name" type="s" direction="in" />
|
<arg name="property_name" type="s" direction="in"/>
|
||||||
<arg name="value" type="v" direction="in" />
|
<arg name="value" type="v" direction="in"/>
|
||||||
</method>
|
</method>
|
||||||
<method name="GetAll">
|
<method name="GetAll">
|
||||||
<arg name="interface_name" type="s" direction="in" />
|
<arg name="interface_name" type="s" direction="in"/>
|
||||||
<arg name="values" type="a{sv}" direction="out" />
|
<arg name="values" type="a{sv}" direction="out"/>
|
||||||
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0"
|
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
|
||||||
value="QVariantMap" />
|
|
||||||
</method>
|
</method>
|
||||||
<signal name="PropertiesChanged">
|
<signal name="PropertiesChanged">
|
||||||
<arg name="interface_name" type="s" direction="out" />
|
<arg name="interface_name" type="s" direction="out"/>
|
||||||
<arg name="changed_properties" type="a{sv}"
|
<arg name="changed_properties" type="a{sv}" direction="out"/>
|
||||||
direction="out" />
|
<annotation name="org.qtproject.QtDBus.QtTypeName.Out1" value="QVariantMap"/>
|
||||||
<annotation name="org.qtproject.QtDBus.QtTypeName.Out1"
|
<arg name="invalidated_properties" type="as" direction="out"/>
|
||||||
value="QVariantMap" />
|
|
||||||
<arg name="invalidated_properties" type="as"
|
|
||||||
direction="out" />
|
|
||||||
</signal>
|
</signal>
|
||||||
</interface>
|
</interface>
|
||||||
<interface name="org.freedesktop.DBus.Introspectable">
|
<interface name="org.freedesktop.DBus.Introspectable">
|
||||||
<method name="Introspect">
|
<method name="Introspect">
|
||||||
<arg name="xml_data" type="s" direction="out" />
|
<arg name="xml_data" type="s" direction="out"/>
|
||||||
</method>
|
</method>
|
||||||
</interface>
|
</interface>
|
||||||
<interface name="org.freedesktop.DBus.Peer">
|
<interface name="org.freedesktop.DBus.Peer">
|
||||||
<method name="Ping" />
|
<method name="Ping"/>
|
||||||
<method name="GetMachineId">
|
<method name="GetMachineId">
|
||||||
<arg name="machine_uuid" type="s" direction="out" />
|
<arg name="machine_uuid" type="s" direction="out"/>
|
||||||
</method>
|
</method>
|
||||||
</interface>
|
</interface>
|
||||||
</node>
|
</node>
|
||||||
|
|
48
src/IconStore.zig
Normal file
48
src/IconStore.zig
Normal 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;
|
||||||
|
}
|
|
@ -1,15 +1,8 @@
|
||||||
const c = @import("ffi.zig").c;
|
const c = @import("ffi.zig").c;
|
||||||
const Image = @import("Image.zig");
|
|
||||||
|
|
||||||
/// Strings must be deallocated manually
|
/// Strings must be deallocated manually
|
||||||
id: [:0]c.gchar,
|
id: [:0]c.gchar,
|
||||||
alias: [:0]c.gchar,
|
alias: [:0]c.gchar,
|
||||||
name: [:0]c.gchar,
|
name: [:0]c.gchar,
|
||||||
image: Image,
|
icon_url: ?[:0]c.gchar,
|
||||||
notifications: c_int,
|
notifications: c_int,
|
||||||
|
|
||||||
const Self = @This();
|
|
||||||
|
|
||||||
pub fn deinit(self: *Self) void {
|
|
||||||
self.image.deinit();
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const c = @import("ffi.zig").c;
|
const c = @import("ffi.zig").c;
|
||||||
const Room = @import("Room.zig");
|
const Room = @import("Room.zig");
|
||||||
|
const IconStore = @import("IconStore.zig");
|
||||||
|
|
||||||
rooms: std.ArrayList(Room),
|
rooms: std.ArrayList(Room),
|
||||||
rooms_lock: std.Thread.Mutex,
|
rooms_lock: std.Thread.Mutex,
|
||||||
room_arena: std.heap.ArenaAllocator,
|
room_arena: std.heap.ArenaAllocator,
|
||||||
|
icon_store: IconStore,
|
||||||
dbus: *c.nhdbus,
|
dbus: *c.nhdbus,
|
||||||
|
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
@ -14,6 +16,7 @@ pub fn deinit(self: *Self) void {
|
||||||
|
|
||||||
self.room_arena.deinit();
|
self.room_arena.deinit();
|
||||||
self.rooms.deinit();
|
self.rooms.deinit();
|
||||||
|
self.icon_store.deinit();
|
||||||
c.g_object_unref(self.dbus);
|
c.g_object_unref(self.dbus);
|
||||||
|
|
||||||
self.* = undefined;
|
self.* = undefined;
|
||||||
|
|
125
src/dbus.zig
125
src/dbus.zig
|
@ -4,6 +4,7 @@ const c = ffi.c;
|
||||||
const State = @import("State.zig");
|
const State = @import("State.zig");
|
||||||
const Room = @import("Room.zig");
|
const Room = @import("Room.zig");
|
||||||
const Image = @import("Image.zig");
|
const Image = @import("Image.zig");
|
||||||
|
const IconStore = @import("IconStore.zig");
|
||||||
|
|
||||||
pub fn onRoomsReceived(proxy: *c.nhdbus, res: *c.GAsyncResult, s: *State) void {
|
pub fn onRoomsReceived(proxy: *c.nhdbus, res: *c.GAsyncResult, s: *State) void {
|
||||||
var rooms: ?*c.GVariant = null;
|
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_id: [*c]c.gchar = undefined;
|
||||||
var room_alias: [*c]c.gchar = undefined;
|
var room_alias: [*c]c.gchar = undefined;
|
||||||
var room_name: [*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 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(
|
c.g_variant_get(
|
||||||
room,
|
room,
|
||||||
"(&s&s&s(iiibiiay)i)",
|
"(&s&s&s&si)",
|
||||||
&room_id,
|
&room_id,
|
||||||
&room_alias,
|
&room_alias,
|
||||||
&room_name,
|
&room_name,
|
||||||
&img_width,
|
&icon_url,
|
||||||
&img_height,
|
|
||||||
&img_stride,
|
|
||||||
&img_has_alpha,
|
|
||||||
&img_bit_depth,
|
|
||||||
@as(?*anyopaque, null), // channel count
|
|
||||||
&data_iter,
|
|
||||||
&room_notifications,
|
&room_notifications,
|
||||||
);
|
);
|
||||||
|
|
||||||
const bytes = arena.alloc(
|
const icon_url_s = std.mem.span(icon_url);
|
||||||
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 r = Room{
|
const r = Room{
|
||||||
.id = arena.dupeZ(u8, std.mem.span(room_id)) catch return,
|
.id = arena.dupeZ(u8, std.mem.span(room_id)) catch return,
|
||||||
.alias = arena.dupeZ(u8, std.mem.span(room_alias)) catch return,
|
.alias = arena.dupeZ(u8, std.mem.span(room_alias)) catch return,
|
||||||
.name = arena.dupeZ(u8, std.mem.span(room_name)) catch return,
|
.name = arena.dupeZ(u8, std.mem.span(room_name)) catch return,
|
||||||
.image = Image.init(
|
.icon_url = if (icon_url_s.len == 0)
|
||||||
img_width,
|
null
|
||||||
img_height,
|
else
|
||||||
img_stride,
|
arena.dupeZ(u8, icon_url_s) catch return,
|
||||||
img_has_alpha,
|
|
||||||
img_bit_depth,
|
|
||||||
arena.dupe(u8, bytes) catch return,
|
|
||||||
),
|
|
||||||
.notifications = room_notifications,
|
.notifications = room_notifications,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -100,6 +76,89 @@ fn readRooms(rooms: *c.GVariant, s: *State) void {
|
||||||
std.log.info("Read {} rooms", .{s.rooms.items.len});
|
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 {
|
fn compareRoom(_: void, lhs: Room, rhs: Room) bool {
|
||||||
if (lhs.notifications == rhs.notifications) {
|
if (lhs.notifications == rhs.notifications) {
|
||||||
return std.ascii.lessThanIgnoreCase(
|
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 Image = @import("Image.zig");
|
||||||
const State = @import("State.zig");
|
const State = @import("State.zig");
|
||||||
const Room = @import("Room.zig");
|
const Room = @import("Room.zig");
|
||||||
|
const IconStore = @import("IconStore.zig");
|
||||||
|
|
||||||
pub const log = @import("glib-log").log(c, "rofi-nheko", 512);
|
pub const log = @import("glib-log").log(c, "rofi-nheko", 512);
|
||||||
// log levels are handled by glib, so zig shouldn't filter
|
// 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;
|
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;
|
var err: ?*c.GError = null;
|
||||||
|
|
||||||
const proxy = c.nhdbus__proxy_new_for_bus_sync(
|
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;
|
ffi.checkGError(err) catch return 0;
|
||||||
state_p.dbus = proxy.?;
|
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.mode_set_private_data(m, state_p);
|
||||||
|
|
||||||
c.nhdbus__call_rooms(
|
c.nhdbus__call_rooms(
|
||||||
|
@ -180,7 +185,11 @@ fn getIcon(
|
||||||
state(m).rooms_lock.lock();
|
state(m).rooms_lock.lock();
|
||||||
defer state(m).rooms_lock.unlock();
|
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;
|
const img_surface = (img.createCairoSurface() catch return null) orelse return null;
|
||||||
defer c.cairo_surface_destroy(img_surface);
|
defer c.cairo_surface_destroy(img_surface);
|
||||||
|
|
Loading…
Reference in a new issue