summaryrefslogtreecommitdiffstats
path: root/chrome/browser/chromeos/wm_ipc.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/chromeos/wm_ipc.cc')
-rw-r--r--chrome/browser/chromeos/wm_ipc.cc210
1 files changed, 210 insertions, 0 deletions
diff --git a/chrome/browser/chromeos/wm_ipc.cc b/chrome/browser/chromeos/wm_ipc.cc
new file mode 100644
index 0000000..1bb9a52
--- /dev/null
+++ b/chrome/browser/chromeos/wm_ipc.cc
@@ -0,0 +1,210 @@
+// Copyright (c) 2010 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/chromeos/wm_ipc.h"
+
+#include <gdk/gdkx.h>
+extern "C" {
+#include <X11/Xlib.h>
+}
+
+#include "app/x11_util.h"
+#include "base/logging.h"
+#include "base/singleton.h"
+#include "base/scoped_ptr.h"
+
+namespace chromeos {
+
+namespace {
+
+// A value from the Atom enum and the actual name that should be used to
+// look up its ID on the X server.
+struct AtomInfo {
+ WmIpc::AtomType atom;
+ const char* name;
+};
+
+// Each value from the Atom enum must be present here.
+static const AtomInfo kAtomInfos[] = {
+ { WmIpc::ATOM_CHROME_LOGGED_IN, "_CHROME_LOGGED_IN" },
+ { WmIpc::ATOM_CHROME_WINDOW_TYPE, "_CHROME_WINDOW_TYPE" },
+ { WmIpc::ATOM_CHROME_WM_MESSAGE, "_CHROME_WM_MESSAGE" },
+ { WmIpc::ATOM_MANAGER, "MANAGER" },
+ { WmIpc::ATOM_STRING, "STRING" },
+ { WmIpc::ATOM_UTF8_STRING, "UTF8_STRING" },
+ { WmIpc::ATOM_WM_S0, "WM_S0" },
+};
+
+bool SetIntProperty(XID xid, Atom xatom, const std::vector<int>& values) {
+ DCHECK(!values.empty());
+
+ // XChangeProperty expects values of type 32 to be longs.
+ scoped_array<long> data(new long[values.size()]);
+ for (size_t i = 0; i < values.size(); ++i)
+ data[i] = values[i];
+
+ // TODO: Trap errors and return false on failure.
+ XChangeProperty(x11_util::GetXDisplay(),
+ xid,
+ xatom,
+ xatom,
+ 32, // size in bits of items in 'value'
+ PropModeReplace,
+ reinterpret_cast<const unsigned char*>(data.get()),
+ values.size()); // num items
+ XFlush(x11_util::GetXDisplay());
+ return true;
+}
+
+} // namespace
+
+// static
+WmIpc* WmIpc::instance() {
+ static WmIpc* instance = NULL;
+ if (!instance)
+ instance = Singleton<WmIpc>::get();
+ return instance;
+}
+
+bool WmIpc::SetWindowType(GtkWidget* widget,
+ WmIpcWindowType type,
+ const std::vector<int>* params) {
+ std::vector<int> values;
+ values.push_back(type);
+ if (params)
+ values.insert(values.end(), params->begin(), params->end());
+ return SetIntProperty(x11_util::GetX11WindowFromGtkWidget(widget),
+ type_to_atom_[ATOM_CHROME_WINDOW_TYPE], values);
+}
+
+WmIpcWindowType WmIpc::GetWindowType(GtkWidget* widget,
+ std::vector<int>* params) {
+ std::vector<int> properties;
+ if (x11_util::GetIntArrayProperty(
+ x11_util::GetX11WindowFromGtkWidget(widget),
+ atom_to_string_[type_to_atom_[ATOM_CHROME_WINDOW_TYPE]],
+ &properties)) {
+ int type = properties.front();
+ if (params) {
+ params->clear();
+ params->insert(params->begin(), properties.begin() + 1, properties.end());
+ }
+ return static_cast<WmIpcWindowType>(type);
+ } else {
+ return WM_IPC_WINDOW_UNKNOWN;
+ }
+}
+
+void WmIpc::SendMessage(const Message& msg) {
+ XEvent e;
+ e.xclient.type = ClientMessage;
+ e.xclient.window = wm_;
+ e.xclient.message_type = type_to_atom_[ATOM_CHROME_WM_MESSAGE];
+ e.xclient.format = 32; // 32-bit values
+ e.xclient.data.l[0] = msg.type();
+
+ // XClientMessageEvent only gives us five 32-bit items, and we're using
+ // the first one for our message type.
+ DCHECK_LE(msg.max_params(), 4);
+ for (int i = 0; i < msg.max_params(); ++i)
+ e.xclient.data.l[i+1] = msg.param(i);
+
+ XSendEvent(x11_util::GetXDisplay(),
+ wm_,
+ False, // propagate
+ 0, // empty event mask
+ &e);
+}
+
+bool WmIpc::DecodeMessage(const GdkEventClient& event, Message* msg) {
+ if (wm_message_atom_ != gdk_x11_atom_to_xatom(event.message_type))
+ return false;
+
+ if (event.data_format != 32) {
+ DLOG(WARNING) << "Ignoring ClientEventMessage with invalid bit "
+ << "format " << event.data_format
+ << " (expected 32-bit values)";
+ return false;
+ }
+
+ msg->set_type(static_cast<WmIpcMessageType>(event.data.l[0]));
+ if (msg->type() < 0) {
+ DLOG(WARNING) << "Ignoring ClientEventMessage with invalid message "
+ << "type " << msg->type();
+ return false;
+ }
+
+ // XClientMessageEvent only gives us five 32-bit items, and we're using
+ // the first one for our message type.
+ DCHECK_LE(msg->max_params(), 4);
+ for (int i = 0; i < msg->max_params(); ++i)
+ msg->set_param(i, event.data.l[i+1]); // l[0] contains message type
+
+ return true;
+}
+
+void WmIpc::HandleNonChromeClientMessageEvent(const GdkEventClient& event) {
+ // Only do these lookups once; they should never change.
+ static GdkAtom manager_gdk_atom =
+ gdk_x11_xatom_to_atom(type_to_atom_[ATOM_MANAGER]);
+ static Atom wm_s0_atom = type_to_atom_[ATOM_WM_S0];
+
+ if (event.message_type == manager_gdk_atom &&
+ static_cast<Atom>(event.data.l[1]) == wm_s0_atom) {
+ InitWmInfo();
+ }
+}
+
+void WmIpc::SetLoggedInProperty(bool logged_in) {
+ std::vector<int> values;
+ values.push_back(static_cast<int>(logged_in));
+ SetIntProperty(gdk_x11_get_default_root_xwindow(),
+ type_to_atom_[ATOM_CHROME_LOGGED_IN],
+ values);
+}
+
+WmIpc::WmIpc() {
+ scoped_array<char*> names(new char*[kNumAtoms]);
+ scoped_array<Atom> atoms(new Atom[kNumAtoms]);
+
+ for (int i = 0; i < kNumAtoms; ++i) {
+ // Need to const_cast because XInternAtoms() wants a char**.
+ names[i] = const_cast<char*>(kAtomInfos[i].name);
+ }
+
+ XInternAtoms(x11_util::GetXDisplay(), names.get(), kNumAtoms,
+ False, // only_if_exists
+ atoms.get());
+
+ for (int i = 0; i < kNumAtoms; ++i) {
+ type_to_atom_[kAtomInfos[i].atom] = atoms[i];
+ atom_to_string_[atoms[i]] = kAtomInfos[i].name;
+ }
+
+ wm_message_atom_ = type_to_atom_[ATOM_CHROME_WM_MESSAGE];
+
+ // Make sure that we're selecting structure changes on the root window;
+ // the window manager uses StructureNotifyMask when sending the ClientMessage
+ // event to announce that it's taken the manager selection.
+ GdkWindow* root = gdk_get_default_root_window();
+ GdkEventMask event_mask = gdk_window_get_events(root);
+ gdk_window_set_events(
+ root, static_cast<GdkEventMask>(event_mask | GDK_STRUCTURE_MASK));
+
+ InitWmInfo();
+}
+
+void WmIpc::InitWmInfo() {
+ wm_ = XGetSelectionOwner(x11_util::GetXDisplay(), type_to_atom_[ATOM_WM_S0]);
+
+ // Let the window manager know which version of the IPC messages we support.
+ Message msg(chromeos::WM_IPC_MESSAGE_WM_NOTIFY_IPC_VERSION);
+ // TODO: The version number is the latest listed in wm_ipc.h --
+ // ideally, once this header is shared between Chrome and the Chrome OS window
+ // manager, we'll just define the version statically in the header.
+ msg.set_param(0, 1);
+ SendMessage(msg);
+}
+
+} // namespace chromeos