// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
/*
* Copyright (C) 2010-2015 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Authored by: Jason Smith
* Marco Trevisan (TreviƱo) <3v1n0@ubuntu.com>
*/
#include "config.h"
#include
#include
#include
#include
#include "ApplicationLauncherIcon.h"
#include "FavoriteStore.h"
#include "unity-shared/DesktopApplicationManager.h"
#include
#include
namespace unity
{
namespace launcher
{
namespace
{
DECLARE_LOGGER(logger, "unity.launcher.icon.application");
// We use the "application-" prefix since the manager is protected, to avoid name clash
const std::string DEFAULT_ICON = "application-default-icon";
enum MenuItemType
{
STICK = 0,
QUIT,
APP_NAME,
SEPARATOR,
SIZE
};
}
NUX_IMPLEMENT_OBJECT_TYPE(ApplicationLauncherIcon);
ApplicationLauncherIcon::ApplicationLauncherIcon(ApplicationPtr const& app)
: WindowedLauncherIcon(IconType::APPLICATION)
, startup_notification_timestamp_(0)
, use_custom_bg_color_(false)
, bg_color_(nux::color::White)
{
LOG_INFO(logger) << "Created ApplicationLauncherIcon: "
<< tooltip_text()
<< ", icon: " << icon_name()
<< ", sticky: " << (app->sticky() ? "yes" : "no")
<< ", visible: " << (app->visible() ? "yes" : "no")
<< ", active: " << (app->active() ? "yes" : "no")
<< ", running: " << (app->running() ? "yes" : "no");
SetApplication(app);
EnsureWindowsLocation();
}
ApplicationLauncherIcon::~ApplicationLauncherIcon()
{
UnsetApplication();
}
ApplicationPtr ApplicationLauncherIcon::GetApplication() const
{
return app_;
}
void ApplicationLauncherIcon::SetApplication(ApplicationPtr const& app)
{
if (app_ == app)
return;
if (!app)
{
Remove();
return;
}
bool was_sticky = IsSticky();
UnsetApplication();
app_ = app;
app_->seen = true;
SetupApplicationSignalsConnections();
// Let's update the icon properties to match the new application ones
app_->title.changed.emit(app_->title());
app_->icon.changed.emit(app_->icon());
app_->visible.changed.emit(app_->visible());
app_->active.changed.emit(app_->active());
app_->running.changed.emit(app_->running());
app_->urgent.changed.emit(app_->urgent());
app_->starting.changed.emit(app_->starting() || GetQuirk(Quirk::STARTING));
app_->desktop_file.changed.emit(app_->desktop_file());
// Make sure we set the LauncherIcon stick bit too...
if (app_->sticky() || was_sticky)
Stick(false); // don't emit the signal
}
void ApplicationLauncherIcon::UnsetApplication()
{
if (!app_ || removed())
return;
/* Removing the unity-seen flag to the wrapped bamf application, on remove
* request we make sure that if the application is re-opened while the
* removal process is still ongoing, the application will be shown on the
* launcher. Disconnecting from signals we make sure that this icon won't be
* updated or will change visibility (no duplicated icon). */
signals_conn_.Clear();
app_->sticky = false;
app_->seen = false;
}
void ApplicationLauncherIcon::SetupApplicationSignalsConnections()
{
// Lambda functions should be fine here because when the application the icon
// is only ever removed when the application is closed.
signals_conn_.Add(app_->window_opened.connect([this](ApplicationWindowPtr const& win) {
signals_conn_.Add(win->monitor.changed.connect([this] (int) { EnsureWindowsLocation(); }));
EnsureWindowsLocation();
}));
signals_conn_.Add(app_->window_closed.connect([this] (ApplicationWindowPtr const&) { EnsureWindowsLocation(); }));
for (auto& win : app_->GetWindows())
signals_conn_.Add(win->monitor.changed.connect([this] (int) { EnsureWindowsLocation(); }));
signals_conn_.Add(app_->urgent.changed.connect([this](bool urgent) {
LOG_DEBUG(logger) << tooltip_text() << " urgent now " << (urgent ? "true" : "false");
SetQuirk(Quirk::URGENT, urgent);
}));
signals_conn_.Add(app_->starting.changed.connect([this](bool starting) {
LOG_DEBUG(logger) << tooltip_text() << " starting now " << (starting ? "true" : "false");
SetQuirk(Quirk::STARTING, starting);
}));
signals_conn_.Add(app_->active.changed.connect([this](bool active) {
LOG_DEBUG(logger) << tooltip_text() << " active now " << (active ? "true" : "false");
SetQuirk(Quirk::ACTIVE, active);
}));
signals_conn_.Add(app_->desktop_file.changed.connect([this](std::string const& desktop_file) {
LOG_DEBUG(logger) << tooltip_text() << " desktop_file now " << desktop_file;
UpdateDesktopFile();
}));
signals_conn_.Add(app_->title.changed.connect([this](std::string const& name) {
LOG_DEBUG(logger) << tooltip_text() << " name now " << name;
if (menu_items_.size() == MenuItemType::SIZE)
menu_items_[MenuItemType::APP_NAME] = nullptr;
tooltip_text = name;
}));
signals_conn_.Add(app_->icon.changed.connect([this](std::string const& icon) {
LOG_DEBUG(logger) << tooltip_text() << " icon now " << icon;
icon_name = (icon.empty() ? DEFAULT_ICON : icon);
}));
signals_conn_.Add(app_->running.changed.connect([this](bool running) {
LOG_DEBUG(logger) << tooltip_text() << " running now " << (running ? "true" : "false");
SetQuirk(Quirk::RUNNING, running);
if (running)
{
_source_manager.Remove(ICON_REMOVE_TIMEOUT);
EnsureWindowState();
UpdateIconGeometries(GetCenters());
}
}));
signals_conn_.Add(app_->visible.changed.connect([this](bool visible) {
SetQuirk(Quirk::VISIBLE, IsSticky() ? true : visible);
}));
signals_conn_.Add(app_->closed.connect([this] {
LOG_DEBUG(logger) << tooltip_text() << " closed";
OnApplicationClosed();
}));
}
WindowList ApplicationLauncherIcon::GetManagedWindows() const
{
return app_ ? app_->GetWindows() : WindowList();
}
void ApplicationLauncherIcon::OnApplicationClosed()
{
if (IsSticky())
return;
SetQuirk(Quirk::VISIBLE, false);
HideTooltip();
/* Use a timeout to remove the icon, this avoids
* that we remove an application that is going
* to be reopened soon. So applications that
* have a splash screen won't be removed from
* the launcher while the splash is closed and
* a new window is opened. */
_source_manager.AddTimeoutSeconds(1, [this] {
Remove();
return false;
}, ICON_REMOVE_TIMEOUT);
}
// Move to WindowedLauncherIcon?!
bool ApplicationLauncherIcon::GetQuirk(AbstractLauncherIcon::Quirk quirk, int monitor) const
{
if (quirk == Quirk::ACTIVE)
{
if (!WindowedLauncherIcon::GetQuirk(Quirk::ACTIVE, monitor))
return false;
if (app_->type() == AppType::WEBAPP)
return true;
// Sometimes BAMF is not fast enough to update the active application
// while quickly switching between apps, so we double check that the
// real active window is part of the selection (see bug #1111620)
return app_->OwnsWindow(WindowManager::Default().GetActiveWindow());
}
return WindowedLauncherIcon::GetQuirk(quirk, monitor);
}
void ApplicationLauncherIcon::Remove()
{
LogUnityEvent(ApplicationEventType::LEAVE);
UnsetApplication();
WindowedLauncherIcon::Remove();
}
bool ApplicationLauncherIcon::IsSticky() const
{
if (app_)
return app_->sticky() && WindowedLauncherIcon::IsSticky();
return false;
}
bool ApplicationLauncherIcon::IsUserVisible() const
{
return app_ ? app_->visible() : false;
}
void ApplicationLauncherIcon::UpdateDesktopFile()
{
std::string const& filename = app_->desktop_file();
if (desktop_file_monitor_)
glib_signals_.Disconnect(desktop_file_monitor_, "changed");
auto old_uri = RemoteUri();
UpdateRemoteUri();
UpdateDesktopQuickList();
UpdateBackgroundColor();
auto const& new_uri = RemoteUri();
if (!filename.empty())
{
// add a file watch to the desktop file so that if/when the app is removed
// we can remove ourself from the launcher and when it's changed
// we can update the quicklist.
glib::Object desktop_file(g_file_new_for_path(filename.c_str()));
desktop_file_monitor_ = g_file_monitor_file(desktop_file, G_FILE_MONITOR_NONE,
nullptr, nullptr);
g_file_monitor_set_rate_limit(desktop_file_monitor_, 2000);
glib_signals_.Add(desktop_file_monitor_, "changed",
[this, desktop_file] (GFileMonitor*, GFile*, GFile*, GFileMonitorEvent event_type) {
switch (event_type)
{
case G_FILE_MONITOR_EVENT_DELETED:
{
_source_manager.AddTimeoutSeconds(1, [this, desktop_file] {
if (!g_file_query_exists(desktop_file, nullptr))
{
UnStick();
LogUnityEvent(ApplicationEventType::DELETE);
}
return false;
});
break;
}
case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
{
UpdateDesktopQuickList();
UpdateBackgroundColor();
break;
}
default:
break;
}
});
}
else if (app_->sticky())
{
UnStick();
}
if (old_uri != new_uri)
{
bool update_saved_uri = (!filename.empty() && app_->sticky());
if (update_saved_uri)
WindowedLauncherIcon::UnStick();
uri_changed.emit(new_uri);
if (update_saved_uri)
Stick();
}
}
std::string ApplicationLauncherIcon::DesktopFile() const
{
return app_->desktop_file();
}
void ApplicationLauncherIcon::OpenInstanceWithUris(std::set const& uris, Time timestamp)
{
glib::Error error;
glib::Object desktopInfo(g_desktop_app_info_new_from_filename(DesktopFile().c_str()));
auto appInfo = glib::object_cast(desktopInfo);
GdkDisplay* display = gdk_display_get_default();
glib::Object app_launch_context(gdk_display_get_app_launch_context(display));
startup_notification_timestamp_ = timestamp;
if (startup_notification_timestamp_ > 0)
gdk_app_launch_context_set_timestamp(app_launch_context, startup_notification_timestamp_);
if (g_app_info_supports_uris(appInfo))
{
GList* list = nullptr;
for (auto it : uris)
list = g_list_prepend(list, g_strdup(it.c_str()));
g_app_info_launch_uris(appInfo, list, glib::object_cast(app_launch_context), &error);
g_list_free_full(list, g_free);
}
else if (g_app_info_supports_files(appInfo))
{
GList* list = nullptr;
for (auto it : uris)
{
GFile* file = g_file_new_for_uri(it.c_str());
list = g_list_prepend(list, file);
}
g_app_info_launch(appInfo, list, glib::object_cast(app_launch_context), &error);
g_list_free_full(list, g_object_unref);
}
else
{
g_app_info_launch(appInfo, nullptr, glib::object_cast(app_launch_context), &error);
}
if (error)
{
LOG_WARN(logger) << error;
}
FullyAnimateQuirk(Quirk::STARTING);
}
void ApplicationLauncherIcon::OpenInstanceLauncherIcon(Time timestamp)
{
std::set empty;
OpenInstanceWithUris(empty, timestamp);
}
void ApplicationLauncherIcon::Focus(ActionArg arg)
{
ApplicationWindowPtr window = app_->GetFocusableWindow();
if (window)
{
// If we have a window, try to focus it.
if (window->Focus())
return;
}
else if (app_->type() == AppType::WEBAPP)
{
// Webapps are again special.
OpenInstanceLauncherIcon(arg.timestamp);
return;
}
bool show_only_visible = arg.source == ActionArg::Source::SWITCHER;
app_->Focus(show_only_visible, arg.monitor);
}
void ApplicationLauncherIcon::UpdateDesktopQuickList()
{
std::string const& desktop_file = DesktopFile();
if (menu_desktop_shortcuts_)
{
for (GList *l = dbusmenu_menuitem_get_children(menu_desktop_shortcuts_); l; l = l->next)
{
glib_signals_.Disconnect(l->data, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED);
}
menu_desktop_shortcuts_ = nullptr;
}
if (desktop_file.empty())
return;
menu_desktop_shortcuts_ = dbusmenu_menuitem_new();
dbusmenu_menuitem_set_root(menu_desktop_shortcuts_, TRUE);
// Build a desktop shortcuts object and tell it that our
// environment is Unity to handle the filtering
desktop_shortcuts_ = indicator_desktop_shortcuts_new(desktop_file.c_str(), "Unity");
// This will get us a list of the nicks available, it should
// always be at least one entry of NULL if there either aren't
// any or they're filtered for the environment we're in
const gchar** nicks = indicator_desktop_shortcuts_get_nicks(desktop_shortcuts_);
for (int index = 0; nicks[index]; ++index)
{
// Build a dbusmenu item for each nick that is the desktop
// file that is built from it's name and includes a callback
// to the desktop shortcuts object to execute the nick
glib::String name(indicator_desktop_shortcuts_nick_get_name(desktop_shortcuts_,
nicks[index]));
glib::Object item(dbusmenu_menuitem_new());
dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_LABEL, name);
dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
auto nick = glib::gchar_to_string(nicks[index]);
glib_signals_.Add(item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
[this, nick] (DbusmenuMenuitem* item, unsigned timestamp) {
GdkDisplay* display = gdk_display_get_default();
glib::Object context(gdk_display_get_app_launch_context(display));
gdk_app_launch_context_set_timestamp(context, timestamp);
auto gcontext = glib::object_cast(context);
indicator_desktop_shortcuts_nick_exec_with_context(desktop_shortcuts_, nick.c_str(), gcontext);
});
dbusmenu_menuitem_child_append(menu_desktop_shortcuts_, item);
}
}
void ApplicationLauncherIcon::UpdateBackgroundColor()
{
bool last_use_custom_bg_color = use_custom_bg_color_;
nux::Color last_bg_color(bg_color_);
std::string const& color = DesktopUtilities::GetBackgroundColor(DesktopFile());
use_custom_bg_color_ = !color.empty();
if (use_custom_bg_color_)
bg_color_ = nux::Color(color);
if (last_use_custom_bg_color != use_custom_bg_color_ ||
last_bg_color != bg_color_)
{
EmitNeedsRedraw();
}
}
void ApplicationLauncherIcon::EnsureMenuItemsStaticQuicklist()
{
// make a client for desktop file actions
if (!menu_desktop_shortcuts_.IsType(DBUSMENU_TYPE_MENUITEM))
{
UpdateDesktopQuickList();
}
}
void ApplicationLauncherIcon::Quit() const
{
app_->Quit();
}
void ApplicationLauncherIcon::AboutToRemove()
{
UnStick();
Quit();
}
void ApplicationLauncherIcon::Stick(bool save)
{
if (IsSticky() && !save)
return;
app_->sticky = true;
if (RemoteUri().empty())
{
if (save)
app_->CreateLocalDesktopFile();
}
else
{
WindowedLauncherIcon::Stick(save);
if (save)
LogUnityEvent(ApplicationEventType::ACCESS);
}
}
void ApplicationLauncherIcon::UnStick()
{
if (!IsSticky())
return;
LogUnityEvent(ApplicationEventType::ACCESS);
WindowedLauncherIcon::UnStick();
SetQuirk(Quirk::VISIBLE, app_->visible());
app_->sticky = false;
if (!IsRunning())
Remove();
}
void ApplicationLauncherIcon::ToggleSticky()
{
if (IsSticky())
{
UnStick();
}
else
{
Stick();
}
}
void ApplicationLauncherIcon::LogUnityEvent(ApplicationEventType type)
{
if (RemoteUri().empty())
return;
auto const& unity_app = ApplicationManager::Default().GetUnityApplication();
unity_app->LogEvent(type, GetSubject());
}
ApplicationSubjectPtr ApplicationLauncherIcon::GetSubject()
{
auto subject = std::make_shared();
subject->uri = RemoteUri();
subject->current_uri = subject->uri();
subject->interpretation = ZEITGEIST_NFO_SOFTWARE;
subject->manifestation = ZEITGEIST_NFO_SOFTWARE_ITEM;
subject->mimetype = "application/x-desktop";
subject->text = tooltip_text();
return subject;
}
void ApplicationLauncherIcon::EnsureMenuItemsDefaultReady()
{
if (menu_items_.size() == MenuItemType::SIZE)
return;
menu_items_.resize(MenuItemType::SIZE);
/* (Un)Stick to Launcher */
glib::Object menu_item(dbusmenu_menuitem_new());
const char* label = !IsSticky() ? _("Lock to Launcher") : _("Unlock from Launcher");
dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, label);
dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
glib_signals_.Add(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
[this] (DbusmenuMenuitem*, unsigned) {
ToggleSticky();
});
menu_items_[MenuItemType::STICK] = menu_item;
/* Quit */
menu_item = dbusmenu_menuitem_new();
dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Quit"));
dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
glib_signals_.Add(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
[this] (DbusmenuMenuitem*, unsigned) {
Quit();
});
menu_items_[MenuItemType::QUIT] = menu_item;
/* Separator */
menu_item = dbusmenu_menuitem_new();
dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR);
menu_items_[MenuItemType::SEPARATOR] = menu_item;
}
AbstractLauncherIcon::MenuItemsVector ApplicationLauncherIcon::GetMenus()
{
MenuItemsVector result;
glib::Object quit_item;
bool separator_needed = false;
EnsureMenuItemsDefaultReady();
EnsureMenuItemsStaticQuicklist();
for (auto const& menus : {GetRemoteMenus(), menu_desktop_shortcuts_})
{
if (!menus.IsType(DBUSMENU_TYPE_MENUITEM))
continue;
for (GList* l = dbusmenu_menuitem_get_children(menus); l; l = l->next)
{
glib::Object item(static_cast(l->data), glib::AddRef());
if (!item.IsType(DBUSMENU_TYPE_MENUITEM))
continue;
if (dbusmenu_menuitem_property_get_bool(item, DBUSMENU_MENUITEM_PROP_VISIBLE))
{
dbusmenu_menuitem_property_set_bool(item, QuicklistMenuItem::MARKUP_ENABLED_PROPERTY, FALSE);
const gchar* type = dbusmenu_menuitem_property_get(item, DBUSMENU_MENUITEM_PROP_TYPE);
if (!type) // (g_strcmp0 (type, DBUSMENU_MENUITEM_PROP_LABEL) == 0)
{
if (dbusmenu_menuitem_property_get_bool(item, QuicklistMenuItem::QUIT_ACTION_PROPERTY))
{
quit_item = item;
continue;
}
const gchar* l = dbusmenu_menuitem_property_get(item, DBUSMENU_MENUITEM_PROP_LABEL);
auto const& label = glib::gchar_to_string(l);
if (label == _("Quit") || label == "Quit" ||
label == _("Exit") || label == "Exit" ||
label == _("Close") || label == "Close")
{
quit_item = item;
continue;
}
}
separator_needed = true;
result.push_back(item);
}
}
}
if (separator_needed)
{
result.push_back(menu_items_[MenuItemType::SEPARATOR]);
separator_needed = false;
}
if (!menu_items_[MenuItemType::APP_NAME])
{
glib::String app_name(g_markup_escape_text(app_->title().c_str(), -1));
std::string bold_app_name(""+app_name.Str()+"");
glib::Object item(dbusmenu_menuitem_new());
dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_LABEL, bold_app_name.c_str());
dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_ACCESSIBLE_DESC, app_name.Str().c_str());
dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
dbusmenu_menuitem_property_set_bool(item, QuicklistMenuItem::MARKUP_ENABLED_PROPERTY, TRUE);
glib_signals_.Add(item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
[this] (DbusmenuMenuitem*, unsigned timestamp) {
_source_manager.AddIdle([this, timestamp] {
ActivateLauncherIcon(ActionArg(ActionArg::Source::LAUNCHER, 0, timestamp));
return false;
});
});
menu_items_[MenuItemType::APP_NAME] = item;
}
result.push_back(menu_items_[MenuItemType::APP_NAME]);
result.push_back(menu_items_[MenuItemType::SEPARATOR]);
auto const& windows_menu_items = GetWindowsMenuItems();
if (!windows_menu_items.empty())
{
result.insert(end(result), begin(windows_menu_items), end(windows_menu_items));
result.push_back(menu_items_[MenuItemType::SEPARATOR]);
}
const char* label = !IsSticky() ? _("Lock to Launcher") : _("Unlock from Launcher");
dbusmenu_menuitem_property_set(menu_items_[MenuItemType::STICK], DBUSMENU_MENUITEM_PROP_LABEL, label);
result.push_back(menu_items_[MenuItemType::STICK]);
if (IsRunning())
{
if (DesktopFile().empty() && !IsSticky())
{
/* Add to Dash */
glib::Object menu_item(dbusmenu_menuitem_new());
dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Add to Dash"));
dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
glib_signals_.Add(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
[this] (DbusmenuMenuitem*, unsigned) {
app_->CreateLocalDesktopFile();
});
result.push_back(menu_item);
}
if (!quit_item)
quit_item = menu_items_[MenuItemType::QUIT];
dbusmenu_menuitem_property_set(quit_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Quit"));
result.push_back(quit_item);
}
return result;
}
void ApplicationLauncherIcon::UpdateIconGeometries(std::vector const& centers)
{
if (app_->type() == AppType::WEBAPP)
return;
return WindowedLauncherIcon::UpdateIconGeometries(centers);
}
void ApplicationLauncherIcon::UpdateRemoteUri()
{
std::string const& desktop_id = app_->desktop_id();
if (!desktop_id.empty())
{
remote_uri_ = FavoriteStore::URI_PREFIX_APP + desktop_id;
}
else
{
remote_uri_.clear();
}
}
std::string ApplicationLauncherIcon::GetRemoteUri() const
{
return remote_uri_;
}
bool ApplicationLauncherIcon::OnShouldHighlightOnDrag(DndData const& dnd_data)
{
for (auto type : dnd_data.Types())
{
for (auto supported_type : GetSupportedTypes())
{
if (g_content_type_is_a(type.c_str(), supported_type.c_str()))
{
if (!dnd_data.UrisByType(type).empty())
return true;
}
}
}
return false;
}
nux::DndAction ApplicationLauncherIcon::OnQueryAcceptDrop(DndData const& dnd_data)
{
#ifdef USE_X11
return dnd_data.Uris().empty() ? nux::DNDACTION_NONE : nux::DNDACTION_COPY;
#else
return nux::DNDACTION_NONE;
#endif
}
void ApplicationLauncherIcon::OnAcceptDrop(DndData const& dnd_data)
{
auto timestamp = nux::GetGraphicsDisplay()->GetCurrentEvent().x11_timestamp;
OpenInstanceWithUris(dnd_data.Uris(), timestamp);
}
bool ApplicationLauncherIcon::AllowDetailViewInSwitcher() const
{
return app_->type() != AppType::WEBAPP;
}
uint64_t ApplicationLauncherIcon::SwitcherPriority()
{
// Webapps always go at the back.
if (app_->type() == AppType::WEBAPP)
return 0;
return WindowedLauncherIcon::SwitcherPriority();
}
nux::Color ApplicationLauncherIcon::BackgroundColor() const
{
if (use_custom_bg_color_)
return bg_color_;
return WindowedLauncherIcon::BackgroundColor();
}
const std::set ApplicationLauncherIcon::GetSupportedTypes()
{
std::set supported_types;
for (auto& type : app_->GetSupportedMimeTypes())
{
unity::glib::String super_type(g_content_type_from_mime_type(type.c_str()));
supported_types.insert(super_type.Str());
}
return supported_types;
}
std::string ApplicationLauncherIcon::GetName() const
{
return "ApplicationLauncherIcon";
}
void ApplicationLauncherIcon::AddProperties(debug::IntrospectionData& introspection)
{
WindowedLauncherIcon::AddProperties(introspection);
introspection.add("desktop_file", DesktopFile())
.add("desktop_id", app_->desktop_id());
}
} // namespace launcher
} // namespace unity