SNI: Fix freeze when connecting to Qt SNI apps

Qt waits until the callback to RegisterItem is done. Thus, we can't
query the item and need to defer it
This commit is contained in:
scorpion-26 2023-04-14 23:44:30 +02:00
parent a02bce9b91
commit b50ecb0f6c

View file

@ -29,45 +29,14 @@ namespace SNI
}; };
std::vector<Item> items; std::vector<Item> items;
std::vector<Item> clientsToQuery;
// Gtk stuff, TODO: Allow more than one instance // Gtk stuff, TODO: Allow more than one instance
// Simply removing the gtk_drawing_areas doesn't trigger proper redrawing // Simply removing the gtk_drawing_areas doesn't trigger proper redrawing
// HACK: Make an outer permanent and an inner box, which will be deleted and readded // HACK: Make an outer permanent and an inner box, which will be deleted and readded
Widget* parentBox; Widget* parentBox;
Widget* iconBox; Widget* iconBox;
// SNI implements the GTK-Thingies itself internally
static void InvalidateWidget()
{
parentBox->RemoveChild(iconBox);
auto container = Widget::Create<Box>();
container->SetSpacing({4, false});
iconBox = container.get();
for (auto& item : items)
{
if (item.iconData)
{
auto texture = Widget::Create<Texture>();
texture->SetHorizontalTransform({0, true, Alignment::Fill});
texture->SetBuf(item.w, item.h, item.iconData);
iconBox->AddChild(std::move(texture));
}
}
parentBox->AddChild(std::move(container));
}
void WidgetSNI(Widget& parent)
{
// Add parent box
auto box = Widget::Create<Box>();
auto container = Widget::Create<Box>();
iconBox = container.get();
parentBox = box.get();
InvalidateWidget();
box->AddChild(std::move(container));
parent.AddChild(std::move(box));
}
static Item CreateItem(std::string&& name, std::string&& object) static Item CreateItem(std::string&& name, std::string&& object)
{ {
Item item{}; Item item{};
@ -198,6 +167,13 @@ namespace SNI
return item; return item;
} }
static void ItemPropertyChanged(GDBusConnection*, const char* sender, const char* object, const char* interface, const char* signal,
GVariant* params, void*)
{
LOG("ItemPropertyChanged");
}
static void InvalidateWidget();
static void DBusNameVanished(GDBusConnection*, const char* name, void*) static void DBusNameVanished(GDBusConnection*, const char* name, void*)
{ {
auto it = std::find_if(items.begin(), items.end(), auto it = std::find_if(items.begin(), items.end(),
@ -216,8 +192,65 @@ namespace SNI
} }
} }
static TimerResult UpdateWidgets(Box&)
{
for (auto& client : clientsToQuery)
{
LOG("SNI: Creating Item " << client.name << " " << client.object);
Item item = CreateItem(std::move(client.name), std::move(client.object));
// Add handler for removing
g_bus_watch_name_on_connection(dbusConnection, item.name.c_str(), G_BUS_NAME_WATCHER_FLAGS_NONE, nullptr, DBusNameVanished, nullptr,
nullptr);
// Add handler for icon change
g_dbus_connection_signal_subscribe(dbusConnection, item.name.c_str(), "org.kde.StatusNotifierItem", nullptr, nullptr, nullptr,
G_DBUS_SIGNAL_FLAGS_NONE, ItemPropertyChanged, nullptr, nullptr);
items.push_back(std::move(item));
}
if (clientsToQuery.size() > 0)
{
InvalidateWidget();
}
clientsToQuery.clear();
return TimerResult::Ok;
}
// SNI implements the GTK-Thingies itself internally
static void InvalidateWidget()
{
parentBox->RemoveChild(iconBox);
auto container = Widget::Create<Box>();
container->SetSpacing({4, false});
iconBox = container.get();
for (auto& item : items)
{
if (item.iconData)
{
auto texture = Widget::Create<Texture>();
texture->SetHorizontalTransform({0, true, Alignment::Fill});
texture->SetBuf(item.w, item.h, item.iconData);
iconBox->AddChild(std::move(texture));
}
}
parentBox->AddChild(std::move(container));
}
void WidgetSNI(Widget& parent)
{
// Add parent box
auto box = Widget::Create<Box>();
auto container = Widget::Create<Box>();
container->AddTimer<Box>(UpdateWidgets, 1000, TimerDispatchBehaviour::LateDispatch);
iconBox = container.get();
parentBox = box.get();
InvalidateWidget();
box->AddChild(std::move(container));
parent.AddChild(std::move(box));
}
// Methods // Methods
static void RegisterItem(sniWatcher*, GDBusMethodInvocation* invocation, const char* service) static bool RegisterItem(sniWatcher* watcher, GDBusMethodInvocation* invocation, const char* service)
{ {
std::string name; std::string name;
std::string object; std::string object;
@ -241,16 +274,15 @@ namespace SNI
if (it != items.end()) if (it != items.end())
{ {
LOG("Rejecting " << name << " " << object); LOG("Rejecting " << name << " " << object);
return; return false;
} }
sni_watcher_emit_status_notifier_item_registered(watcher, service);
sni_watcher_complete_register_status_notifier_item(watcher, invocation);
LOG("SNI: Registered Item " << name << " " << object); LOG("SNI: Registered Item " << name << " " << object);
Item item = CreateItem(std::move(name), std::move(object)); clientsToQuery.push_back({std::move(name), std::move(object)});
// Add handler for removing return true;
g_bus_watch_name_on_connection(dbusConnection, item.name.c_str(), G_BUS_NAME_WATCHER_FLAGS_NONE, nullptr, DBusNameVanished, nullptr, nullptr);
items.push_back(std::move(item));
InvalidateWidget();
} }
static void RegisterHost(sniWatcher*, GDBusMethodInvocation*, const char*) static void RegisterHost(sniWatcher*, GDBusMethodInvocation*, const char*)
{ {
LOG("TODO: Implement RegisterHost!"); LOG("TODO: Implement RegisterHost!");
@ -303,6 +335,10 @@ namespace SNI
std::string hostName = "org.kde.StatusNotifierHost-" + std::to_string(getpid()); std::string hostName = "org.kde.StatusNotifierHost-" + std::to_string(getpid());
g_bus_own_name(G_BUS_TYPE_SESSION, hostName.c_str(), (GBusNameOwnerFlags)flags, +emptyCallback, +emptyCallback, +emptyCallback, nullptr, g_bus_own_name(G_BUS_TYPE_SESSION, hostName.c_str(), (GBusNameOwnerFlags)flags, +emptyCallback, +emptyCallback, +emptyCallback, nullptr,
nullptr); nullptr);
// Host is always available
sni_watcher_set_is_status_notifier_host_registered(watcherSkeleton, true);
sni_watcher_emit_status_notifier_host_registered(watcherSkeleton);
} }
void Shutdown() {} void Shutdown() {}