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>
2
#include "Nux/BaseWindow.h"
23
4
#include "BamfLauncherIcon.h"
24
#include "FavoriteStore.h"
25
5
#include "Launcher.h"
26
#include "WindowManager.h"
27
#include "UBusMessages.h"
28
#include "ubus-server.h"
6
#include "PluginAdapter.h"
30
#include <glib/gi18n-lib.h>
31
8
#include <gio/gdesktopappinfo.h>
32
#include <libindicator/indicator-desktop-shortcuts.h>
34
#include <UnityCore/GLibWrapper.h>
36
using unity::FavoriteStore;
40
BamfLauncherIcon* self;
41
IndicatorDesktopShortcuts* shortcuts;
44
typedef struct _ShortcutData ShortcutData;
45
static void shortcut_data_destroy(ShortcutData* data)
47
g_object_unref(data->shortcuts);
49
g_slice_free(ShortcutData, data);
52
static void shortcut_activated(DbusmenuMenuitem* _sender, guint timestamp, gpointer userdata)
54
ShortcutData* data = (ShortcutData*)userdata;
55
indicator_desktop_shortcuts_nick_exec(data->shortcuts, data->nick);
58
void BamfLauncherIcon::ActivateLauncherIcon(ActionArg arg)
60
SimpleLauncherIcon::ActivateLauncherIcon(arg);
61
bool scaleWasActive = WindowManager::Default()->IsScaleActive();
66
active = bamf_view_is_active(BAMF_VIEW(m_App));
67
running = bamf_view_is_running(BAMF_VIEW(m_App));
69
if (arg.target && OwnsWindow (arg.target))
71
WindowManager::Default()->Activate(arg.target);
75
/* We should check each child to see if there is
76
* an unmapped (!= minimized) window around and
77
* if so force "Focus" behaviour */
79
if (arg.source != ActionArg::SWITCHER)
81
bool any_visible = false;
82
for (l = bamf_view_get_children(BAMF_VIEW(m_App)); l; l = l->next)
10
BamfLauncherIcon::BamfLauncherIcon (Launcher* IconManager, BamfApplication *app, CompScreen *screen, NUX_FILE_LINE_DECL)
11
: SimpleLauncherIcon(IconManager)
15
char *icon_name = bamf_view_get_icon (BAMF_VIEW (m_App));
17
SetTooltipText (bamf_view_get_name (BAMF_VIEW (app)));
18
SetIconName (icon_name);
20
if (bamf_view_is_sticky (BAMF_VIEW (m_App)))
23
SetVisible (bamf_view_user_visible (BAMF_VIEW (m_App)));
25
SetActive (bamf_view_is_active (BAMF_VIEW (m_App)));
26
SetRunning (bamf_view_is_running (BAMF_VIEW (m_App)));
30
g_signal_connect (app, "running-changed", (GCallback) &BamfLauncherIcon::OnRunningChanged, this);
31
g_signal_connect (app, "active-changed", (GCallback) &BamfLauncherIcon::OnActiveChanged, this);
32
g_signal_connect (app, "user-visible-changed", (GCallback) &BamfLauncherIcon::OnUserVisibleChanged, this);
33
g_signal_connect (app, "closed", (GCallback) &BamfLauncherIcon::OnClosed, this);
36
BamfLauncherIcon::~BamfLauncherIcon()
41
BamfLauncherIcon::OnMouseClick ()
46
GDesktopAppInfo *appInfo;
48
children = bamf_view_get_children (BAMF_VIEW (m_App));
49
active = bamf_view_is_active (BAMF_VIEW (m_App));
50
running = bamf_view_is_running (BAMF_VIEW (m_App));
84
view = static_cast <BamfView*> (l->data);
86
if (BAMF_IS_WINDOW(view))
88
Window xid = bamf_window_get_xid(BAMF_WINDOW(view));
90
if (WindowManager::Default ()->IsWindowOnCurrentDesktop(xid))
92
if (!WindowManager::Default ()->IsWindowMapped(xid))
104
* 1) Nothing running -> launch application
105
* 2) Running and active -> spread application
106
* 3) Running and not active -> focus application
107
* 4) Spread is active and different icon pressed -> change spread
108
* 5) Spread is active -> Spread de-activated, and fall through
111
if (!running) // #1 above
113
if (GetQuirk(QUIRK_STARTING))
54
appInfo = g_desktop_app_info_new_from_filename (bamf_application_get_desktop_file (BAMF_APPLICATION (m_App)));
55
g_app_info_launch (G_APP_INFO (appInfo), NULL, NULL, NULL);
56
g_object_unref (appInfo);
118
WindowManager::Default()->TerminateScale();
121
SetQuirk(QUIRK_STARTING, true);
122
OpenInstanceLauncherIcon(ActionArg ());
124
else // app is running
128
if (scaleWasActive) // #5 above
130
WindowManager::Default()->TerminateScale();
135
if (arg.source != ActionArg::SWITCHER)
141
if (scaleWasActive) // #4 above
143
WindowManager::Default()->TerminateScale();
145
if (arg.source != ActionArg::SWITCHER)
155
if (arg.source != ActionArg::SWITCHER)
156
ubus_server_send_message(ubus_server_get_default(), UBUS_LAUNCHER_ACTION_DONE, NULL);
159
BamfLauncherIcon::BamfLauncherIcon(Launcher* IconManager, BamfApplication* app)
160
: SimpleLauncherIcon(IconManager)
161
, _supported_types_filled(false)
162
, _fill_supported_types_id(0)
164
_cached_desktop_file = NULL;
168
_dnd_hover_timer = 0;
169
_dnd_hovered = false;
170
_launcher = IconManager;
171
_desktop_file_monitor = NULL;
172
_menu_desktop_shortcuts = NULL;
173
_on_desktop_file_changed_handler_id = 0;
174
_window_moved_id = 0;
175
char* icon_name = bamf_view_get_icon(BAMF_VIEW(m_App));
177
tooltip_text = BamfName();
178
SetIconName(icon_name);
179
SetIconType(TYPE_APPLICATION);
181
if (bamf_view_is_sticky(BAMF_VIEW(m_App)))
182
SetQuirk(QUIRK_VISIBLE, true);
184
SetQuirk(QUIRK_VISIBLE, bamf_view_user_visible(BAMF_VIEW(m_App)));
186
SetQuirk(QUIRK_ACTIVE, bamf_view_is_active(BAMF_VIEW(m_App)));
187
SetQuirk(QUIRK_RUNNING, bamf_view_is_running(BAMF_VIEW(m_App)));
191
g_signal_connect(app, "child-removed", (GCallback) &BamfLauncherIcon::OnChildRemoved, this);
192
g_signal_connect(app, "child-added", (GCallback) &BamfLauncherIcon::OnChildAdded, this);
193
g_signal_connect(app, "urgent-changed", (GCallback) &BamfLauncherIcon::OnUrgentChanged, this);
194
g_signal_connect(app, "running-changed", (GCallback) &BamfLauncherIcon::OnRunningChanged, this);
195
g_signal_connect(app, "active-changed", (GCallback) &BamfLauncherIcon::OnActiveChanged, this);
196
g_signal_connect(app, "user-visible-changed", (GCallback) &BamfLauncherIcon::OnUserVisibleChanged, this);
197
g_signal_connect(app, "closed", (GCallback) &BamfLauncherIcon::OnClosed, this);
206
WindowManager::Default()->window_minimized.connect(sigc::mem_fun(this, &BamfLauncherIcon::OnWindowMinimized));
207
WindowManager::Default()->window_moved.connect(sigc::mem_fun(this, &BamfLauncherIcon::OnWindowMoved));
208
WindowManager::Default()->compiz_screen_viewport_switch_ended.connect(sigc::mem_fun(this, &BamfLauncherIcon::OnViewPortSwitchEnded));
209
WindowManager::Default()->terminate_expo.connect(sigc::mem_fun(this, &BamfLauncherIcon::OnViewPortSwitchEnded));
210
IconManager->hidden_changed.connect(sigc::mem_fun(this, &BamfLauncherIcon::OnLauncherHiddenChanged));
215
// Calls when there are no higher priority events pending to the default main loop.
216
_fill_supported_types_id = g_idle_add((GSourceFunc)FillSupportedTypes, this);
220
BamfLauncherIcon::~BamfLauncherIcon()
222
g_object_set_qdata(G_OBJECT(m_App), g_quark_from_static_string("unity-seen"), GINT_TO_POINTER(0));
224
// We might not have created the menu items yet
225
for (auto it = _menu_clients.begin(); it != _menu_clients.end(); it++)
227
g_object_unref(G_OBJECT(it->second));
230
if (_menu_items.find("Pin") != _menu_items.end())
232
g_signal_handler_disconnect(G_OBJECT(_menu_items["Pin"]),
233
_menu_callbacks["Pin"]);
236
if (_menu_items.find("Quit") != _menu_items.end())
238
g_signal_handler_disconnect(G_OBJECT(_menu_items["Quit"]),
239
_menu_callbacks["Quit"]);
242
for (auto it = _menu_items.begin(); it != _menu_items.end(); it++)
244
g_object_unref(G_OBJECT(it->second));
247
for (auto it = _menu_items_extra.begin(); it != _menu_items_extra.end(); it++)
249
g_object_unref(G_OBJECT(it->second));
252
if (G_IS_OBJECT(_menu_desktop_shortcuts))
253
g_object_unref(G_OBJECT(_menu_desktop_shortcuts));
255
if (_on_desktop_file_changed_handler_id != 0)
256
g_signal_handler_disconnect(G_OBJECT(_desktop_file_monitor),
257
_on_desktop_file_changed_handler_id);
259
if (_fill_supported_types_id != 0)
260
g_source_remove(_fill_supported_types_id);
262
if (_window_moved_id != 0)
263
g_source_remove(_window_moved_id);
265
g_signal_handlers_disconnect_by_func(m_App, (void*) &BamfLauncherIcon::OnChildRemoved, this);
266
g_signal_handlers_disconnect_by_func(m_App, (void*) &BamfLauncherIcon::OnChildAdded, this);
267
g_signal_handlers_disconnect_by_func(m_App, (void*) &BamfLauncherIcon::OnUrgentChanged, this);
268
g_signal_handlers_disconnect_by_func(m_App, (void*) &BamfLauncherIcon::OnRunningChanged, this);
269
g_signal_handlers_disconnect_by_func(m_App, (void*) &BamfLauncherIcon::OnActiveChanged, this);
270
g_signal_handlers_disconnect_by_func(m_App, (void*) &BamfLauncherIcon::OnUserVisibleChanged, this);
271
g_signal_handlers_disconnect_by_func(m_App, (void*) &BamfLauncherIcon::OnClosed, this);
273
g_object_unref(m_App);
274
g_object_unref(_desktop_file_monitor);
276
g_free(_cached_desktop_file);
277
g_free(_cached_name);
280
std::vector<Window> BamfLauncherIcon::RelatedXids ()
282
std::vector<Window> results;
285
WindowManager *wm = WindowManager::Default ();
287
children = bamf_view_get_children(BAMF_VIEW(m_App));
288
for (l = children; l; l = l->next)
290
view = static_cast <BamfView*> (l->data);
291
if (BAMF_IS_WINDOW(view))
293
guint32 xid = bamf_window_get_xid(BAMF_WINDOW(view));
295
if (wm->IsWindowMapped(xid))
296
results.push_back ((Window) xid);
300
g_list_free(children);
304
std::string BamfLauncherIcon::NameForWindow (Window window)
310
children = bamf_view_get_children(BAMF_VIEW(m_App));
311
for (l = children; l; l = l->next)
313
view = static_cast <BamfView*> (l->data);
314
if (BAMF_IS_WINDOW(view) && (Window) bamf_window_get_xid(BAMF_WINDOW(view)) == window)
316
gchar *name = bamf_view_get_name (view);
323
g_list_free(children);
327
void BamfLauncherIcon::OnLauncherHiddenChanged()
329
UpdateIconGeometries(GetCenter());
332
void BamfLauncherIcon::OnWindowMinimized(guint32 xid)
334
if (!OwnsWindow(xid))
338
UpdateQuirkTimeDelayed(300, QUIRK_SHIMMER);
341
gboolean BamfLauncherIcon::OnWindowMovedTimeout(gpointer data)
343
BamfLauncherIcon *self = static_cast <BamfLauncherIcon *> (data);
344
GList *children = bamf_view_get_children(BAMF_VIEW(self->m_App));
346
bool any_on_current = false;
347
bool found_moved = (self->_window_moved_xid != 0 ? false : true);
349
for (GList *l = children; l; l = l->next)
351
BamfView *view = BAMF_VIEW(l->data);
353
if (BAMF_IS_WINDOW(view))
355
Window xid = bamf_window_get_xid(BAMF_WINDOW(view));
357
if (self->_window_moved_xid == xid)
360
if (WindowManager::Default()->IsWindowOnCurrentDesktop(xid))
361
any_on_current = true;
363
if (found_moved && any_on_current)
368
self->SetHasWindowOnViewport(any_on_current);
369
self->_window_moved_id = 0;
370
g_list_free(children);
375
void BamfLauncherIcon::OnWindowMoved(guint32 moved_win)
377
if (_window_moved_id != 0)
378
g_source_remove(_window_moved_id);
380
_window_moved_xid = moved_win;
382
if (_window_moved_xid == 0)
384
OnWindowMovedTimeout(this);
388
_window_moved_id = g_timeout_add(250,
389
(GSourceFunc)BamfLauncherIcon::OnWindowMovedTimeout, this);
393
void BamfLauncherIcon::OnViewPortSwitchEnded()
398
bool BamfLauncherIcon::IsSticky()
400
return bamf_view_is_sticky(BAMF_VIEW(m_App));
403
void BamfLauncherIcon::UpdateDesktopFile()
405
char* filename = NULL;
406
filename = (char*) bamf_application_get_desktop_file(m_App);
408
if (filename != NULL && g_strcmp0(_cached_desktop_file, filename) != 0)
410
if (_cached_desktop_file != NULL)
411
g_free(_cached_desktop_file);
413
_cached_desktop_file = g_strdup(filename);
415
// add a file watch to the desktop file so that if/when the app is removed
416
// we can remove ourself from the launcher and when it's changed
417
// we can update the quicklist.
418
if (_desktop_file_monitor)
420
if (_on_desktop_file_changed_handler_id != 0)
421
g_signal_handler_disconnect(G_OBJECT(_desktop_file_monitor),
422
_on_desktop_file_changed_handler_id);
423
g_object_unref(_desktop_file_monitor);
426
GFile* desktop_file = g_file_new_for_path(DesktopFile());
427
_desktop_file_monitor = g_file_monitor_file(desktop_file, G_FILE_MONITOR_NONE,
429
g_file_monitor_set_rate_limit (_desktop_file_monitor, 1000);
430
_on_desktop_file_changed_handler_id = g_signal_connect(_desktop_file_monitor,
432
G_CALLBACK(&BamfLauncherIcon::OnDesktopFileChanged),
437
const char* BamfLauncherIcon::DesktopFile()
440
return _cached_desktop_file;
443
const char* BamfLauncherIcon::BamfName()
445
gchar* name = bamf_view_get_name(BAMF_VIEW(m_App));
450
if (_cached_name != NULL)
451
g_free(_cached_name);
458
void BamfLauncherIcon::AddProperties(GVariantBuilder* builder)
460
LauncherIcon::AddProperties(builder);
462
g_variant_builder_add(builder, "{sv}", "desktop-file", g_variant_new_string(DesktopFile()));
467
children = bamf_view_get_children(BAMF_VIEW(m_App));
468
GVariant* xids[(int) g_list_length(children)];
471
for (l = children; l; l = l->next)
473
view = static_cast <BamfView*> (l->data);
475
if (BAMF_IS_WINDOW(view))
477
xids[i++] = g_variant_new_uint32(bamf_window_get_xid(BAMF_WINDOW(view)));
480
g_list_free(children);
481
g_variant_builder_add(builder, "{sv}", "xids", g_variant_new_array(G_VARIANT_TYPE_UINT32, xids, i));
484
bool BamfLauncherIcon::OwnsWindow(Window w)
492
children = bamf_view_get_children(BAMF_VIEW(m_App));
494
for (l = children; l; l = l->next)
496
view = static_cast <BamfView*> (l->data);
498
if (BAMF_IS_WINDOW(view))
500
guint32 xid = bamf_window_get_xid(BAMF_WINDOW(view));
510
g_list_free(children);
514
void BamfLauncherIcon::OpenInstanceWithUris(std::set<std::string> uris)
516
GDesktopAppInfo* appInfo;
517
GError* error = NULL;
519
appInfo = g_desktop_app_info_new_from_filename(DesktopFile());
521
if (g_app_info_supports_uris(G_APP_INFO(appInfo)))
526
list = g_list_prepend(list, g_strdup(it.c_str()));
528
g_app_info_launch_uris(G_APP_INFO(appInfo), list, NULL, &error);
529
g_list_free_full(list, g_free);
531
else if (g_app_info_supports_files(G_APP_INFO(appInfo)))
533
GList* list = NULL, *l;
537
GFile* file = g_file_new_for_uri(it.c_str());
538
list = g_list_prepend(list, file);
540
g_app_info_launch(G_APP_INFO(appInfo), list, NULL, &error);
542
for (l = list; l; l = l->next)
543
g_object_unref(G_FILE(list->data));
549
g_app_info_launch(G_APP_INFO(appInfo), NULL, NULL, &error);
552
g_object_unref(appInfo);
556
g_warning("%s\n", error->message);
560
UpdateQuirkTime(QUIRK_STARTING);
563
void BamfLauncherIcon::OpenInstanceLauncherIcon(ActionArg arg)
565
std::set<std::string> empty;
566
OpenInstanceWithUris(empty);
567
ubus_server_send_message(ubus_server_get_default(), UBUS_LAUNCHER_ACTION_DONE, NULL);
570
void BamfLauncherIcon::Focus(ActionArg arg)
574
bool any_urgent = false;
575
bool any_visible = false;
577
children = bamf_view_get_children(BAMF_VIEW(m_App));
579
std::vector<Window> windows;
581
/* get the list of windows */
582
for (l = children; l; l = l->next)
584
view = static_cast <BamfView*> (l->data);
586
if (BAMF_IS_WINDOW(view))
588
Window xid = bamf_window_get_xid(BAMF_WINDOW(view));
589
bool urgent = bamf_view_is_urgent(view);
591
if (WindowManager::Default ()->IsWindowOnCurrentDesktop (xid) &&
592
WindowManager::Default ()->IsWindowVisible (xid))
598
windows.push_back(xid);
609
windows.push_back(xid);
613
g_list_free(children);
614
if (arg.source != ActionArg::SWITCHER)
618
WindowManager::Default()->FocusWindowGroup(windows,
619
WindowManager::FocusVisibility::ForceUnminimizeInvisible);
623
WindowManager::Default()->FocusWindowGroup(windows,
624
WindowManager::FocusVisibility::ForceUnminimizeOnCurrentDesktop);
628
WindowManager::Default()->FocusWindowGroup(windows,
629
WindowManager::FocusVisibility::OnlyVisible);
632
bool BamfLauncherIcon::Spread(int state, bool force)
636
children = bamf_view_get_children(BAMF_VIEW(m_App));
638
std::vector<Window> windowList;
639
for (l = children; l; l = l->next)
641
view = static_cast <BamfView*> (l->data);
643
if (BAMF_IS_WINDOW(view))
645
guint32 xid = bamf_window_get_xid(BAMF_WINDOW(view));
646
windowList.push_back((Window) xid);
650
g_list_free(children);
651
return WindowManager::Default()->ScaleWindowGroup(windowList, state, force);
654
void BamfLauncherIcon::OnClosed(BamfView* view, gpointer data)
656
BamfLauncherIcon* self = static_cast <BamfLauncherIcon*> (data);
658
if (!bamf_view_is_sticky(BAMF_VIEW(self->m_App)))
662
void BamfLauncherIcon::OnUserVisibleChanged(BamfView* view, gboolean visible,
665
BamfLauncherIcon* self = static_cast <BamfLauncherIcon*> (data);
667
if (!bamf_view_is_sticky(BAMF_VIEW(self->m_App)))
668
self->SetQuirk(QUIRK_VISIBLE, visible);
671
void BamfLauncherIcon::OnRunningChanged(BamfView* view, gboolean running,
674
BamfLauncherIcon* self = static_cast <BamfLauncherIcon*> (data);
675
self->SetQuirk(QUIRK_RUNNING, running);
679
self->EnsureWindowState();
680
self->UpdateIconGeometries(self->GetCenter());
684
void BamfLauncherIcon::OnActiveChanged(BamfView* view, gboolean active, gpointer data)
686
BamfLauncherIcon* self = static_cast <BamfLauncherIcon*> (data);
687
self->SetQuirk(QUIRK_ACTIVE, active);
690
void BamfLauncherIcon::OnUrgentChanged(BamfView* view, gboolean urgent, gpointer data)
692
BamfLauncherIcon* self = static_cast <BamfLauncherIcon*> (data);
693
self->SetQuirk(QUIRK_URGENT, urgent);
696
void BamfLauncherIcon::EnsureWindowState()
700
bool has_visible = false;
702
children = bamf_view_get_children(BAMF_VIEW(m_App));
703
for (l = children; l; l = l->next)
705
if (!BAMF_IS_WINDOW(l->data))
710
Window xid = bamf_window_get_xid(BAMF_WINDOW(l->data));
711
if (WindowManager::Default()->IsWindowOnCurrentDesktop(xid))
718
SetRelatedWindows(count);
719
SetHasWindowOnViewport(has_visible);
721
g_list_free(children);
724
void BamfLauncherIcon::OnChildAdded(BamfView* view, BamfView* child, gpointer data)
726
BamfLauncherIcon* self = static_cast <BamfLauncherIcon*> (data);
727
self->EnsureWindowState();
729
self->UpdateIconGeometries(self->GetCenter());
732
void BamfLauncherIcon::OnChildRemoved(BamfView* view, BamfView* child, gpointer data)
734
BamfLauncherIcon* self = static_cast <BamfLauncherIcon*> (data);
735
self->EnsureWindowState();
738
void BamfLauncherIcon::UpdateDesktopQuickList()
740
IndicatorDesktopShortcuts* desktop_shortcuts;
742
GError* error = NULL;
743
const char *desktop_file;
745
desktop_file = DesktopFile();
747
if (!desktop_file || g_strcmp0(desktop_file, "") == 0)
750
// check that we have the X-Ayatana-Desktop-Shortcuts flag
751
// not sure if we should do this or if libindicator should shut up
752
// and not report errors when it can't find the key.
753
// so FIXME when ted is around
754
keyfile = g_key_file_new();
755
g_key_file_load_from_file(keyfile, desktop_file, G_KEY_FILE_NONE, &error);
759
g_warning("Could not load desktop file for: %s", desktop_file);
760
g_key_file_free(keyfile);
765
if (g_key_file_has_key(keyfile, G_KEY_FILE_DESKTOP_GROUP,
766
"X-Ayatana-Desktop-Shortcuts", NULL))
768
DbusmenuMenuitem* root = dbusmenu_menuitem_new();
769
dbusmenu_menuitem_set_root(root, TRUE);
770
desktop_shortcuts = indicator_desktop_shortcuts_new(desktop_file, "Unity");
771
const gchar** nicks = indicator_desktop_shortcuts_get_nicks(desktop_shortcuts);
776
while (((gpointer*) nicks)[index])
779
DbusmenuMenuitem* item;
780
name = indicator_desktop_shortcuts_nick_get_name(desktop_shortcuts,
782
ShortcutData* data = g_slice_new0(ShortcutData);
784
data->shortcuts = INDICATOR_DESKTOP_SHORTCUTS(g_object_ref(desktop_shortcuts));
785
data->nick = g_strdup(nicks[index]);
787
item = dbusmenu_menuitem_new();
788
dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_LABEL, name);
789
dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
790
dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
791
g_signal_connect_data(item, "item-activated",
792
(GCallback) shortcut_activated, (gpointer) data,
793
(GClosureNotify) shortcut_data_destroy, (GConnectFlags)0);
795
dbusmenu_menuitem_child_append(root, item);
803
if (G_IS_OBJECT(_menu_desktop_shortcuts))
804
g_object_unref(G_OBJECT(_menu_desktop_shortcuts));
806
_menu_desktop_shortcuts = root;
809
g_key_file_free(keyfile);
812
void BamfLauncherIcon::UpdateMenus()
816
children = bamf_view_get_children(BAMF_VIEW(m_App));
817
for (l = children; l; l = l->next)
819
if (!BAMF_IS_INDICATOR(l->data))
822
BamfIndicator* indicator = BAMF_INDICATOR(l->data);
823
std::string path = bamf_indicator_get_dbus_menu_path(indicator);
825
// we already have this
826
if (_menu_clients.find(path) != _menu_clients.end())
829
DbusmenuClient* client = dbusmenu_client_new(bamf_indicator_get_remote_address(indicator), path.c_str());
830
_menu_clients[path] = client;
833
g_list_free(children);
835
// add dynamic quicklist
836
if (_menuclient_dynamic_quicklist != NULL)
838
auto menu_client = DBUSMENU_CLIENT(g_object_ref(_menuclient_dynamic_quicklist));
839
_menu_clients["dynamicquicklist"] = menu_client;
842
// make a client for desktop file actions
843
if (!DBUSMENU_IS_MENUITEM(_menu_desktop_shortcuts))
845
UpdateDesktopQuickList();
850
void BamfLauncherIcon::OnQuit(DbusmenuMenuitem* item, int time, BamfLauncherIcon* self)
855
children = bamf_view_get_children(BAMF_VIEW(self->m_App));
857
for (l = children; l; l = l->next)
859
view = static_cast <BamfView*> (l->data);
861
if (BAMF_IS_WINDOW(view))
863
guint32 xid = bamf_window_get_xid(BAMF_WINDOW(view));
864
WindowManager::Default()->Close(xid);
868
g_list_free(children);
871
void BamfLauncherIcon::Stick()
873
BamfView* view = BAMF_VIEW(m_App);
875
if (bamf_view_is_sticky(view))
878
const gchar* desktop_file = DesktopFile();
879
bamf_view_set_sticky(view, true);
881
if (desktop_file && strlen(desktop_file) > 0)
882
FavoriteStore::GetDefault().AddFavorite(desktop_file, -1);
885
void BamfLauncherIcon::UnStick(void)
887
BamfView* view = BAMF_VIEW(this->m_App);
889
if (!bamf_view_is_sticky(view))
892
const gchar* desktop_file = DesktopFile();
893
bamf_view_set_sticky(view, false);
894
if (bamf_view_is_closed(view))
897
if (desktop_file && strlen(desktop_file) > 0)
898
FavoriteStore::GetDefault().RemoveFavorite(desktop_file);
901
void BamfLauncherIcon::OnTogglePin(DbusmenuMenuitem* item, int time, BamfLauncherIcon* self)
903
BamfView* view = BAMF_VIEW(self->m_App);
904
bool sticky = bamf_view_is_sticky(view);
905
const gchar* desktop_file = self->DesktopFile();
913
bamf_view_set_sticky(view, true);
915
if (desktop_file && strlen(desktop_file) > 0)
916
FavoriteStore::GetDefault().AddFavorite(desktop_file, -1);
920
void BamfLauncherIcon::EnsureMenuItemsReady()
922
DbusmenuMenuitem* menu_item;
925
if (_menu_items.find("Pin") == _menu_items.end())
927
menu_item = dbusmenu_menuitem_new();
929
dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE, DBUSMENU_MENUITEM_TOGGLE_CHECK);
930
dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Keep in launcher"));
931
dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
932
dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
934
_menu_callbacks["Pin"] = g_signal_connect(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, (GCallback) &BamfLauncherIcon::OnTogglePin, this);
936
_menu_items["Pin"] = menu_item;
938
int checked = !bamf_view_is_sticky(BAMF_VIEW(m_App)) ?
939
DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED : DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED;
941
dbusmenu_menuitem_property_set_int(_menu_items["Pin"],
942
DBUSMENU_MENUITEM_PROP_TOGGLE_STATE,
947
if (_menu_items.find("Quit") == _menu_items.end())
949
menu_item = dbusmenu_menuitem_new();
951
dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Quit"));
952
dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
953
dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
955
_menu_callbacks["Quit"] = g_signal_connect(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, (GCallback) &BamfLauncherIcon::OnQuit, this);
957
_menu_items["Quit"] = menu_item;
961
static void OnAppLabelActivated(DbusmenuMenuitem* sender,
965
BamfLauncherIcon* self = NULL;
970
self = static_cast <BamfLauncherIcon*> (data);
971
self->ActivateLauncherIcon(ActionArg(ActionArg::OTHER, 0));
974
std::list<DbusmenuMenuitem*> BamfLauncherIcon::GetMenus()
976
std::map<std::string, DbusmenuClient*>::iterator it;
977
std::list<DbusmenuMenuitem*> result;
978
bool first_separator_needed = false;
979
DbusmenuMenuitem* item = NULL;
981
// FIXME for O: hack around the wrong abstraction
984
for (it = _menu_clients.begin(); it != _menu_clients.end(); it++)
987
DbusmenuClient* client = (*it).second;
988
DbusmenuMenuitem* root = dbusmenu_client_get_root(client);
990
if (!root || !dbusmenu_menuitem_property_get_bool(root, DBUSMENU_MENUITEM_PROP_VISIBLE))
993
for (child = dbusmenu_menuitem_get_children(root); child != NULL; child = g_list_next(child))
995
DbusmenuMenuitem* item = (DbusmenuMenuitem*) child->data;
997
if (!item || !DBUSMENU_IS_MENUITEM(item))
1000
if (dbusmenu_menuitem_property_get_bool(item, DBUSMENU_MENUITEM_PROP_VISIBLE))
1002
first_separator_needed = true;
1004
result.push_back(item);
1009
// FIXME: this should totally be added as a _menu_client
1010
if (DBUSMENU_IS_MENUITEM(_menu_desktop_shortcuts))
1012
GList* child = NULL;
1013
DbusmenuMenuitem* root = _menu_desktop_shortcuts;
1015
for (child = dbusmenu_menuitem_get_children(root); child != NULL; child = g_list_next(child))
1017
DbusmenuMenuitem* item = (DbusmenuMenuitem*) child->data;
1022
first_separator_needed = true;
1024
result.push_back(item);
1028
if (first_separator_needed)
1030
auto first_sep = _menu_items_extra.find("FirstSeparator");
1031
if (first_sep != _menu_items_extra.end())
1033
item = first_sep->second;
1037
item = dbusmenu_menuitem_new();
1038
dbusmenu_menuitem_property_set(item,
1039
DBUSMENU_MENUITEM_PROP_TYPE,
1040
DBUSMENU_CLIENT_TYPES_SEPARATOR);
1041
_menu_items_extra["FirstSeparator"] = item;
1043
result.push_back(item);
1046
auto app_name_item = _menu_items_extra.find("AppName");
1047
if (app_name_item != _menu_items_extra.end())
1049
item = app_name_item->second;
1054
app_name = g_markup_escape_text(BamfName(), -1);
1056
item = dbusmenu_menuitem_new();
1057
dbusmenu_menuitem_property_set(item,
1058
DBUSMENU_MENUITEM_PROP_LABEL,
1060
dbusmenu_menuitem_property_set_bool(item,
1061
DBUSMENU_MENUITEM_PROP_ENABLED,
1063
g_signal_connect(item, "item-activated", (GCallback) OnAppLabelActivated, this);
1066
_menu_items_extra["AppName"] = item;
1068
result.push_back(item);
1070
auto second_sep = _menu_items_extra.find("SecondSeparator");
1071
if (second_sep != _menu_items_extra.end())
1073
item = second_sep->second;
1077
item = dbusmenu_menuitem_new();
1078
dbusmenu_menuitem_property_set(item,
1079
DBUSMENU_MENUITEM_PROP_TYPE,
1080
DBUSMENU_CLIENT_TYPES_SEPARATOR);
1081
_menu_items_extra["SecondSeparator"] = item;
1083
result.push_back(item);
1085
EnsureMenuItemsReady();
1087
std::map<std::string, DbusmenuMenuitem*>::iterator it_m;
1088
std::list<DbusmenuMenuitem*>::iterator it_l;
1090
for (it_m = _menu_items.begin(); it_m != _menu_items.end(); it_m++)
1092
const char* key = ((*it_m).first).c_str();
1093
if (g_strcmp0(key , "Quit") == 0 && !bamf_view_is_running(BAMF_VIEW(m_App)))
1097
std::string label_default = dbusmenu_menuitem_property_get((*it_m).second, DBUSMENU_MENUITEM_PROP_LABEL);
1098
for (it_l = result.begin(); it_l != result.end(); it_l++)
1100
const gchar* type = dbusmenu_menuitem_property_get(*it_l, DBUSMENU_MENUITEM_PROP_TYPE);
1101
if (type == NULL)//(g_strcmp0 (type, DBUSMENU_MENUITEM_PROP_LABEL) == 0)
1103
std::string label_menu = dbusmenu_menuitem_property_get(*it_l, DBUSMENU_MENUITEM_PROP_LABEL);
1104
if (label_menu.compare(label_default) == 0)
1113
result.push_back((*it_m).second);
1120
void BamfLauncherIcon::UpdateIconGeometries(nux::Point3 center)
1122
GList* children, *l;
1126
if (_launcher->Hidden() && !_launcher->ShowOnEdge())
1133
geo.x = center.x - 24;
1134
geo.y = center.y - 24;
1139
children = bamf_view_get_children(BAMF_VIEW(m_App));
1141
for (l = children; l; l = l->next)
1143
view = static_cast <BamfView*> (l->data);
1145
if (BAMF_IS_WINDOW(view))
1147
guint32 xid = bamf_window_get_xid(BAMF_WINDOW(view));
1148
WindowManager::Default()->SetWindowIconGeometry((Window)xid, geo);
1152
g_list_free(children);
1155
void BamfLauncherIcon::OnCenterStabilized(nux::Point3 center)
1157
UpdateIconGeometries(center);
1160
const gchar* BamfLauncherIcon::GetRemoteUri()
1164
const gchar* desktop_file = DesktopFile();
1165
gchar* basename = g_path_get_basename(desktop_file);
1167
_remote_uri = g_strdup_printf("application://%s", basename);
1175
std::set<std::string> BamfLauncherIcon::ValidateUrisForLaunch(unity::DndData& uris)
1177
std::set<std::string> result;
1178
gboolean is_home_launcher = g_str_has_suffix(DesktopFile(), "nautilus-home.desktop");
1180
if (is_home_launcher)
1182
for (auto k : uris.Uris())
1187
for (auto i : uris.Types())
1188
for (auto j : GetSupportedTypes())
1189
if (g_content_type_is_a(i.c_str(), j.c_str()))
1191
for (auto k : uris.UrisByType(i))
1200
gboolean BamfLauncherIcon::OnDndHoveredTimeout(gpointer data)
1202
BamfLauncherIcon* self = static_cast <BamfLauncherIcon*> (data);
1204
// for now, let's not do this, it turns out to be quite buggy
1205
//if (self->_dnd_hovered && bamf_view_is_running(BAMF_VIEW(self->m_App)))
1206
// self->Spread(CompAction::StateInitEdgeDnd, true);
1208
self->_dnd_hover_timer = 0;
1212
void BamfLauncherIcon::OnDndEnter()
1214
_dnd_hovered = true;
1215
_dnd_hover_timer = g_timeout_add(1000, &BamfLauncherIcon::OnDndHoveredTimeout, this);
1218
void BamfLauncherIcon::OnDndLeave()
1220
_dnd_hovered = false;
1222
if (_dnd_hover_timer)
1223
g_source_remove(_dnd_hover_timer);
1224
_dnd_hover_timer = 0;
1227
nux::DndAction BamfLauncherIcon::OnQueryAcceptDrop(unity::DndData& dnd_data)
1229
return ValidateUrisForLaunch(dnd_data).empty() ? nux::DNDACTION_NONE : nux::DNDACTION_COPY;
1232
void BamfLauncherIcon::OnAcceptDrop(unity::DndData& dnd_data)
1234
OpenInstanceWithUris(ValidateUrisForLaunch(dnd_data));
1237
void BamfLauncherIcon::OnDesktopFileChanged(GFileMonitor* monitor,
1240
GFileMonitorEvent event_type,
1243
BamfLauncherIcon* self = static_cast<BamfLauncherIcon*>(data);
1246
case G_FILE_MONITOR_EVENT_DELETED:
1249
case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
1250
self->UpdateDesktopQuickList();
1258
BamfLauncherIcon::ShowInSwitcher()
1260
return GetQuirk(QUIRK_RUNNING) && GetQuirk(QUIRK_VISIBLE);
1264
BamfLauncherIcon::SwitcherPriority()
1266
GList* children, *l;
1268
unsigned long long result = 0;
1270
children = bamf_view_get_children(BAMF_VIEW(m_App));
1272
/* get the list of windows */
1273
for (l = children; l; l = l->next)
1275
view = static_cast <BamfView*> (l->data);
1277
if (BAMF_IS_WINDOW(view))
1279
guint32 xid = bamf_window_get_xid(BAMF_WINDOW(view));
1280
result = std::max(result, WindowManager::Default()->GetWindowActiveNumber (xid));
1284
g_list_free(children);
1288
const std::set<std::string>&
1289
BamfLauncherIcon::GetSupportedTypes()
1291
if (!_supported_types_filled)
1292
FillSupportedTypes(this);
1294
return _supported_types;
1298
BamfLauncherIcon::FillSupportedTypes(gpointer data)
1300
BamfLauncherIcon* self = static_cast <BamfLauncherIcon*> (data);
1302
if (self->_fill_supported_types_id)
1304
g_source_remove(self->_fill_supported_types_id);
1305
self->_fill_supported_types_id = 0;
1308
if (!self->_supported_types_filled)
1310
self->_supported_types_filled = true;
1312
self->_supported_types.clear();
1314
const char* desktop_file = self->DesktopFile();
1316
if (!desktop_file || strlen(desktop_file) <= 1)
1319
GKeyFile* key_file = g_key_file_new();
1320
unity::glib::Error error;
1322
g_key_file_load_from_file(key_file, desktop_file, (GKeyFileFlags) 0, &error);
1326
g_key_file_free(key_file);
1330
char** mimes = g_key_file_get_string_list(key_file, "Desktop Entry", "MimeType", NULL, NULL);
1333
g_key_file_free(key_file);
1337
for (int i=0; mimes[i]; i++)
1339
unity::glib::String super_type(g_content_type_from_mime_type(mimes[i]));
1340
self->_supported_types.insert(super_type.Str());
1343
g_key_file_free(key_file);
62
std::list<Window> windowList;
63
for (l = children; l; l = l->next)
65
view = (BamfView *) l->data;
67
if (BAMF_IS_WINDOW (view))
69
guint32 xid = bamf_window_get_xid (BAMF_WINDOW (view));
71
windowList.push_back ((Window) xid);
75
if (windowList.size () > 1)
77
std::string *match = PluginAdapter::Default ()->MatchStringForXids (&windowList);
78
PluginAdapter::Default ()->InitiateScale (match);
84
for (l = children; l; l = l->next)
86
view = (BamfView *) l->data;
88
if (BAMF_IS_WINDOW (view))
90
guint32 xid = bamf_window_get_xid (BAMF_WINDOW (view));
92
CompWindow *window = m_Screen->findWindow ((Window) xid);
102
BamfLauncherIcon::OnClosed (BamfView *view, gpointer data)
104
BamfLauncherIcon *self = (BamfLauncherIcon *) data;
106
if (!bamf_view_is_sticky (BAMF_VIEW (self->m_App)))
111
BamfLauncherIcon::OnUserVisibleChanged (BamfView *view, gboolean visible, gpointer data)
113
BamfLauncherIcon *self = (BamfLauncherIcon *) data;
115
if (!bamf_view_is_sticky (BAMF_VIEW (self->m_App)))
116
self->SetVisible (visible);
120
BamfLauncherIcon::OnRunningChanged (BamfView *view, gboolean running, gpointer data)
122
BamfLauncherIcon *self = (BamfLauncherIcon *) data;
123
self->SetRunning (running);
127
BamfLauncherIcon::OnActiveChanged (BamfView *view, gboolean active, gpointer data)
129
BamfLauncherIcon *self = (BamfLauncherIcon *) data;
130
self->SetActive (active);