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

Unified Diff: ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc

Issue 2165083002: Linux: Refactor X11DesktopHandler (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add GetTimestamp() in libgtk2ui files Created 4 years, 4 months 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 side-by-side diff with in-line comments
Download patch
Index: ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
index aeadc78f2fe40a9863c39daa451852a86f78cf9f..11f8fe57ec53ad1cc3ff8ece36767da798cdb445 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
@@ -91,6 +91,7 @@ const char* kAtomsToCache[] = {
"UTF8_STRING",
"WM_DELETE_WINDOW",
"WM_PROTOCOLS",
+ "_NET_ACTIVE_WINDOW",
"_NET_FRAME_EXTENTS",
"_NET_WM_CM_S0",
"_NET_WM_DESKTOP",
@@ -182,6 +183,11 @@ DesktopWindowTreeHostX11::DesktopWindowTreeHostX11(
custom_window_shape_(false),
urgency_hint_set_(false),
activatable_(true),
+ has_pointer_(false),
+ has_pointer_grab_(false),
+ has_pointer_focus_(false),
+ has_window_focus_(false),
+ has_focus_(false),
close_widget_factory_(this) {
}
@@ -230,20 +236,75 @@ gfx::Rect DesktopWindowTreeHostX11::GetX11RootWindowOuterBounds() const {
return window_shape_.get();
}
-void DesktopWindowTreeHostX11::HandleNativeWidgetActivationChanged(
- bool active) {
- if (active) {
+void DesktopWindowTreeHostX11::BeforeActivationStateChanged() {
+ was_active_ = IsActive();
+ had_pointer_grab_ = has_pointer_grab_;
+ had_window_focus_ = has_window_focus_;
+}
+
+void DesktopWindowTreeHostX11::AfterActivationStateChanged() {
+ if (had_pointer_grab_ && !has_pointer_grab_)
+ dispatcher()->OnHostLostMouseGrab();
+ if (had_window_focus_ && !has_window_focus_)
+ OnHostLostWindowCapture();
danakj 2016/08/19 21:43:45 Why do we not do this if we had pointer focus but
Tom (Use chromium acct) 2016/08/22 20:27:07 You're right, I was unclear about the definition o
danakj 2016/08/26 19:58:43 Agree, thanks for figuring out what it means
+
+ if (!was_active_ && IsActive()) {
FlashFrame(false);
OnHostActivated();
+ // TODO(thomasanderson): Remove this window shuffling and use XWindowCache
+ // instead.
open_windows().remove(xwindow_);
open_windows().insert(open_windows().begin(), xwindow_);
- } else {
- ReleaseCapture();
}
+ if (was_active_ != IsActive()) {
+ desktop_native_widget_aura_->HandleActivationChanged(IsActive());
+ native_widget_delegate_->AsWidget()->GetRootView()->SchedulePaint();
+ }
+}
- desktop_native_widget_aura_->HandleActivationChanged(active);
+void DesktopWindowTreeHostX11::OnCrossingEvent(bool enter,
+ bool focus,
danakj 2016/08/19 21:43:45 focus_in_window_or_ancestor?
Tom (Use chromium acct) 2016/08/22 20:27:07 Done.
+ int detail) {
+ if (detail == NotifyInferior)
danakj 2016/08/19 21:43:45 When the mouse moves from the root into |xwindow_|
danakj 2016/08/19 23:17:32 Oh I see. EnterNotify with Inferior means we're c
Tom (Use chromium acct) 2016/08/22 20:27:07 Done.
+ return;
+
+ BeforeActivationStateChanged();
+
+ has_pointer_ = enter;
+ if (focus && !has_window_focus_)
danakj 2016/08/19 21:43:45 // If focus is not in an ancestor then this crossi
Tom (Use chromium acct) 2016/08/22 20:27:07 Done. I wrote something different though.
+ has_pointer_focus_ = has_pointer_;
- native_widget_delegate_->AsWidget()->GetRootView()->SchedulePaint();
+ AfterActivationStateChanged();
+}
+
+void DesktopWindowTreeHostX11::OnFocusEvent(bool focus_in,
+ int mode,
+ int detail) {
+ if (detail == NotifyInferior)
danakj 2016/08/19 23:29:58 Can you say the same thing here moreorless?
Tom (Use chromium acct) 2016/08/22 20:27:07 Done.
+ return;
+ BeforeActivationStateChanged();
+ if (mode != NotifyWhileGrabbed && detail != NotifyPointer)
danakj 2016/08/19 23:29:58 Can you throw some comments here kinda like the he
danakj 2016/08/19 23:59:30 Also can you explain by ignore Pointer here in a c
danakj 2016/08/19 23:59:30 Maybe better would be to say that while grabbed we
Tom (Use chromium acct) 2016/08/22 20:27:07 Done.
Tom (Use chromium acct) 2016/08/22 20:27:07 Done.
+ has_focus_ = focus_in;
+ if (mode != NotifyGrab && mode != NotifyUngrab &&
+ mode != XINotifyPassiveGrab && mode != XINotifyPassiveUngrab) {
+ if (detail != NotifyPointer)
+ has_window_focus_ = focus_in;
+ if (has_pointer_) {
+ switch (detail) {
+ case NotifyAncestor:
+ case NotifyVirtual:
danakj 2016/08/19 23:59:30 Can you leave a comment why NonLinear(Virtual) are
Tom (Use chromium acct) 2016/08/22 20:27:07 Done.
+ has_pointer_focus_ = !focus_in;
+ break;
+ case NotifyPointer:
+ has_pointer_focus_ = focus_in;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ ignore_input_ = false;
+ AfterActivationStateChanged();
}
void DesktopWindowTreeHostX11::AddObserver(
@@ -308,8 +369,8 @@ void DesktopWindowTreeHostX11::OnNativeWidgetCreated(
window()->SetProperty(kViewsWindowForRootWindow, content_window_);
window()->SetProperty(kHostForRootWindow, this);
- // Ensure that the X11DesktopHandler exists so that it dispatches activation
- // messages to us.
+ // Ensure that the X11DesktopHandler exists so that it tracks create/destroy
+ // notify events.
X11DesktopHandler::get();
// TODO(erg): Unify this code once the other consumer goes away.
@@ -406,7 +467,7 @@ void DesktopWindowTreeHostX11::ShowWindowWithState(
ui::WindowShowState show_state) {
if (compositor())
compositor()->SetVisible(true);
- if (!window_mapped_)
+ if (!IsVisible())
MapWindow(show_state);
switch (show_state) {
@@ -426,8 +487,7 @@ void DesktopWindowTreeHostX11::ShowWindowWithState(
// Makes the window activated by default if the state is not INACTIVE or
// MINIMIZED.
if (show_state != ui::SHOW_STATE_INACTIVE &&
- show_state != ui::SHOW_STATE_MINIMIZED &&
- activatable_) {
+ show_state != ui::SHOW_STATE_MINIMIZED) {
Activate();
}
@@ -443,7 +503,7 @@ void DesktopWindowTreeHostX11::ShowMaximizedWithBounds(
}
bool DesktopWindowTreeHostX11::IsVisible() const {
- return window_mapped_;
+ return window_mapped_ && !wait_for_unmap_;
}
void DesktopWindowTreeHostX11::SetSize(const gfx::Size& requested_size) {
@@ -614,22 +674,77 @@ void DesktopWindowTreeHostX11::SetShape(
}
void DesktopWindowTreeHostX11::Activate() {
- if (!window_mapped_)
+ if (!IsVisible() || !activatable_)
return;
- X11DesktopHandler::get()->ActivateWindow(xwindow_);
+ BeforeActivationStateChanged();
+
+ ignore_input_ = false;
+
+ // wmii says that it supports _NET_ACTIVE_WINDOW but does not.
+ // https://code.google.com/p/wmii/issues/detail?id=266
+ static bool wm_supports_active_window =
+ ui::GuessWindowManager() != ui::WM_WMII &&
+ ui::WmSupportsHint(atom_cache_.GetAtom("_NET_ACTIVE_WINDOW"));
+
+ Time timestamp = ui::X11EventSource::GetInstance()->GetTimestamp();
+
+ if (wm_supports_active_window) {
+ XEvent xclient;
+ memset(&xclient, 0, sizeof(xclient));
+ xclient.type = ClientMessage;
+ xclient.xclient.window = xwindow_;
+ xclient.xclient.message_type = atom_cache_.GetAtom("_NET_ACTIVE_WINDOW");
+ xclient.xclient.format = 32;
+ xclient.xclient.data.l[0] = 1; // Specified we are an app.
+ xclient.xclient.data.l[1] = timestamp;
+ // TODO(thomasanderson): if another chrome window is active, specify that in
+ // data.l[2]. The EWMH spec claims this may make the WM more likely to
+ // service our _NET_ACTIVE_WINDOW request.
+ xclient.xclient.data.l[2] = None;
+ xclient.xclient.data.l[3] = 0;
+ xclient.xclient.data.l[4] = 0;
+
+ XSendEvent(xdisplay_, x_root_window_, False,
+ SubstructureRedirectMask | SubstructureNotifyMask, &xclient);
+ } else {
+ XRaiseWindow(xdisplay_, xwindow_);
+ // Directly ask the X server to give focus to the window. Note that the call
+ // will raise an X error if the window is not mapped.
+ XSetInputFocus(xdisplay_, xwindow_, RevertToParent, timestamp);
+ // At this point, we know we will receive focus, and some tests depend on a
+ // window being IsActive() immediately after an Activate(), so just set this
+ // state now.
+ has_pointer_focus_ = false;
+ has_window_focus_ = true;
+ }
+ AfterActivationStateChanged();
}
void DesktopWindowTreeHostX11::Deactivate() {
- if (!IsActive())
- return;
+ BeforeActivationStateChanged();
+
+ // Ignore future input events.
+ ignore_input_ = true;
ReleaseCapture();
- X11DesktopHandler::get()->DeactivateWindow(xwindow_);
+ XLowerWindow(xdisplay_, xwindow_);
+
+ AfterActivationStateChanged();
}
bool DesktopWindowTreeHostX11::IsActive() const {
- return X11DesktopHandler::get()->IsActiveWindow(xwindow_);
+ // Focus and stacking order are independent in X11. Since we cannot guarantee
+ // a window is topmost iff it has focus, just use the focus state to determine
+ // if a window is active. Note that Activate() and Deactivate() change the
+ // stacking order in addition to changing the focus state.
+ bool is_active = (has_focus_ || has_pointer_focus_) && !ignore_input_;
danakj 2016/08/19 23:29:58 FWIW normally an X window will show itself as visi
Tom (Use chromium acct) 2016/08/22 20:27:07 The cross-platform code seems to want a window to
danakj 2016/08/22 20:32:42 OK just to be clear then, when alt-tabbing does th
+
+ // is_active => window_mapped_
+ // !window_mapped_ => !is_active
+ DCHECK(!is_active || window_mapped_);
+
+ return is_active;
}
void DesktopWindowTreeHostX11::Maximize() {
@@ -650,7 +765,7 @@ void DesktopWindowTreeHostX11::Maximize() {
// Some WMs do not respect maximization hints on unmapped windows, so we
// save this one for later too.
- should_maximize_after_map_ = !window_mapped_;
+ should_maximize_after_map_ = !IsVisible();
// When we are in the process of requesting to maximize a window, we can
// accurately keep track of our restored bounds instead of relying on the
@@ -971,7 +1086,7 @@ void DesktopWindowTreeHostX11::SizeConstraintsChanged() {
gfx::Transform DesktopWindowTreeHostX11::GetRootTransform() const {
display::Display display = display::Screen::GetScreen()->GetPrimaryDisplay();
- if (window_mapped_) {
+ if (IsVisible()) {
aura::Window* win = const_cast<aura::Window*>(window());
display = display::Screen::GetScreen()->GetDisplayNearestWindow(win);
}
@@ -996,9 +1111,8 @@ void DesktopWindowTreeHostX11::ShowImpl() {
}
void DesktopWindowTreeHostX11::HideImpl() {
- if (window_mapped_) {
+ if (IsVisible()) {
XWithdrawWindow(xdisplay_, xwindow_, 0);
- window_mapped_ = false;
wait_for_unmap_ = true;
}
native_widget_delegate_->OnNativeWidgetVisibilityChanged(false);
@@ -1424,7 +1538,7 @@ void DesktopWindowTreeHostX11::OnFrameExtentsUpdated() {
}
void DesktopWindowTreeHostX11::UpdateMinAndMaxSize() {
- if (!window_mapped_)
+ if (!IsVisible())
return;
gfx::Size minimum_in_pixels =
@@ -1480,7 +1594,6 @@ void DesktopWindowTreeHostX11::UpdateWMUserTime(
PropModeReplace,
reinterpret_cast<const unsigned char *>(&wm_user_time_ms),
1);
- X11DesktopHandler::get()->set_wm_user_time_ms(wm_user_time_ms);
}
}
@@ -1681,17 +1794,14 @@ void DesktopWindowTreeHostX11::MapWindow(ui::WindowShowState show_state) {
// If SHOW_STATE_INACTIVE, tell the window manager not to focus the window
// when mapping. This is done by setting the _NET_WM_USER_TIME to 0. See e.g.
// http://standards.freedesktop.org/wm-spec/latest/ar01s05.html
- unsigned long wm_user_time_ms = (show_state == ui::SHOW_STATE_INACTIVE) ?
- 0 : X11DesktopHandler::get()->wm_user_time_ms();
+ ignore_input_ = show_state == ui::SHOW_STATE_INACTIVE;
+ unsigned long wm_user_time_ms =
+ ignore_input_ ? 0 : ui::X11EventSource::GetInstance()->GetTimestamp();
if (show_state == ui::SHOW_STATE_INACTIVE || wm_user_time_ms != 0) {
- XChangeProperty(xdisplay_,
- xwindow_,
- atom_cache_.GetAtom("_NET_WM_USER_TIME"),
- XA_CARDINAL,
- 32,
- PropModeReplace,
- reinterpret_cast<const unsigned char *>(&wm_user_time_ms),
- 1);
+ XChangeProperty(
+ xdisplay_, xwindow_, atom_cache_.GetAtom("_NET_WM_USER_TIME"),
+ XA_CARDINAL, 32, PropModeReplace,
+ reinterpret_cast<const unsigned char*>(&wm_user_time_ms), 1);
}
ui::X11EventSource* event_source = ui::X11EventSource::GetInstance();
@@ -1753,15 +1863,15 @@ uint32_t DesktopWindowTreeHostX11::DispatchEvent(
switch (xev->type) {
case EnterNotify:
case LeaveNotify: {
+ OnCrossingEvent(xev->type == EnterNotify, xev->xcrossing.focus,
+ xev->xcrossing.detail);
+
// Ignore EventNotify and LeaveNotify events from children of |xwindow_|.
// NativeViewGLSurfaceGLX adds a child to |xwindow_|.
- // TODO(pkotwicz|tdanderson): Figure out whether the suppression is
- // necessary. crbug.com/385716
- if (xev->xcrossing.detail == NotifyInferior)
- break;
-
- ui::MouseEvent mouse_event(xev);
- DispatchMouseEvent(&mouse_event);
+ if (xev->xcrossing.detail != NotifyInferior) {
+ ui::MouseEvent mouse_event(xev);
+ DispatchMouseEvent(&mouse_event);
+ }
break;
}
case Expose: {
@@ -1777,8 +1887,7 @@ uint32_t DesktopWindowTreeHostX11::DispatchEvent(
}
case KeyRelease: {
// There is no way to deactivate a window in X11 so ignore input if
- // window is supposed to be 'inactive'. See comments in
- // X11DesktopHandler::DeactivateWindow() for more details.
+ // window is supposed to be 'inactive'.
if (!IsActive() && !HasCapture())
break;
@@ -1809,18 +1918,12 @@ uint32_t DesktopWindowTreeHostX11::DispatchEvent(
}
break;
}
- case FocusOut:
- if (xev->xfocus.mode != NotifyGrab) {
- ReleaseCapture();
- OnHostLostWindowCapture();
- X11DesktopHandler::get()->ProcessXEvent(xev);
- } else {
- dispatcher()->OnHostLostMouseGrab();
- }
- break;
case FocusIn:
- X11DesktopHandler::get()->ProcessXEvent(xev);
+ case FocusOut: {
danakj 2016/08/19 21:43:45 nit: {} are not needed since there's no vars decla
Tom (Use chromium acct) 2016/08/22 20:27:07 Done.
+ OnFocusEvent(xev->type == FocusIn, event->xfocus.mode,
+ event->xfocus.detail);
break;
+ }
case ConfigureNotify: {
DCHECK_EQ(xwindow_, xev->xconfigure.window);
DCHECK_EQ(xwindow_, xev->xconfigure.event);
@@ -1860,6 +1963,22 @@ uint32_t DesktopWindowTreeHostX11::DispatchEvent(
if (!factory->ShouldProcessXI2Event(xev))
break;
+ XIEnterEvent* enter_event = static_cast<XIEnterEvent*>(xev->xcookie.data);
+ switch (static_cast<XIEvent*>(xev->xcookie.data)->evtype) {
+ case XI_Enter:
+ case XI_Leave:
+ OnCrossingEvent(enter_event->evtype == XI_Enter, enter_event->focus,
+ enter_event->detail);
+ break;
+ case XI_FocusIn:
+ case XI_FocusOut:
+ OnFocusEvent(enter_event->evtype == XI_FocusIn, enter_event->mode,
danakj 2016/08/19 23:59:30 Would you consider rewriting the mode to non-XI co
Tom (Use chromium acct) 2016/08/22 20:27:07 Done.
+ enter_event->detail);
+ break;
+ default:
+ break;
+ }
+
ui::EventType type = ui::EventTypeFromNative(xev);
XEvent last_event;
int num_coalesced = 0;
@@ -1941,7 +2060,13 @@ uint32_t DesktopWindowTreeHostX11::DispatchEvent(
break;
}
case UnmapNotify: {
danakj 2016/08/19 21:43:45 jw do we care about DestroyNotify? Presumably no..
Tom (Use chromium acct) 2016/08/22 20:27:07 no
+ window_mapped_ = false;
wait_for_unmap_ = false;
+ has_pointer_ = false;
+ has_pointer_grab_ = false;
+ has_pointer_focus_ = false;
+ has_window_focus_ = false;
+ has_focus_ = false;
FOR_EACH_OBSERVER(DesktopWindowTreeHostObserverX11,
observer_list_,
OnWindowUnmapped(xwindow_));

Powered by Google App Engine
This is Rietveld 408576698