偶尔一下的折腾
是社会道德的沦丧,还是人性的缺失,今天fortime带你探索消失的网页微信通知和不能横排的ibus-rime
消失的网页微信通知
由于firefox用着用着就占越来越多的内存,偶尔需要重启一下,在上面用网页微信的话,又要重新登录,当天的聊天记录又会没有了。所以,我最近用epiphany的app模式使用网页微信。用着用着,发现经常漏消息,通知栏的消息经常会消失。难道是因为webkit2gtk没有实现好libnotify,设置的expire时间不对?
没有过期时间的GnomeShell通知实现
通过grep,在WebKitWebView.cpp的webkitWebViewShowNotification
下找到了调用libnotify的notify_notification_show
的代码。
static gboolean webkitWebViewShowNotification(WebKitWebView*, WebKitNotification* webNotification)
{
#if USE(LIBNOTIFY)
if (!notify_is_initted())
notify_init(g_get_prgname());
NotifyNotification* notification = NOTIFY_NOTIFICATION(g_object_get_data(G_OBJECT(webNotification), gNotifyNotificationID))
;
if (!notification) {
notification = notify_notification_new(webkit_notification_get_title(webNotification),
webkit_notification_get_body(webNotification), nullptr);
notify_notification_add_action(notification, "default", _("Acknowledge"), NOTIFY_ACTION_CALLBACK(notifyNotificationClic
ked), webNotification, nullptr);
notify_notification_set_timeout(notification, NOTIFY_EXPIRES_NEVER);
g_signal_connect_object(notification, "closed", G_CALLBACK(notifyNotificationClosed), webNotification, static_cast<GCon
nectFlags>(0));
g_signal_connect(webNotification, "closed", G_CALLBACK(webNotificationClosed), nullptr);
g_object_set_data_full(G_OBJECT(webNotification), gNotifyNotificationID, notification, static_cast<GDestroyNotify>(g_ob
ject_unref));
} else {
notify_notification_update(notification, webkit_notification_get_title(webNotification),
webkit_notification_get_body(webNotification), nullptr);
notify_notification_set_timeout(notification, NOTIFY_EXPIRES_NEVER);
}
notify_notification_show(notification, nullptr);
return TRUE;
#else
UNUSED_PARAM(webNotification);
return FALSE;
#endif
}
哈哈,果然没有调用libnotify的notify_notification_set_timeout
,果断设置为NOTIFY_EXPIRES_NEVER
。打包,测试,GG😭。难道不能永久不过期?来一下60秒,打包,测试,GG😭。Google一下,GnomeShell没有实现libnotify的过期😫。难道firefox有什么黑科技,它是怎么实现通知的?
firefox与webkit2gtk的通知实现比较
nsresult
nsAlertsIconListener::ShowAlert(GdkPixbuf* aPixbuf)
{
if (!mBackend->IsActiveListener(mAlertName, this))
return NS_OK;
mNotification = notify_notification_new(mAlertTitle.get(), mAlertText.get(),
nullptr, nullptr);
if (!mNotification)
return NS_ERROR_OUT_OF_MEMORY;
nsCOMPtr<nsIObserverService> obsServ =
do_GetService("@mozilla.org/observer-service;1");
if (obsServ)
obsServ->AddObserver(this, "quit-application", true);
if (aPixbuf)
notify_notification_set_icon_from_pixbuf(mNotification, aPixbuf);
NS_ADDREF(this);
if (mAlertHasAction) {
// What we put as the label doesn't matter here, if the action
// string is "default" then that makes the entire bubble clickable
// rather than creating a button.
notify_notification_add_action(mNotification, "default", "Activate",
notify_action_cb, this, nullptr);
}
// Fedora 10 calls NotifyNotification "closed" signal handlers with a
// different signature, so a marshaller is used instead of a C callback to
// get the user_data (this) in a parseable format. |closure| is created
// with a floating reference, which gets sunk by g_signal_connect_closure().
GClosure* closure = g_closure_new_simple(sizeof(GClosure), this);
g_closure_set_marshal(closure, notify_closed_marshal);
mClosureHandler = g_signal_connect_closure(mNotification, "closed", closure, FALSE);
GError* error = nullptr;
if (!notify_notification_show(mNotification, &error)) {
NS_WARNING(error->message);
g_error_free(error);
return NS_ERROR_FAILURE;
}
if (mAlertListener)
mAlertListener->Observe(nullptr, "alertshow", mAlertCookie.get());
return NS_OK;
}
哈,也是没有设置超时。而且还比webkit2gtk少了注册一些回调。如
g_signal_connect(webNotification, "closed", G_CALLBACK(webNotificationClosed), nullptr);
处理网页关闭通知的回调处理。
微信 - Do everything, but not good enough
既然firefox没有黑科技,那我只能继续测试了。每次测试还要找别人发微信消息给我,太麻烦了,自己写个button来触发通知。问题来了,我自己的测试网页发的通知没有消失。是时候看一下微信怎么发消息了。
function c(e, n) {
h.length >= M.total && h.shift().close();
var o, c;
return g && r() && angular.isString(e) && n && (angular.isString(n.icon) || angular.isObject(n.icon)) && i() === l && (o = t(e, n)), c = a(o), h.push(c), M.autoClose && o && !o.ieVerification && o.addEventListener && o.addEventListener("show", function() {
var e = c;
setTimeout(function() {
e.close()
}, M.autoClose)
}), o
}
心里万马奔腾,我怎么不早点看微信代码。估计是不同平台处理通知的逻辑不一样,微信网页版自己维护了通知列表,并5秒自动失效。由于firefox没有把网页的通知关闭signal转发给libnotify,所以系统的通知没有消失,而由于webkit2gtk实现的完整,所以通知5秒后消失了。这样magic的逻辑,微信应该加个开关啊。
解决方法
F12执行一下angular.element(document.querySelector('html')).injector().get('notificationFactory').config().autoClose=0
把超时设置为0,就不会自动消失了。
TODO
- 如何自动执行F12那行呢?epiphany没有greasemonkey。
- webkit2gtk通知没有显示icon,怎么去到pixbuf来显示呢?
- 点击通知,如何bring forth窗口呢?
不能横排的ibus-rime
好像哪次更新ibus后,Google Docs上输入没有候选字。我就想改一下ibus的配置,看看能不能好转。不过,以前我想改一下ibus-rime的方向一直都没有成功过。这次我在default.custom.yaml和输入法的custom.yaml上加style/horizontal: true
,嗯,还是没有成功。是不是由于true
不对呢?我把各种true都试了,还是不行。
又要施展源代码大法
// rime_settings.c
#include "rime_config.h"
#include <string.h>
#include <ibus.h>
#include <rime_api.h>
#include "rime_settings.h"
static struct ColorSchemeDefinition preset_color_schemes[] = {
{ "aqua", 0xffffff, 0x0a3dfa },
{ "azure", 0xffffff, 0x0a3dea },
{ "ink", 0xffffff, 0x000000 },
{ "luna", 0x000000, 0xffff7f },
{ NULL, 0, 0 }
};
static struct IBusRimeSettings ibus_rime_settings_default = {
FALSE,
IBUS_ORIENTATION_SYSTEM,
&preset_color_schemes[0],
};
struct IBusRimeSettings g_ibus_rime_settings;
static void
select_color_scheme(struct IBusRimeSettings* settings,
const char* color_scheme_id)
{
struct ColorSchemeDefinition* c;
for (c = preset_color_schemes; c->color_scheme_id; ++c) {
if (!strcmp(c->color_scheme_id, color_scheme_id)) {
settings->color_scheme = c;
g_debug("selected color scheme: %s", color_scheme_id);
return;
}
}
// fallback to default
settings->color_scheme = &preset_color_schemes[0];
}
void
ibus_rime_load_settings()
{
g_ibus_rime_settings = ibus_rime_settings_default;
RimeConfig config = {0};
if (!RimeConfigOpen("ibus_rime", &config)) {
g_error("error loading settings for ibus_rime");
return;
}
Bool inline_preedit = False;
if (RimeConfigGetBool(&config, "style/inline_preedit", &inline_preedit)) {
g_ibus_rime_settings.embed_preedit_text = !!inline_preedit;
}
Bool horizontal = False;
if (RimeConfigGetBool(&config, "style/horizontal", &horizontal)) {
g_ibus_rime_settings.lookup_table_orientation =
horizontal ? IBUS_ORIENTATION_HORIZONTAL : IBUS_ORIENTATION_VERTICAL;
}
const char* color_scheme =
RimeConfigGetCString(&config, "style/color_scheme");
if (color_scheme) {
select_color_scheme(&g_ibus_rime_settings, color_scheme);
}
RimeConfigClose(&config);
}
RimeConfigOpen("ibus_rime", &config)
不就是读取了rime的配置吗,那是为什么没有生效呢?然后有去看看librime,究竟是怎么加载default.yaml的。看着看着,突然想到"ibus_rime"
是不是不是指default.yaml呢?说干就干,创建一个*~/.config/ibus/rime/build/ibus_rime.yaml*,内容为:
style:
horizontal: True
inline_preedit: True
color_scheme: azure
哇,还真生效了,inline_preedit也出来了,颜色也有。在测试的过程中,发现重启系统后,Google Docs是有显示侯选字的,但执行多几次ibus-daemon -drx
后,又没有了。所以,这可能是ibus某些很深的逻辑没有处理好。
总结
以上说这么多,其实,就是为了记录:
angular.element(document.querySelector('html')).injector().get('notificationFactory').config().autoClose=0
- ibus-rime的配置文件是ibus_rime.yaml,而且要放build下。