Back to index

unity  6.0.0
DeviceLauncherIcon.cpp
Go to the documentation of this file.
00001 // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
00002 /*
00003  * Copyright (C) 2010 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: Neil Jagdish Patel <neil.patel@canonical.com>
00018  */
00019 
00020 #include "DeviceLauncherIcon.h"
00021 
00022 #include <algorithm>
00023 #include <list>
00024 
00025 #include <glib/gi18n-lib.h>
00026 #include <libnotify/notify.h>
00027 #include <NuxCore/Logger.h>
00028 
00029 #include "DevicesSettings.h"
00030 #include "unity-shared/IconLoader.h"
00031 #include "unity-shared/ubus-server.h"
00032 #include "unity-shared/UBusMessages.h"
00033 
00034 namespace unity
00035 {
00036 namespace launcher
00037 {
00038 namespace
00039 {
00040 
00041 nux::logging::Logger logger("unity.launcher");
00042 
00043 const unsigned int volume_changed_timeout =  500;
00044 
00045 }
00046 
00047 DeviceLauncherIcon::DeviceLauncherIcon(glib::Object<GVolume> const& volume)
00048   : SimpleLauncherIcon()
00049   , volume_(volume)
00050 {
00051   signal_volume_changed_.Connect(volume, "changed", sigc::mem_fun(this, &DeviceLauncherIcon::OnVolumeChanged));
00052 
00053   DevicesSettings::GetDefault().changed.connect(sigc::mem_fun(this, &DeviceLauncherIcon::OnSettingsChanged));
00054 
00055   // Checks if in favorites!
00056   glib::String uuid(g_volume_get_identifier(volume_, G_VOLUME_IDENTIFIER_KIND_UUID));
00057   DeviceList favorites = DevicesSettings::GetDefault().GetFavorites();
00058   DeviceList::iterator pos = std::find(favorites.begin(), favorites.end(), uuid.Str());
00059 
00060   keep_in_launcher_ = pos != favorites.end();
00061 
00062   UpdateDeviceIcon();
00063   UpdateVisibility();
00064 }
00065 
00066 void DeviceLauncherIcon::OnVolumeChanged(GVolume* volume)
00067 {
00068   if (!G_IS_VOLUME(volume))
00069     return;
00070 
00071   changed_timeout_.reset(new glib::Timeout(volume_changed_timeout, [this]() {
00072     UpdateDeviceIcon();
00073     UpdateVisibility();
00074     return false;
00075   }));
00076 }
00077 
00078 void DeviceLauncherIcon::UpdateVisibility()
00079 {
00080   switch (DevicesSettings::GetDefault().GetDevicesOption())
00081   {
00082     case DevicesSettings::NEVER:
00083       SetQuirk(QUIRK_VISIBLE, false);
00084       break;
00085     case DevicesSettings::ONLY_MOUNTED:
00086       if (keep_in_launcher_)
00087       {
00088         SetQuirk(QUIRK_VISIBLE, true);
00089       }
00090       else
00091       {
00092         glib::Object<GMount> mount(g_volume_get_mount(volume_));
00093         SetQuirk(QUIRK_VISIBLE, mount);
00094       }
00095       break;
00096     case DevicesSettings::ALWAYS:
00097       SetQuirk(QUIRK_VISIBLE, true);
00098       break;
00099   }
00100 }
00101 
00102 void DeviceLauncherIcon::UpdateDeviceIcon()
00103 {
00104   name_ = glib::String(g_volume_get_name(volume_)).Str();
00105 
00106   glib::Object<GIcon> icon(g_volume_get_icon(volume_));
00107   glib::String icon_string(g_icon_to_string(icon));
00108 
00109   tooltip_text = name_;
00110   icon_name = icon_string.Str();
00111 
00112   SetIconType(TYPE_DEVICE);
00113   SetQuirk(QUIRK_RUNNING, false);
00114 }
00115 
00116 bool
00117 DeviceLauncherIcon::CanEject()
00118 {
00119   return g_volume_can_eject(volume_);
00120 }
00121 
00122 std::list<DbusmenuMenuitem*> DeviceLauncherIcon::GetMenus()
00123 {
00124   std::list<DbusmenuMenuitem*> result;
00125   DbusmenuMenuitem* menu_item;
00126   glib::Object<GDrive> drive(g_volume_get_drive(volume_));
00127 
00128   // "Lock to Launcher"/"Unlock from Launcher" item
00129   if (DevicesSettings::GetDefault().GetDevicesOption() == DevicesSettings::ONLY_MOUNTED
00130       && drive && !g_drive_is_media_removable (drive))
00131   {
00132     menu_item = dbusmenu_menuitem_new();
00133 
00134     dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, !keep_in_launcher_ ? _("Lock to Launcher") : _("Unlock from Launcher"));
00135     dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
00136     dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
00137 
00138     g_signal_connect(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
00139                      G_CALLBACK(&DeviceLauncherIcon::OnTogglePin), this);
00140 
00141     result.push_back(menu_item);
00142   }
00143 
00144   // "Open" item
00145   menu_item = dbusmenu_menuitem_new();
00146 
00147   dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Open"));
00148   dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
00149   dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
00150 
00151   g_signal_connect(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
00152                    G_CALLBACK(&DeviceLauncherIcon::OnOpen), this);
00153 
00154   result.push_back(menu_item);
00155 
00156   // "Eject" item
00157   if (drive && g_drive_can_eject(drive))
00158   {
00159     menu_item = dbusmenu_menuitem_new();
00160 
00161     GList *list = g_drive_get_volumes(drive);
00162     if (list != NULL)
00163     {
00164       if (g_list_length (list) ==  1)
00165         dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Eject"));
00166       else
00167         dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Eject parent drive"));
00168 
00169       g_list_free_full(list, g_object_unref);
00170     }
00171 
00172     dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
00173     dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
00174 
00175     g_signal_connect(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
00176                      G_CALLBACK(&DeviceLauncherIcon::OnEject), this);
00177 
00178     result.push_back(menu_item);
00179   }
00180 
00181   // "Safely remove" item
00182   if (drive && g_drive_can_stop(drive))
00183   {
00184     menu_item = dbusmenu_menuitem_new();
00185 
00186     GList *list = g_drive_get_volumes(drive);
00187     if (list != NULL)
00188     {
00189       if (g_list_length (list) ==  1)
00190         dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Safely remove"));
00191       else
00192         dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Safely remove parent drive"));
00193 
00194       g_list_free_full(list, g_object_unref);
00195     }
00196 
00197     dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
00198     dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
00199 
00200     g_signal_connect(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
00201                      G_CALLBACK(&DeviceLauncherIcon::OnDriveStop), this);
00202 
00203     result.push_back(menu_item);
00204   }
00205 
00206   // "Unmount" item
00207   if (!g_volume_can_eject(volume_))  // Don't need Unmount if can Eject
00208   {
00209     glib::Object<GMount> mount(g_volume_get_mount(volume_));
00210 
00211     if (mount && g_mount_can_unmount(mount))
00212     {
00213       menu_item = dbusmenu_menuitem_new();
00214 
00215       dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Unmount"));
00216       dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
00217       dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
00218 
00219       g_signal_connect(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
00220                        G_CALLBACK(&DeviceLauncherIcon::OnUnmount), this);
00221 
00222       result.push_back(menu_item);
00223     }
00224   }
00225 
00226   return result;
00227 }
00228 
00229 void DeviceLauncherIcon::ShowMount(GMount* mount)
00230 {
00231   if (G_IS_MOUNT(mount))
00232   {
00233     glib::Object<GFile> root(g_mount_get_root(mount));
00234 
00235     if (G_IS_FILE(root.RawPtr()))
00236     {
00237       glib::String uri(g_file_get_uri(root));
00238       glib::Error error;
00239 
00240       g_app_info_launch_default_for_uri(uri.Value(), NULL, &error);
00241 
00242       if (error)
00243       {
00244         LOG_WARNING(logger) << "Cannot open volume '" << name_
00245                             << "': Unable to show " << uri
00246                             << ": " << error;
00247       }
00248     }
00249     else
00250     {
00251       LOG_WARNING(logger) << "Cannot open volume '" << name_
00252                           << "': Mount has no root";
00253     }
00254   }
00255   else
00256   {
00257     LOG_WARNING(logger) << "Cannot open volume '" << name_
00258                         << "': Mount-point is invalid";
00259   }
00260 }
00261 
00262 void DeviceLauncherIcon::ActivateLauncherIcon(ActionArg arg)
00263 {
00264   SimpleLauncherIcon::ActivateLauncherIcon(arg);
00265   SetQuirk(QUIRK_STARTING, true);
00266 
00267   glib::Object<GMount> mount(g_volume_get_mount(volume_));
00268 
00269   if (G_IS_MOUNT(mount.RawPtr()))
00270     ShowMount(mount);
00271   else
00272     g_volume_mount(volume_,
00273                    (GMountMountFlags)0,
00274                    NULL,
00275                    NULL,
00276                    (GAsyncReadyCallback)&DeviceLauncherIcon::OnMountReady,
00277                    this);
00278 }
00279 
00280 void DeviceLauncherIcon::OnMountReady(GObject* object,
00281                                       GAsyncResult* result,
00282                                       DeviceLauncherIcon* self)
00283 {
00284   glib::Error error;
00285 
00286   if (g_volume_mount_finish(self->volume_, result, &error))
00287   {
00288     glib::Object<GMount> mount(g_volume_get_mount(self->volume_));
00289     self->ShowMount(mount);
00290   }
00291   else
00292   {
00293     LOG_WARNING(logger) << "Cannot open volume '" << self->name_ << "' : " <<
00294                             (error ? error.Message() : "Mount operation failed");
00295   }
00296 }
00297 
00298 void DeviceLauncherIcon::OnEjectReady(GObject* object,
00299                                       GAsyncResult* result,
00300                                       DeviceLauncherIcon* self)
00301 {
00302   if (g_volume_eject_with_operation_finish(self->volume_, result, NULL))
00303   {
00304     IconLoader::GetDefault().LoadFromGIconString(self->icon_name(), 48,
00305                                                  sigc::bind(sigc::mem_fun(self, &DeviceLauncherIcon::ShowNotification), self->name_));
00306   }
00307 }
00308 
00309 void DeviceLauncherIcon::ShowNotification(std::string const& icon_name,
00310                                           unsigned size,
00311                                           glib::Object<GdkPixbuf> const& pixbuf,
00312                                           std::string const& name)
00313 {
00314   glib::Object<NotifyNotification> notification(notify_notification_new(name.c_str(),
00315                                                                         _("The drive has been successfully ejected"),
00316                                                                         NULL));
00317 
00318   notify_notification_set_hint(notification,
00319                                "x-canonical-private-synchronous",
00320                                g_variant_new_boolean(TRUE));
00321 
00322   if (GDK_IS_PIXBUF(pixbuf.RawPtr()))
00323     notify_notification_set_image_from_pixbuf(notification, pixbuf);
00324 
00325   notify_notification_show(notification, NULL);
00326 }
00327 
00328 void DeviceLauncherIcon::Eject()
00329 {
00330   glib::Object<GMountOperation> mount_op(gtk_mount_operation_new(NULL));
00331 
00332   g_volume_eject_with_operation(volume_,
00333                                 (GMountUnmountFlags)0,
00334                                 mount_op,
00335                                 NULL,
00336                                 (GAsyncReadyCallback)OnEjectReady,
00337                                 this);
00338 }
00339 
00340 void DeviceLauncherIcon::OnTogglePin(DbusmenuMenuitem* item,
00341                                      int time,
00342                                      DeviceLauncherIcon* self)
00343 {
00344   glib::String uuid(g_volume_get_identifier(self->volume_, G_VOLUME_IDENTIFIER_KIND_UUID));
00345 
00346   self->keep_in_launcher_ = !self->keep_in_launcher_;
00347 
00348   if (!self->keep_in_launcher_)
00349   {
00350     // If the volume is not mounted hide the icon
00351     glib::Object<GMount> mount(g_volume_get_mount(self->volume_));
00352 
00353     if (!mount)
00354       self->SetQuirk(QUIRK_VISIBLE, false);
00355 
00356     // Remove from favorites
00357     if (!uuid.Str().empty())
00358       DevicesSettings::GetDefault().RemoveFavorite(uuid.Str());
00359   }
00360   else
00361   {
00362     if (!uuid.Str().empty())
00363       DevicesSettings::GetDefault().AddFavorite(uuid.Str());
00364   }
00365 }
00366 
00367 void DeviceLauncherIcon::OnOpen(DbusmenuMenuitem* item,
00368                                 int time,
00369                                 DeviceLauncherIcon* self)
00370 {
00371   self->ActivateLauncherIcon(ActionArg(ActionArg::OTHER, 0));
00372 }
00373 
00374 void DeviceLauncherIcon::OnEject(DbusmenuMenuitem* item,
00375                                  int time,
00376                                  DeviceLauncherIcon* self)
00377 {
00378   self->Eject();
00379 }
00380 
00381 void DeviceLauncherIcon::OnUnmountReady(GObject* object,
00382                                         GAsyncResult* result,
00383                                         DeviceLauncherIcon* self)
00384 {
00385   if (G_IS_MOUNT(object))
00386     g_mount_unmount_with_operation_finish(G_MOUNT(object), result, NULL);
00387 }
00388 
00389 void DeviceLauncherIcon::Unmount()
00390 {
00391   glib::Object<GMount> mount(g_volume_get_mount(volume_));
00392 
00393   if (mount)
00394   {
00395     glib::Object<GMountOperation> op(gtk_mount_operation_new(NULL));
00396 
00397     g_mount_unmount_with_operation(mount,
00398                                    (GMountUnmountFlags)0,
00399                                    op,
00400                                    NULL,
00401                                    (GAsyncReadyCallback)OnUnmountReady,
00402                                    this);
00403   }
00404 }
00405 
00406 void DeviceLauncherIcon::OnUnmount(DbusmenuMenuitem* item,
00407                                    int time,
00408                                    DeviceLauncherIcon* self)
00409 {
00410   self->Unmount();
00411 }
00412 
00413 void DeviceLauncherIcon::OnRemoved()
00414 {
00415   Remove();
00416 }
00417 
00418 void DeviceLauncherIcon::OnDriveStop(DbusmenuMenuitem* item,
00419                                      int time,
00420                                      DeviceLauncherIcon* self)
00421 {
00422   self->StopDrive();
00423 }
00424 
00425 void DeviceLauncherIcon::StopDrive()
00426 {
00427   glib::Object<GDrive> drive(g_volume_get_drive(volume_));
00428   glib::Object<GMountOperation> mount_op(gtk_mount_operation_new(NULL));
00429 
00430   g_drive_stop(drive,
00431                (GMountUnmountFlags)0,
00432                mount_op,
00433                NULL,
00434                NULL,
00435                NULL);
00436 }
00437 
00438 void DeviceLauncherIcon::OnSettingsChanged()
00439 {
00440   // Checks if in favourites!
00441   glib::String uuid(g_volume_get_identifier(volume_, G_VOLUME_IDENTIFIER_KIND_UUID));
00442   DeviceList favorites = DevicesSettings::GetDefault().GetFavorites();
00443   DeviceList::iterator pos = std::find(favorites.begin(), favorites.end(), uuid.Str());
00444 
00445   keep_in_launcher_ = pos != favorites.end();
00446 
00447   UpdateVisibility();
00448 }
00449 
00450 std::string DeviceLauncherIcon::GetName() const
00451 {
00452   return "DeviceLauncherIcon";
00453 }
00454 
00455 } // namespace launcher
00456 } // namespace unity