-
Notifications
You must be signed in to change notification settings - Fork 1
/
sni.c
113 lines (109 loc) · 3.64 KB
/
sni.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#include "wlchewing.h"
#include "sni.h"
#include <unistd.h>
static const sd_bus_vtable service_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("Category", "s", NULL, offsetof(struct wlchewing_sni, category),
SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Id", "s", NULL, offsetof(struct wlchewing_sni, id),
SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Title", "s", NULL, offsetof(struct wlchewing_sni, title),
SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Status", "s", NULL, offsetof(struct wlchewing_sni, status),
SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("WindowId", "u", NULL, offsetof(struct wlchewing_sni, window_id),
SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("IconName", "s", NULL, offsetof(struct wlchewing_sni, icon_name),
SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_SIGNAL("NewIcon", "", 0),
SD_BUS_VTABLE_END
};
static int handle_owner_changed(sd_bus_message *m, void *userdata,
sd_bus_error *ret_error) {
struct wlchewing_sni *sni = userdata;
int res;
sd_bus_error err = SD_BUS_ERROR_NULL;
char *service, *old_owner, *new_owner;
res = sd_bus_message_read(m, "sss", &service, &old_owner, &new_owner);
if (res < 0) {
wlchewing_err("Failed to parse NameOwnerChanged message: %s",
strerror(-res));
}
if (!strcmp(service, "org.freedesktop.StatusNotifierWatcher")) {
res = sd_bus_call_method(sni->bus,
"org.freedesktop.StatusNotifierWatcher",
"/StatusNotifierWatcher",
"org.freedesktop.StatusNotifierWatcher",
"RegisterStatusNotifierItem", &err, NULL, "s",
sni->service_name);
if (res < 0) {
wlchewing_err("Failed to register sni: %s: %s",
err.name, err.message);
}
}
return 0;
}
int sni_set_icon(struct wlchewing_sni *sni, bool english) {
if (!sni) {
return 0;
}
if (english == sni->english) {
return 0;
}
sni->english = english;
sni->icon_name = english ? "wlchewing-eng" : "wlchewing-bopomofo";
int res;
res = sd_bus_emit_signal(sni->bus, "/StatusNotifierItem",
"org.freedesktop.StatusNotifierItem", "NewIcon", "");
if (res < 0) {
wlchewing_err("Failed to emit NewIcon: %s", strerror(-res));
return res;
}
return 0;
}
int sni_setup(struct wlchewing_sni *sni) {
sni->category = "SystemServices";
sni->id = "wlchewing";
sni->title = "Wayland Chinese zhuyin input method with libchewing";
sni->status = "Active";
sni->icon_name = "wlchewing-bopomofo";
int res;
char buf[64];
res = sd_bus_open_user(&sni->bus);
if (res < 0) {
wlchewing_err("Failed to open bus connection: %s",
strerror(-res));
return res;
}
sprintf(buf, "org.freedesktop.StatusNotifierItem-%ld-%d", (long)getpid(), 1);
sni->service_name = strdup(buf);
res = sd_bus_add_object_vtable(sni->bus, &sni->slot, "/StatusNotifierItem",
"org.freedesktop.StatusNotifierItem", service_vtable, sni);
if (res < 0) {
wlchewing_err("Failed to add object: %s", strerror(-res));
return res;
}
res = sd_bus_request_name(sni->bus, buf, 0);
if (res < 0) {
wlchewing_err("Failed to request name: %s", strerror(-res));
return res;
}
res = sd_bus_match_signal(sni->bus, &sni->signal_slot,
"org.freedesktop.DBus", "/org/freedesktop/DBus",
"org.freedesktop.DBus", "NameOwnerChanged",
handle_owner_changed, sni);
if (res < 0) {
wlchewing_err("Failed to listen to NameOwnerChanged: %s",
strerror(-res));
return res;
}
sd_bus_error err = SD_BUS_ERROR_NULL;
res = sd_bus_call_method(sni->bus, "org.freedesktop.StatusNotifierWatcher",
"/StatusNotifierWatcher", "org.freedesktop.StatusNotifierWatcher",
"RegisterStatusNotifierItem", &err, NULL, "s",
sni->service_name);
if (res < 0) {
wlchewing_err("Failed to register sni: %s: %s", err.name, err.message);
}
return sd_bus_get_fd(sni->bus);
}