summaryrefslogtreecommitdiffstats
path: root/ash/monitor/multi_monitor_manager.cc
blob: 01a9f0232c64926261d0c2ccfc217367acf591d0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ash/monitor/multi_monitor_manager.h"

#include <string>
#include <vector>

#include "base/command_line.h"
#include "base/stl_util.h"
#include "base/string_split.h"
#include "ui/aura/aura_switches.h"
#include "ui/aura/env.h"
#include "ui/aura/monitor.h"
#include "ui/aura/root_window.h"
#include "ui/aura/root_window_host.h"
#include "ui/gfx/rect.h"
#include "ui/aura/window_property.h"

DECLARE_WINDOW_PROPERTY_TYPE(aura::Monitor*);

namespace ash {
namespace internal {
namespace {

aura::Monitor* Copy(aura::Monitor* m) {
  aura::Monitor* monitor = new aura::Monitor;
  monitor->set_bounds(m->bounds());
  return monitor;
}

}  // namespace

DEFINE_WINDOW_PROPERTY_KEY(aura::Monitor*, kMonitorKey, NULL);

using std::string;
using std::vector;
using aura::Monitor;
using aura::RootWindow;
using aura::Window;

MultiMonitorManager::MultiMonitorManager() {
  Init();
}

MultiMonitorManager::~MultiMonitorManager() {
  // All monitors must have been deleted when root windows are deleted.
  DCHECK(!monitors_.size());
}

// static
void MultiMonitorManager::AddRemoveMonitor() {
  MultiMonitorManager* manager = static_cast<MultiMonitorManager*>(
      aura::Env::GetInstance()->monitor_manager());
  manager->AddRemoveMonitorImpl();
}

void MultiMonitorManager::CycleMonitor() {
  MultiMonitorManager* manager = static_cast<MultiMonitorManager*>(
      aura::Env::GetInstance()->monitor_manager());
  manager->CycleMonitorImpl();
}

void MultiMonitorManager::OnNativeMonitorsChanged(
    const std::vector<const aura::Monitor*>& new_monitors) {
  size_t min = std::min(monitors_.size(), new_monitors.size());

  // For m19, we only care about 1st monitor as primary, and
  // don't differentiate the rest of monitors as all secondary
  // monitors have the same content.
  // TODO(oshima): Fix this so that we can differentiate outputs
  // and keep a content on one monitor stays on the same monitor
  // when a monitor is added or removed.
  for (size_t i = 0; i < min; ++i) {
    Monitor* current_monitor = monitors_[i];
    const Monitor* new_monitor = new_monitors[i];
    if (current_monitor->bounds() != new_monitor->bounds()) {
      current_monitor->set_bounds(new_monitor->bounds());
      NotifyBoundsChanged(current_monitor);
    }
  }

  if (monitors_.size() < new_monitors.size()) {
    // New monitors added
    for (size_t i = min; i < new_monitors.size(); ++i) {
      Monitor* monitor = new Monitor();
      monitor->set_bounds(new_monitors[i]->bounds());
      monitors_.push_back(monitor);
      NotifyMonitorAdded(monitor);
    }
  } else {
    // Monitors are removed. We keep the monitor for the primary
    // monitor (at index 0) because it needs the monitor information
    // even if it doesn't exit.
    while (monitors_.size() > new_monitors.size() && monitors_.size() > 1) {
      Monitor* monitor = monitors_.back();
      // Monitor object is deleted in OnWindowDestroying.
      NotifyMonitorRemoved(monitor);
      DCHECK(find(monitors_.begin(), monitors_.end(), monitor) ==
             monitors_.end());
    }
  }
}

RootWindow* MultiMonitorManager::CreateRootWindowForMonitor(
    Monitor* monitor) {
  RootWindow* root_window = new RootWindow(monitor->bounds());
  root_window->AddObserver(this);
  root_window->AddRootWindowObserver(this);
  root_window->SetProperty(kMonitorKey, monitor);
  return root_window;
}

const Monitor* MultiMonitorManager::GetMonitorNearestWindow(
    const Window* window) const {
  if (!window) {
    MultiMonitorManager* manager = const_cast<MultiMonitorManager*>(this);
    return manager->GetMonitorAt(0);
  }
  const RootWindow* root = window->GetRootWindow();
  return root ? root->GetProperty(kMonitorKey) : NULL;
}

const Monitor* MultiMonitorManager::GetMonitorNearestPoint(
    const gfx::Point& point) const {
  // TODO(oshima): For m19, mouse is constrained within
  // the primary window.
  MultiMonitorManager* manager = const_cast<MultiMonitorManager*>(this);
  return manager->GetMonitorAt(0);
}

Monitor* MultiMonitorManager::GetMonitorAt(size_t index) {
  return index < monitors_.size() ? monitors_[index] : NULL;
}

size_t MultiMonitorManager::GetNumMonitors() const {
  return monitors_.size();
}

Monitor* MultiMonitorManager::GetMonitorNearestWindow(const Window* window) {
  const MonitorManager* manager = this;
  return const_cast<Monitor*>(manager->GetMonitorNearestWindow(window));
}

void MultiMonitorManager::OnRootWindowResized(const aura::RootWindow* root,
                                              const gfx::Size& old_size) {
  if (!use_fullscreen_host_window()) {
    Monitor* monitor = root->GetProperty(kMonitorKey);
    monitor->set_size(root->GetHostSize());
    NotifyBoundsChanged(monitor);
  }
}

void MultiMonitorManager::OnWindowDestroying(Window* window) {
  RootWindow* root = static_cast<RootWindow*>(window);
  root->RemoveObserver(this);
  // Don't remove RootWindowObserver because the observer list in
  // RootWindowObserver class has already been destroyed by this time.

  Monitor* monitor = window->GetProperty(kMonitorKey);
  monitors_.erase(std::find(monitors_.begin(), monitors_.end(), monitor));
  delete monitor;
}

void MultiMonitorManager::Init() {
  // TODO(oshima): Move this logic to MonitorChangeObserver.
  const string size_str = CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
      switches::kAuraHostWindowSize);
  vector<string> parts;
  base::SplitString(size_str, ',', &parts);
  for (vector<string>::const_iterator iter = parts.begin();
       iter != parts.end(); ++iter) {
    monitors_.push_back(CreateMonitorFromSpec(*iter));
  }
  if (monitors_.empty())
    monitors_.push_back(CreateMonitorFromSpec("" /* default */));
}

void MultiMonitorManager::AddRemoveMonitorImpl() {
  std::vector<const Monitor*> new_monitors;
  if (monitors_.size() > 1) {
    // Remove if there is more than one monitor.
    int count = monitors_.size() - 1;
    for (Monitors::const_iterator iter = monitors_.begin(); count-- > 0; ++iter)
      new_monitors.push_back(Copy(*iter));
  } else {
    // Add if there is only one monitor.
    new_monitors.push_back(Copy(monitors_[0]));
    aura::Monitor* extra_monitor = new Monitor;
    extra_monitor->set_bounds(gfx::Rect(100, 100, 1440, 800));
    new_monitors.push_back(extra_monitor);
  }
  if (new_monitors.size())
    OnNativeMonitorsChanged(new_monitors);
  STLDeleteContainerPointers(new_monitors.begin(), new_monitors.end());
}

void MultiMonitorManager::CycleMonitorImpl() {
  if (monitors_.size() > 1) {
    std::vector<const Monitor*> new_monitors;
    for (Monitors::const_iterator iter = monitors_.begin() + 1;
         iter != monitors_.end(); ++iter)
      new_monitors.push_back(Copy(*iter));
    new_monitors.push_back(Copy(monitors_.front()));
    OnNativeMonitorsChanged(new_monitors);
    STLDeleteContainerPointers(new_monitors.begin(), new_monitors.end());
  }
}

}  // namespace internal
}  // namespace ash