1// Copyright 2014 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_topmost_window_finder.h"
6
7#include <X11/Xutil.h>
8
9#include "ui/aura/client/screen_position_client.h"
10#include "ui/aura/window.h"
11#include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h"
12
13namespace views {
14
15X11TopmostWindowFinder::X11TopmostWindowFinder() : toplevel_(None) {
16}
17
18X11TopmostWindowFinder::~X11TopmostWindowFinder() {
19}
20
21aura::Window* X11TopmostWindowFinder::FindLocalProcessWindowAt(
22    const gfx::Point& screen_loc,
23    const std::set<aura::Window*>& ignore) {
24  screen_loc_ = screen_loc;
25  ignore_ = ignore;
26
27  std::vector<aura::Window*> local_process_windows =
28      DesktopWindowTreeHostX11::GetAllOpenWindows();
29  bool found_local_process_window = false;
30  for (size_t i = 0; i < local_process_windows.size(); ++i) {
31    if (ShouldStopIteratingAtLocalProcessWindow(local_process_windows[i])) {
32      found_local_process_window = true;
33      break;
34    }
35  }
36  if (!found_local_process_window)
37    return NULL;
38
39  ui::EnumerateTopLevelWindows(this);
40  return DesktopWindowTreeHostX11::GetContentWindowForXID(toplevel_);
41}
42
43XID X11TopmostWindowFinder::FindWindowAt(const gfx::Point& screen_loc) {
44  screen_loc_ = screen_loc;
45  ui::EnumerateTopLevelWindows(this);
46  return toplevel_;
47}
48
49bool X11TopmostWindowFinder::ShouldStopIterating(XID xid) {
50  if (!ui::IsWindowVisible(xid))
51    return false;
52
53  aura::Window* window =
54      views::DesktopWindowTreeHostX11::GetContentWindowForXID(xid);
55  if (window) {
56    if (ShouldStopIteratingAtLocalProcessWindow(window)) {
57      toplevel_ = xid;
58      return true;
59    }
60    return false;
61  }
62
63  if (ui::WindowContainsPoint(xid, screen_loc_)) {
64    toplevel_ = xid;
65    return true;
66  }
67  return false;
68}
69
70bool X11TopmostWindowFinder::ShouldStopIteratingAtLocalProcessWindow(
71    aura::Window* window) {
72  if (ignore_.find(window) != ignore_.end())
73    return false;
74
75  // Currently |window|->IsVisible() always returns true.
76  // TODO(pkotwicz): Fix this. crbug.com/353038
77  if (!window->IsVisible())
78    return false;
79
80  DesktopWindowTreeHostX11* host =
81      DesktopWindowTreeHostX11::GetHostForXID(
82          window->GetHost()->GetAcceleratedWidget());
83  if (!host->GetX11RootWindowOuterBounds().Contains(screen_loc_))
84    return false;
85
86  ::Region shape = host->GetWindowShape();
87  if (!shape)
88    return true;
89
90  aura::client::ScreenPositionClient* screen_position_client =
91      aura::client::GetScreenPositionClient(window->GetRootWindow());
92  gfx::Point window_loc(screen_loc_);
93  screen_position_client->ConvertPointFromScreen(window, &window_loc);
94  return XPointInRegion(shape, window_loc.x(), window_loc.y()) == True;
95}
96
97}  // namespace views
98