Home | History | Annotate | Download | only in desktop_aura
      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