1
// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
3
* Copyright (C) 2010 Canonical Ltd
5
* This program is free software: you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License version 3 as
7
* published by the Free Software Foundation.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17
* Authored by: Jason Smith <jason.smith@canonical.com>
21
#include "Nux/BaseWindow.h"
23
#include "BamfLauncherIcon.h"
25
#include "PluginAdapter.h"
26
#include "FavoriteStore.h"
28
#include "ubus-server.h"
29
#include "UBusMessages.h"
31
#include <glib/gi18n-lib.h>
32
#include <gio/gdesktopappinfo.h>
33
#include <libindicator/indicator-desktop-shortcuts.h>
34
#include <core/core.h>
35
#include <core/atoms.h>
37
using unity::FavoriteStore;
41
BamfLauncherIcon* self;
42
IndicatorDesktopShortcuts* shortcuts;
45
typedef struct _ShortcutData ShortcutData;
46
static void shortcut_data_destroy(ShortcutData* data)
48
g_object_unref(data->shortcuts);
50
g_slice_free(ShortcutData, data);
53
static void shortcut_activated(DbusmenuMenuitem* _sender, guint timestamp, gpointer userdata)
55
ShortcutData* data = (ShortcutData*)userdata;
56
indicator_desktop_shortcuts_nick_exec(data->shortcuts, data->nick);
59
void BamfLauncherIcon::Activate(ActionArg arg)
61
ActivateLauncherIcon(arg);
65
void BamfLauncherIcon::ActivateLauncherIcon(ActionArg arg)
67
bool scaleWasActive = PluginAdapter::Default()->IsScaleActive();
70
active = bamf_view_is_active(BAMF_VIEW(m_App));
71
running = bamf_view_is_running(BAMF_VIEW(m_App));
73
if (arg.target && OwnsWindow (arg.target))
75
CompWindow* window = m_Screen->findWindow(arg.target);
81
* 1) Nothing running -> launch application
82
* 2) Running and active -> spread application
83
* 3) Running and not active -> focus application
84
* 4) Spread is active and different icon pressed -> change spread
85
* 5) Spread is active -> Spread de-activated, and fall through
88
if (!running) // #1 above
90
if (GetQuirk(QUIRK_STARTING))
95
PluginAdapter::Default()->TerminateScale();
98
SetQuirk(QUIRK_STARTING, true);
99
OpenInstanceLauncherIcon(ActionArg ());
101
else // app is running
105
if (scaleWasActive) // #5 above
107
PluginAdapter::Default()->TerminateScale();
112
if (arg.source != ActionArg::SWITCHER)
118
if (scaleWasActive) // #4 above
120
PluginAdapter::Default()->TerminateScale();
122
if (arg.source != ActionArg::SWITCHER)
132
ubus_server_send_message(ubus_server_get_default(), UBUS_LAUNCHER_ACTION_DONE, NULL);
135
BamfLauncherIcon::BamfLauncherIcon(Launcher* IconManager, BamfApplication* app, CompScreen* screen)
136
: SimpleLauncherIcon(IconManager)
138
_cached_desktop_file = NULL;
143
_dnd_hover_timer = 0;
144
_dnd_hovered = false;
145
_launcher = IconManager;
146
_menu_desktop_shortcuts = NULL;
147
char* icon_name = bamf_view_get_icon(BAMF_VIEW(m_App));
149
tooltip_text = BamfName();
150
SetIconName(icon_name);
151
SetIconType(TYPE_APPLICATION);
153
if (bamf_view_is_sticky(BAMF_VIEW(m_App)))
154
SetQuirk(QUIRK_VISIBLE, true);
156
SetQuirk(QUIRK_VISIBLE, bamf_view_user_visible(BAMF_VIEW(m_App)));
158
SetQuirk(QUIRK_ACTIVE, bamf_view_is_active(BAMF_VIEW(m_App)));
159
SetQuirk(QUIRK_RUNNING, bamf_view_is_running(BAMF_VIEW(m_App)));
163
g_signal_connect(app, "child-removed", (GCallback) &BamfLauncherIcon::OnChildRemoved, this);
164
g_signal_connect(app, "child-added", (GCallback) &BamfLauncherIcon::OnChildAdded, this);
165
g_signal_connect(app, "urgent-changed", (GCallback) &BamfLauncherIcon::OnUrgentChanged, this);
166
g_signal_connect(app, "running-changed", (GCallback) &BamfLauncherIcon::OnRunningChanged, this);
167
g_signal_connect(app, "active-changed", (GCallback) &BamfLauncherIcon::OnActiveChanged, this);
168
g_signal_connect(app, "user-visible-changed", (GCallback) &BamfLauncherIcon::OnUserVisibleChanged, this);
169
g_signal_connect(app, "closed", (GCallback) &BamfLauncherIcon::OnClosed, this);
176
// add a file watch to the desktop file so that if/when the app is removed we can remove ourself from the launcher.
177
GFile* _desktop_file = g_file_new_for_path(DesktopFile());
178
_desktop_file_monitor = g_file_monitor_file(_desktop_file,
183
_on_desktop_file_changed_handler_id = g_signal_connect(_desktop_file_monitor,
185
G_CALLBACK(&BamfLauncherIcon::OnDesktopFileChanged),
188
PluginAdapter::Default()->window_minimized.connect(sigc::mem_fun(this, &BamfLauncherIcon::OnWindowMinimized));
189
IconManager->hidden_changed.connect(sigc::mem_fun(this, &BamfLauncherIcon::OnLauncherHiddenChanged));
196
BamfLauncherIcon::~BamfLauncherIcon()
198
g_object_set_qdata(G_OBJECT(m_App), g_quark_from_static_string("unity-seen"), GINT_TO_POINTER(0));
200
// We might not have created the menu items yet
201
if (_menu_items.find("Pin") != _menu_items.end())
203
g_signal_handler_disconnect((gpointer) _menu_items["Pin"],
204
_menu_callbacks["Pin"]);
207
if (_menu_items.find("Quit") != _menu_items.end())
209
g_signal_handler_disconnect((gpointer) _menu_items["Quit"],
210
_menu_callbacks["Quit"]);
213
if (_on_desktop_file_changed_handler_id != 0)
214
g_signal_handler_disconnect((gpointer) _desktop_file_monitor,
215
_on_desktop_file_changed_handler_id);
217
g_signal_handlers_disconnect_by_func(m_App, (void*) &BamfLauncherIcon::OnChildRemoved, this);
218
g_signal_handlers_disconnect_by_func(m_App, (void*) &BamfLauncherIcon::OnChildAdded, this);
219
g_signal_handlers_disconnect_by_func(m_App, (void*) &BamfLauncherIcon::OnUrgentChanged, this);
220
g_signal_handlers_disconnect_by_func(m_App, (void*) &BamfLauncherIcon::OnRunningChanged, this);
221
g_signal_handlers_disconnect_by_func(m_App, (void*) &BamfLauncherIcon::OnActiveChanged, this);
222
g_signal_handlers_disconnect_by_func(m_App, (void*) &BamfLauncherIcon::OnUserVisibleChanged, this);
223
g_signal_handlers_disconnect_by_func(m_App, (void*) &BamfLauncherIcon::OnClosed, this);
225
g_object_unref(m_App);
226
g_object_unref(_desktop_file_monitor);
228
g_free(_cached_desktop_file);
229
g_free(_cached_name);
232
std::vector<Window> BamfLauncherIcon::RelatedXids ()
234
std::vector<Window> results;
238
children = bamf_view_get_children(BAMF_VIEW(m_App));
239
for (l = children; l; l = l->next)
241
view = (BamfView*) l->data;
242
if (BAMF_IS_WINDOW(view))
243
results.push_back ((Window) bamf_window_get_xid(BAMF_WINDOW(view)));
246
g_list_free(children);
250
void BamfLauncherIcon::OnLauncherHiddenChanged()
252
UpdateIconGeometries(GetCenter());
255
void BamfLauncherIcon::OnWindowMinimized(guint32 xid)
257
if (!OwnsWindow(xid))
261
UpdateQuirkTimeDelayed(300, QUIRK_SHIMMER);
264
bool BamfLauncherIcon::IsSticky()
266
return bamf_view_is_sticky(BAMF_VIEW(m_App));
269
const char* BamfLauncherIcon::DesktopFile()
271
char* filename = NULL;
272
filename = (char*) bamf_application_get_desktop_file(m_App);
274
if (filename != NULL)
276
if (_cached_desktop_file != NULL)
277
g_free(_cached_desktop_file);
279
_cached_desktop_file = g_strdup(filename);
282
return _cached_desktop_file;
285
const char* BamfLauncherIcon::BamfName()
287
const char* name = NULL;
288
name = bamf_view_get_name(BAMF_VIEW(m_App));
293
if (_cached_name != NULL)
294
g_free(_cached_name);
296
_cached_name = g_strdup(name);
301
void BamfLauncherIcon::AddProperties(GVariantBuilder* builder)
303
LauncherIcon::AddProperties(builder);
305
g_variant_builder_add(builder, "{sv}", "desktop-file", g_variant_new_string(bamf_application_get_desktop_file(m_App)));
310
children = bamf_view_get_children(BAMF_VIEW(m_App));
311
GVariant* xids[(int) g_list_length(children)];
314
for (l = children; l; l = l->next)
316
view = (BamfView*) l->data;
318
if (BAMF_IS_WINDOW(view))
320
xids[i++] = g_variant_new_uint32(bamf_window_get_xid(BAMF_WINDOW(view)));
323
g_list_free(children);
324
g_variant_builder_add(builder, "{sv}", "xids", g_variant_new_array(G_VARIANT_TYPE_UINT32, xids, i));
327
bool BamfLauncherIcon::OwnsWindow(Window w)
333
children = bamf_view_get_children(BAMF_VIEW(m_App));
335
for (l = children; l; l = l->next)
337
view = (BamfView*) l->data;
339
if (BAMF_IS_WINDOW(view))
341
guint32 xid = bamf_window_get_xid(BAMF_WINDOW(view));
351
g_list_free(children);
355
void BamfLauncherIcon::OpenInstanceWithUris(std::list<char*> uris)
357
GDesktopAppInfo* appInfo;
358
GError* error = NULL;
359
std::list<char*>::iterator it;
361
appInfo = g_desktop_app_info_new_from_filename(bamf_application_get_desktop_file(BAMF_APPLICATION(m_App)));
363
if (g_app_info_supports_uris(G_APP_INFO(appInfo)))
367
for (it = uris.begin(); it != uris.end(); it++)
368
list = g_list_prepend(list, *it);
370
g_app_info_launch_uris(G_APP_INFO(appInfo), list, NULL, &error);
373
else if (g_app_info_supports_files(G_APP_INFO(appInfo)))
375
GList* list = NULL, *l;
376
for (it = uris.begin(); it != uris.end(); it++)
378
GFile* file = g_file_new_for_uri(*it);
379
list = g_list_prepend(list, file);
381
g_app_info_launch(G_APP_INFO(appInfo), list, NULL, &error);
383
for (l = list; l; l = l->next)
384
g_object_unref(G_FILE(list->data));
390
g_app_info_launch(G_APP_INFO(appInfo), NULL, NULL, &error);
393
g_object_unref(appInfo);
397
g_warning("%s\n", error->message);
401
UpdateQuirkTime(QUIRK_STARTING);
404
void BamfLauncherIcon::OpenInstanceLauncherIcon(ActionArg arg)
406
std::list<char*> empty;
407
OpenInstanceWithUris(empty);
408
ubus_server_send_message(ubus_server_get_default(), UBUS_LAUNCHER_ACTION_DONE, NULL);
411
void BamfLauncherIcon::Focus()
415
bool any_urgent = false;
416
bool any_on_current = false;
417
bool any_mapped = false;
419
children = bamf_view_get_children(BAMF_VIEW(m_App));
421
CompWindowList windows;
423
/* get the list of windows */
424
for (l = children; l; l = l->next)
426
view = (BamfView*) l->data;
428
if (BAMF_IS_WINDOW(view))
430
guint32 xid = bamf_window_get_xid(BAMF_WINDOW(view));
432
CompWindow* window = m_Screen->findWindow((Window) xid);
436
if (bamf_view_is_urgent(view))
438
windows.push_back(window);
446
g_list_free(children);
452
for (auto win : m_Screen->clientList())
454
if (std::find(windows.begin(), windows.end(), win) != windows.end())
459
/* filter based on workspace */
460
for (CompWindow* &win : windows)
462
if (win->defaultViewport() == m_Screen->vp())
464
any_on_current = true;
467
if (!win->minimized())
472
if (any_on_current && any_mapped)
478
// FIXME we cant use the compiz tracking since it is currently broken
479
/*for (it = windows.begin (); it != windows.end (); it++)
481
if ((*it)->state () & CompWindowStateDemandsAttentionMask)
487
for (l = children; l; l = l->next)
489
view = (BamfView*) l->data;
491
if (BAMF_IS_WINDOW(view))
493
guint32 xid = bamf_window_get_xid(BAMF_WINDOW(view));
495
CompWindow* window = m_Screen->findWindow((Window) xid);
497
if (window && bamf_view_is_urgent(view))
505
else if (any_on_current)
507
// to ensure proper stacking we process windows in reverse order (high to low)
508
// then we active the first window and raise each following window. Due to the
509
// way stack requests work (async), each subsequent raise call will stack below
513
for (CompWindow* &win : windows)
515
if (win->defaultViewport() == m_Screen->vp() &&
516
((any_mapped && !win->minimized()) || !any_mapped))
533
(*(windows.rbegin()))->activate();
536
g_list_free(children);
539
bool BamfLauncherIcon::Spread(int state, bool force)
543
children = bamf_view_get_children(BAMF_VIEW(m_App));
545
std::list<Window> windowList;
546
for (l = children; l; l = l->next)
548
view = (BamfView*) l->data;
550
if (BAMF_IS_WINDOW(view))
552
guint32 xid = bamf_window_get_xid(BAMF_WINDOW(view));
553
CompWindow* window = m_Screen->findWindow((Window) xid);
555
// filter by workspace
556
if (window && window->defaultViewport() == m_Screen->vp())
558
windowList.push_back((Window) xid);
563
if (windowList.size() > 1 || (windowList.size() > 0 && force))
565
std::string match = PluginAdapter::Default()->MatchStringForXids(&windowList);
566
PluginAdapter::Default()->InitiateScale(match, state);
567
g_list_free(children);
571
g_list_free(children);
576
void BamfLauncherIcon::OnClosed(BamfView* view, gpointer data)
578
BamfLauncherIcon* self = (BamfLauncherIcon*) data;
580
if (!bamf_view_is_sticky(BAMF_VIEW(self->m_App)))
584
void BamfLauncherIcon::OnUserVisibleChanged(BamfView* view, gboolean visible,
587
BamfLauncherIcon* self = (BamfLauncherIcon*) data;
589
if (!bamf_view_is_sticky(BAMF_VIEW(self->m_App)))
590
self->SetQuirk(QUIRK_VISIBLE, visible);
593
void BamfLauncherIcon::OnRunningChanged(BamfView* view, gboolean running,
596
BamfLauncherIcon* self = (BamfLauncherIcon*) data;
597
self->SetQuirk(QUIRK_RUNNING, running);
601
self->EnsureWindowState();
602
self->UpdateIconGeometries(self->GetCenter());
606
void BamfLauncherIcon::OnActiveChanged(BamfView* view, gboolean active, gpointer data)
608
BamfLauncherIcon* self = (BamfLauncherIcon*) data;
609
self->SetQuirk(QUIRK_ACTIVE, active);
612
void BamfLauncherIcon::OnUrgentChanged(BamfView* view, gboolean urgent, gpointer data)
614
BamfLauncherIcon* self = (BamfLauncherIcon*) data;
615
self->SetQuirk(QUIRK_URGENT, urgent);
618
void BamfLauncherIcon::EnsureWindowState()
623
bool has_visible = false;
625
children = bamf_view_get_children(BAMF_VIEW(m_App));
626
for (l = children; l; l = l->next)
628
if (!BAMF_IS_WINDOW(l->data))
633
guint32 xid = bamf_window_get_xid(BAMF_WINDOW(l->data));
634
CompWindow* window = m_Screen->findWindow((Window) xid);
636
if (window && window->defaultViewport() == m_Screen->vp())
640
SetRelatedWindows(count);
641
SetHasWindowOnViewport(has_visible);
643
g_list_free(children);
646
void BamfLauncherIcon::OnChildAdded(BamfView* view, BamfView* child, gpointer data)
648
BamfLauncherIcon* self = (BamfLauncherIcon*) data;
649
self->EnsureWindowState();
651
self->UpdateIconGeometries(self->GetCenter());
654
void BamfLauncherIcon::OnChildRemoved(BamfView* view, BamfView* child, gpointer data)
656
BamfLauncherIcon* self = (BamfLauncherIcon*) data;
657
self->EnsureWindowState();
660
void BamfLauncherIcon::UpdateMenus()
663
IndicatorDesktopShortcuts* desktop_shortcuts;
665
children = bamf_view_get_children(BAMF_VIEW(m_App));
666
for (l = children; l; l = l->next)
668
if (!BAMF_IS_INDICATOR(l->data))
671
BamfIndicator* indicator = BAMF_INDICATOR(l->data);
672
std::string path = bamf_indicator_get_dbus_menu_path(indicator);
674
// we already have this
675
if (_menu_clients.find(path) != _menu_clients.end())
678
DbusmenuClient* client = dbusmenu_client_new(bamf_indicator_get_remote_address(indicator), path.c_str());
679
_menu_clients[path] = client;
682
g_list_free(children);
684
// add dynamic quicklist
685
if (_menuclient_dynamic_quicklist != NULL)
686
_menu_clients["dynamicquicklist"] = _menuclient_dynamic_quicklist;
688
// make a client for desktop file actions
689
if (!DBUSMENU_IS_MENUITEM(_menu_desktop_shortcuts) &&
690
g_strcmp0(DesktopFile(), """"))
693
GError* error = NULL;
695
// check that we have the X-Ayatana-Desktop-Shortcuts flag
696
// not sure if we should do this or if libindicator should shut up
697
// and not report errors when it can't find the key.
698
// so FIXME when ted is around
699
keyfile = g_key_file_new();
700
g_key_file_load_from_file(keyfile, DesktopFile(), G_KEY_FILE_NONE, &error);
704
g_warning("Could not load desktop file for: %s" , DesktopFile());
709
if (g_key_file_has_key(keyfile, G_KEY_FILE_DESKTOP_GROUP,
710
"X-Ayatana-Desktop-Shortcuts", NULL))
712
DbusmenuMenuitem* root = dbusmenu_menuitem_new();
713
dbusmenu_menuitem_set_root(root, TRUE);
714
desktop_shortcuts = indicator_desktop_shortcuts_new(bamf_application_get_desktop_file(m_App),
716
const gchar** nicks = indicator_desktop_shortcuts_get_nicks(desktop_shortcuts);
721
while (((gpointer*) nicks)[index])
724
DbusmenuMenuitem* item;
725
name = indicator_desktop_shortcuts_nick_get_name(desktop_shortcuts,
727
ShortcutData* data = g_slice_new0(ShortcutData);
729
data->shortcuts = INDICATOR_DESKTOP_SHORTCUTS(g_object_ref(desktop_shortcuts));
730
data->nick = g_strdup(nicks[index]);
732
item = dbusmenu_menuitem_new();
733
dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_LABEL, name);
734
dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
735
dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
736
g_signal_connect_data(item, "item-activated",
737
(GCallback) shortcut_activated, (gpointer) data,
738
(GClosureNotify) shortcut_data_destroy, (GConnectFlags)0);
740
dbusmenu_menuitem_child_append(root, item);
748
_menu_desktop_shortcuts = root;
749
g_key_file_free(keyfile);
756
void BamfLauncherIcon::OnQuit(DbusmenuMenuitem* item, int time, BamfLauncherIcon* self)
761
children = bamf_view_get_children(BAMF_VIEW(self->m_App));
763
for (l = children; l; l = l->next)
765
view = (BamfView*) l->data;
767
if (BAMF_IS_WINDOW(view))
769
guint32 xid = bamf_window_get_xid(BAMF_WINDOW(view));
770
CompWindow* window = self->m_Screen->findWindow((Window) xid);
773
window->close(self->m_Screen->getCurrentTime());
777
g_list_free(children);
780
void BamfLauncherIcon::UnStick(void)
782
BamfView* view = BAMF_VIEW(this->m_App);
784
if (!bamf_view_is_sticky(view))
787
const gchar* desktop_file = bamf_application_get_desktop_file(this->m_App);
788
bamf_view_set_sticky(view, false);
789
if (bamf_view_is_closed(view))
792
if (desktop_file && strlen(desktop_file) > 0)
793
FavoriteStore::GetDefault().RemoveFavorite(desktop_file);
796
void BamfLauncherIcon::OnTogglePin(DbusmenuMenuitem* item, int time, BamfLauncherIcon* self)
798
BamfView* view = BAMF_VIEW(self->m_App);
799
bool sticky = bamf_view_is_sticky(view);
800
const gchar* desktop_file = bamf_application_get_desktop_file(self->m_App);
808
bamf_view_set_sticky(view, true);
810
if (desktop_file && strlen(desktop_file) > 0)
811
FavoriteStore::GetDefault().AddFavorite(desktop_file, -1);
815
void BamfLauncherIcon::EnsureMenuItemsReady()
817
DbusmenuMenuitem* menu_item;
820
if (_menu_items.find("Pin") == _menu_items.end())
822
menu_item = dbusmenu_menuitem_new();
823
g_object_ref(menu_item);
825
dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE, DBUSMENU_MENUITEM_TOGGLE_CHECK);
826
dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Keep in launcher"));
827
dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
828
dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
830
_menu_callbacks["Pin"] = g_signal_connect(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, (GCallback) &BamfLauncherIcon::OnTogglePin, this);
832
_menu_items["Pin"] = menu_item;
834
int checked = !bamf_view_is_sticky(BAMF_VIEW(m_App)) ?
835
DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED : DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED;
837
dbusmenu_menuitem_property_set_int(_menu_items["Pin"],
838
DBUSMENU_MENUITEM_PROP_TOGGLE_STATE,
843
if (_menu_items.find("Quit") == _menu_items.end())
845
menu_item = dbusmenu_menuitem_new();
846
g_object_ref(menu_item);
848
dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Quit"));
849
dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
850
dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
852
_menu_callbacks["Quit"] = g_signal_connect(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, (GCallback) &BamfLauncherIcon::OnQuit, this);
854
_menu_items["Quit"] = menu_item;
858
static void OnAppLabelActivated(DbusmenuMenuitem* sender,
862
BamfLauncherIcon* self = NULL;
867
self = (BamfLauncherIcon*) data;
868
self->ActivateLauncherIcon(ActionArg(ActionArg::OTHER, 0));
871
std::list<DbusmenuMenuitem*> BamfLauncherIcon::GetMenus()
873
std::map<std::string, DbusmenuClient*>::iterator it;
874
std::list<DbusmenuMenuitem*> result;
875
bool first_separator_needed = false;
876
DbusmenuMenuitem* item = NULL;
878
// FIXME for O: hack around the wrong abstraction
881
for (it = _menu_clients.begin(); it != _menu_clients.end(); it++)
884
DbusmenuClient* client = (*it).second;
885
DbusmenuMenuitem* root = dbusmenu_client_get_root(client);
887
for (child = dbusmenu_menuitem_get_children(root); child != NULL; child = g_list_next(child))
889
DbusmenuMenuitem* item = (DbusmenuMenuitem*) child->data;
894
first_separator_needed = true;
896
result.push_back(item);
900
// FIXME: this should totally be added as a _menu_client
901
if (DBUSMENU_IS_MENUITEM(_menu_desktop_shortcuts))
904
DbusmenuMenuitem* root = _menu_desktop_shortcuts;
906
for (child = dbusmenu_menuitem_get_children(root); child != NULL; child = g_list_next(child))
908
DbusmenuMenuitem* item = (DbusmenuMenuitem*) child->data;
913
first_separator_needed = true;
915
result.push_back(item);
919
if (first_separator_needed)
921
item = dbusmenu_menuitem_new();
922
dbusmenu_menuitem_property_set(item,
923
DBUSMENU_MENUITEM_PROP_TYPE,
924
DBUSMENU_CLIENT_TYPES_SEPARATOR);
925
result.push_back(item);
929
app_name = g_markup_escape_text(BamfName(), -1);
931
item = dbusmenu_menuitem_new();
932
dbusmenu_menuitem_property_set(item,
933
DBUSMENU_MENUITEM_PROP_LABEL,
935
dbusmenu_menuitem_property_set_bool(item,
936
DBUSMENU_MENUITEM_PROP_ENABLED,
938
g_signal_connect(item, "item-activated", (GCallback) OnAppLabelActivated, this);
939
result.push_back(item);
942
item = dbusmenu_menuitem_new();
943
dbusmenu_menuitem_property_set(item,
944
DBUSMENU_MENUITEM_PROP_TYPE,
945
DBUSMENU_CLIENT_TYPES_SEPARATOR);
946
result.push_back(item);
948
EnsureMenuItemsReady();
950
std::map<std::string, DbusmenuMenuitem*>::iterator it_m;
951
std::list<DbusmenuMenuitem*>::iterator it_l;
953
for (it_m = _menu_items.begin(); it_m != _menu_items.end(); it_m++)
955
const char* key = ((*it_m).first).c_str();
956
if (g_strcmp0(key , "Quit") == 0 && !bamf_view_is_running(BAMF_VIEW(m_App)))
960
std::string label_default = dbusmenu_menuitem_property_get((*it_m).second, DBUSMENU_MENUITEM_PROP_LABEL);
961
for (it_l = result.begin(); it_l != result.end(); it_l++)
963
const gchar* type = dbusmenu_menuitem_property_get(*it_l, DBUSMENU_MENUITEM_PROP_TYPE);
964
if (type == NULL)//(g_strcmp0 (type, DBUSMENU_MENUITEM_PROP_LABEL) == 0)
966
std::string label_menu = dbusmenu_menuitem_property_get(*it_l, DBUSMENU_MENUITEM_PROP_LABEL);
967
if (label_menu.compare(label_default) == 0)
976
result.push_back((*it_m).second);
983
void BamfLauncherIcon::UpdateIconGeometries(nux::Point3 center)
989
if (_launcher->Hidden() && !_launcher->ShowOnEdge())
996
data[0] = center.x - 24;
997
data[1] = center.y - 24;
1002
children = bamf_view_get_children(BAMF_VIEW(m_App));
1004
for (l = children; l; l = l->next)
1006
view = (BamfView*) l->data;
1008
if (BAMF_IS_WINDOW(view))
1010
guint32 xid = bamf_window_get_xid(BAMF_WINDOW(view));
1012
XChangeProperty(m_Screen->dpy(), xid, Atoms::wmIconGeometry,
1013
XA_CARDINAL, 32, PropModeReplace,
1014
(unsigned char*) data, 4);
1018
g_list_free(children);
1021
void BamfLauncherIcon::OnCenterStabilized(nux::Point3 center)
1023
UpdateIconGeometries(center);
1026
const gchar* BamfLauncherIcon::GetRemoteUri()
1030
const gchar* desktop_file = bamf_application_get_desktop_file(BAMF_APPLICATION(m_App));
1031
gchar* basename = g_path_get_basename(desktop_file);
1033
_remote_uri = g_strdup_printf("application://%s", basename);
1041
std::list<char*> BamfLauncherIcon::ValidateUrisForLaunch(std::list<char*> uris)
1044
const char* desktop_file;
1045
GError* error = NULL;
1046
std::list<char*> results;
1048
desktop_file = DesktopFile();
1050
if (!desktop_file || strlen(desktop_file) <= 1)
1053
key_file = g_key_file_new();
1054
g_key_file_load_from_file(key_file, desktop_file, (GKeyFileFlags) 0, &error);
1058
g_error_free(error);
1059
g_key_file_free(key_file);
1063
char** mimes = g_key_file_get_string_list(key_file, "Desktop Entry", "MimeType", NULL, NULL);
1066
g_key_file_free(key_file);
1070
std::list<char*>::iterator it;
1071
for (it = uris.begin(); it != uris.end(); it++)
1073
GFile* file = g_file_new_for_uri(*it);
1074
GFileInfo* info = g_file_query_info(file, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, G_FILE_QUERY_INFO_NONE, NULL, NULL);
1075
const char* content_type = g_file_info_get_content_type(info);
1078
for (; mimes[i]; i++)
1080
char* super_type = g_content_type_from_mime_type(mimes[i]);
1081
if (g_content_type_is_a(content_type, super_type))
1083
results.push_back(*it);
1090
g_object_unref(file);
1091
g_object_unref(info);
1095
g_key_file_free(key_file);
1099
gboolean BamfLauncherIcon::OnDndHoveredTimeout(gpointer data)
1101
BamfLauncherIcon* self = (BamfLauncherIcon*) data;
1102
if (self->_dnd_hovered && bamf_view_is_running(BAMF_VIEW(self->m_App)))
1103
self->Spread(CompAction::StateInitEdgeDnd, true);
1105
self->_dnd_hover_timer = 0;
1109
void BamfLauncherIcon::OnDndEnter()
1111
_dnd_hovered = true;
1112
_dnd_hover_timer = g_timeout_add(1000, &BamfLauncherIcon::OnDndHoveredTimeout, this);
1115
void BamfLauncherIcon::OnDndLeave()
1117
_dnd_hovered = false;
1119
if (_dnd_hover_timer)
1120
g_source_remove(_dnd_hover_timer);
1121
_dnd_hover_timer = 0;
1124
nux::DndAction BamfLauncherIcon::OnQueryAcceptDrop(std::list<char*> uris)
1126
return ValidateUrisForLaunch(uris).empty() ? nux::DNDACTION_NONE : nux::DNDACTION_COPY;
1129
void BamfLauncherIcon::OnAcceptDrop(std::list<char*> uris)
1131
OpenInstanceWithUris(ValidateUrisForLaunch(uris));
1134
void BamfLauncherIcon::OnDesktopFileChanged(GFileMonitor* monitor,
1137
GFileMonitorEvent event_type,
1140
BamfLauncherIcon* self = static_cast<BamfLauncherIcon*>(data);
1143
case G_FILE_MONITOR_EVENT_DELETED:
1152
BamfLauncherIcon::ShowInSwitcher()
1154
return GetQuirk(QUIRK_RUNNING) && GetQuirk(QUIRK_VISIBLE);
1158
BamfLauncherIcon::SwitcherPriority()
1160
GList* children, *l;
1162
unsigned int result = 0;
1164
children = bamf_view_get_children(BAMF_VIEW(m_App));
1166
/* get the list of windows */
1167
for (l = children; l; l = l->next)
1169
view = (BamfView*) l->data;
1171
if (BAMF_IS_WINDOW(view))
1173
guint32 xid = bamf_window_get_xid(BAMF_WINDOW(view));
1174
CompWindow* window = m_Screen->findWindow((Window) xid);
1177
result = std::max(result, window->activeNum());
1181
g_list_free(children);