x11_desktop_handler.cc revision f2477e01787aa58f445919b809d89e252beef54f
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 <X11/Xatom.h> 8#include <X11/Xlib.h> 9 10#include "base/message_loop/message_loop.h" 11#include "ui/aura/env.h" 12#include "ui/aura/root_window.h" 13#include "ui/base/x/x11_util.h" 14 15#if !defined(OS_CHROMEOS) 16#include "ui/views/ime/input_method.h" 17#include "ui/views/widget/desktop_aura/desktop_root_window_host_x11.h" 18#endif 19 20namespace { 21 22const char* kAtomsToCache[] = { 23 "_NET_ACTIVE_WINDOW", 24 "_NET_SUPPORTED", 25 NULL 26}; 27 28// Our global instance. Deleted when our Env() is deleted. 29views::X11DesktopHandler* g_handler = NULL; 30 31} // namespace 32 33namespace views { 34 35// static 36X11DesktopHandler* X11DesktopHandler::get() { 37 if (!g_handler) 38 g_handler = new X11DesktopHandler; 39 40 return g_handler; 41} 42 43X11DesktopHandler::X11DesktopHandler() 44 : xdisplay_(gfx::GetXDisplay()), 45 x_root_window_(DefaultRootWindow(xdisplay_)), 46 current_window_(None), 47 atom_cache_(xdisplay_, kAtomsToCache), 48 wm_supports_active_window_(false) { 49 base::MessagePumpX11::Current()->AddDispatcherForRootWindow(this); 50 aura::Env::GetInstance()->AddObserver(this); 51 52 XWindowAttributes attr; 53 XGetWindowAttributes(xdisplay_, x_root_window_, &attr); 54 XSelectInput(xdisplay_, x_root_window_, 55 attr.your_event_mask | PropertyChangeMask | 56 StructureNotifyMask | SubstructureNotifyMask); 57 58 std::vector<Atom> atoms; 59 if (ui::GetAtomArrayProperty(x_root_window_, "_NET_ACTIVE_WINDOW", &atoms)) { 60 Atom active_window = atom_cache_.GetAtom("_NET_ACTIVE_WINDOW"); 61 for (std::vector<Atom>::iterator iter = atoms.begin(); iter != atoms.end(); 62 ++iter) { 63 if (*(iter) == active_window) { 64 wm_supports_active_window_ = true; 65 break; 66 } 67 } 68 } 69} 70 71X11DesktopHandler::~X11DesktopHandler() { 72 aura::Env::GetInstance()->RemoveObserver(this); 73 base::MessagePumpX11::Current()->RemoveDispatcherForRootWindow(this); 74} 75 76void X11DesktopHandler::ActivateWindow(::Window window) { 77 if (wm_supports_active_window_) { 78 DCHECK_EQ(gfx::GetXDisplay(), xdisplay_); 79 80 XEvent xclient; 81 memset(&xclient, 0, sizeof(xclient)); 82 xclient.type = ClientMessage; 83 xclient.xclient.window = window; 84 xclient.xclient.message_type = atom_cache_.GetAtom("_NET_ACTIVE_WINDOW"); 85 xclient.xclient.format = 32; 86 xclient.xclient.data.l[0] = 1; // Specified we are an app. 87 xclient.xclient.data.l[1] = CurrentTime; 88 xclient.xclient.data.l[2] = None; 89 xclient.xclient.data.l[3] = 0; 90 xclient.xclient.data.l[4] = 0; 91 92 XSendEvent(xdisplay_, x_root_window_, False, 93 SubstructureRedirectMask | SubstructureNotifyMask, 94 &xclient); 95 } else { 96 XRaiseWindow(xdisplay_, window); 97 OnActiveWindowChanged(window); 98 } 99} 100 101bool X11DesktopHandler::IsActiveWindow(::Window window) const { 102 return window == current_window_; 103} 104 105void X11DesktopHandler::ProcessXEvent(const base::NativeEvent& event) { 106 switch (event->type) { 107 case EnterNotify: 108 if (event->xcrossing.focus == True && 109 current_window_ != event->xcrossing.window) 110 OnActiveWindowChanged(event->xcrossing.window); 111 break; 112 case LeaveNotify: 113 if (event->xcrossing.focus == False && 114 current_window_ == event->xcrossing.window) 115 OnActiveWindowChanged(None); 116 break; 117 default: 118 NOTREACHED(); 119 } 120} 121 122bool X11DesktopHandler::Dispatch(const base::NativeEvent& event) { 123 // Check for a change to the active window. 124 switch (event->type) { 125 case PropertyNotify: { 126 ::Atom active_window = atom_cache_.GetAtom("_NET_ACTIVE_WINDOW"); 127 128 if (event->xproperty.window == x_root_window_ && 129 event->xproperty.atom == active_window) { 130 int window; 131 if (ui::GetIntProperty(x_root_window_, "_NET_ACTIVE_WINDOW", &window) && 132 window) { 133 OnActiveWindowChanged(static_cast< ::Window>(window)); 134 } 135 } 136 break; 137 } 138 } 139 140 return true; 141} 142 143void X11DesktopHandler::OnWindowInitialized(aura::Window* window) { 144} 145 146void X11DesktopHandler::OnWillDestroyEnv() { 147 g_handler = NULL; 148 delete this; 149} 150 151void X11DesktopHandler::OnActiveWindowChanged(::Window xid) { 152 if (current_window_ == xid) 153 return; 154 DesktopRootWindowHostX11* old_host = 155 views::DesktopRootWindowHostX11::GetHostForXID(current_window_); 156 if (old_host) 157 old_host->HandleNativeWidgetActivationChanged(false); 158 159 DesktopRootWindowHostX11* new_host = 160 views::DesktopRootWindowHostX11::GetHostForXID(xid); 161 if (new_host) 162 new_host->HandleNativeWidgetActivationChanged(true); 163 164 current_window_ = xid; 165} 166 167} // namespace views 168