1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/ui/gtk/gconf_titlebar_listener.h" 6 7 #include <gtk/gtk.h> 8 9 #include "base/environment.h" 10 #include "base/memory/scoped_ptr.h" 11 #include "base/memory/singleton.h" 12 #include "base/nix/xdg_util.h" 13 #include "chrome/browser/ui/gtk/browser_titlebar.h" 14 15 namespace { 16 17 // The GConf key we read for the button placement string. Even through the key 18 // has "metacity" in it, it's shared between metacity and compiz. 19 const char* kButtonLayoutKey = "/apps/metacity/general/button_layout"; 20 21 // GConf requires us to subscribe to a parent directory before we can subscribe 22 // to changes in an individual key in that directory. 23 const char* kMetacityGeneral = "/apps/metacity/general"; 24 25 } // namespace 26 27 // Public interface: 28 29 // static 30 GConfTitlebarListener* GConfTitlebarListener::GetInstance() { 31 return Singleton<GConfTitlebarListener>::get(); 32 } 33 34 void GConfTitlebarListener::SetTitlebarButtons(BrowserTitlebar* titlebar) { 35 if (client_) { 36 titlebar->BuildButtons(current_value_); 37 titlebars_.insert(titlebar); 38 } else { 39 titlebar->BuildButtons(BrowserTitlebar::kDefaultButtonString); 40 } 41 } 42 43 void GConfTitlebarListener::RemoveObserver(BrowserTitlebar* titlebar) { 44 titlebars_.erase(titlebar); 45 } 46 47 // Protected: 48 49 GConfTitlebarListener::~GConfTitlebarListener() {} 50 51 // Private: 52 53 GConfTitlebarListener::GConfTitlebarListener() : client_(NULL) { 54 scoped_ptr<base::Environment> env(base::Environment::Create()); 55 if (base::nix::GetDesktopEnvironment(env.get()) == 56 base::nix::DESKTOP_ENVIRONMENT_GNOME) { 57 client_ = gconf_client_get_default(); 58 // If we fail to get a context, that's OK, since we'll just fallback on 59 // not receiving gconf keys. 60 if (client_) { 61 // Get the initial value of the key. 62 GError* error = NULL; 63 GConfValue* gconf_value = gconf_client_get(client_, kButtonLayoutKey, 64 &error); 65 if (HandleGError(error, kButtonLayoutKey)) 66 return; 67 ParseAndStoreValue(gconf_value); 68 if (gconf_value) 69 gconf_value_free(gconf_value); 70 71 // Register that we're interested in the values of this directory. 72 gconf_client_add_dir(client_, kMetacityGeneral, 73 GCONF_CLIENT_PRELOAD_ONELEVEL, &error); 74 if (HandleGError(error, kMetacityGeneral)) 75 return; 76 77 // Register to get notifies about changes to this key. 78 gconf_client_notify_add( 79 client_, kButtonLayoutKey, 80 reinterpret_cast<void (*)(GConfClient*, guint, GConfEntry*, void*)>( 81 OnChangeNotificationThunk), 82 this, NULL, &error); 83 if (HandleGError(error, kButtonLayoutKey)) 84 return; 85 } 86 } 87 } 88 89 void GConfTitlebarListener::OnChangeNotification(GConfClient* client, 90 guint cnxn_id, 91 GConfEntry* entry) { 92 if (strcmp(gconf_entry_get_key(entry), kButtonLayoutKey) == 0) { 93 GConfValue* gconf_value = gconf_entry_get_value(entry); 94 ParseAndStoreValue(gconf_value); 95 96 // Broadcast the new configuration to all windows: 97 for (std::set<BrowserTitlebar*>::const_iterator it = titlebars_.begin(); 98 it != titlebars_.end(); ++it) { 99 (*it)->BuildButtons(current_value_); 100 } 101 } 102 } 103 104 bool GConfTitlebarListener::HandleGError(GError* error, const char* key) { 105 if (error != NULL) { 106 LOG(ERROR) << "Error with gconf key '" << key << "': " << error->message; 107 g_error_free(error); 108 g_object_unref(client_); 109 client_ = NULL; 110 return true; 111 } 112 return false; 113 } 114 115 void GConfTitlebarListener::ParseAndStoreValue(GConfValue* gconf_value) { 116 if (gconf_value) { 117 const char* value = gconf_value_get_string(gconf_value); 118 current_value_ = value ? value : BrowserTitlebar::kDefaultButtonString; 119 } else { 120 current_value_ = BrowserTitlebar::kDefaultButtonString; 121 } 122 } 123