Back to index

unity  6.0.0
LauncherEntryRemoteModel.cpp
Go to the documentation of this file.
00001 // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
00002 /*
00003  * Copyright (C) 2011-2012 Canonical Ltd
00004  *
00005  * This program is free software: you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License version 3 as
00007  * published by the Free Software Foundation.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00016  *
00017  * Authored by: Mikkel Kamstrup Erlandsen <mikkel.kamstrup@canonical.com>
00018  *              Marco Trevisan (TreviƱo) <3v1n0@ubuntu.com>
00019  */
00020 
00021 #include <NuxCore/Logger.h>
00022 #include <UnityCore/DesktopUtilities.h>
00023 
00024 #include "LauncherEntryRemoteModel.h"
00025 
00026 namespace unity
00027 {
00028 
00029 namespace
00030 {
00031 nux::logging::Logger logger("launcher.entry.remote.model");
00032 }
00033 
00045 LauncherEntryRemoteModel::LauncherEntryRemoteModel()
00046   : _launcher_entry_dbus_signal_id(0)
00047   , _dbus_name_owner_changed_signal_id(0)
00048 {
00049   glib::Error error;
00050 
00051   _conn = g_bus_get_sync(G_BUS_TYPE_SESSION, nullptr, &error);
00052   if (error)
00053   {
00054     LOG_ERROR(logger) << "Unable to connect to session bus: " << error.Message();
00055     return;
00056   }
00057 
00058   /* Listen for *all* signals on the "com.canonical.Unity.LauncherEntry"
00059    * interface, no matter who the sender is */
00060   _launcher_entry_dbus_signal_id =
00061     g_dbus_connection_signal_subscribe(_conn,
00062                                        nullptr,                  // sender
00063                                        "com.canonical.Unity.LauncherEntry", // iface
00064                                        nullptr,                  // member
00065                                        nullptr,                  // path
00066                                        nullptr,                  // arg0
00067                                        G_DBUS_SIGNAL_FLAGS_NONE,
00068                                        &OnEntrySignalReceived,
00069                                        this,
00070                                        nullptr);
00071 
00072   _dbus_name_owner_changed_signal_id =
00073     g_dbus_connection_signal_subscribe(_conn,
00074                                        "org.freedesktop.DBus",   // sender
00075                                        "org.freedesktop.DBus",   // interface
00076                                        "NameOwnerChanged",       // member
00077                                        "/org/freedesktop/DBus",  // path
00078                                        nullptr,                  // arg0
00079                                        G_DBUS_SIGNAL_FLAGS_NONE,
00080                                        &OnDBusNameOwnerChanged,
00081                                        this,
00082                                        nullptr);
00083 }
00084 
00085 LauncherEntryRemoteModel::~LauncherEntryRemoteModel()
00086 {
00087   if (_conn)
00088   {
00089     if (_launcher_entry_dbus_signal_id)
00090     {
00091       g_dbus_connection_signal_unsubscribe(_conn,
00092                                            _launcher_entry_dbus_signal_id);
00093     }
00094 
00095     if (_dbus_name_owner_changed_signal_id)
00096     {
00097       g_dbus_connection_signal_unsubscribe(_conn,
00098                                            _dbus_name_owner_changed_signal_id);
00099     }
00100   }
00101 }
00102 
00107 unsigned int LauncherEntryRemoteModel::Size() const
00108 {
00109   return _entries_by_uri.size();
00110 }
00111 
00120 LauncherEntryRemote::Ptr LauncherEntryRemoteModel::LookupByUri(std::string const& app_uri)
00121 {
00122   auto target_en = _entries_by_uri.find(app_uri);
00123 
00124   return (target_en != _entries_by_uri.end()) ? target_en->second : nullptr;
00125 }
00126 
00134 LauncherEntryRemote::Ptr LauncherEntryRemoteModel::LookupByDesktopId(std::string const& desktop_id)
00135 {
00136   std::string prefix = "application://";
00137   return LookupByUri(prefix + desktop_id);
00138 }
00139 
00144 LauncherEntryRemote::Ptr LauncherEntryRemoteModel::LookupByDesktopFile(std::string const& desktop_file_path)
00145 {
00146   std::string const& desktop_id = DesktopUtilities::GetDesktopID(desktop_file_path);
00147 
00148   if (desktop_id.empty())
00149     return nullptr;
00150 
00151   return LookupByDesktopId(desktop_id);
00152 }
00153 
00158 std::list<std::string> LauncherEntryRemoteModel::GetUris() const
00159 {
00160   std::list<std::string> uris;
00161 
00162   for (auto entry : _entries_by_uri)
00163     uris.push_back(entry.first);
00164 
00165   return uris;
00166 }
00167 
00171 void LauncherEntryRemoteModel::AddEntry(LauncherEntryRemote::Ptr const& entry)
00172 {
00173   auto existing_entry = LookupByUri(entry->AppUri());
00174 
00175   if (existing_entry)
00176   {
00177     existing_entry->Update(entry);
00178   }
00179   else
00180   {
00181     _entries_by_uri[entry->AppUri()] = entry;
00182     entry_added.emit(entry);
00183   }
00184 }
00185 
00189 void LauncherEntryRemoteModel::RemoveEntry(LauncherEntryRemote::Ptr const& entry)
00190 {
00191   _entries_by_uri.erase(entry->AppUri());
00192   entry_removed.emit(entry);
00193 }
00194 
00198 void LauncherEntryRemoteModel::HandleUpdateRequest(std::string const& sender_name,
00199                                                    GVariant* parameters)
00200 {
00201   if (!parameters)
00202     return;
00203 
00204   if (!g_variant_is_of_type(parameters, G_VARIANT_TYPE("(sa{sv})")))
00205   {
00206     LOG_ERROR(logger) << "Received 'com.canonical.Unity.LauncherEntry.Update' with"
00207                          " illegal payload signature '"
00208                       << g_variant_get_type_string(parameters)
00209                       << "'. Expected '(sa{sv})'.";
00210     return;
00211   }
00212 
00213   glib::String app_uri;
00214   GVariantIter* prop_iter;
00215   g_variant_get(parameters, "(sa{sv})", &app_uri, &prop_iter);
00216 
00217   auto entry = LookupByUri(app_uri.Str());
00218 
00219   if (entry)
00220   {
00221     /* It's important that we update the DBus name first since it might
00222      * unset the quicklist if it changes */
00223     entry->SetDBusName(sender_name);
00224     entry->Update(prop_iter);
00225   }
00226   else
00227   {
00228     LauncherEntryRemote::Ptr entry_ptr(new LauncherEntryRemote(sender_name, parameters));
00229     AddEntry(entry_ptr);
00230   }
00231 
00232   g_variant_iter_free(prop_iter);
00233 }
00234 
00235 void LauncherEntryRemoteModel::OnEntrySignalReceived(GDBusConnection* connection,
00236                                                      const gchar* sender_name,
00237                                                      const gchar* object_path,
00238                                                      const gchar* interface_name,
00239                                                      const gchar* signal_name,
00240                                                      GVariant* parameters,
00241                                                      gpointer user_data)
00242 {
00243   auto self = static_cast<LauncherEntryRemoteModel*>(user_data);
00244 
00245   if (!parameters || !signal_name)
00246   {
00247     LOG_ERROR(logger) << "Received DBus signal '" << interface_name << "."
00248                       << signal_name << "' with empty payload from " << sender_name;
00249     return;
00250   }
00251 
00252   if (std::string(signal_name) == "Update")
00253   {
00254     if (!sender_name)
00255     {
00256       LOG_ERROR(logger) << "Received 'com.canonical.Unity.LauncherEntry.Update' from"
00257                            " an undefined sender. This may happen if you are trying "
00258                            "to run Unity on a p2p DBus connection.";
00259       return;
00260     }
00261 
00262     self->HandleUpdateRequest(sender_name, parameters);
00263   }
00264   else
00265   {
00266     LOG_ERROR(logger) << "Unknown signal '" << interface_name << "."
00267                       << signal_name << "' from " << sender_name;
00268   }
00269 }
00270 
00271 void
00272 LauncherEntryRemoteModel::OnDBusNameOwnerChanged(GDBusConnection* connection,
00273                                                  const gchar* sender_name,
00274                                                  const gchar* object_path,
00275                                                  const gchar* interface_name,
00276                                                  const gchar* signal_name,
00277                                                  GVariant* parameters,
00278                                                  gpointer user_data)
00279 {
00280   auto self = static_cast<LauncherEntryRemoteModel*>(user_data);
00281 
00282   if (!parameters || self->_entries_by_uri.empty())
00283     return;
00284 
00285   glib::String name, before, after;
00286   g_variant_get(parameters, "(sss)", &name, &before, &after);
00287 
00288   if (!after || after.Str().empty())
00289   {
00290     // Name gone, find and destroy LauncherEntryRemote
00291     std::vector<LauncherEntryRemote::Ptr> to_rm;
00292 
00293     for (auto it = self->_entries_by_uri.begin(); it != self->_entries_by_uri.end(); ++it)
00294     {
00295       auto entry = it->second;
00296 
00297       if (entry->DBusName() == name.Str())
00298       {
00299         to_rm.push_back(entry);
00300       }
00301     }
00302 
00303     for (auto entry : to_rm)
00304     {
00305       self->RemoveEntry(entry);
00306     }
00307   }
00308 }
00309 
00310 }