Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(347)

Side by Side Diff: ui/views/widget/desktop_root_window_host_linux.cc

Issue 11369220: Move the desktop aura classes into a desktop subdir to make the gyp simpler. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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_root_window_host_linux.h"
6
7 #include <X11/extensions/XInput2.h>
8 #include <X11/Xatom.h>
9 #include <X11/Xutil.h>
10
11 #include "base/message_pump_aurax11.h"
12 #include "base/stringprintf.h"
13 #include "base/utf_string_conversions.h"
14 #include "ui/aura/client/default_capture_client.h"
15 #include "ui/aura/client/screen_position_client.h"
16 #include "ui/aura/client/user_action_client.h"
17 #include "ui/aura/focus_manager.h"
18 #include "ui/aura/root_window.h"
19 #include "ui/views/corewm/compound_event_filter.h"
20 #include "ui/views/corewm/input_method_event_filter.h"
21 #include "ui/aura/window_property.h"
22 #include "ui/base/events/event_utils.h"
23 #include "ui/base/native_theme/native_theme.h"
24 #include "ui/base/touch/touch_factory.h"
25 #include "ui/base/x/x11_util.h"
26 #include "ui/views/ime/input_method_bridge.h"
27 #include "ui/views/widget/desktop_aura/desktop_activation_client.h"
28 #include "ui/views/widget/desktop_aura/desktop_cursor_client.h"
29 #include "ui/views/widget/desktop_aura/desktop_dispatcher_client.h"
30 #include "ui/views/widget/desktop_layout_manager.h"
31 #include "ui/views/widget/desktop_native_widget_aura.h"
32 #include "ui/views/widget/desktop_screen_position_client.h"
33 #include "ui/views/widget/x11_desktop_handler.h"
34 #include "ui/views/widget/x11_desktop_window_move_client.h"
35 #include "ui/views/widget/x11_window_event_filter.h"
36
37 namespace views {
38
39 DesktopRootWindowHostLinux* DesktopRootWindowHostLinux::g_current_capture =
40 NULL;
41
42 DEFINE_WINDOW_PROPERTY_KEY(
43 aura::Window*, kViewsWindowForRootWindow, NULL);
44
45 DEFINE_WINDOW_PROPERTY_KEY(
46 DesktopRootWindowHostLinux*, kHostForRootWindow, NULL);
47
48 namespace {
49
50 // Standard Linux mouse buttons for going back and forward.
51 const int kBackMouseButton = 8;
52 const int kForwardMouseButton = 9;
53
54 // Constants that are part of EWMH.
55 const int k_NET_WM_STATE_ADD = 1;
56 const int k_NET_WM_STATE_REMOVE = 0;
57
58 const char* kAtomsToCache[] = {
59 "WM_DELETE_WINDOW",
60 "WM_S0",
61 "_NET_WM_PID",
62 "_NET_WM_PING",
63 "_NET_WM_STATE",
64 "_NET_WM_STATE_FULLSCREEN",
65 "_NET_WM_STATE_HIDDEN",
66 "_NET_WM_STATE_MAXIMIZED_HORZ",
67 "_NET_WM_STATE_MAXIMIZED_VERT",
68 NULL
69 };
70
71 } // namespace
72
73 ////////////////////////////////////////////////////////////////////////////////
74 // DesktopRootWindowHostLinux, public:
75
76 DesktopRootWindowHostLinux::DesktopRootWindowHostLinux(
77 internal::NativeWidgetDelegate* native_widget_delegate,
78 DesktopNativeWidgetAura* desktop_native_widget_aura,
79 const gfx::Rect& initial_bounds)
80 : close_widget_factory_(this),
81 xdisplay_(base::MessagePumpAuraX11::GetDefaultXDisplay()),
82 xwindow_(0),
83 x_root_window_(DefaultRootWindow(xdisplay_)),
84 atom_cache_(xdisplay_, kAtomsToCache),
85 window_mapped_(false),
86 focus_when_shown_(false),
87 current_cursor_(ui::kCursorNull),
88 native_widget_delegate_(native_widget_delegate),
89 desktop_native_widget_aura_(desktop_native_widget_aura) {
90 }
91
92 DesktopRootWindowHostLinux::~DesktopRootWindowHostLinux() {
93 root_window_->ClearProperty(kHostForRootWindow);
94 }
95
96 // static
97 ui::NativeTheme* DesktopRootWindowHost::GetNativeTheme(aura::Window* window) {
98 return ui::NativeTheme::instance();
99 }
100
101 ////////////////////////////////////////////////////////////////////////////////
102 // DesktopRootWindowHostLinux, private:
103
104 void DesktopRootWindowHostLinux::InitX11Window(
105 const Widget::InitParams& params) {
106 unsigned long attribute_mask = CWBackPixmap;
107 XSetWindowAttributes swa;
108 memset(&swa, 0, sizeof(swa));
109 swa.background_pixmap = None;
110
111 if (params.type == Widget::InitParams::TYPE_MENU) {
112 swa.override_redirect = True;
113 attribute_mask |= CWOverrideRedirect;
114 }
115
116 xwindow_ = XCreateWindow(
117 xdisplay_, x_root_window_,
118 params.bounds.x(), params.bounds.y(),
119 params.bounds.width(), params.bounds.height(),
120 0, // border width
121 CopyFromParent, // depth
122 InputOutput,
123 CopyFromParent, // visual
124 attribute_mask,
125 &swa);
126 base::MessagePumpAuraX11::Current()->AddDispatcherForWindow(this, xwindow_);
127
128 // TODO(erg): Maybe need to set a ViewProp here like in RWHL::RWHL().
129
130 long event_mask = ButtonPressMask | ButtonReleaseMask | FocusChangeMask |
131 KeyPressMask | KeyReleaseMask |
132 EnterWindowMask | LeaveWindowMask |
133 ExposureMask | VisibilityChangeMask |
134 StructureNotifyMask | PropertyChangeMask |
135 PointerMotionMask;
136 XSelectInput(xdisplay_, xwindow_, event_mask);
137 XFlush(xdisplay_);
138
139 if (base::MessagePumpForUI::HasXInput2())
140 ui::TouchFactory::GetInstance()->SetupXI2ForXWindow(xwindow_);
141
142 invisible_cursor_ = ui::CreateInvisibleCursor();
143
144 // TODO(erg): We currently only request window deletion events. We also
145 // should listen for activation events and anything else that GTK+ listens
146 // for, and do something useful.
147 ::Atom protocols[2];
148 protocols[0] = atom_cache_.GetAtom("WM_DELETE_WINDOW");
149 protocols[1] = atom_cache_.GetAtom("_NET_WM_PING");
150 XSetWMProtocols(xdisplay_, xwindow_, protocols, 2);
151
152 // We need a WM_CLIENT_MACHINE and WM_LOCALE_NAME value so we integrate with
153 // the desktop environment.
154 XSetWMProperties(xdisplay_, xwindow_, NULL, NULL, NULL, 0, NULL, NULL, NULL);
155
156 // Likewise, the X server needs to know this window's pid so it knows which
157 // program to kill if the window hangs.
158 pid_t pid = getpid();
159 XChangeProperty(xdisplay_,
160 xwindow_,
161 atom_cache_.GetAtom("_NET_WM_PID"),
162 XA_CARDINAL,
163 32,
164 PropModeReplace,
165 reinterpret_cast<unsigned char*>(&pid), 1);
166 }
167
168 // static
169 aura::Window* DesktopRootWindowHostLinux::GetContentWindowForXID(XID xid) {
170 aura::RootWindow* root = aura::RootWindow::GetForAcceleratedWidget(xid);
171 return root ? root->GetProperty(kViewsWindowForRootWindow) : NULL;
172 }
173
174 // static
175 DesktopRootWindowHostLinux* DesktopRootWindowHostLinux::GetHostForXID(XID xid) {
176 aura::RootWindow* root = aura::RootWindow::GetForAcceleratedWidget(xid);
177 return root ? root->GetProperty(kHostForRootWindow) : NULL;
178 }
179
180 void DesktopRootWindowHostLinux::HandleNativeWidgetActivationChanged(
181 bool active) {
182 native_widget_delegate_->OnNativeWidgetActivationChanged(active);
183 native_widget_delegate_->AsWidget()->GetRootView()->SchedulePaint();
184 }
185
186 // TODO(erg): This method should basically be everything I need form
187 // RootWindowHostLinux::RootWindowHostLinux().
188 aura::RootWindow* DesktopRootWindowHostLinux::InitRootWindow(
189 const Widget::InitParams& params) {
190 bounds_ = params.bounds;
191
192 aura::RootWindow::CreateParams rw_params(bounds_);
193 rw_params.host = this;
194 root_window_ = new aura::RootWindow(rw_params);
195 root_window_->Init();
196 root_window_->AddChild(content_window_);
197 root_window_->SetLayoutManager(new DesktopLayoutManager(root_window_));
198 root_window_->SetProperty(kViewsWindowForRootWindow, content_window_);
199 root_window_->SetProperty(kHostForRootWindow, this);
200 root_window_host_delegate_ = root_window_;
201
202 // If we're given a parent, we need to mark ourselves as transient to another
203 // window. Otherwise activation gets screwy.
204 gfx::NativeView parent = params.GetParent();
205 if (!params.child && params.GetParent())
206 parent->AddTransientChild(content_window_);
207
208 native_widget_delegate_->OnNativeWidgetCreated();
209
210 capture_client_.reset(new aura::client::DefaultCaptureClient(root_window_));
211 aura::client::SetCaptureClient(root_window_, capture_client_.get());
212
213 // Ensure that the X11DesktopHandler exists so that it dispatches activation
214 // messages to us.
215 X11DesktopHandler::get();
216
217 focus_manager_.reset(new aura::FocusManager);
218 root_window_->set_focus_manager(focus_manager_.get());
219
220 activation_client_.reset(
221 new DesktopActivationClient(root_window_->GetFocusManager()));
222 aura::client::SetActivationClient(root_window_,
223 activation_client_.get());
224
225 dispatcher_client_.reset(new DesktopDispatcherClient);
226 aura::client::SetDispatcherClient(root_window_,
227 dispatcher_client_.get());
228
229 cursor_client_.reset(new DesktopCursorClient(root_window_));
230 aura::client::SetCursorClient(root_window_,
231 cursor_client_.get());
232
233 position_client_.reset(new DesktopScreenPositionClient);
234 aura::client::SetScreenPositionClient(root_window_,
235 position_client_.get());
236
237 // No event filter for aura::Env. Create CompoundEvnetFilter per RootWindow.
238 root_window_event_filter_ = new corewm::CompoundEventFilter;
239 // Pass ownership of the filter to the root_window.
240 root_window_->SetEventFilter(root_window_event_filter_);
241
242 input_method_filter_.reset(new corewm::InputMethodEventFilter);
243 input_method_filter_->SetInputMethodPropertyInRootWindow(root_window_);
244 root_window_event_filter_->AddFilter(input_method_filter_.get());
245
246 // TODO(erg): Unify this code once the other consumer goes away.
247 x11_window_event_filter_.reset(
248 new X11WindowEventFilter(root_window_, activation_client_.get()));
249 x11_window_event_filter_->SetUseHostWindowBorders(false);
250 root_window_event_filter_->AddFilter(x11_window_event_filter_.get());
251
252 x11_window_move_client_.reset(new X11DesktopWindowMoveClient);
253 aura::client::SetWindowMoveClient(root_window_,
254 x11_window_move_client_.get());
255
256 focus_manager_->SetFocusedWindow(content_window_, NULL);
257 return root_window_;
258 }
259
260 bool DesktopRootWindowHostLinux::IsWindowManagerPresent() {
261 // Per ICCCM 2.8, "Manager Selections", window managers should take ownership
262 // of WM_Sn selections (where n is a screen number).
263 return XGetSelectionOwner(
264 xdisplay_, atom_cache_.GetAtom("WM_S0")) != None;
265 }
266
267 void DesktopRootWindowHostLinux::SetWMSpecState(bool enabled,
268 ::Atom state1,
269 ::Atom state2) {
270 XEvent xclient;
271 memset(&xclient, 0, sizeof(xclient));
272 xclient.type = ClientMessage;
273 xclient.xclient.window = xwindow_;
274 xclient.xclient.message_type = atom_cache_.GetAtom("_NET_WM_STATE");
275 xclient.xclient.format = 32;
276 xclient.xclient.data.l[0] =
277 enabled ? k_NET_WM_STATE_ADD : k_NET_WM_STATE_REMOVE;
278 xclient.xclient.data.l[1] = state1;
279 xclient.xclient.data.l[2] = state2;
280 xclient.xclient.data.l[3] = 1;
281 xclient.xclient.data.l[4] = 0;
282
283 XSendEvent(xdisplay_, x_root_window_, False,
284 SubstructureRedirectMask | SubstructureNotifyMask,
285 &xclient);
286 }
287
288 bool DesktopRootWindowHostLinux::HasWMSpecProperty(const char* property) const {
289 return window_properties_.find(atom_cache_.GetAtom(property)) !=
290 window_properties_.end();
291 }
292
293 ////////////////////////////////////////////////////////////////////////////////
294 // DesktopRootWindowHostLinux, DesktopRootWindowHost implementation:
295
296 aura::RootWindow* DesktopRootWindowHostLinux::Init(
297 aura::Window* content_window,
298 const Widget::InitParams& params) {
299 content_window_ = content_window;
300
301 // TODO(erg): Check whether we *should* be building a RootWindowHost here, or
302 // whether we should be proxying requests to another DRWHL.
303
304 // In some situations, views tries to make a zero sized window, and that
305 // makes us crash. Make sure we have valid sizes.
306 Widget::InitParams sanitized_params = params;
307 if (sanitized_params.bounds.width() == 0)
308 sanitized_params.bounds.set_width(100);
309 if (sanitized_params.bounds.height() == 0)
310 sanitized_params.bounds.set_height(100);
311
312 InitX11Window(sanitized_params);
313 return InitRootWindow(sanitized_params);
314 }
315
316 void DesktopRootWindowHostLinux::Close() {
317 // TODO(erg): Might need to do additional hiding tasks here.
318
319 if (!close_widget_factory_.HasWeakPtrs()) {
320 // And we delay the close so that if we are called from an ATL callback,
321 // we don't destroy the window before the callback returned (as the caller
322 // may delete ourselves on destroy and the ATL callback would still
323 // dereference us when the callback returns).
324 MessageLoop::current()->PostTask(
325 FROM_HERE,
326 base::Bind(&DesktopRootWindowHostLinux::CloseNow,
327 close_widget_factory_.GetWeakPtr()));
328 }
329 }
330
331 void DesktopRootWindowHostLinux::CloseNow() {
332 // Remove the event listeners we've installed. We need to remove these
333 // because otherwise we get assert during ~RootWindow().
334 root_window_event_filter_->RemoveFilter(x11_window_event_filter_.get());
335 root_window_event_filter_->RemoveFilter(input_method_filter_.get());
336
337 // Actually free our native resources.
338 base::MessagePumpAuraX11::Current()->RemoveDispatcherForWindow(xwindow_);
339 XDestroyWindow(xdisplay_, xwindow_);
340 xwindow_ = None;
341
342 desktop_native_widget_aura_->OnHostClosed();
343 }
344
345 aura::RootWindowHost* DesktopRootWindowHostLinux::AsRootWindowHost() {
346 return this;
347 }
348
349 void DesktopRootWindowHostLinux::ShowWindowWithState(
350 ui::WindowShowState show_state) {
351 if (show_state != ui::SHOW_STATE_DEFAULT &&
352 show_state != ui::SHOW_STATE_NORMAL) {
353 // Only forwarding to Show().
354 NOTIMPLEMENTED();
355 }
356
357 Show();
358 }
359
360 void DesktopRootWindowHostLinux::ShowMaximizedWithBounds(
361 const gfx::Rect& restored_bounds) {
362 // TODO(erg):
363 NOTIMPLEMENTED();
364
365 // TODO(erg): We shouldn't completely fall down here.
366 Show();
367 }
368
369 bool DesktopRootWindowHostLinux::IsVisible() const {
370 return window_mapped_;
371 }
372
373 void DesktopRootWindowHostLinux::SetSize(const gfx::Size& size) {
374 // TODO(erg):
375 NOTIMPLEMENTED();
376 }
377
378 void DesktopRootWindowHostLinux::CenterWindow(const gfx::Size& size) {
379 gfx::Rect parent_bounds = GetWorkAreaBoundsInScreen();
380
381 // If |window_|'s transient parent bounds are big enough to contain |size|,
382 // use them instead.
383 if (content_window_->transient_parent()) {
384 gfx::Rect transient_parent_rect =
385 content_window_->transient_parent()->GetBoundsInScreen();
386 if (transient_parent_rect.height() >= size.height() &&
387 transient_parent_rect.width() >= size.width()) {
388 parent_bounds = transient_parent_rect;
389 }
390 }
391
392 gfx::Rect window_bounds(
393 parent_bounds.x() + (parent_bounds.width() - size.width()) / 2,
394 parent_bounds.y() + (parent_bounds.height() - size.height()) / 2,
395 size.width(),
396 size.height());
397 // Don't size the window bigger than the parent, otherwise the user may not be
398 // able to close or move it.
399 window_bounds.AdjustToFit(parent_bounds);
400
401 SetBounds(window_bounds);
402 }
403
404 void DesktopRootWindowHostLinux::GetWindowPlacement(
405 gfx::Rect* bounds,
406 ui::WindowShowState* show_state) const {
407 *bounds = bounds_;
408
409 // TODO(erg): This needs a better implementation. For now, we're just pass
410 // back the normal state until we keep track of this.
411 *show_state = ui::SHOW_STATE_NORMAL;
412 }
413
414 gfx::Rect DesktopRootWindowHostLinux::GetWindowBoundsInScreen() const {
415 return bounds_;
416 }
417
418 gfx::Rect DesktopRootWindowHostLinux::GetClientAreaBoundsInScreen() const {
419 // TODO(erg): The NativeWidgetAura version returns |bounds_|, claiming its
420 // needed for View::ConvertPointToScreen() to work
421 // correctly. DesktopRootWindowHostWin::GetClientAreaBoundsInScreen() just
422 // asks windows what it thinks the client rect is.
423 //
424 // Attempts to calculate the rect by asking the NonClientFrameView what it
425 // thought its GetBoundsForClientView() were broke combobox drop down
426 // placement.
427 return bounds_;
428 }
429
430 gfx::Rect DesktopRootWindowHostLinux::GetRestoredBounds() const {
431 // TODO(erg):
432 NOTIMPLEMENTED();
433 return gfx::Rect();
434 }
435
436 gfx::Rect DesktopRootWindowHostLinux::GetWorkAreaBoundsInScreen() const {
437 std::vector<int> value;
438 if (ui::GetIntArrayProperty(x_root_window_, "_NET_WORKAREA", &value) &&
439 value.size() >= 4) {
440 return gfx::Rect(value[0], value[1], value[2], value[3]);
441 }
442
443 // TODO(erg): As a fallback, we should return the bounds for the current
444 // monitor. However, that's pretty difficult and requires futzing with XRR.
445 NOTIMPLEMENTED();
446 return gfx::Rect();
447 }
448
449 void DesktopRootWindowHostLinux::SetShape(gfx::NativeRegion native_region) {
450 // TODO(erg):
451 NOTIMPLEMENTED();
452 }
453
454 void DesktopRootWindowHostLinux::Activate() {
455 X11DesktopHandler::get()->ActivateWindow(xwindow_);
456 }
457
458 void DesktopRootWindowHostLinux::Deactivate() {
459 // Deactivating a window means activating nothing.
460 X11DesktopHandler::get()->ActivateWindow(None);
461 }
462
463 bool DesktopRootWindowHostLinux::IsActive() const {
464 return X11DesktopHandler::get()->IsActiveWindow(xwindow_);
465 }
466
467 void DesktopRootWindowHostLinux::Maximize() {
468 SetWMSpecState(true,
469 atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"),
470 atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"));
471 }
472
473 void DesktopRootWindowHostLinux::Minimize() {
474 XIconifyWindow(xdisplay_, xwindow_, 0);
475 }
476
477 void DesktopRootWindowHostLinux::Restore() {
478 SetWMSpecState(false,
479 atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"),
480 atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"));
481 }
482
483 bool DesktopRootWindowHostLinux::IsMaximized() const {
484 return (HasWMSpecProperty("_NET_WM_STATE_MAXIMIZED_VERT") ||
485 HasWMSpecProperty("_NET_WM_STATE_MAXIMIZED_HORZ"));
486 }
487
488 bool DesktopRootWindowHostLinux::IsMinimized() const {
489 return HasWMSpecProperty("_NET_WM_STATE_HIDDEN");
490 }
491
492 void DesktopRootWindowHostLinux::OnCaptureReleased() {
493 native_widget_delegate_->OnMouseCaptureLost();
494 g_current_capture = NULL;
495 }
496
497 void DesktopRootWindowHostLinux::DispatchMouseEvent(ui::MouseEvent* event) {
498 if (!g_current_capture || g_current_capture == this) {
499 root_window_host_delegate_->OnHostMouseEvent(event);
500 } else {
501 // Another DesktopRootWindowHostLinux has installed itself as
502 // capture. Translate the event's location and dispatch to the other.
503 event->ConvertLocationToTarget(root_window_,
504 g_current_capture->root_window_);
505 g_current_capture->root_window_host_delegate_->OnHostMouseEvent(event);
506 }
507 }
508
509 bool DesktopRootWindowHostLinux::HasCapture() const {
510 return g_current_capture == this;
511 }
512
513 void DesktopRootWindowHostLinux::SetAlwaysOnTop(bool always_on_top) {
514 // TODO(erg):
515 NOTIMPLEMENTED();
516 }
517
518 InputMethod* DesktopRootWindowHostLinux::CreateInputMethod() {
519 ui::InputMethod* host = input_method_filter_->input_method();
520 return new InputMethodBridge(this, host);
521 }
522
523 internal::InputMethodDelegate*
524 DesktopRootWindowHostLinux::GetInputMethodDelegate() {
525 return this;
526 }
527
528 void DesktopRootWindowHostLinux::SetWindowTitle(const string16& title) {
529 XStoreName(xdisplay_, xwindow_, UTF16ToUTF8(title).c_str());
530 }
531
532 void DesktopRootWindowHostLinux::ClearNativeFocus() {
533 // This method is weird and misnamed. Instead of clearing the native focus,
534 // it sets the focus to our |content_window_|, which will trigger a cascade
535 // of focus changes into views.
536 if (content_window_ && content_window_->GetFocusManager() &&
537 content_window_->Contains(
538 content_window_->GetFocusManager()->GetFocusedWindow())) {
539 content_window_->GetFocusManager()->SetFocusedWindow(content_window_, NULL);
540 }
541 }
542
543 Widget::MoveLoopResult DesktopRootWindowHostLinux::RunMoveLoop(
544 const gfx::Vector2d& drag_offset) {
545 SetCapture();
546
547 if (x11_window_move_client_->RunMoveLoop(content_window_, drag_offset) ==
548 aura::client::MOVE_SUCCESSFUL)
549 return Widget::MOVE_LOOP_SUCCESSFUL;
550
551 return Widget::MOVE_LOOP_CANCELED;
552 }
553
554 void DesktopRootWindowHostLinux::EndMoveLoop() {
555 x11_window_move_client_->EndMoveLoop();
556 }
557
558 void DesktopRootWindowHostLinux::SetVisibilityChangedAnimationsEnabled(
559 bool value) {
560 // Much like the previous NativeWidgetGtk, we don't have anything to do here.
561 }
562
563 bool DesktopRootWindowHostLinux::ShouldUseNativeFrame() {
564 return false;
565 }
566
567 void DesktopRootWindowHostLinux::FrameTypeChanged() {
568 }
569
570 NonClientFrameView* DesktopRootWindowHostLinux::CreateNonClientFrameView() {
571 return NULL;
572 }
573
574 void DesktopRootWindowHostLinux::SetFullscreen(bool fullscreen) {
575 SetWMSpecState(fullscreen,
576 atom_cache_.GetAtom("_NET_WM_STATE_FULLSCREEN"),
577 None);
578 }
579
580 bool DesktopRootWindowHostLinux::IsFullscreen() const {
581 return HasWMSpecProperty("_NET_WM_STATE_FULLSCREEN");
582 }
583
584 void DesktopRootWindowHostLinux::SetOpacity(unsigned char opacity) {
585 // TODO(erg):
586 NOTIMPLEMENTED();
587 }
588
589 void DesktopRootWindowHostLinux::SetWindowIcons(
590 const gfx::ImageSkia& window_icon, const gfx::ImageSkia& app_icon) {
591 // TODO(erg):
592 NOTIMPLEMENTED();
593 }
594
595 void DesktopRootWindowHostLinux::SetAccessibleName(const string16& name) {
596 // TODO(erg):
597 NOTIMPLEMENTED();
598 }
599
600 void DesktopRootWindowHostLinux::SetAccessibleRole(
601 ui::AccessibilityTypes::Role role) {
602 // TODO(erg):
603 NOTIMPLEMENTED();
604 }
605
606 void DesktopRootWindowHostLinux::SetAccessibleState(
607 ui::AccessibilityTypes::State state) {
608 // TODO(erg):
609 NOTIMPLEMENTED();
610 }
611
612 void DesktopRootWindowHostLinux::InitModalType(ui::ModalType modal_type) {
613 // TODO(erg):
614 NOTIMPLEMENTED();
615 }
616
617 void DesktopRootWindowHostLinux::FlashFrame(bool flash_frame) {
618 // TODO(erg):
619 NOTIMPLEMENTED();
620 }
621
622 void DesktopRootWindowHostLinux::OnNativeWidgetFocus() {
623 native_widget_delegate_->AsWidget()->GetInputMethod()->OnFocus();
624 }
625
626 void DesktopRootWindowHostLinux::OnNativeWidgetBlur() {
627 if (xwindow_)
628 native_widget_delegate_->AsWidget()->GetInputMethod()->OnBlur();
629 }
630
631 ////////////////////////////////////////////////////////////////////////////////
632 // DesktopRootWindowHostLinux, aura::RootWindowHost implementation:
633
634 void DesktopRootWindowHostLinux::SetDelegate(
635 aura::RootWindowHostDelegate* delegate) {
636 root_window_host_delegate_ = delegate;
637 }
638
639 aura::RootWindow* DesktopRootWindowHostLinux::GetRootWindow() {
640 return root_window_;
641 }
642
643 gfx::AcceleratedWidget DesktopRootWindowHostLinux::GetAcceleratedWidget() {
644 return xwindow_;
645 }
646
647 void DesktopRootWindowHostLinux::Show() {
648 if (!window_mapped_) {
649 // Before we map the window, set size hints. Otherwise, some window managers
650 // will ignore toplevel XMoveWindow commands.
651 XSizeHints size_hints;
652 size_hints.flags = PPosition;
653 size_hints.x = bounds_.x();
654 size_hints.y = bounds_.y();
655 XSetWMNormalHints(xdisplay_, xwindow_, &size_hints);
656
657 XMapWindow(xdisplay_, xwindow_);
658
659 // We now block until our window is mapped. Some X11 APIs will crash and
660 // burn if passed |xwindow_| before the window is mapped, and XMapWindow is
661 // asynchronous.
662 base::MessagePumpAuraX11::Current()->BlockUntilWindowMapped(xwindow_);
663 window_mapped_ = true;
664 }
665 }
666
667 void DesktopRootWindowHostLinux::Hide() {
668 if (window_mapped_) {
669 XWithdrawWindow(xdisplay_, xwindow_, 0);
670 window_mapped_ = false;
671 }
672 }
673
674 void DesktopRootWindowHostLinux::ToggleFullScreen() {
675 NOTIMPLEMENTED();
676 }
677
678 gfx::Rect DesktopRootWindowHostLinux::GetBounds() const {
679 return bounds_;
680 }
681
682 void DesktopRootWindowHostLinux::SetBounds(const gfx::Rect& bounds) {
683 bool origin_changed = bounds_.origin() != bounds.origin();
684 bool size_changed = bounds_.size() != bounds.size();
685 XWindowChanges changes = {0};
686 unsigned value_mask = 0;
687
688 if (size_changed) {
689 changes.width = bounds.width();
690 changes.height = bounds.height();
691 value_mask |= CWHeight | CWWidth;
692 }
693
694 if (origin_changed) {
695 changes.x = bounds.x();
696 changes.y = bounds.y();
697 value_mask |= CWX | CWY;
698 }
699 if (value_mask)
700 XConfigureWindow(xdisplay_, xwindow_, value_mask, &changes);
701
702 // Assume that the resize will go through as requested, which should be the
703 // case if we're running without a window manager. If there's a window
704 // manager, it can modify or ignore the request, but (per ICCCM) we'll get a
705 // (possibly synthetic) ConfigureNotify about the actual size and correct
706 // |bounds_| later.
707 bounds_ = bounds;
708
709 if (origin_changed)
710 native_widget_delegate_->AsWidget()->OnNativeWidgetMove();
711 if (size_changed)
712 root_window_host_delegate_->OnHostResized(bounds.size());
713 else
714 root_window_host_delegate_->OnHostPaint();
715 }
716
717 gfx::Point DesktopRootWindowHostLinux::GetLocationOnNativeScreen() const {
718 return bounds_.origin();
719 }
720
721 void DesktopRootWindowHostLinux::SetCapture() {
722 // This is vaguely based on the old NativeWidgetGtk implementation.
723 //
724 // X11's XPointerGrab() shouldn't be used for everything; it doesn't map
725 // cleanly to Windows' SetCapture(). GTK only provides a separate concept of
726 // a grab that wasn't the X11 pointer grab, but was instead a manual
727 // redirection of the event. (You need to drop into GDK if you want to
728 // perform a raw X11 grab).
729
730 if (g_current_capture)
731 g_current_capture->OnCaptureReleased();
732
733 g_current_capture = this;
734
735 // TODO(erg): In addition to the above, NativeWidgetGtk performs a full X
736 // pointer grab when our NativeWidget is of type Menu. However, things work
737 // without it. Clicking inside a chrome window causes a release capture, and
738 // clicking outside causes an activation change. Since previous attempts at
739 // using XPointerGrab() to implement this have locked my X server, I'm going
740 // to skip this for now.
741 }
742
743 void DesktopRootWindowHostLinux::ReleaseCapture() {
744 if (g_current_capture)
745 g_current_capture->OnCaptureReleased();
746 }
747
748 void DesktopRootWindowHostLinux::SetCursor(gfx::NativeCursor cursor) {
749 XDefineCursor(xdisplay_, xwindow_, cursor.platform());
750 }
751
752 bool DesktopRootWindowHostLinux::QueryMouseLocation(
753 gfx::Point* location_return) {
754 ::Window root_return, child_return;
755 int root_x_return, root_y_return, win_x_return, win_y_return;
756 unsigned int mask_return;
757 XQueryPointer(xdisplay_,
758 xwindow_,
759 &root_return,
760 &child_return,
761 &root_x_return, &root_y_return,
762 &win_x_return, &win_y_return,
763 &mask_return);
764 *location_return = gfx::Point(
765 std::max(0, std::min(bounds_.width(), win_x_return)),
766 std::max(0, std::min(bounds_.height(), win_y_return)));
767 return (win_x_return >= 0 && win_x_return < bounds_.width() &&
768 win_y_return >= 0 && win_y_return < bounds_.height());
769 }
770
771 bool DesktopRootWindowHostLinux::ConfineCursorToRootWindow() {
772 NOTIMPLEMENTED();
773 return false;
774 }
775
776 void DesktopRootWindowHostLinux::UnConfineCursor() {
777 NOTIMPLEMENTED();
778 }
779
780 void DesktopRootWindowHostLinux::MoveCursorTo(const gfx::Point& location) {
781 NOTIMPLEMENTED();
782 }
783
784 void DesktopRootWindowHostLinux::SetFocusWhenShown(bool focus_when_shown) {
785 static const char* k_NET_WM_USER_TIME = "_NET_WM_USER_TIME";
786 focus_when_shown_ = focus_when_shown;
787 if (IsWindowManagerPresent() && !focus_when_shown_) {
788 ui::SetIntProperty(xwindow_,
789 k_NET_WM_USER_TIME,
790 k_NET_WM_USER_TIME,
791 0);
792 }
793 }
794
795 bool DesktopRootWindowHostLinux::CopyAreaToSkCanvas(
796 const gfx::Rect& source_bounds,
797 const gfx::Point& dest_offset,
798 SkCanvas* canvas) {
799 NOTIMPLEMENTED();
800 return false;
801 }
802
803 bool DesktopRootWindowHostLinux::GrabSnapshot(
804 const gfx::Rect& snapshot_bounds,
805 std::vector<unsigned char>* png_representation) {
806 NOTIMPLEMENTED();
807 return false;
808 }
809
810 void DesktopRootWindowHostLinux::PostNativeEvent(
811 const base::NativeEvent& native_event) {
812 DCHECK(xwindow_);
813 DCHECK(xdisplay_);
814 XEvent xevent = *native_event;
815 xevent.xany.display = xdisplay_;
816 xevent.xany.window = xwindow_;
817
818 switch (xevent.type) {
819 case EnterNotify:
820 case LeaveNotify:
821 case MotionNotify:
822 case KeyPress:
823 case KeyRelease:
824 case ButtonPress:
825 case ButtonRelease: {
826 // The fields used below are in the same place for all of events
827 // above. Using xmotion from XEvent's unions to avoid repeating
828 // the code.
829 xevent.xmotion.root = x_root_window_;
830 xevent.xmotion.time = CurrentTime;
831
832 gfx::Point point(xevent.xmotion.x, xevent.xmotion.y);
833 root_window_->ConvertPointToNativeScreen(&point);
834 xevent.xmotion.x_root = point.x();
835 xevent.xmotion.y_root = point.y();
836 }
837 default:
838 break;
839 }
840 XSendEvent(xdisplay_, xwindow_, False, 0, &xevent);
841 }
842
843 void DesktopRootWindowHostLinux::OnDeviceScaleFactorChanged(
844 float device_scale_factor) {
845 }
846
847 void DesktopRootWindowHostLinux::PrepareForShutdown() {
848 }
849
850 ////////////////////////////////////////////////////////////////////////////////
851 // DesktopRootWindowHostLinux, views::internal::InputMethodDelegate:
852
853 void DesktopRootWindowHostLinux::DispatchKeyEventPostIME(
854 const ui::KeyEvent& key) {
855 FocusManager* focus_manager =
856 native_widget_delegate_->AsWidget()->GetFocusManager();
857 if (native_widget_delegate_->OnKeyEvent(key) || !focus_manager)
858 return;
859 focus_manager->OnKeyEvent(key);
860 }
861
862 ////////////////////////////////////////////////////////////////////////////////
863 // DesktopRootWindowHostLinux, MessageLoop::Dispatcher implementation:
864
865 bool DesktopRootWindowHostLinux::Dispatch(const base::NativeEvent& event) {
866 XEvent* xev = event;
867
868 // May want to factor CheckXEventForConsistency(xev); into a common location
869 // since it is called here.
870 switch (xev->type) {
871 case Expose:
872 // TODO(erg): Can we only redraw the affected areas?
873 root_window_host_delegate_->OnHostPaint();
874 break;
875 case KeyPress: {
876 ui::KeyEvent keydown_event(xev, false);
877 root_window_host_delegate_->OnHostKeyEvent(&keydown_event);
878 break;
879 }
880 case KeyRelease: {
881 ui::KeyEvent keyup_event(xev, false);
882 root_window_host_delegate_->OnHostKeyEvent(&keyup_event);
883 break;
884 }
885 case ButtonPress: {
886 if (static_cast<int>(xev->xbutton.button) == kBackMouseButton ||
887 static_cast<int>(xev->xbutton.button) == kForwardMouseButton) {
888 aura::client::UserActionClient* gesture_client =
889 aura::client::GetUserActionClient(root_window_);
890 if (gesture_client) {
891 gesture_client->OnUserAction(
892 static_cast<int>(xev->xbutton.button) == kBackMouseButton ?
893 aura::client::UserActionClient::BACK :
894 aura::client::UserActionClient::FORWARD);
895 }
896 break;
897 }
898 } // fallthrough
899 case ButtonRelease: {
900 ui::MouseEvent mouseev(xev);
901 DispatchMouseEvent(&mouseev);
902 break;
903 }
904 case FocusOut:
905 if (xev->xfocus.mode != NotifyGrab) {
906 ReleaseCapture();
907 root_window_host_delegate_->OnHostLostWindowCapture();
908 } else {
909 root_window_host_delegate_->OnHostLostMouseGrab();
910 }
911 break;
912 case ConfigureNotify: {
913 DCHECK_EQ(xwindow_, xev->xconfigure.window);
914 DCHECK_EQ(xwindow_, xev->xconfigure.event);
915 // It's possible that the X window may be resized by some other means than
916 // from within aura (e.g. the X window manager can change the size). Make
917 // sure the root window size is maintained properly.
918 gfx::Rect bounds(xev->xconfigure.x, xev->xconfigure.y,
919 xev->xconfigure.width, xev->xconfigure.height);
920 bool size_changed = bounds_.size() != bounds.size();
921 bool origin_changed = bounds_.origin() != bounds.origin();
922 bounds_ = bounds;
923 if (size_changed)
924 root_window_host_delegate_->OnHostResized(bounds.size());
925 if (origin_changed)
926 root_window_host_delegate_->OnHostMoved(bounds_.origin());
927 break;
928 }
929 case GenericEvent: {
930 ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
931 if (!factory->ShouldProcessXI2Event(xev))
932 break;
933
934 ui::EventType type = ui::EventTypeFromNative(xev);
935 XEvent last_event;
936 int num_coalesced = 0;
937
938 switch (type) {
939 // case ui::ET_TOUCH_MOVED:
940 // num_coalesced = CoalescePendingMotionEvents(xev, &last_event);
941 // if (num_coalesced > 0)
942 // xev = &last_event;
943 // // fallthrough
944 // case ui::ET_TOUCH_PRESSED:
945 // case ui::ET_TOUCH_RELEASED: {
946 // ui::TouchEvent touchev(xev);
947 // root_window_host_delegate_->OnHostTouchEvent(&touchev);
948 // break;
949 // }
950 case ui::ET_MOUSE_MOVED:
951 case ui::ET_MOUSE_DRAGGED:
952 case ui::ET_MOUSE_PRESSED:
953 case ui::ET_MOUSE_RELEASED:
954 case ui::ET_MOUSE_ENTERED:
955 case ui::ET_MOUSE_EXITED: {
956 if (type == ui::ET_MOUSE_MOVED || type == ui::ET_MOUSE_DRAGGED) {
957 // If this is a motion event, we want to coalesce all pending motion
958 // events that are at the top of the queue.
959 num_coalesced = ui::CoalescePendingMotionEvents(xev, &last_event);
960 if (num_coalesced > 0)
961 xev = &last_event;
962 } else if (type == ui::ET_MOUSE_PRESSED) {
963 XIDeviceEvent* xievent =
964 static_cast<XIDeviceEvent*>(xev->xcookie.data);
965 int button = xievent->detail;
966 if (button == kBackMouseButton || button == kForwardMouseButton) {
967 aura::client::UserActionClient* gesture_client =
968 aura::client::GetUserActionClient(
969 root_window_host_delegate_->AsRootWindow());
970 if (gesture_client) {
971 bool reverse_direction =
972 ui::IsTouchpadEvent(xev) && ui::IsNaturalScrollEnabled();
973 gesture_client->OnUserAction(
974 (button == kBackMouseButton && !reverse_direction) ||
975 (button == kForwardMouseButton && reverse_direction) ?
976 aura::client::UserActionClient::BACK :
977 aura::client::UserActionClient::FORWARD);
978 }
979 break;
980 }
981 }
982 ui::MouseEvent mouseev(xev);
983 DispatchMouseEvent(&mouseev);
984 break;
985 }
986 case ui::ET_MOUSEWHEEL: {
987 ui::MouseWheelEvent mouseev(xev);
988 DispatchMouseEvent(&mouseev);
989 break;
990 }
991 case ui::ET_SCROLL_FLING_START:
992 case ui::ET_SCROLL_FLING_CANCEL:
993 case ui::ET_SCROLL: {
994 ui::ScrollEvent scrollev(xev);
995 root_window_host_delegate_->OnHostScrollEvent(&scrollev);
996 break;
997 }
998 case ui::ET_UNKNOWN:
999 break;
1000 default:
1001 NOTREACHED();
1002 }
1003
1004 // If we coalesced an event we need to free its cookie.
1005 if (num_coalesced > 0)
1006 XFreeEventData(xev->xgeneric.display, &last_event.xcookie);
1007 break;
1008 }
1009 case MapNotify: {
1010 // If there's no window manager running, we need to assign the X input
1011 // focus to our host window.
1012 if (!IsWindowManagerPresent() && focus_when_shown_)
1013 XSetInputFocus(xdisplay_, xwindow_, RevertToNone, CurrentTime);
1014 break;
1015 }
1016 case ClientMessage: {
1017 Atom message_type = static_cast<Atom>(xev->xclient.data.l[0]);
1018 if (message_type == atom_cache_.GetAtom("WM_DELETE_WINDOW")) {
1019 // We have received a close message from the window manager.
1020 root_window_->OnRootWindowHostCloseRequested();
1021 } else if (message_type == atom_cache_.GetAtom("_NET_WM_PING")) {
1022 XEvent reply_event = *xev;
1023 reply_event.xclient.window = x_root_window_;
1024
1025 XSendEvent(xdisplay_,
1026 reply_event.xclient.window,
1027 False,
1028 SubstructureRedirectMask | SubstructureNotifyMask,
1029 &reply_event);
1030 }
1031 break;
1032 }
1033 case MappingNotify: {
1034 switch (xev->xmapping.request) {
1035 case MappingModifier:
1036 case MappingKeyboard:
1037 XRefreshKeyboardMapping(&xev->xmapping);
1038 root_window_->OnKeyboardMappingChanged();
1039 break;
1040 case MappingPointer:
1041 ui::UpdateButtonMap();
1042 break;
1043 default:
1044 NOTIMPLEMENTED() << " Unknown request: " << xev->xmapping.request;
1045 break;
1046 }
1047 break;
1048 }
1049 case MotionNotify: {
1050 // Discard all but the most recent motion event that targets the same
1051 // window with unchanged state.
1052 XEvent last_event;
1053 while (XPending(xev->xany.display)) {
1054 XEvent next_event;
1055 XPeekEvent(xev->xany.display, &next_event);
1056 if (next_event.type == MotionNotify &&
1057 next_event.xmotion.window == xev->xmotion.window &&
1058 next_event.xmotion.subwindow == xev->xmotion.subwindow &&
1059 next_event.xmotion.state == xev->xmotion.state) {
1060 XNextEvent(xev->xany.display, &last_event);
1061 xev = &last_event;
1062 } else {
1063 break;
1064 }
1065 }
1066
1067 ui::MouseEvent mouseev(xev);
1068 DispatchMouseEvent(&mouseev);
1069 break;
1070 }
1071 case PropertyNotify: {
1072 // Get our new window property state if the WM has told us its changed.
1073 ::Atom state = atom_cache_.GetAtom("_NET_WM_STATE");
1074
1075 std::vector< ::Atom> atom_list;
1076 if (xev->xproperty.atom == state &&
1077 ui::GetAtomArrayProperty(xwindow_, "_NET_WM_STATE", &atom_list)) {
1078 window_properties_.clear();
1079 std::copy(atom_list.begin(), atom_list.end(),
1080 inserter(window_properties_, window_properties_.begin()));
1081
1082 // Now that we have different window properties, we may need to
1083 // relayout the window. (The windows code doesn't need this because
1084 // their window change is synchronous.)
1085 native_widget_delegate_->AsWidget()->GetRootView()->Layout();
1086 }
1087 }
1088 }
1089 return true;
1090 }
1091
1092 ////////////////////////////////////////////////////////////////////////////////
1093 // DesktopRootWindowHost, public:
1094
1095 // static
1096 DesktopRootWindowHost* DesktopRootWindowHost::Create(
1097 internal::NativeWidgetDelegate* native_widget_delegate,
1098 DesktopNativeWidgetAura* desktop_native_widget_aura,
1099 const gfx::Rect& initial_bounds) {
1100 return new DesktopRootWindowHostLinux(native_widget_delegate,
1101 desktop_native_widget_aura,
1102 initial_bounds);
1103 }
1104
1105 } // namespace views
OLDNEW
« no previous file with comments | « ui/views/widget/desktop_root_window_host_linux.h ('k') | ui/views/widget/desktop_root_window_host_win.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698