Chromium Code Reviews| Index: chrome/browser/ui/gtk/xfwm_titlebar_listener.cc |
| =================================================================== |
| --- chrome/browser/ui/gtk/xfwm_titlebar_listener.cc (revision 0) |
| +++ chrome/browser/ui/gtk/xfwm_titlebar_listener.cc (revision 0) |
| @@ -0,0 +1,194 @@ |
| +// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "chrome/browser/ui/gtk/xfwm_titlebar_listener.h" |
| + |
| +#include "base/memory/scoped_ptr.h" |
| +#include "chrome/browser/ui/gtk/browser_titlebar.h" |
| +#include "content/public/browser/browser_thread.h" |
| +#include "dbus/bus.h" |
| +#include "dbus/message.h" |
| +#include "dbus/object_proxy.h" |
| + |
| +using content::BrowserThread; |
| + |
| +namespace { |
| + |
| +// Converts |xfwm4_value| from XFWM4's format to the Metacity format. |
| +std::string ToMetacityFormat(const std::string& xfwm4_value) { |
| + std::string retval; |
| + for (size_t i = 0; i < xfwm4_value.length(); ++i) { |
| + switch (xfwm4_value[i]) { |
| + // The left/right separator. |
| + case '|': |
| + if (retval[retval.length() - 1] == ',') |
| + retval[retval.length() - 1] = ':'; |
| + else |
| + retval.push_back(':'); |
| + break; |
| + // Close. |
| + case 'C': |
| + retval.append("close,"); |
| + break; |
| + // Hide AKA minimize. |
| + case 'H': |
| + retval.append("minimize,"); |
| + break; |
| + // Maximze. |
| + case 'M': |
| + retval.append("maximize,"); |
| + break; |
| + // We don't care about Options, Shade, and Stick. |
| + case 'O': |
| + case 'S': |
| + case 'T': |
| + break; |
| + // XFWM4 does not define any other valid values. |
| + default: |
| + NOTREACHED(); |
| + break; |
| + } |
| + } |
| + // Trim trailing comma if there is one. |
| + if (retval[retval.length() - 1] == ',') |
| + retval.erase(retval.length() - 1); |
| + LOG(ERROR) << "ToMetacityFormat " << xfwm4_value << " -> " << retval; |
| + return retval; |
| +} |
| + |
| +const char kXfconfService[] = "org.xfce.Xfconf"; |
| +const char kXfconfPath[] = "/org/xfce/Xfconf"; |
| +const char kXfconfInterface[] = "org.xfce.Xfconf"; |
| +const char kXfconfGetPropertyMethod[] = "GetProperty"; |
| +const char kXfconfPropertyChangedSignal[] = "PropertyChanged"; |
| + |
| +const char kXfwm4Channel[] = "xfwm4"; |
| +const char kXfwm4ButtonLayoutProperty[] = "/general/button_layout"; |
| + |
| +} // namespace |
| + |
| +XfwmTitlebarListener::XfwmTitlebarListener() |
| + : object_proxy_(NULL), |
| + init_event_(false, false), |
| + weak_ptr_factory_(this) {} |
| + |
| +XfwmTitlebarListener::~XfwmTitlebarListener() {} |
| + |
| +bool XfwmTitlebarListener::Init() { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + |
| + dbus::Bus::Options options; |
| + options.bus_type = dbus::Bus::SESSION; |
| + options.connection_type = dbus::Bus::PRIVATE; |
| + options.dbus_thread_message_loop_proxy = |
| + BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE); |
| + session_bus_ = new dbus::Bus(options); |
| + object_proxy_ = session_bus_->GetObjectProxy(kXfconfService, |
| + dbus::ObjectPath(kXfconfPath)); |
| + |
| + // Whether retrieving the DBus setting succeeded or not. |
| + // Written on the FILE thread before |init_event_| fires and read from the UI |
| + // tread after |init_event_| fires. |
| + bool succeeded = false; |
| + // Ditto, but stores the current button values from DBus. |
| + std::string current_value; |
| + |
| + BrowserThread::PostTask( |
| + BrowserThread::FILE, FROM_HERE, |
| + base::Bind(&XfwmTitlebarListener::GetCurrentButtonSettingOnFileThread, |
| + this, |
| + &succeeded, |
| + ¤t_value)); |
| + init_event_.Wait(); |
|
satorux1
2012/11/01 04:09:08
I'd suggest to call kXfconfGetPropertyMethod async
|
| + |
| + if (!succeeded) |
| + return false; |
| + |
| + current_value_ = current_value; |
| + object_proxy_->ConnectToSignal( |
| + kXfconfInterface, |
| + kXfconfPropertyChangedSignal, |
| + base::Bind(&XfwmTitlebarListener::OnPropertyChangedSignal, |
| + weak_ptr_factory_.GetWeakPtr()), |
| + base::Bind(&XfwmTitlebarListener::OnPropertyChangedSignalConnected, |
| + weak_ptr_factory_.GetWeakPtr())); |
| + |
| + return true; |
| +} |
| + |
| +std::string XfwmTitlebarListener::GetCurrentValue() { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + return current_value_; |
| +} |
| + |
| +void XfwmTitlebarListener::OnPropertyChangedSignalConnected( |
| + const std::string& interface, |
| + const std::string& signal, |
| + bool succeeded) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + DCHECK_EQ(kXfconfInterface, interface); |
| + DCHECK_EQ(kXfconfPropertyChangedSignal, signal); |
| + |
| + if (!succeeded) |
| + LOG(ERROR) << "Connect to " << interface << " " << signal << " failed."; |
| +} |
| + |
| +void XfwmTitlebarListener::OnPropertyChangedSignal(dbus::Signal* signal) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + |
| + // Read the signal and return on error or if the signal is not interesting. |
| + dbus::MessageReader reader(signal); |
| + std::string channel; |
| + if (!reader.PopString(&channel)) { |
| + LOG(ERROR) << "Invalid signal: " << signal->ToString(); |
| + return; |
| + } |
| + if (channel != kXfwm4Channel) |
| + return; |
| + |
| + std::string property; |
| + if (!reader.PopString(&property)) { |
| + LOG(ERROR) << "Invalid signal: " << signal->ToString(); |
| + return; |
| + } |
| + if (property != kXfwm4ButtonLayoutProperty) |
| + return; |
| + |
| + // Got an interest value, hopefully. |
| + std::string value; |
| + if (!reader.PopVariantOfString(&value)) { |
| + LOG(ERROR) << "Invalid signal: " << signal->ToString(); |
| + return; |
| + } |
| + |
| + // Set value and broadcast the new value to all windows: |
| + current_value_ = value.empty() ? BrowserTitlebar::kDefaultButtonString : |
| + ToMetacityFormat(value); |
| + TitlebarListener::GetInstance()->SetTitleBars(current_value_); |
| +} |
| + |
| +void XfwmTitlebarListener::GetCurrentButtonSettingOnFileThread( |
| + bool* succeeded, std::string* result) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| + |
| + dbus::MethodCall method_call(kXfconfInterface, kXfconfGetPropertyMethod); |
| + dbus::MessageWriter writer(&method_call); |
| + writer.AppendString(kXfwm4Channel); |
| + writer.AppendString(kXfwm4ButtonLayoutProperty); |
| + |
| + scoped_ptr<dbus::Response> response( |
| + object_proxy_->CallMethodAndBlock( |
| + &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT)); |
| + |
| + dbus::MessageReader reader(response.get()); |
| + std::string value; |
| + *succeeded = reader.PopVariantOfString(&value); |
| + if (*succeeded) |
| + *result = value; |
| + else |
| + LOG(ERROR) << "Invalid response: " << response->ToString(); |
| + |
| + // Wake up the UI thread. |
| + init_event_.Signal(); |
| +} |
| Property changes on: chrome/browser/ui/gtk/xfwm_titlebar_listener.cc |
| ___________________________________________________________________ |
| Added: svn:eol-style |
| + LF |