Back to index

unity  6.0.0
BamfLauncherIcon.cpp
Go to the documentation of this file.
00001 // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
00002 /*
00003  * Copyright (C) 2010-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: Jason Smith <jason.smith@canonical.com>
00018  *              Marco Trevisan (TreviƱo) <3v1n0@ubuntu.com>
00019  */
00020 
00021 #include <boost/algorithm/string.hpp>
00022 
00023 #include <Nux/Nux.h>
00024 #include <Nux/BaseWindow.h>
00025 
00026 #include <UnityCore/Variant.h>
00027 #include <UnityCore/GLibWrapper.h>
00028 #include <UnityCore/DesktopUtilities.h>
00029 
00030 #include "BamfLauncherIcon.h"
00031 #include "FavoriteStore.h"
00032 #include "Launcher.h"
00033 #include "MultiMonitor.h"
00034 #include "unity-shared/WindowManager.h"
00035 #include "unity-shared/UBusMessages.h"
00036 #include "unity-shared/ubus-server.h"
00037 
00038 #include <glib/gi18n-lib.h>
00039 #include <gio/gdesktopappinfo.h>
00040 
00041 namespace unity
00042 {
00043 namespace launcher
00044 {
00045 namespace
00046 {
00047   // We use the "bamf-" prefix since the manager is protected, to avoid name clash
00048   const std::string WINDOW_MOVE_TIMEOUT = "bamf-window-move";
00049   const std::string ICON_REMOVE_TIMEOUT = "bamf-icon-remove";
00050   //const std::string ICON_DND_OVER_TIMEOUT = "bamf-icon-dnd-over";
00051 }
00052 
00053 NUX_IMPLEMENT_OBJECT_TYPE(BamfLauncherIcon);
00054 
00055 BamfLauncherIcon::BamfLauncherIcon(BamfApplication* app)
00056   : SimpleLauncherIcon()
00057   , _bamf_app(app, glib::AddRef())
00058   , _supported_types_filled(false)
00059   , use_custom_bg_color_(false)
00060   , bg_color_(nux::color::White)
00061 {
00062   g_object_set_qdata(G_OBJECT(app), g_quark_from_static_string("unity-seen"),
00063                      GUINT_TO_POINTER(1));
00064   auto bamf_view = glib::object_cast<BamfView>(_bamf_app);
00065 
00066   glib::String icon(bamf_view_get_icon(bamf_view));
00067 
00068   tooltip_text = BamfName();
00069   icon_name = icon.Str();
00070   SetIconType(TYPE_APPLICATION);
00071 
00072   if (IsSticky())
00073     SetQuirk(QUIRK_VISIBLE, true);
00074   else
00075     SetQuirk(QUIRK_VISIBLE, bamf_view_user_visible(bamf_view));
00076 
00077   SetQuirk(QUIRK_ACTIVE, bamf_view_is_active(bamf_view));
00078   SetQuirk(QUIRK_RUNNING, bamf_view_is_running(bamf_view));
00079 
00080   glib::SignalBase* sig;
00081 
00082   sig = new glib::Signal<void, BamfView*, BamfView*>(bamf_view, "child-added",
00083                           [&] (BamfView*, BamfView*) {
00084                             EnsureWindowState();
00085                             UpdateMenus();
00086                             UpdateIconGeometries(GetCenters());
00087                           });
00088   _gsignals.Add(sig);
00089 
00090   sig = new glib::Signal<void, BamfView*, BamfView*>(bamf_view, "child-removed",
00091                           [&] (BamfView*, BamfView*) { EnsureWindowState(); });
00092   _gsignals.Add(sig);
00093 
00094   sig = new glib::Signal<void, BamfView*, gboolean>(bamf_view, "urgent-changed",
00095                           [&] (BamfView*, gboolean urgent) {
00096                             SetQuirk(QUIRK_URGENT, urgent);
00097                           });
00098   _gsignals.Add(sig);
00099 
00100   sig = new glib::Signal<void, BamfView*, gboolean>(bamf_view, "active-changed",
00101                           [&] (BamfView*, gboolean active) {
00102                             SetQuirk(QUIRK_ACTIVE, active);
00103                           });
00104   _gsignals.Add(sig);
00105 
00106   sig = new glib::Signal<void, BamfView*, gboolean>(bamf_view, "running-changed",
00107                           [&] (BamfView*, gboolean running) {
00108                             SetQuirk(QUIRK_RUNNING, running);
00109 
00110                             if (running)
00111                             {
00112                               EnsureWindowState();
00113                               UpdateIconGeometries(GetCenters());
00114                               _source_manager.Remove(ICON_REMOVE_TIMEOUT);
00115                             }
00116                           });
00117   _gsignals.Add(sig);
00118 
00119   sig = new glib::Signal<void, BamfView*, gboolean>(bamf_view, "user-visible-changed",
00120                           [&] (BamfView*, gboolean visible) {
00121                             if (!IsSticky())
00122                               SetQuirk(QUIRK_VISIBLE, visible);
00123                           });
00124   _gsignals.Add(sig);
00125 
00126   sig = new glib::Signal<void, BamfView*>(bamf_view, "closed",
00127                           [&] (BamfView*) {
00128                             if (!IsSticky())
00129                             {
00130                               SetQuirk(QUIRK_VISIBLE, false);
00131 
00132                               /* Use a timeout to remove the icon, this avoids
00133                                * that we remove an application that is going
00134                                * to be reopened soon. So applications that
00135                                * have a splash screen won't be removed from
00136                                * the launcher while the splash is closed and
00137                                * a new window is opened. */
00138                               auto timeout = std::make_shared<glib::TimeoutSeconds>(1);
00139                               _source_manager.Add(timeout, ICON_REMOVE_TIMEOUT);
00140                               timeout->Run([&] { Remove(); return false; });
00141                             }
00142                           });
00143   _gsignals.Add(sig);
00144 
00145   WindowManager::Default()->window_minimized.connect(sigc::mem_fun(this, &BamfLauncherIcon::OnWindowMinimized));
00146   WindowManager::Default()->window_moved.connect(sigc::mem_fun(this, &BamfLauncherIcon::OnWindowMoved));
00147   WindowManager::Default()->compiz_screen_viewport_switch_ended.connect(sigc::mem_fun(this, &BamfLauncherIcon::EnsureWindowState));
00148   WindowManager::Default()->terminate_expo.connect(sigc::mem_fun(this, &BamfLauncherIcon::EnsureWindowState));
00149 
00150   EnsureWindowState();
00151   UpdateMenus();
00152   UpdateDesktopFile();
00153   UpdateBackgroundColor();
00154 
00155   // hack
00156   SetProgress(0.0f);
00157 
00158   // Calls when there are no higher priority events pending to the default main loop.
00159   auto idle = std::make_shared<glib::Idle>([&] { FillSupportedTypes(); return false; });
00160   _source_manager.Add(idle);
00161 }
00162 
00163 BamfLauncherIcon::~BamfLauncherIcon()
00164 {
00165   if (_bamf_app)
00166     g_object_set_qdata(G_OBJECT(_bamf_app.RawPtr()),
00167                        g_quark_from_static_string("unity-seen"), nullptr);
00168 }
00169 
00170 void BamfLauncherIcon::Remove()
00171 {
00172   /* Removing the unity-seen flag to the wrapped bamf application, on remove
00173    * request we make sure that if the bamf application is re-opened while
00174    * the removal process is still ongoing, the application will be shown
00175    * on the launcher. Disconnecting from signals and nullifying the _bamf_app
00176    * we make sure that this icon won't be reused (no duplicated icon). */
00177   _gsignals.Disconnect(_bamf_app);
00178   g_object_set_qdata(G_OBJECT(_bamf_app.RawPtr()),
00179                      g_quark_from_static_string("unity-seen"), nullptr);
00180   _bamf_app = nullptr;
00181 
00182   SimpleLauncherIcon::Remove();
00183 }
00184 
00185 bool BamfLauncherIcon::IsSticky() const
00186 {
00187   return bamf_view_is_sticky(BAMF_VIEW(_bamf_app.RawPtr()));
00188 }
00189 
00190 bool BamfLauncherIcon::IsVisible() const
00191 {
00192   return GetQuirk(QUIRK_VISIBLE);
00193 }
00194 
00195 bool BamfLauncherIcon::IsActive() const
00196 {
00197   return GetQuirk(QUIRK_ACTIVE);
00198 }
00199 
00200 bool BamfLauncherIcon::IsRunning() const
00201 {
00202   return GetQuirk(QUIRK_RUNNING);
00203 }
00204 
00205 bool BamfLauncherIcon::IsUrgent() const
00206 {
00207   return GetQuirk(QUIRK_URGENT);
00208 }
00209 
00210 void BamfLauncherIcon::ActivateLauncherIcon(ActionArg arg)
00211 {
00212   SimpleLauncherIcon::ActivateLauncherIcon(arg);
00213   WindowManager* wm = WindowManager::Default();
00214   bool scaleWasActive = wm->IsScaleActive();
00215 
00216   bool active = IsActive();
00217   bool user_visible = IsRunning();
00218 
00219   if (arg.target && OwnsWindow(arg.target))
00220   {
00221     wm->Activate(arg.target);
00222     return;
00223   }
00224 
00225   /* We should check each child to see if there is
00226    * an unmapped (!= minimized) window around and
00227    * if so force "Focus" behaviour */
00228 
00229   if (arg.source != ActionArg::SWITCHER)
00230   {
00231     auto bamf_view = glib::object_cast<BamfView>(_bamf_app);
00232     user_visible = bamf_view_user_visible(bamf_view);
00233 
00234     if (active)
00235     {
00236       bool any_visible = false;
00237       bool any_mapped = false;
00238       bool any_on_top = false;
00239       bool any_on_monitor = (arg.monitor < 0);
00240       int active_monitor = arg.monitor;
00241       GList* children = bamf_view_get_children(bamf_view);
00242 
00243       for (GList* l = children; l; l = l->next)
00244       {
00245         if (!BAMF_IS_WINDOW(l->data))
00246           continue;
00247 
00248         auto view = static_cast<BamfView*>(l->data);
00249         auto win = static_cast<BamfWindow*>(l->data);
00250         Window xid = bamf_window_get_xid(win);
00251 
00252         if (!any_visible && wm->IsWindowOnCurrentDesktop(xid))
00253         {
00254           any_visible = true;
00255         }
00256 
00257         if (!any_mapped && wm->IsWindowMapped(xid))
00258         {
00259           any_mapped = true;
00260         }
00261 
00262         if (!any_on_top && wm->IsWindowOnTop(xid))
00263         {
00264           any_on_top = true;
00265         }
00266 
00267         if (!any_on_monitor && bamf_window_get_monitor(win) == arg.monitor &&
00268             wm->IsWindowMapped(xid) && wm->IsWindowVisible(xid))
00269         {
00270           any_on_monitor = true;
00271         }
00272 
00273         if (bamf_view_is_active(view))
00274         {
00275           active_monitor = bamf_window_get_monitor(win);
00276         }
00277       }
00278 
00279       g_list_free(children);
00280 
00281       if (!any_visible || !any_mapped || !any_on_top)
00282         active = false;
00283 
00284       if (any_on_monitor && arg.monitor >= 0 && active_monitor != arg.monitor)
00285         active = false;
00286     }
00287   }
00288 
00289   /* Behaviour:
00290    * 1) Nothing running, or nothing visible -> launch application
00291    * 2) Running and active -> spread application
00292    * 3) Running and not active -> focus application
00293    * 4) Spread is active and different icon pressed -> change spread
00294    * 5) Spread is active -> Spread de-activated, and fall through
00295    */
00296 
00297   if (!IsRunning() || (IsRunning() && !user_visible)) // #1 above
00298   {
00299     if (GetQuirk(QUIRK_STARTING))
00300       return;
00301 
00302     if (scaleWasActive)
00303     {
00304       wm->TerminateScale();
00305     }
00306 
00307     SetQuirk(QUIRK_STARTING, true);
00308     OpenInstanceLauncherIcon(ActionArg());
00309   }
00310   else // app is running
00311   {
00312     if (active)
00313     {
00314       if (scaleWasActive) // #5 above
00315       {
00316         wm->TerminateScale();
00317         Focus(arg);
00318       }
00319       else // #2 above
00320       {
00321         if (arg.source != ActionArg::SWITCHER)
00322         {
00323           Spread(true, 0, false);
00324         }
00325       }
00326     }
00327     else
00328     {
00329       if (scaleWasActive) // #4 above
00330       {
00331         wm->TerminateScale();
00332         Focus(arg);
00333         if (arg.source != ActionArg::SWITCHER)
00334           Spread(true, 0, false);
00335       }
00336       else // #3 above
00337       {
00338         Focus(arg);
00339       }
00340     }
00341   }
00342 
00343   if (arg.source != ActionArg::SWITCHER)
00344     ubus_server_send_message(ubus_server_get_default(), UBUS_LAUNCHER_ACTION_DONE, nullptr);
00345 }
00346 
00347 std::vector<Window> BamfLauncherIcon::GetWindows(WindowFilterMask filter, int monitor)
00348 {
00349   WindowManager* wm = WindowManager::Default();
00350   std::vector<Window> results;
00351   GList* children, *l;
00352 
00353   monitor = (filter & WindowFilter::ON_ALL_MONITORS) ? -1 : monitor;
00354   bool mapped = (filter & WindowFilter::MAPPED);
00355   bool user_visible = (filter & WindowFilter::USER_VISIBLE);
00356   bool current_desktop = (filter & WindowFilter::ON_CURRENT_DESKTOP);
00357 
00358   children = bamf_view_get_children(BAMF_VIEW(_bamf_app.RawPtr()));
00359   for (l = children; l; l = l->next)
00360   {
00361     if (!BAMF_IS_WINDOW(l->data))
00362       continue;
00363 
00364     auto window = static_cast<BamfWindow*>(l->data);
00365     auto view = static_cast<BamfView*>(l->data);
00366 
00367     if ((monitor >= 0 && bamf_window_get_monitor(window) == monitor) || monitor < 0)
00368     {
00369       if ((user_visible && bamf_view_user_visible(view)) || !user_visible)
00370       {
00371         guint32 xid = bamf_window_get_xid(window);
00372 
00373         if ((mapped && wm->IsWindowMapped(xid)) || !mapped)
00374         {
00375           if ((current_desktop && wm->IsWindowOnCurrentDesktop(xid)) || !current_desktop)
00376           {
00377             results.push_back(xid);
00378           }
00379         }
00380       }
00381     }
00382   }
00383 
00384   g_list_free(children);
00385   return results;
00386 }
00387 
00388 std::vector<Window> BamfLauncherIcon::Windows()
00389 {
00390   return GetWindows(WindowFilter::MAPPED|WindowFilter::ON_ALL_MONITORS);
00391 }
00392 
00393 std::vector<Window> BamfLauncherIcon::WindowsOnViewport()
00394 {
00395   WindowFilterMask filter = 0;
00396   filter |= WindowFilter::MAPPED;
00397   filter |= WindowFilter::USER_VISIBLE;
00398   filter |= WindowFilter::ON_CURRENT_DESKTOP;
00399   filter |= WindowFilter::ON_ALL_MONITORS;
00400 
00401   return GetWindows(filter);
00402 }
00403 
00404 std::vector<Window> BamfLauncherIcon::WindowsForMonitor(int monitor)
00405 {
00406   WindowFilterMask filter = 0;
00407   filter |= WindowFilter::MAPPED;
00408   filter |= WindowFilter::USER_VISIBLE;
00409   filter |= WindowFilter::ON_CURRENT_DESKTOP;
00410 
00411   return GetWindows(filter, monitor);
00412 }
00413 
00414 std::string BamfLauncherIcon::NameForWindow(Window window)
00415 {
00416   std::string result;
00417   GList* children, *l;
00418 
00419   children = bamf_view_get_children(BAMF_VIEW(_bamf_app.RawPtr()));
00420   for (l = children; l; l = l->next)
00421   {
00422     if (!BAMF_IS_WINDOW(l->data))
00423       continue;
00424 
00425     if (bamf_window_get_xid(static_cast<BamfWindow*>(l->data)) == window)
00426     {
00427       auto view = static_cast<BamfView*>(l->data);
00428       result = glib::String(bamf_view_get_name(view)).Str();
00429       break;
00430     }
00431   }
00432 
00433   g_list_free(children);
00434   return result;
00435 }
00436 
00437 void BamfLauncherIcon::OnWindowMinimized(guint32 xid)
00438 {
00439   if (!OwnsWindow(xid))
00440     return;
00441 
00442   Present(0.5f, 600);
00443   UpdateQuirkTimeDelayed(300, QUIRK_SHIMMER);
00444 }
00445 
00446 void BamfLauncherIcon::OnWindowMoved(guint32 moved_win)
00447 {
00448   if (!OwnsWindow(moved_win))
00449     return;
00450 
00451   auto timeout = std::make_shared<glib::Timeout>(250);
00452   _source_manager.Add(timeout, WINDOW_MOVE_TIMEOUT);
00453 
00454   timeout->Run([&] {
00455     EnsureWindowState();
00456     UpdateIconGeometries(GetCenters());
00457 
00458     return false;
00459   });
00460 }
00461 
00462 void BamfLauncherIcon::UpdateDesktopFile()
00463 {
00464   const char* filename = bamf_application_get_desktop_file(_bamf_app);
00465 
00466   if (filename != nullptr && filename[0] != '\0' && _desktop_file != filename)
00467   {
00468     _desktop_file = filename;
00469 
00470     // add a file watch to the desktop file so that if/when the app is removed
00471     // we can remove ourself from the launcher and when it's changed
00472     // we can update the quicklist.
00473     if (_desktop_file_monitor)
00474       _gsignals.Disconnect(_desktop_file_monitor, "changed");
00475 
00476     glib::Object<GFile> desktop_file(g_file_new_for_path(_desktop_file.c_str()));
00477     _desktop_file_monitor = g_file_monitor_file(desktop_file, G_FILE_MONITOR_NONE,
00478                                                 nullptr, nullptr);
00479     g_file_monitor_set_rate_limit(_desktop_file_monitor, 1000);
00480 
00481     auto sig = new glib::Signal<void, GFileMonitor*, GFile*, GFile*, GFileMonitorEvent>(_desktop_file_monitor, "changed",
00482                                 [&] (GFileMonitor*, GFile*, GFile*, GFileMonitorEvent event_type) {
00483                                   switch (event_type)
00484                                   {
00485                                     case G_FILE_MONITOR_EVENT_DELETED:
00486                                       UnStick();
00487                                       break;
00488                                     case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
00489                                       UpdateDesktopQuickList();
00490                                       UpdateBackgroundColor();
00491                                       break;
00492                                     default:
00493                                       break;
00494                                   }
00495                                 });
00496     _gsignals.Add(sig);
00497   }
00498 }
00499 
00500 std::string BamfLauncherIcon::DesktopFile()
00501 {
00502   UpdateDesktopFile();
00503   return _desktop_file;
00504 }
00505 
00506 std::string BamfLauncherIcon::BamfName() const
00507 {
00508   glib::String name(bamf_view_get_name(BAMF_VIEW(_bamf_app.RawPtr())));
00509   return name.Str();
00510 }
00511 
00512 void BamfLauncherIcon::AddProperties(GVariantBuilder* builder)
00513 {
00514   SimpleLauncherIcon::AddProperties(builder);
00515 
00516   GVariantBuilder xids_builder;
00517   g_variant_builder_init(&xids_builder, G_VARIANT_TYPE ("au"));
00518 
00519   for (auto xid : GetWindows())
00520     g_variant_builder_add(&xids_builder, "u", xid);
00521 
00522   variant::BuilderWrapper(builder)
00523     .add("desktop_file", DesktopFile())
00524     .add("desktop_id", GetDesktopID())
00525     .add("application_id", GPOINTER_TO_UINT(_bamf_app.RawPtr()))
00526     .add("xids", g_variant_builder_end(&xids_builder))
00527     .add("sticky", IsSticky());
00528 }
00529 
00530 bool BamfLauncherIcon::OwnsWindow(Window xid) const
00531 {
00532   GList* children, *l;
00533   bool owns = false;
00534 
00535   if (!xid || !_bamf_app)
00536     return owns;
00537 
00538   children = bamf_view_get_children(BAMF_VIEW(_bamf_app.RawPtr()));
00539 
00540   for (l = children; l; l = l->next)
00541   {
00542     if (!BAMF_IS_WINDOW(l->data))
00543       continue;
00544 
00545     if (bamf_window_get_xid(static_cast<BamfWindow*>(l->data)) == xid)
00546     {
00547       owns = true;
00548       break;
00549     }
00550   }
00551 
00552   g_list_free(children);
00553   return owns;
00554 }
00555 
00556 void BamfLauncherIcon::OpenInstanceWithUris(std::set<std::string> uris)
00557 {
00558   glib::Error error;
00559   glib::Object<GDesktopAppInfo> desktopInfo(g_desktop_app_info_new_from_filename(DesktopFile().c_str()));
00560   auto appInfo = glib::object_cast<GAppInfo>(desktopInfo);
00561 
00562   if (g_app_info_supports_uris(appInfo))
00563   {
00564     GList* list = nullptr;
00565 
00566     for (auto  it : uris)
00567       list = g_list_prepend(list, g_strdup(it.c_str()));
00568 
00569     g_app_info_launch_uris(appInfo, list, nullptr, &error);
00570     g_list_free_full(list, g_free);
00571   }
00572   else if (g_app_info_supports_files(appInfo))
00573   {
00574     GList* list = nullptr;
00575 
00576     for (auto it : uris)
00577     {
00578       GFile* file = g_file_new_for_uri(it.c_str());
00579       list = g_list_prepend(list, file);
00580     }
00581 
00582     g_app_info_launch(appInfo, list, nullptr, &error);
00583     g_list_free_full(list, g_object_unref);
00584   }
00585   else
00586   {
00587     g_app_info_launch(appInfo, nullptr, nullptr, &error);
00588   }
00589 
00590   if (error)
00591     g_warning("%s\n", error.Message().c_str());
00592 
00593   UpdateQuirkTime(QUIRK_STARTING);
00594 }
00595 
00596 void BamfLauncherIcon::OpenInstanceLauncherIcon(ActionArg arg)
00597 {
00598   std::set<std::string> empty;
00599   OpenInstanceWithUris(empty);
00600   ubus_server_send_message(ubus_server_get_default(), UBUS_LAUNCHER_ACTION_DONE, nullptr);
00601 }
00602 
00603 void BamfLauncherIcon::Focus(ActionArg arg)
00604 {
00605   bool any_urgent = false;
00606   bool any_visible = false;
00607   bool any_user_visible = false;
00608   WindowManager* wm = WindowManager::Default();
00609 
00610   std::vector<Window> windows;
00611   GList* children = bamf_view_get_children(BAMF_VIEW(_bamf_app.RawPtr()));
00612 
00613   /* get the list of windows */
00614   for (GList* l = children; l; l = l->next)
00615   {
00616     if (!BAMF_IS_WINDOW(l->data))
00617       continue;
00618 
00619     auto view = static_cast<BamfView*>(l->data);
00620 
00621     Window xid = bamf_window_get_xid(static_cast<BamfWindow*>(l->data));
00622     bool urgent = bamf_view_is_urgent(view);
00623     bool user_visible = bamf_view_user_visible(view);
00624 
00625     if (any_urgent)
00626     {
00627       if (urgent)
00628         windows.push_back(xid);
00629     }
00630     else if (any_user_visible && !urgent)
00631     {
00632       if (user_visible)
00633         windows.push_back(xid);
00634     }
00635     else
00636     {
00637       if (urgent || user_visible)
00638       {
00639         windows.clear();
00640         any_visible = false;
00641         any_urgent = (any_urgent || urgent);
00642         any_user_visible = (any_user_visible || user_visible);
00643       }
00644 
00645       windows.push_back(xid);
00646     }
00647 
00648     if (wm->IsWindowOnCurrentDesktop(xid) && wm->IsWindowVisible(xid))
00649     {
00650       any_visible = true;
00651     }
00652   }
00653 
00654   g_list_free(children);
00655 
00656   auto visibility = WindowManager::FocusVisibility::OnlyVisible;
00657 
00658   if (arg.source != ActionArg::SWITCHER)
00659   {
00660     if (any_visible)
00661     {
00662       visibility = WindowManager::FocusVisibility::ForceUnminimizeInvisible;
00663     }
00664     else
00665     {
00666       visibility = WindowManager::FocusVisibility::ForceUnminimizeOnCurrentDesktop;
00667     }
00668   }
00669 
00670   bool only_top_win = !any_urgent;
00671   wm->FocusWindowGroup(windows, visibility, arg.monitor, only_top_win);
00672 }
00673 
00674 bool BamfLauncherIcon::Spread(bool current_desktop, int state, bool force)
00675 {
00676   auto windows = GetWindows(current_desktop ? WindowFilter::ON_CURRENT_DESKTOP : 0);
00677   return WindowManager::Default()->ScaleWindowGroup(windows, state, force);
00678 }
00679 
00680 void BamfLauncherIcon::EnsureWindowState()
00681 {
00682   GList* children, *l;
00683   std::vector<bool> monitors;
00684   monitors.resize(max_num_monitors);
00685 
00686   children = bamf_view_get_children(BAMF_VIEW(_bamf_app.RawPtr()));
00687   for (l = children; l; l = l->next)
00688   {
00689     if (!BAMF_IS_WINDOW(l->data))
00690       continue;
00691 
00692     auto window = static_cast<BamfWindow*>(l->data);
00693     Window xid = bamf_window_get_xid(window);
00694     int monitor = bamf_window_get_monitor(window);
00695 
00696     if (monitor >= 0 && WindowManager::Default()->IsWindowOnCurrentDesktop(xid))
00697       monitors[monitor] = true;
00698   }
00699 
00700   for (int i = 0; i < max_num_monitors; i++)
00701     SetWindowVisibleOnMonitor(monitors[i], i);
00702 
00703   EmitNeedsRedraw();
00704 
00705   g_list_free(children);
00706 }
00707 
00708 void BamfLauncherIcon::UpdateDesktopQuickList()
00709 {
00710   std::string const& desktop_file = DesktopFile();
00711 
00712   if (desktop_file.empty())
00713     return;
00714 
00715   if (_menu_desktop_shortcuts)
00716   {
00717     for (GList *l = dbusmenu_menuitem_get_children(_menu_desktop_shortcuts); l; l = l->next)
00718     {
00719       _gsignals.Disconnect(l->data, "item-activated");
00720     }
00721   }
00722 
00723   _menu_desktop_shortcuts = dbusmenu_menuitem_new();
00724   dbusmenu_menuitem_set_root(_menu_desktop_shortcuts, TRUE);
00725 
00726   // Build a desktop shortcuts object and tell it that our
00727   // environment is Unity to handle the filtering
00728   _desktop_shortcuts = indicator_desktop_shortcuts_new(desktop_file.c_str(), "Unity");
00729   // This will get us a list of the nicks available, it should
00730   // always be at least one entry of NULL if there either aren't
00731   // any or they're filtered for the environment we're in
00732   const gchar** nicks = indicator_desktop_shortcuts_get_nicks(_desktop_shortcuts);
00733 
00734   int index = 0;
00735   while (nicks[index])
00736   {
00737     // Build a dbusmenu item for each nick that is the desktop
00738     // file that is built from it's name and includes a callback
00739     // to the desktop shortcuts object to execute the nick
00740     glib::String name(indicator_desktop_shortcuts_nick_get_name(_desktop_shortcuts,
00741                                                                 nicks[index]));
00742     glib::Object<DbusmenuMenuitem> item(dbusmenu_menuitem_new());
00743     dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_LABEL, name);
00744     dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
00745     dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
00746     dbusmenu_menuitem_property_set(item, "shortcut-nick", nicks[index]);
00747 
00748     auto sig = new glib::Signal<void, DbusmenuMenuitem*, gint>(item, "item-activated",
00749                                 [&] (DbusmenuMenuitem* item, gint) {
00750                                   const gchar *nick;
00751                                   nick = dbusmenu_menuitem_property_get(item, "shortcut-nick");
00752                                   indicator_desktop_shortcuts_nick_exec(_desktop_shortcuts, nick);
00753                                 });
00754     _gsignals.Add(sig);
00755 
00756     dbusmenu_menuitem_child_append(_menu_desktop_shortcuts, item);
00757     index++;
00758   }
00759 }
00760 
00761 //
00762 // ColorStrToARGB:
00763 // Parses a color string in the form: "#rrggbbaa", where # and aa are optional.
00764 // Returns the color in 32-bit ARGB format: 0xaarrggbb.
00765 //
00766 // In Nux 3.x, this function is superseded by:
00767 //   nux::color::Color(std::string const& hex)
00768 // (even though this function is much smaller and faster)
00769 //
00770 // I would really like to #if NUX_VERSION <= ... around this code, but
00771 // no such integer macro seems to exist in the Nux headers.
00772 //
00773 unsigned int ColorStrToARGB(const char *str)
00774 {
00775   unsigned int ret = 0;
00776   if (str)
00777   {
00778     const char *hex = str[0] == '#' ? str + 1 : str;
00779     int digits = 0, color = 0;
00780     if (sscanf(hex, "%x%n", &color, &digits))
00781     {
00782       if (hex[digits])  // extra characters after the hex
00783         ret = 0;
00784       else if (digits == 6)
00785         ret = (unsigned int)color | 0xff000000;
00786       else if (digits == 8)   // Convert RGBA to ARGB:
00787         ret = ((unsigned int)color >> 8) | ((unsigned int)color << 24);
00788     }
00789   }
00790   return ret;
00791 }
00792 
00793 void BamfLauncherIcon::UpdateBackgroundColor()
00794 {
00795   bool last_use_custom_bg_color = use_custom_bg_color_;
00796   nux::Color last_bg_color(bg_color_);
00797 
00798   std::string const& color = DesktopUtilities::GetBackgroundColor(DesktopFile());
00799 
00800   use_custom_bg_color_ = !color.empty();
00801 
00802   if (use_custom_bg_color_)
00803     bg_color_ = nux::Color(ColorStrToARGB(color.c_str()));
00804 
00805   if (last_use_custom_bg_color != use_custom_bg_color_ ||
00806       last_bg_color != bg_color_)
00807     EmitNeedsRedraw();
00808 }
00809 
00810 void BamfLauncherIcon::UpdateMenus()
00811 {
00812   GList* children, *l;
00813 
00814   children = bamf_view_get_children(BAMF_VIEW(_bamf_app.RawPtr()));
00815   for (l = children; l; l = l->next)
00816   {
00817     if (!BAMF_IS_INDICATOR(l->data))
00818       continue;
00819 
00820     auto indicator = static_cast<BamfIndicator*>(l->data);
00821     std::string path = bamf_indicator_get_dbus_menu_path(indicator);
00822 
00823     // we already have this
00824     if (_menu_clients.find(path) != _menu_clients.end())
00825       continue;
00826 
00827     std::string address = bamf_indicator_get_remote_address(indicator);
00828     DbusmenuClient* client = dbusmenu_client_new(address.c_str(), path.c_str());
00829     _menu_clients[path] = glib::Object<DbusmenuClient>(client);
00830   }
00831 
00832   g_list_free(children);
00833 
00834   // add dynamic quicklist
00835   if (_menuclient_dynamic_quicklist && DBUSMENU_IS_CLIENT(_menuclient_dynamic_quicklist.RawPtr()))
00836   {
00837     if (_menu_clients["dynamicquicklist"] != _menuclient_dynamic_quicklist)
00838     {
00839       _menu_clients["dynamicquicklist"] = _menuclient_dynamic_quicklist;
00840     }
00841   }
00842   else if (_menu_clients["dynamicquicklist"])
00843   {
00844     _menu_clients.erase("dynamicquicklist");
00845     _menuclient_dynamic_quicklist = nullptr;
00846   }
00847 
00848   // make a client for desktop file actions
00849   if (!DBUSMENU_IS_MENUITEM(_menu_desktop_shortcuts.RawPtr()))
00850   {
00851     UpdateDesktopQuickList();
00852   }
00853 }
00854 
00855 void BamfLauncherIcon::Quit()
00856 {
00857   GList* children, *l;
00858 
00859   children = bamf_view_get_children(BAMF_VIEW(_bamf_app.RawPtr()));
00860 
00861   for (l = children; l; l = l->next)
00862   {
00863     if (!BAMF_IS_WINDOW(l->data))
00864       continue;
00865 
00866     Window xid = bamf_window_get_xid(static_cast<BamfWindow*>(l->data));
00867     WindowManager::Default()->Close(xid);
00868   }
00869 
00870   g_list_free(children);
00871 }
00872 
00873 void BamfLauncherIcon::Stick(bool save)
00874 {
00875   if (IsSticky())
00876     return;
00877 
00878   std::string const& desktop_file = DesktopFile();
00879   bamf_view_set_sticky(BAMF_VIEW(_bamf_app.RawPtr()), true);
00880 
00881   if (save && !desktop_file.empty())
00882     FavoriteStore::Instance().AddFavorite(desktop_file, -1);
00883 }
00884 
00885 void BamfLauncherIcon::UnStick()
00886 {
00887   if (!IsSticky())
00888     return;
00889 
00890   std::string const& desktop_file = DesktopFile();
00891   BamfView* view = BAMF_VIEW(_bamf_app.RawPtr());
00892   bamf_view_set_sticky(view, false);
00893 
00894   if (bamf_view_is_closed(view) || !bamf_view_user_visible(view))
00895     Remove();
00896 
00897   if (!desktop_file.empty())
00898     FavoriteStore::Instance().RemoveFavorite(desktop_file);
00899 }
00900 
00901 void BamfLauncherIcon::ToggleSticky()
00902 {
00903   if (IsSticky())
00904   {
00905     UnStick();
00906   }
00907   else
00908   {
00909     Stick();
00910   }
00911 }
00912 
00913 void BamfLauncherIcon::EnsureMenuItemsReady()
00914 {
00915   DbusmenuMenuitem* menu_item;
00916 
00917   /* Pin */
00918   if (_menu_items.find("Pin") == _menu_items.end())
00919   {
00920     menu_item = dbusmenu_menuitem_new();
00921     dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
00922     dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
00923 
00924     _gsignals.Add(new glib::Signal<void, DbusmenuMenuitem*, int>(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
00925                                     [&] (DbusmenuMenuitem*, int) {
00926                                       ToggleSticky();
00927                                     }));
00928 
00929     _menu_items["Pin"] = glib::Object<DbusmenuMenuitem>(menu_item);
00930   }
00931 
00932   const char* label = !IsSticky() ? _("Lock to Launcher") : _("Unlock from Launcher");
00933 
00934   dbusmenu_menuitem_property_set(_menu_items["Pin"], DBUSMENU_MENUITEM_PROP_LABEL, label);
00935 
00936 
00937   /* Quit */
00938   if (_menu_items.find("Quit") == _menu_items.end())
00939   {
00940     menu_item = dbusmenu_menuitem_new();
00941     dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Quit"));
00942     dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
00943     dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
00944 
00945     _gsignals.Add(new glib::Signal<void, DbusmenuMenuitem*, int>(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
00946                                     [&] (DbusmenuMenuitem*, int) {
00947                                       Quit();
00948                                     }));
00949 
00950     _menu_items["Quit"] = glib::Object<DbusmenuMenuitem>(menu_item);
00951   }
00952 }
00953 
00954 std::list<DbusmenuMenuitem*> BamfLauncherIcon::GetMenus()
00955 {
00956   std::list<DbusmenuMenuitem*> result;
00957   bool first_separator_needed = false;
00958   DbusmenuMenuitem* item = nullptr;
00959 
00960   // FIXME for O: hack around the wrong abstraction
00961   UpdateMenus();
00962 
00963   for (auto it = _menu_clients.begin(); it != _menu_clients.end(); ++it)
00964   {
00965     GList* child = nullptr;
00966     DbusmenuClient* client = it->second;
00967     if (!client)
00968       continue;
00969     DbusmenuMenuitem* root = dbusmenu_client_get_root(client);
00970 
00971     if (!root || !dbusmenu_menuitem_property_get_bool(root, DBUSMENU_MENUITEM_PROP_VISIBLE))
00972       continue;
00973 
00974     for (child = dbusmenu_menuitem_get_children(root); child; child = child->next)
00975     {
00976       DbusmenuMenuitem* item = (DbusmenuMenuitem*) child->data;
00977 
00978       if (!item || !DBUSMENU_IS_MENUITEM(item))
00979         continue;
00980 
00981       if (dbusmenu_menuitem_property_get_bool(item, DBUSMENU_MENUITEM_PROP_VISIBLE))
00982       {
00983         first_separator_needed = true;
00984         dbusmenu_menuitem_property_set_bool(item, "unity-use-markup", FALSE);
00985 
00986         result.push_back(item);
00987       }
00988     }
00989   }
00990 
00991   // FIXME: this should totally be added as a _menu_client
00992   if (DBUSMENU_IS_MENUITEM(_menu_desktop_shortcuts.RawPtr()))
00993   {
00994     GList* child = nullptr;
00995 
00996     for (child = dbusmenu_menuitem_get_children(_menu_desktop_shortcuts); child; child = child->next)
00997     {
00998       DbusmenuMenuitem* item = (DbusmenuMenuitem*) child->data;
00999 
01000       if (!item)
01001         continue;
01002 
01003       first_separator_needed = true;
01004 
01005       result.push_back(item);
01006     }
01007   }
01008 
01009   if (first_separator_needed)
01010   {
01011     auto first_sep = _menu_items_extra.find("FirstSeparator");
01012     if (first_sep != _menu_items_extra.end())
01013     {
01014       item = first_sep->second;
01015     }
01016     else
01017     {
01018       item = dbusmenu_menuitem_new();
01019       dbusmenu_menuitem_property_set(item,
01020                                      DBUSMENU_MENUITEM_PROP_TYPE,
01021                                      DBUSMENU_CLIENT_TYPES_SEPARATOR);
01022       _menu_items_extra["FirstSeparator"] = glib::Object<DbusmenuMenuitem>(item);
01023     }
01024     result.push_back(item);
01025   }
01026 
01027   auto app_name_item = _menu_items_extra.find("AppName");
01028   if (app_name_item != _menu_items_extra.end())
01029   {
01030     item = app_name_item->second;
01031   }
01032   else
01033   {
01034     glib::String app_name(g_markup_escape_text(BamfName().c_str(), -1));
01035     std::ostringstream bold_app_name;
01036     bold_app_name << "<b>" << app_name << "</b>";
01037 
01038     item = dbusmenu_menuitem_new();
01039     dbusmenu_menuitem_property_set(item,
01040                                    DBUSMENU_MENUITEM_PROP_LABEL,
01041                                    bold_app_name.str().c_str());
01042     dbusmenu_menuitem_property_set_bool(item,
01043                                         DBUSMENU_MENUITEM_PROP_ENABLED,
01044                                         true);
01045     dbusmenu_menuitem_property_set_bool(item,
01046                                         "unity-use-markup",
01047                                         true);
01048 
01049     _gsignals.Add(new glib::Signal<void, DbusmenuMenuitem*, int>(item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
01050                                     [&] (DbusmenuMenuitem*, int) {
01051                                       auto idle = std::make_shared<glib::Idle>();
01052                                       _source_manager.Add(idle);
01053                                       idle->Run([&] {
01054                                         ActivateLauncherIcon(ActionArg());
01055                                         return false;
01056                                       });
01057                                     }));
01058 
01059     _menu_items_extra["AppName"] = glib::Object<DbusmenuMenuitem>(item);
01060   }
01061   result.push_back(item);
01062 
01063   auto second_sep = _menu_items_extra.find("SecondSeparator");
01064   if (second_sep != _menu_items_extra.end())
01065   {
01066     item = second_sep->second;
01067   }
01068   else
01069   {
01070     item = dbusmenu_menuitem_new();
01071     dbusmenu_menuitem_property_set(item,
01072                                    DBUSMENU_MENUITEM_PROP_TYPE,
01073                                    DBUSMENU_CLIENT_TYPES_SEPARATOR);
01074     _menu_items_extra["SecondSeparator"] = glib::Object<DbusmenuMenuitem>(item);
01075   }
01076   result.push_back(item);
01077 
01078   EnsureMenuItemsReady();
01079 
01080   for (auto it_m = _menu_items.begin(); it_m != _menu_items.end(); ++it_m)
01081   {
01082     if (!IsRunning() && it_m->first == "Quit")
01083       continue;
01084 
01085     bool exists = false;
01086     std::string label_default(dbusmenu_menuitem_property_get(it_m->second, DBUSMENU_MENUITEM_PROP_LABEL));
01087 
01088     for (auto menu_item : result)
01089     {
01090       const gchar* type = dbusmenu_menuitem_property_get(menu_item, DBUSMENU_MENUITEM_PROP_TYPE);
01091       if (type == nullptr)//(g_strcmp0 (type, DBUSMENU_MENUITEM_PROP_LABEL) == 0)
01092       {
01093         std::string label_menu(dbusmenu_menuitem_property_get(menu_item, DBUSMENU_MENUITEM_PROP_LABEL));
01094         if (label_menu == label_default)
01095         {
01096           exists = true;
01097           break;
01098         }
01099       }
01100     }
01101 
01102     if (!exists)
01103       result.push_back(it_m->second);
01104   }
01105 
01106   return result;
01107 }
01108 
01109 void BamfLauncherIcon::UpdateIconGeometries(std::vector<nux::Point3> center)
01110 {
01111   GList* children, *l;
01112   nux::Geometry geo;
01113 
01114   geo.width = 48;
01115   geo.height = 48;
01116 
01117   children = bamf_view_get_children(BAMF_VIEW(_bamf_app.RawPtr()));
01118 
01119   for (l = children; l; l = l->next)
01120   {
01121     if (!BAMF_IS_WINDOW(l->data))
01122       continue;
01123 
01124     Window xid = bamf_window_get_xid(static_cast<BamfWindow*>(l->data));
01125     int monitor = bamf_window_get_monitor(static_cast<BamfWindow*>(l->data));
01126     monitor = std::max<int>(0, std::min<int>(center.size() - 1, monitor));
01127 
01128     geo.x = center[monitor].x - 24;
01129     geo.y = center[monitor].y - 24;
01130     WindowManager::Default()->SetWindowIconGeometry(xid, geo);
01131   }
01132 
01133   g_list_free(children);
01134 }
01135 
01136 void BamfLauncherIcon::OnCenterStabilized(std::vector<nux::Point3> center)
01137 {
01138   UpdateIconGeometries(center);
01139 }
01140 
01141 std::string BamfLauncherIcon::GetDesktopID()
01142 {
01143   std::string const& desktop_file = DesktopFile();
01144 
01145   return DesktopUtilities::GetDesktopID(desktop_file);
01146 }
01147 
01148 std::string BamfLauncherIcon::GetRemoteUri()
01149 {
01150   if (_remote_uri.empty())
01151   {
01152     const std::string prefix = "application://";
01153     std::string const& desktop_id = GetDesktopID();
01154 
01155     if (!desktop_id.empty())
01156     {
01157       _remote_uri = prefix + desktop_id;
01158     }
01159   }
01160 
01161   return _remote_uri;
01162 }
01163 
01164 std::set<std::string> BamfLauncherIcon::ValidateUrisForLaunch(DndData const& uris)
01165 {
01166   std::set<std::string> result;
01167 
01168   for (auto uri : uris.Uris())
01169     result.insert(uri);
01170 
01171   return result;
01172 }
01173 
01174 void BamfLauncherIcon::OnDndHovered()
01175 {
01176   // for now, let's not do this, it turns out to be quite buggy
01177   //if (IsRunning())
01178   //  Spread(CompAction::StateInitEdgeDnd, true);
01179 }
01180 
01181 void BamfLauncherIcon::OnDndEnter()
01182 {
01183   /* Disabled, since the DND code is currently disabled as well.
01184   auto timeout = std::make_shared<glib::Timeout>(1000);
01185   _source_manager.Add(timeout, ICON_DND_OVER_TIMEOUT);
01186   timeout->Run([&] { OnDndHovered(); return false; });
01187   */
01188 }
01189 
01190 void BamfLauncherIcon::OnDndLeave()
01191 {
01192   /* Disabled, since the DND code is currently disabled as well.
01193   _source_manager.Remove(ICON_DND_OVER_TIMEOUT);
01194   */
01195 }
01196 
01197 bool BamfLauncherIcon::OnShouldHighlightOnDrag(DndData const& dnd_data)
01198 {
01199   bool is_home_launcher = boost::algorithm::ends_with(DesktopFile(), "nautilus-home.desktop") ||
01200                           boost::algorithm::ends_with(DesktopFile(), "nautilus.desktop");
01201 
01202   if (is_home_launcher)
01203   {
01204     return true;
01205   }
01206 
01207   for (auto type : dnd_data.Types())
01208   {
01209     for (auto supported_type : GetSupportedTypes())
01210     {
01211       if (g_content_type_is_a(type.c_str(), supported_type.c_str()))
01212       {
01213         if (!dnd_data.UrisByType(type).empty())
01214           return true;
01215       }
01216     }
01217   }
01218 
01219   return false;
01220 }
01221 
01222 nux::DndAction BamfLauncherIcon::OnQueryAcceptDrop(DndData const& dnd_data)
01223 {
01224   return ValidateUrisForLaunch(dnd_data).empty() ? nux::DNDACTION_NONE : nux::DNDACTION_COPY;
01225 }
01226 
01227 void BamfLauncherIcon::OnAcceptDrop(DndData const& dnd_data)
01228 {
01229   OpenInstanceWithUris(ValidateUrisForLaunch(dnd_data));
01230 }
01231 
01232 bool BamfLauncherIcon::ShowInSwitcher(bool current)
01233 {
01234   bool result = false;
01235 
01236   if (IsRunning() && IsVisible())
01237   {
01238     // If current is true, we only want to show the current workspace.
01239     if (!current)
01240     {
01241       result = true;
01242     }
01243     else
01244     {
01245       for (int i = 0; i < max_num_monitors; i++)
01246       {
01247         if (WindowVisibleOnMonitor(i))
01248         {
01249           result = true;
01250           break;
01251         }
01252       }
01253     }
01254   }
01255 
01256   return result;
01257 }
01258 
01259 unsigned long long BamfLauncherIcon::SwitcherPriority()
01260 {
01261   GList* children, *l;
01262   unsigned long long result = 0;
01263 
01264   children = bamf_view_get_children(BAMF_VIEW(_bamf_app.RawPtr()));
01265 
01266   /* get the list of windows */
01267   for (l = children; l; l = l->next)
01268   {
01269     if (!BAMF_IS_WINDOW(l->data))
01270       continue;
01271 
01272     Window xid = bamf_window_get_xid(static_cast<BamfWindow*>(l->data));
01273     result = std::max(result, WindowManager::Default()->GetWindowActiveNumber(xid));
01274   }
01275 
01276   g_list_free(children);
01277   return result;
01278 }
01279 
01280 nux::Color BamfLauncherIcon::BackgroundColor() const
01281 {
01282   if (use_custom_bg_color_)
01283     return bg_color_;
01284 
01285   return SimpleLauncherIcon::BackgroundColor();
01286 }
01287 
01288 const std::set<std::string>& BamfLauncherIcon::GetSupportedTypes()
01289 {
01290   if (!_supported_types_filled)
01291     FillSupportedTypes();
01292 
01293   return _supported_types;
01294 }
01295 
01296 void BamfLauncherIcon::FillSupportedTypes()
01297 {
01298   if (!_supported_types_filled)
01299   {
01300     _supported_types_filled = true;
01301     _supported_types.clear();
01302 
01303     std::string const& desktop_file = DesktopFile();
01304 
01305     if (desktop_file.empty())
01306       return;
01307 
01308     GKeyFile* key_file = g_key_file_new();
01309     glib::Error error;
01310 
01311     g_key_file_load_from_file(key_file, desktop_file.c_str(), (GKeyFileFlags) 0, &error);
01312 
01313     if (error)
01314     {
01315       g_key_file_free(key_file);
01316       return;
01317     }
01318 
01319     char** mimes = g_key_file_get_string_list(key_file, "Desktop Entry", "MimeType", nullptr, nullptr);
01320     if (!mimes)
01321     {
01322       g_key_file_free(key_file);
01323       return;
01324     }
01325 
01326     for (int i = 0; mimes[i]; i++)
01327     {
01328       unity::glib::String super_type(g_content_type_from_mime_type(mimes[i]));
01329       _supported_types.insert(super_type.Str());
01330     }
01331 
01332     g_key_file_free(key_file);
01333     g_strfreev(mimes);
01334   }
01335 }
01336 
01337 std::string BamfLauncherIcon::GetName() const
01338 {
01339   return "BamfLauncherIcon";
01340 }
01341 
01342 } // namespace launcher
01343 } // namespace unity