1ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// Copyright 2013 The Chromium Authors. All rights reserved. 2ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// Use of this source code is governed by a BSD-style license that can be 3ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// found in the LICENSE file. 4ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 5ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "chrome/browser/ui/libgtk2ui/app_indicator_icon.h" 6ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 7ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include <gtk/gtk.h> 8ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include <dlfcn.h> 9ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 10ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/bind.h" 1146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "base/environment.h" 12ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/file_util.h" 1346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "base/md5.h" 14ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/memory/ref_counted_memory.h" 1546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "base/nix/xdg_util.h" 16ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/strings/stringprintf.h" 17ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/strings/utf_string_conversions.h" 18ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/threading/sequenced_worker_pool.h" 1946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "chrome/browser/ui/libgtk2ui/app_indicator_icon_menu.h" 20ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "content/public/browser/browser_thread.h" 21ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "ui/base/models/menu_model.h" 2246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "ui/gfx/image/image.h" 23ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "ui/gfx/image/image_skia.h" 24ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 25ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochnamespace { 26ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 27ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochtypedef enum { 28ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch APP_INDICATOR_CATEGORY_APPLICATION_STATUS, 29ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch APP_INDICATOR_CATEGORY_COMMUNICATIONS, 30ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch APP_INDICATOR_CATEGORY_SYSTEM_SERVICES, 31ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch APP_INDICATOR_CATEGORY_HARDWARE, 32ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch APP_INDICATOR_CATEGORY_OTHER 33ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch} AppIndicatorCategory; 34ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 35ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochtypedef enum { 36ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch APP_INDICATOR_STATUS_PASSIVE, 37ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch APP_INDICATOR_STATUS_ACTIVE, 38ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch APP_INDICATOR_STATUS_ATTENTION 39ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch} AppIndicatorStatus; 40ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 41ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochtypedef AppIndicator* (*app_indicator_new_func)(const gchar* id, 42ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch const gchar* icon_name, 43ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch AppIndicatorCategory category); 44ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 45ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochtypedef AppIndicator* (*app_indicator_new_with_path_func)( 46ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch const gchar* id, 47ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch const gchar* icon_name, 48ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch AppIndicatorCategory category, 49ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch const gchar* icon_theme_path); 50ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 51ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochtypedef void (*app_indicator_set_status_func)(AppIndicator* self, 52ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch AppIndicatorStatus status); 53ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 54ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochtypedef void (*app_indicator_set_attention_icon_full_func)( 55ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch AppIndicator* self, 56ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch const gchar* icon_name, 57ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch const gchar* icon_desc); 58ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 59ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochtypedef void (*app_indicator_set_menu_func)(AppIndicator* self, GtkMenu* menu); 60ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 61ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochtypedef void (*app_indicator_set_icon_full_func)(AppIndicator* self, 62ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch const gchar* icon_name, 63ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch const gchar* icon_desc); 64ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 65ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochtypedef void (*app_indicator_set_icon_theme_path_func)( 66ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch AppIndicator* self, 67ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch const gchar* icon_theme_path); 68ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool g_attempted_load = false; 704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool g_opened = false; 71ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 72ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// Retrieved functions from libappindicator. 73ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochapp_indicator_new_func app_indicator_new = NULL; 74ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochapp_indicator_new_with_path_func app_indicator_new_with_path = NULL; 75ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochapp_indicator_set_status_func app_indicator_set_status = NULL; 76ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochapp_indicator_set_attention_icon_full_func 77ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch app_indicator_set_attention_icon_full = NULL; 78ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochapp_indicator_set_menu_func app_indicator_set_menu = NULL; 79ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochapp_indicator_set_icon_full_func app_indicator_set_icon_full = NULL; 80ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochapp_indicator_set_icon_theme_path_func app_indicator_set_icon_theme_path = NULL; 81ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 82ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid EnsureMethodsLoaded() { 834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (g_attempted_load) 84ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch return; 854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) g_attempted_load = true; 87ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 88f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Only use libappindicator where it is needed to support dbus based status 89f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // icons. In particular, libappindicator does not support a click action. 90f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) scoped_ptr<base::Environment> env(base::Environment::Create()); 91f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) base::nix::DesktopEnvironment environment = 92f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) base::nix::GetDesktopEnvironment(env.get()); 93f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (environment != base::nix::DESKTOP_ENVIRONMENT_KDE4 && 94f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) environment != base::nix::DESKTOP_ENVIRONMENT_UNITY) { 95f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return; 96f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 97f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 98ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch void* indicator_lib = dlopen("libappindicator.so", RTLD_LAZY); 99ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch if (!indicator_lib) { 100ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch indicator_lib = dlopen("libappindicator.so.1", RTLD_LAZY); 101ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch } 102ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch if (!indicator_lib) { 103ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch indicator_lib = dlopen("libappindicator.so.0", RTLD_LAZY); 104ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch } 105ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch if (!indicator_lib) { 106ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch return; 107ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch } 108ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 1094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) g_opened = true; 110ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 111ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch app_indicator_new = reinterpret_cast<app_indicator_new_func>( 112ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch dlsym(indicator_lib, "app_indicator_new")); 113ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 114ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch app_indicator_new_with_path = 115ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch reinterpret_cast<app_indicator_new_with_path_func>( 116ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch dlsym(indicator_lib, "app_indicator_new_with_path")); 117ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 118ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch app_indicator_set_status = reinterpret_cast<app_indicator_set_status_func>( 119ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch dlsym(indicator_lib, "app_indicator_set_status")); 120ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 121ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch app_indicator_set_attention_icon_full = 122ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch reinterpret_cast<app_indicator_set_attention_icon_full_func>( 123ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch dlsym(indicator_lib, "app_indicator_set_attention_icon_full")); 124ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 125ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch app_indicator_set_menu = reinterpret_cast<app_indicator_set_menu_func>( 126ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch dlsym(indicator_lib, "app_indicator_set_menu")); 127ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 128ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch app_indicator_set_icon_full = 129ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch reinterpret_cast<app_indicator_set_icon_full_func>( 130ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch dlsym(indicator_lib, "app_indicator_set_icon_full")); 131ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 132ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch app_indicator_set_icon_theme_path = 133ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch reinterpret_cast<app_indicator_set_icon_theme_path_func>( 134ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch dlsym(indicator_lib, "app_indicator_set_icon_theme_path")); 135ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch} 136ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 13746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// Returns whether a temporary directory should be created for each app 13846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// indicator image. 13946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)bool ShouldCreateTempDirectoryPerImage(bool using_kde4) { 14046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) // Create a new temporary directory for each image on Unity since using a 14146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) // single temporary directory seems to have issues when changing icons in 14246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) // quick succession. 14346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) return !using_kde4; 14446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)} 14546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 14646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// Returns the subdirectory of |temp_dir| in which the app indicator image 14746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// should be saved. 14846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)base::FilePath GetImageDirectoryPath(bool using_kde4, 14946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) const base::FilePath& temp_dir) { 15046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) // On KDE4, an image located in a directory ending with 15146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) // "icons/hicolor/16x16/apps" can be used as the app indicator image because 15246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) // "/usr/share/icons/hicolor/16x16/apps" exists. 15346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) return using_kde4 ? 15446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) temp_dir.AppendASCII("icons").AppendASCII("hicolor").AppendASCII("16x16"). 15546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) AppendASCII("apps") : 15646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) temp_dir; 15746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)} 15846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 15946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)std::string GetImageFileNameForKDE4( 16046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) const scoped_refptr<base::RefCountedMemory>& png_data) { 16146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) // On KDE4, the name of the image file for each different looking bitmap must 16246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) // be unique. It must also be unique across runs of Chrome. 16346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) base::MD5Digest digest; 16446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) base::MD5Sum(png_data->front_as<char>(), png_data->size(), &digest); 16546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) return base::StringPrintf("chrome_app_indicator_%s.png", 16646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) base::MD5DigestToBase16(digest).c_str()); 16746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)} 16846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 16946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)std::string GetImageFileNameForNonKDE4(int icon_change_count, 17046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) const std::string& id) { 17146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) return base::StringPrintf("%s_%d.png", id.c_str(), icon_change_count); 17246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)} 17346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 17446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// Returns the "icon theme path" given the file path of the app indicator image. 17546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)std::string GetIconThemePath(bool using_kde4, 17646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) const base::FilePath& image_path) { 17746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) return using_kde4 ? 17846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) image_path.DirName().DirName().DirName().DirName().value() : 17946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) image_path.DirName().value(); 18046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)} 18146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 18246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)base::FilePath CreateTempImageFile(bool using_kde4, 18346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) gfx::ImageSkia* image_ptr, 1844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) int icon_change_count, 18546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) std::string id, 18646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) const base::FilePath& previous_file_path) { 1874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) scoped_ptr<gfx::ImageSkia> image(image_ptr); 1884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) scoped_refptr<base::RefCountedMemory> png_data = 1904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) gfx::Image(*image.get()).As1xPNGBytes(); 1914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (png_data->size() == 0) { 1924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // If the bitmap could not be encoded to PNG format, skip it. 1934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) LOG(WARNING) << "Could not encode icon"; 1944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return base::FilePath(); 1954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 1964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::FilePath new_file_path; 19846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) if (previous_file_path.empty() || 19946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) ShouldCreateTempDirectoryPerImage(using_kde4)) { 20046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) base::FilePath tmp_dir; 20146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) if (!base::CreateNewTempDirectory(base::FilePath::StringType(), &tmp_dir)) 20246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) return base::FilePath(); 20346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) new_file_path = GetImageDirectoryPath(using_kde4, tmp_dir); 20446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) if (new_file_path != tmp_dir) { 20546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) if (!base::CreateDirectory(new_file_path)) 20646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) return base::FilePath(); 20746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) } 20846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) } else { 20946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) new_file_path = previous_file_path.DirName(); 21046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) } 21146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 21246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) new_file_path = new_file_path.Append(using_kde4 ? 21346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) GetImageFileNameForKDE4(png_data) : 21446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) GetImageFileNameForNonKDE4(icon_change_count, id)); 2154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 2164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) int bytes_written = 217a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::WriteFile(new_file_path, 218a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) png_data->front_as<char>(), png_data->size()); 2194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 2204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (bytes_written != static_cast<int>(png_data->size())) 2214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return base::FilePath(); 2224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return new_file_path; 2234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 2244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 22546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void DeleteTempDirectory(const base::FilePath& dir_path) { 22646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) if (dir_path.empty()) 2274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return; 22846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) base::DeleteFile(dir_path, true); 2294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 2304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 231ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch} // namespace 232ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 233ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochnamespace libgtk2ui { 234ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 235a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)AppIndicatorIcon::AppIndicatorIcon(std::string id, 236a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) const gfx::ImageSkia& image, 237a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const base::string16& tool_tip) 238ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch : id_(id), 23946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) using_kde4_(false), 240ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch icon_(NULL), 241ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch menu_model_(NULL), 242ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch icon_change_count_(0), 2431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) weak_factory_(this) { 24446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) scoped_ptr<base::Environment> env(base::Environment::Create()); 24546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) using_kde4_ = base::nix::GetDesktopEnvironment(env.get()) == 24646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) base::nix::DESKTOP_ENVIRONMENT_KDE4; 24746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 248ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch EnsureMethodsLoaded(); 2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) tool_tip_ = base::UTF16ToUTF8(tool_tip); 250a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) SetImage(image); 251ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch} 252ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben MurdochAppIndicatorIcon::~AppIndicatorIcon() { 253ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch if (icon_) { 254ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch app_indicator_set_status(icon_, APP_INDICATOR_STATUS_PASSIVE); 255ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch g_object_unref(icon_); 256ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch content::BrowserThread::GetBlockingPool()->PostTask( 257ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch FROM_HERE, 25846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) base::Bind(&DeleteTempDirectory, icon_file_path_.DirName())); 259ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch } 260ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch} 261ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 2624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// static 263ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochbool AppIndicatorIcon::CouldOpen() { 264ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch EnsureMethodsLoaded(); 2654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return g_opened; 266ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch} 267ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 268ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid AppIndicatorIcon::SetImage(const gfx::ImageSkia& image) { 2694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!g_opened) 270a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return; 271a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 272a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) ++icon_change_count_; 273a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 274a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // We create a deep copy of the image since it may have been freed by the time 275a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // it's accessed in the other thread. 276a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) scoped_ptr<gfx::ImageSkia> safe_image(image.DeepCopy()); 277a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) base::PostTaskAndReplyWithResult( 278a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) content::BrowserThread::GetBlockingPool() 279a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) ->GetTaskRunnerWithShutdownBehavior( 280a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) base::SequencedWorkerPool::SKIP_ON_SHUTDOWN).get(), 281a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) FROM_HERE, 2824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::Bind(&CreateTempImageFile, 28346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) using_kde4_, 284a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) safe_image.release(), 285a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) icon_change_count_, 28646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) id_, 28746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) icon_file_path_), 288a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) base::Bind(&AppIndicatorIcon::SetImageFromFile, 2891e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) weak_factory_.GetWeakPtr())); 290ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch} 291ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 292ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid AppIndicatorIcon::SetPressedImage(const gfx::ImageSkia& image) { 293ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // Ignore pressed images, since the standard on Linux is to not highlight 294ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // pressed status icons. 295ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch} 296ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 297a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void AppIndicatorIcon::SetToolTip(const base::string16& tool_tip) { 298a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) DCHECK(!tool_tip_.empty()); 2995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) tool_tip_ = base::UTF16ToUTF8(tool_tip); 30046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) UpdateClickActionReplacementMenuItem(); 301ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch} 302ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 303ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid AppIndicatorIcon::UpdatePlatformContextMenu(ui::MenuModel* model) { 3044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!g_opened) 305ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch return; 306ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 307ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch menu_model_ = model; 308ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 309a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // The icon is created asynchronously so it might not exist when the menu is 310a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // set. 311a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (icon_) 312ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch SetMenu(); 313ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch} 314ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 315424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)void AppIndicatorIcon::RefreshPlatformContextMenu() { 31646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) menu_->Refresh(); 317424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)} 318424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 3194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void AppIndicatorIcon::SetImageFromFile(const base::FilePath& icon_file_path) { 320e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 3214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (icon_file_path.empty()) 3224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return; 3234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 3244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::FilePath old_path = icon_file_path_; 3254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) icon_file_path_ = icon_file_path; 3264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 3274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) std::string icon_name = 3284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) icon_file_path_.BaseName().RemoveExtension().value(); 32946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) std::string icon_dir = GetIconThemePath(using_kde4_, icon_file_path); 3304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!icon_) { 3314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) icon_ = 3324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) app_indicator_new_with_path(id_.c_str(), 3334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) icon_name.c_str(), 3344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) APP_INDICATOR_CATEGORY_APPLICATION_STATUS, 3354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) icon_dir.c_str()); 3364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) app_indicator_set_status(icon_, APP_INDICATOR_STATUS_ACTIVE); 3374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) SetMenu(); 3384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } else { 3394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // Currently we are creating a new temp directory every time the icon is 3404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // set. So we need to set the directory each time. 3414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) app_indicator_set_icon_theme_path(icon_, icon_dir.c_str()); 3424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) app_indicator_set_icon_full(icon_, icon_name.c_str(), "icon"); 3434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 34446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) if (ShouldCreateTempDirectoryPerImage(using_kde4_)) { 34546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) // Delete previous icon directory. 34646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) content::BrowserThread::GetBlockingPool()->PostTask( 34746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) FROM_HERE, 34846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) base::Bind(&DeleteTempDirectory, old_path.DirName())); 34946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) } 350ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch } 351ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch} 352ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 353ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid AppIndicatorIcon::SetMenu() { 35446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) menu_.reset(new AppIndicatorIconMenu(menu_model_)); 35546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) UpdateClickActionReplacementMenuItem(); 35646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) app_indicator_set_menu(icon_, menu_->GetGtkMenu()); 357ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch} 358ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 35946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void AppIndicatorIcon::UpdateClickActionReplacementMenuItem() { 36046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) // The menu may not have been created yet. 36146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) if (!menu_.get()) 36246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) return; 363ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 36446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) if (!delegate()->HasClickAction() && menu_model_) 36546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) return; 366ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 36746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) DCHECK(!tool_tip_.empty()); 36846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) menu_->UpdateClickActionReplacementMenuItem( 36946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) tool_tip_.c_str(), 37046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) base::Bind(&AppIndicatorIcon::OnClickActionReplacementMenuItemActivated, 37146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) base::Unretained(this))); 372ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch} 373ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 37446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void AppIndicatorIcon::OnClickActionReplacementMenuItemActivated() { 375ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch if (delegate()) 376ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch delegate()->OnClick(); 377ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch} 378ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 379ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch} // namespace libgtk2ui 380