Only update dbus menu when it has been changed

The dbus menu implementaion of KDE would send the about-to-show signal
whenever the menu has been changed, resulting in infinite loop on our
side.
This commit is contained in:
Cheng Zhao 2017-07-20 20:50:14 +09:00
parent 3283238555
commit 74df5f84fd

View file

@ -165,6 +165,18 @@ void SetMenuItemID(DbusmenuMenuitem* item, int id) {
g_object_set_data(G_OBJECT(item), "menu-id", GINT_TO_POINTER(id + 1));
}
std::string GetMenuModelStatus(AtomMenuModel* model) {
std::string ret;
for (int i = 0; i < model->GetItemCount(); ++i) {
int status = model->GetTypeAt(i) | (model->IsVisibleAt(i) << 30)
| (model->IsEnabledAt(i) << 29)
| (model->IsItemCheckedAt(i) << 28);
ret += base::StringPrintf(
"%s-%d\n", base::UTF16ToUTF8(model->GetLabelAt(i)).c_str(), status);
}
return ret;
}
} // namespace
GlobalMenuBarX11::GlobalMenuBarX11(NativeWindowViews* window)
@ -309,6 +321,16 @@ void GlobalMenuBarX11::OnSubMenuShow(DbusmenuMenuitem* item) {
if (!model || !GetMenuItemID(item, &id))
return;
// Do not update menu if the submenu has not been changed.
std::string status = GetMenuModelStatus(model);
char* old = static_cast<char*>(g_object_get_data(G_OBJECT(item), "status"));
if (old && status == old)
return;
// Save the new status.
g_object_set_data_full(G_OBJECT(item), "status", g_strdup(status.c_str()),
g_free);
// Clear children.
GList *children = menuitem_take_children(item);
g_list_foreach(children, reinterpret_cast<GFunc>(g_object_unref), NULL);