x11_desktop_handler.cc revision d0247b1b59f9c528cb6df88b4f2b9afaf80d181e
1// Copyright (c) 2012 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 "ui/views/widget/desktop_aura/x11_desktop_handler.h"
6
7#include "base/message_loop/message_loop.h"
8#include "ui/aura/env.h"
9#include "ui/aura/focus_manager.h"
10#include "ui/aura/root_window.h"
11#include "ui/base/x/x11_util.h"
12
13#if !defined(OS_CHROMEOS)
14#include "ui/views/ime/input_method.h"
15#include "ui/views/widget/desktop_aura/desktop_root_window_host_x11.h"
16#endif
17
18namespace {
19
20const char* kAtomsToCache[] = {
21  "_NET_ACTIVE_WINDOW",
22  NULL
23};
24
25// Our global instance. Deleted when our Env() is deleted.
26views::X11DesktopHandler* g_handler = NULL;
27
28}  // namespace
29
30namespace views {
31
32// static
33X11DesktopHandler* X11DesktopHandler::get() {
34  if (!g_handler)
35    g_handler = new X11DesktopHandler;
36
37  return g_handler;
38}
39
40X11DesktopHandler::X11DesktopHandler()
41    : xdisplay_(ui::GetXDisplay()),
42      x_root_window_(DefaultRootWindow(xdisplay_)),
43      current_window_(None),
44      atom_cache_(xdisplay_, kAtomsToCache) {
45  base::MessagePumpX11::Current()->AddDispatcherForRootWindow(this);
46  aura::Env::GetInstance()->AddObserver(this);
47
48  XWindowAttributes attr;
49  XGetWindowAttributes(xdisplay_, x_root_window_, &attr);
50  XSelectInput(xdisplay_, x_root_window_,
51               attr.your_event_mask | PropertyChangeMask |
52               StructureNotifyMask | SubstructureNotifyMask);
53}
54
55X11DesktopHandler::~X11DesktopHandler() {
56  aura::Env::GetInstance()->RemoveObserver(this);
57  base::MessagePumpX11::Current()->RemoveDispatcherForRootWindow(this);
58}
59
60void X11DesktopHandler::ActivateWindow(::Window window) {
61  DCHECK_EQ(ui::GetXDisplay(), xdisplay_);
62
63  XEvent xclient;
64  memset(&xclient, 0, sizeof(xclient));
65  xclient.type = ClientMessage;
66  xclient.xclient.window = window;
67  xclient.xclient.message_type = atom_cache_.GetAtom("_NET_ACTIVE_WINDOW");
68  xclient.xclient.format = 32;
69  xclient.xclient.data.l[0] = 1;  // Specified we are an app.
70  xclient.xclient.data.l[1] = CurrentTime;
71  xclient.xclient.data.l[2] = None;
72  xclient.xclient.data.l[3] = 0;
73  xclient.xclient.data.l[4] = 0;
74
75  XSendEvent(xdisplay_, x_root_window_, False,
76             SubstructureRedirectMask | SubstructureNotifyMask,
77             &xclient);
78}
79
80bool X11DesktopHandler::IsActiveWindow(::Window window) const {
81  return window == current_window_;
82}
83
84bool X11DesktopHandler::Dispatch(const base::NativeEvent& event) {
85  // Check for a change to the active window.
86  switch (event->type) {
87    case PropertyNotify: {
88      ::Atom active_window = atom_cache_.GetAtom("_NET_ACTIVE_WINDOW");
89
90      if (event->xproperty.window == x_root_window_ &&
91          event->xproperty.atom == active_window) {
92        int window;
93        if (ui::GetIntProperty(x_root_window_, "_NET_ACTIVE_WINDOW", &window) &&
94            window) {
95          OnActiveWindowChanged(static_cast< ::Window>(window));
96        }
97      }
98      break;
99    }
100  }
101
102  return true;
103}
104
105void X11DesktopHandler::OnWindowInitialized(aura::Window* window) {
106}
107
108void X11DesktopHandler::OnWillDestroyEnv() {
109  g_handler = NULL;
110  delete this;
111}
112
113void X11DesktopHandler::OnActiveWindowChanged(::Window xid) {
114  DesktopRootWindowHostX11* old_host =
115      views::DesktopRootWindowHostX11::GetHostForXID(current_window_);
116  if (old_host)
117    old_host->HandleNativeWidgetActivationChanged(false);
118
119  DesktopRootWindowHostX11* new_host =
120      views::DesktopRootWindowHostX11::GetHostForXID(xid);
121  if (new_host)
122    new_host->HandleNativeWidgetActivationChanged(true);
123
124  current_window_ = xid;
125}
126
127}  // namespace views
128