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