Merge lp:~3v1n0/unity/app-quicklist-quit-override into lp:unity

Proposed by Marco Trevisan (Treviño)
Status: Merged
Approved by: Christopher Townsend
Approved revision: no longer in the source branch.
Merged at revision: 3397
Proposed branch: lp:~3v1n0/unity/app-quicklist-quit-override
Merge into: lp:unity
Prerequisite: lp:~3v1n0/unity/app-icon-quicklist-cleanup
Diff against target: 473 lines (+238/-63)
8 files modified
launcher/ApplicationLauncherIcon.cpp (+38/-57)
launcher/ApplicationLauncherIcon.h (+1/-1)
launcher/LauncherIcon.cpp (+18/-2)
launcher/LauncherIcon.h (+3/-2)
launcher/QuicklistMenuItem.cpp (+1/-0)
launcher/QuicklistMenuItem.h (+1/-0)
tests/data/applications/ubuntu-software-center.desktop (+11/-0)
tests/test_application_launcher_icon.cpp (+165/-1)
To merge this branch: bzr merge lp:~3v1n0/unity/app-quicklist-quit-override
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
Christopher Townsend Approve
Review via email: mp+172040@code.launchpad.net

Commit message

ApplicationLauncherIcon: improve the way we override the Quit quicklist item

If a quit action is defined in static (desktop file action) or dynamic way we
use it to override the default one, placing it to the proper position.
Also override more labels by default and if a quicklist item has the
QuicklistMenuItem::QUIT_ACTION_PROPERTY (defined as "unity-quit-action")
property set to TRUE, then we use this item as the quit quicklist item.

Factorized the code we use to generate both static and dynamic ql items.

Description of the change

Improved the code to override the quit quicklist entry so that it can be overridden by multiple labels and by a dbusmenu property.

Added virtual GetRemoteMenus to LauncherIcon so that it can be overridden in tests and it's finally possible to test quicklist remote entries.

Added a bunch of new tests to cover Remote quicklist entries, desktop actions quicklists, and Quit QL overriding.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Christopher Townsend (townsend) wrote :

Merges and compiles cleanly. Tests run and pass. Code looks good.

+1

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'launcher/ApplicationLauncherIcon.cpp'
2--- launcher/ApplicationLauncherIcon.cpp 2013-06-28 14:06:31 +0000
3+++ launcher/ApplicationLauncherIcon.cpp 2013-06-28 14:06:31 +0000
4@@ -871,7 +871,7 @@
5 }
6 }
7
8-void ApplicationLauncherIcon::EnsureMenuItemsControlReady()
9+void ApplicationLauncherIcon::EnsureMenuItemsDefaultReady()
10 {
11 if (_menu_items.size() == MenuItemType::SIZE)
12 return;
13@@ -914,24 +914,18 @@
14 AbstractLauncherIcon::MenuItemsVector ApplicationLauncherIcon::GetMenus()
15 {
16 MenuItemsVector result;
17+ glib::Object<DbusmenuMenuitem> quit_item;
18 bool separator_needed = false;
19
20- EnsureMenuItemsControlReady();
21+ EnsureMenuItemsDefaultReady();
22 UpdateMenus();
23
24- std::vector<glib::Object<DbusmenuClient>> menu_clients = { _menuclient_dynamic_quicklist };
25-
26- for (auto const& client : menu_clients)
27+ for (auto const& menus : {GetRemoteMenus(), _menu_desktop_shortcuts})
28 {
29- if (!client || !client.IsType(DBUSMENU_TYPE_CLIENT))
30- continue;
31-
32- DbusmenuMenuitem* root = dbusmenu_client_get_root(client);
33-
34- if (!root || !dbusmenu_menuitem_property_get_bool(root, DBUSMENU_MENUITEM_PROP_VISIBLE))
35- continue;
36-
37- for (GList* l = dbusmenu_menuitem_get_children(root); l; l = l->next)
38+ if (!menus.IsType(DBUSMENU_TYPE_MENUITEM))
39+ continue;
40+
41+ for (GList* l = dbusmenu_menuitem_get_children(menus); l; l = l->next)
42 {
43 glib::Object<DbusmenuMenuitem> item(static_cast<DbusmenuMenuitem*>(l->data), glib::AddRef());
44
45@@ -940,29 +934,36 @@
46
47 if (dbusmenu_menuitem_property_get_bool(item, DBUSMENU_MENUITEM_PROP_VISIBLE))
48 {
49+ dbusmenu_menuitem_property_set_bool(item, QuicklistMenuItem::MARKUP_ENABLED_PROPERTY, FALSE);
50+
51+ const gchar* type = dbusmenu_menuitem_property_get(item, DBUSMENU_MENUITEM_PROP_TYPE);
52+
53+ if (!type) // (g_strcmp0 (type, DBUSMENU_MENUITEM_PROP_LABEL) == 0)
54+ {
55+ if (dbusmenu_menuitem_property_get_bool(item, QuicklistMenuItem::QUIT_ACTION_PROPERTY))
56+ {
57+ quit_item = item;
58+ continue;
59+ }
60+
61+ const gchar* l = dbusmenu_menuitem_property_get(item, DBUSMENU_MENUITEM_PROP_LABEL);
62+ auto const& label = glib::gchar_to_string(l);
63+
64+ if (label == _("Quit") || label == "Quit" ||
65+ label == _("Exit") || label == "Exit" ||
66+ label == _("Close") || label == "Close")
67+ {
68+ quit_item = item;
69+ continue;
70+ }
71+ }
72+
73 separator_needed = true;
74- dbusmenu_menuitem_property_set_bool(item, QuicklistMenuItem::MARKUP_ENABLED_PROPERTY, FALSE);
75-
76 result.push_back(item);
77 }
78 }
79 }
80
81- // FIXME: this should totally be added as a _menu_client
82- if (DBUSMENU_IS_MENUITEM(_menu_desktop_shortcuts.RawPtr()))
83- {
84- for (GList* l = dbusmenu_menuitem_get_children(_menu_desktop_shortcuts); l; l = l->next)
85- {
86- glib::Object<DbusmenuMenuitem> item(static_cast<DbusmenuMenuitem*>(l->data), glib::AddRef());
87-
88- if (!item.IsType(DBUSMENU_TYPE_MENUITEM))
89- continue;
90-
91- separator_needed = true;
92- result.push_back(item);
93- }
94- }
95-
96 if (separator_needed)
97 {
98 result.push_back(_menu_items[MenuItemType::SEPARATOR]);
99@@ -975,9 +976,7 @@
100 std::string bold_app_name("<b>"+app_name.Str()+"</b>");
101
102 glib::Object<DbusmenuMenuitem> item(dbusmenu_menuitem_new());
103- dbusmenu_menuitem_property_set(item,
104- DBUSMENU_MENUITEM_PROP_LABEL,
105- bold_app_name.c_str());
106+ dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_LABEL, bold_app_name.c_str());
107 dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
108 dbusmenu_menuitem_property_set_bool(item, QuicklistMenuItem::MARKUP_ENABLED_PROPERTY, TRUE);
109
110@@ -1011,29 +1010,11 @@
111
112 if (IsRunning())
113 {
114- bool exists = false;
115- auto const& it = _menu_items[MenuItemType::QUIT];
116- const gchar* label = dbusmenu_menuitem_property_get(it, DBUSMENU_MENUITEM_PROP_LABEL);
117- auto const& label_default = glib::gchar_to_string(label);
118-
119- for (auto menu_item : result)
120- {
121- const gchar* type = dbusmenu_menuitem_property_get(menu_item, DBUSMENU_MENUITEM_PROP_TYPE);
122-
123- if (!type)//(g_strcmp0 (type, DBUSMENU_MENUITEM_PROP_LABEL) == 0)
124- {
125- label = dbusmenu_menuitem_property_get(menu_item, DBUSMENU_MENUITEM_PROP_LABEL);
126-
127- if (glib::gchar_to_string(label) == label_default)
128- {
129- exists = true;
130- break;
131- }
132- }
133- }
134-
135- if (!exists)
136- result.push_back(it);
137+ if (!quit_item)
138+ quit_item = _menu_items[MenuItemType::QUIT];
139+
140+ dbusmenu_menuitem_property_set(quit_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Quit"));
141+ result.push_back(quit_item);
142 }
143
144 return result;
145
146=== modified file 'launcher/ApplicationLauncherIcon.h'
147--- launcher/ApplicationLauncherIcon.h 2013-06-28 14:06:31 +0000
148+++ launcher/ApplicationLauncherIcon.h 2013-06-28 14:06:31 +0000
149@@ -114,7 +114,7 @@
150 void DisconnectApplicationSignalsConnections();
151 void EnsureWindowState();
152 void EnsureMenuItemsWindowsReady();
153- void EnsureMenuItemsControlReady();
154+ void EnsureMenuItemsDefaultReady();
155 void UpdateBackgroundColor();
156 void UpdateMenus();
157 void UpdateDesktopQuickList();
158
159=== modified file 'launcher/LauncherIcon.cpp'
160--- launcher/LauncherIcon.cpp 2013-05-24 16:16:40 +0000
161+++ launcher/LauncherIcon.cpp 2013-06-28 14:06:31 +0000
162@@ -1113,7 +1113,7 @@
163 if (_remote_urgent)
164 SetQuirk(Quirk::URGENT, false);
165
166- _menuclient_dynamic_quicklist = nullptr;
167+ _remote_menus = nullptr;
168 }
169
170 void
171@@ -1160,7 +1160,7 @@
172 void
173 LauncherIcon::OnRemoteQuicklistChanged(LauncherEntryRemote* remote)
174 {
175- _menuclient_dynamic_quicklist = remote->Quicklist();
176+ _remote_menus = remote->Quicklist();
177 }
178
179 void
180@@ -1194,6 +1194,22 @@
181 SetProgress(remote->Progress());
182 }
183
184+glib::Object<DbusmenuMenuitem> LauncherIcon::GetRemoteMenus() const
185+{
186+ if (!_remote_menus.IsType(DBUSMENU_TYPE_CLIENT))
187+ return glib::Object<DbusmenuMenuitem>();
188+
189+ glib::Object<DbusmenuMenuitem> root(dbusmenu_client_get_root(_remote_menus), glib::AddRef());
190+
191+ if (!root.IsType(DBUSMENU_TYPE_MENUITEM) ||
192+ !dbusmenu_menuitem_property_get_bool(root, DBUSMENU_MENUITEM_PROP_VISIBLE))
193+ {
194+ return glib::Object<DbusmenuMenuitem>();
195+ }
196+
197+ return root;
198+}
199+
200 void LauncherIcon::EmitNeedsRedraw()
201 {
202 if (OwnsTheReference() && GetReferenceCount() > 0)
203
204=== modified file 'launcher/LauncherIcon.h'
205--- launcher/LauncherIcon.h 2013-05-17 22:53:57 +0000
206+++ launcher/LauncherIcon.h 2013-06-28 14:06:31 +0000
207@@ -198,6 +198,8 @@
208
209 virtual void UnStick();
210
211+ virtual glib::Object<DbusmenuMenuitem> GetRemoteMenus() const;
212+
213 void PerformScroll(ScrollDirection direction, Time timestamp) override;
214
215 protected:
216@@ -291,8 +293,6 @@
217 // This looks like a case for boost::logical::tribool
218 static int _current_theme_is_mono;
219
220- glib::Object<DbusmenuClient> _menuclient_dynamic_quicklist;
221-
222 private:
223 IconType _icon_type;
224
225@@ -339,6 +339,7 @@
226 bool _allow_quicklist_to_show;
227
228 std::list<LauncherEntryRemote::Ptr> _entry_list;
229+ glib::Object<DbusmenuClient> _remote_menus;
230
231 nux::animation::AnimateValue<double> _tooltip_fade_animator;
232
233
234=== modified file 'launcher/QuicklistMenuItem.cpp'
235--- launcher/QuicklistMenuItem.cpp 2013-04-18 10:32:43 +0000
236+++ launcher/QuicklistMenuItem.cpp 2013-06-28 14:06:31 +0000
237@@ -32,6 +32,7 @@
238 const char* QuicklistMenuItem::MARKUP_ACCEL_DISABLED_PROPERTY = "unity-disable-accel";
239 const char* QuicklistMenuItem::MAXIMUM_LABEL_WIDTH_PROPERTY = "unity-max-label-width";
240 const char* QuicklistMenuItem::OVERLAY_MENU_ITEM_PROPERTY = "unity-overlay-item";
241+const char* QuicklistMenuItem::QUIT_ACTION_PROPERTY = "unity-quit-action";
242
243 NUX_IMPLEMENT_OBJECT_TYPE(QuicklistMenuItem);
244
245
246=== modified file 'launcher/QuicklistMenuItem.h'
247--- launcher/QuicklistMenuItem.h 2013-04-09 18:35:24 +0000
248+++ launcher/QuicklistMenuItem.h 2013-06-28 14:06:31 +0000
249@@ -90,6 +90,7 @@
250 static const char* MARKUP_ACCEL_DISABLED_PROPERTY;
251 static const char* MAXIMUM_LABEL_WIDTH_PROPERTY;
252 static const char* OVERLAY_MENU_ITEM_PROPERTY;
253+ static const char* QUIT_ACTION_PROPERTY;
254
255 protected:
256 // Introspection
257
258=== modified file 'tests/data/applications/ubuntu-software-center.desktop'
259--- tests/data/applications/ubuntu-software-center.desktop 2013-03-25 18:22:32 +0000
260+++ tests/data/applications/ubuntu-software-center.desktop 2013-06-28 14:06:31 +0000
261@@ -11,3 +11,14 @@
262 StartupNotify=true
263 X-Ubuntu-Gettext-Domain=software-center
264 X-Unity-IconBackgroundColor=#aabbcc
265+Actions=TestAction;Quit;
266+
267+[Desktop Action TestAction]
268+Name=Test Action
269+Exec=/bin/true
270+OnlyShowIn=Unity;
271+
272+[Desktop Action Quit]
273+Name=Quit
274+Exec=/bin/true
275+OnlyShowIn=Unity;
276\ No newline at end of file
277
278=== modified file 'tests/test_application_launcher_icon.cpp'
279--- tests/test_application_launcher_icon.cpp 2013-06-28 14:06:31 +0000
280+++ tests/test_application_launcher_icon.cpp 2013-06-28 14:06:31 +0000
281@@ -52,12 +52,14 @@
282 ON_CALL(*this, Stick(_)).WillByDefault(Invoke([this] (bool save) { ApplicationLauncherIcon::Stick(save); }));
283 ON_CALL(*this, Stick()).WillByDefault(Invoke([this] { ApplicationLauncherIcon::Stick(); }));
284 ON_CALL(*this, UnStick()).WillByDefault(Invoke([this] { ApplicationLauncherIcon::UnStick(); }));
285+ ON_CALL(*this, GetRemoteMenus()).WillByDefault(Invoke([] { return glib::Object<DbusmenuMenuitem>(); }));
286 }
287
288 MOCK_METHOD1(ActivateLauncherIcon, void(ActionArg));
289 MOCK_METHOD1(Stick, void(bool));
290 MOCK_METHOD0(Stick, void());
291 MOCK_METHOD0(UnStick, void());
292+ MOCK_CONST_METHOD0(GetRemoteMenus, glib::Object<DbusmenuMenuitem>());
293
294 using ApplicationLauncherIcon::IsFileManager;
295 };
296@@ -572,7 +574,7 @@
297 {
298 mock_app->SetRunState(true);
299 auto const& menu_item = GetMenuItemWithLabel(mock_icon, "Quit");
300- EXPECT_NE(menu_item, nullptr);
301+ ASSERT_NE(menu_item, nullptr);
302
303 EXPECT_CALL(*mock_app, Quit());
304 dbusmenu_menuitem_handle_event(menu_item, DBUSMENU_MENUITEM_EVENT_ACTIVATED, nullptr, 0);
305@@ -606,6 +608,168 @@
306 EXPECT_TRUE(method_called);
307 }
308
309+TEST_F(TestApplicationLauncherIcon, QuicklistMenuItemDesktopAction)
310+{
311+ EXPECT_TRUE(HasMenuItemWithLabel(usc_icon, "Test Action"));
312+}
313+
314+TEST_F(TestApplicationLauncherIcon, QuicklistMenuItemDesktopActionOverridesQuitNotRunning)
315+{
316+ mock_app->SetRunState(false);
317+ EXPECT_FALSE(HasMenuItemWithLabel(usc_icon, "Quit"));
318+}
319+
320+TEST_F(TestApplicationLauncherIcon, QuicklistMenuItemDesktopActionOverridesQuitRunning)
321+{
322+ usc_app->SetRunState(true);
323+ auto const& item = GetMenuItemWithLabel(usc_icon, "Quit");
324+ ASSERT_NE(item, nullptr);
325+ EXPECT_CALL(*usc_app, Quit()).Times(0);
326+
327+ dbusmenu_menuitem_handle_event(item, DBUSMENU_MENUITEM_EVENT_ACTIVATED, nullptr, 0);
328+}
329+
330+TEST_F(TestApplicationLauncherIcon, QuicklistMenuItemRemote)
331+{
332+ unsigned time = g_random_int();
333+ glib::Object<DbusmenuMenuitem> root(dbusmenu_menuitem_new());
334+ glib::Object<DbusmenuMenuitem> item(dbusmenu_menuitem_new());
335+ dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_LABEL, "RemoteLabel");
336+ dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
337+ dbusmenu_menuitem_child_append(root, item);
338+
339+ bool cb_called = false;
340+ glib::Signal<void, DbusmenuMenuitem*, unsigned> signal(item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
341+ [&cb_called, item, time] (DbusmenuMenuitem* menu, unsigned timestamp) {
342+ cb_called = true;
343+ EXPECT_EQ(menu, item);
344+ EXPECT_EQ(timestamp, time);
345+ });
346+
347+ ON_CALL(*mock_icon, GetRemoteMenus()).WillByDefault(Invoke([&root] { return root; }));
348+ EXPECT_CALL(*mock_icon, GetRemoteMenus());
349+ EXPECT_TRUE(HasMenuItemWithLabel(mock_icon, "RemoteLabel"));
350+
351+ dbusmenu_menuitem_handle_event(item, DBUSMENU_MENUITEM_EVENT_ACTIVATED, nullptr, time);
352+ EXPECT_TRUE(cb_called);
353+}
354+
355+TEST_F(TestApplicationLauncherIcon, QuicklistMenuItemRemoteDisablesMarkup)
356+{
357+ glib::Object<DbusmenuMenuitem> root(dbusmenu_menuitem_new());
358+ glib::Object<DbusmenuMenuitem> item(dbusmenu_menuitem_new());
359+ dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_LABEL, "RemoteLabel");
360+ dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
361+ dbusmenu_menuitem_property_set_bool(item, QuicklistMenuItem::MARKUP_ENABLED_PROPERTY, TRUE);
362+ ASSERT_TRUE(dbusmenu_menuitem_property_get_bool(item, QuicklistMenuItem::MARKUP_ENABLED_PROPERTY));
363+ dbusmenu_menuitem_child_append(root, item);
364+
365+ ON_CALL(*mock_icon, GetRemoteMenus()).WillByDefault(Invoke([&root] { return root; }));
366+
367+ item = GetMenuItemWithLabel(mock_icon, "RemoteLabel");
368+ ASSERT_NE(item, nullptr);
369+ EXPECT_FALSE(dbusmenu_menuitem_property_get_bool(item, QuicklistMenuItem::MARKUP_ENABLED_PROPERTY));
370+}
371+
372+TEST_F(TestApplicationLauncherIcon, QuicklistMenuItemRemoteIgnoresInvisible)
373+{
374+ glib::Object<DbusmenuMenuitem> root(dbusmenu_menuitem_new());
375+ glib::Object<DbusmenuMenuitem> item(dbusmenu_menuitem_new());
376+ dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_LABEL, "InvisibleLabel");
377+ dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
378+ dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
379+ ASSERT_FALSE(dbusmenu_menuitem_property_get_bool(item, DBUSMENU_MENUITEM_PROP_VISIBLE));
380+ dbusmenu_menuitem_child_append(root, item);
381+
382+ ON_CALL(*mock_icon, GetRemoteMenus()).WillByDefault(Invoke([&root] { return root; }));
383+
384+ EXPECT_FALSE(HasMenuItemWithLabel(mock_icon, "InvisibleLabel"));
385+}
386+
387+struct QuitLabel : TestApplicationLauncherIcon, testing::WithParamInterface<std::string> {};
388+INSTANTIATE_TEST_CASE_P(TestApplicationLauncherIcon, QuitLabel, testing::Values("Quit", "Exit", "Close"));
389+
390+TEST_P(/*TestApplicationLauncherIcon*/QuitLabel, QuicklistMenuItemRemoteOverridesQuitByLabelNotRunning)
391+{
392+ mock_app->SetRunState(false);
393+ glib::Object<DbusmenuMenuitem> root(dbusmenu_menuitem_new());
394+ glib::Object<DbusmenuMenuitem> item(dbusmenu_menuitem_new());
395+ dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_LABEL, GetParam().c_str());
396+ dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
397+ dbusmenu_menuitem_child_append(root, item);
398+
399+ ON_CALL(*mock_icon, GetRemoteMenus()).WillByDefault(Invoke([&root] { return root; }));
400+
401+ EXPECT_FALSE(HasMenuItemWithLabel(mock_icon, GetParam()));
402+}
403+
404+TEST_P(/*TestApplicationLauncherIcon*/QuitLabel, QuicklistMenuItemRemoteOverridesQuitByLabel)
405+{
406+ mock_app->SetRunState(true);
407+ unsigned time = g_random_int();
408+ glib::Object<DbusmenuMenuitem> root(dbusmenu_menuitem_new());
409+ glib::Object<DbusmenuMenuitem> item(dbusmenu_menuitem_new());
410+ dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_LABEL, GetParam().c_str());
411+ dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
412+ dbusmenu_menuitem_child_append(root, item);
413+
414+ bool cb_called = false;
415+ glib::Signal<void, DbusmenuMenuitem*, unsigned> signal(item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
416+ [&cb_called, item, time] (DbusmenuMenuitem* menu, unsigned timestamp) {
417+ cb_called = true;
418+ EXPECT_EQ(menu, item);
419+ EXPECT_EQ(timestamp, time);
420+ });
421+
422+ ON_CALL(*mock_icon, GetRemoteMenus()).WillByDefault(Invoke([&root] { return root; }));
423+
424+ if (GetParam() != "Quit")
425+ ASSERT_FALSE(HasMenuItemWithLabel(mock_icon, GetParam()));
426+
427+ item = GetMenuItemWithLabel(mock_icon, "Quit");
428+ ASSERT_NE(item, nullptr);
429+ EXPECT_CALL(*mock_app, Quit()).Times(0);
430+
431+ dbusmenu_menuitem_handle_event(item, DBUSMENU_MENUITEM_EVENT_ACTIVATED, nullptr, time);
432+ EXPECT_TRUE(cb_called);
433+}
434+
435+TEST_F(TestApplicationLauncherIcon, QuicklistMenuItemRemoteOverridesQuitByPropertyNotRunning)
436+{
437+ mock_app->SetRunState(false);
438+ glib::Object<DbusmenuMenuitem> root(dbusmenu_menuitem_new());
439+ glib::Object<DbusmenuMenuitem> item(dbusmenu_menuitem_new());
440+ dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_LABEL, "Custom Quit Label");
441+ dbusmenu_menuitem_property_set_bool(item, QuicklistMenuItem::QUIT_ACTION_PROPERTY, TRUE);
442+ dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
443+ dbusmenu_menuitem_child_append(root, item);
444+
445+ ON_CALL(*mock_icon, GetRemoteMenus()).WillByDefault(Invoke([&root] { return root; }));
446+
447+ EXPECT_FALSE(HasMenuItemWithLabel(mock_icon, "Custom Quit Label"));
448+ EXPECT_FALSE(HasMenuItemWithLabel(mock_icon, "Quit"));
449+}
450+
451+TEST_F(TestApplicationLauncherIcon, QuicklistMenuItemRemoteOverridesQuitByProperty)
452+{
453+ mock_app->SetRunState(true);
454+ glib::Object<DbusmenuMenuitem> root(dbusmenu_menuitem_new());
455+ glib::Object<DbusmenuMenuitem> item(dbusmenu_menuitem_new());
456+ dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_LABEL, "Custom Quit Label");
457+ dbusmenu_menuitem_property_set_bool(item, QuicklistMenuItem::QUIT_ACTION_PROPERTY, TRUE);
458+ dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
459+ dbusmenu_menuitem_child_append(root, item);
460+
461+ ON_CALL(*mock_icon, GetRemoteMenus()).WillByDefault(Invoke([&root] { return root; }));
462+
463+ EXPECT_FALSE(HasMenuItemWithLabel(mock_icon, "Custom Quit Label"));
464+ auto new_item = GetMenuItemWithLabel(mock_icon, "Quit");
465+ ASSERT_EQ(new_item, item);
466+
467+ EXPECT_CALL(*mock_app, Quit()).Times(0);
468+ dbusmenu_menuitem_handle_event(item, DBUSMENU_MENUITEM_EVENT_ACTIVATED, nullptr, 0);
469+}
470+
471 TEST_F(TestApplicationLauncherIcon, IsFileManager)
472 {
473 EXPECT_FALSE(usc_icon->IsFileManager());