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

Unified Diff: ui/views/widget/desktop_root_window_host_linux.cc

Issue 10916349: linux_aura: Start implementing DesktopRootWindowHostLinux (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 3 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
« no previous file with comments | « ui/views/widget/desktop_root_window_host_linux.h ('k') | ui/views/widget/x11_window_event_filter.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ui/views/widget/desktop_root_window_host_linux.cc
diff --git a/ui/views/widget/desktop_root_window_host_linux.cc b/ui/views/widget/desktop_root_window_host_linux.cc
index c2f28657a357076baaa232a296e31411b0281a71..1d82f018399839c6966c3b72477587a3ec2b1f48 100644
--- a/ui/views/widget/desktop_root_window_host_linux.cc
+++ b/ui/views/widget/desktop_root_window_host_linux.cc
@@ -4,17 +4,172 @@
#include "ui/views/widget/desktop_root_window_host_linux.h"
+#include <X11/extensions/XInput2.h>
+#include <X11/Xatom.h>
+#include <X11/Xutil.h>
+
+#include "base/message_pump_aurax11.h"
+#include "base/stringprintf.h"
+#include "ui/aura/client/screen_position_client.h"
+#include "ui/aura/client/user_action_client.h"
+#include "ui/aura/desktop/desktop_activation_client.h"
+#include "ui/aura/desktop/desktop_dispatcher_client.h"
+#include "ui/aura/focus_manager.h"
#include "ui/aura/root_window.h"
+#include "ui/aura/shared/compound_event_filter.h"
+#include "ui/aura/shared/input_method_event_filter.h"
+#include "ui/base/touch/touch_factory.h"
+#include "ui/base/x/x11_util.h"
+#include "ui/views/widget/desktop_capture_client.h"
+#include "ui/views/widget/x11_desktop_handler.h"
+#include "ui/views/widget/x11_window_event_filter.h"
namespace views {
+namespace {
+
+// Standard Linux mouse buttons for going back and forward.
+const int kBackMouseButton = 8;
+const int kForwardMouseButton = 9;
+
+const char* kAtomsToCache[] = {
+ "WM_DELETE_WINDOW",
+ "_NET_WM_PING",
+ "_NET_WM_PID",
+ "WM_S0",
+ NULL
+};
+
+} // namespace
+
////////////////////////////////////////////////////////////////////////////////
// DesktopRootWindowHostLinux, public:
-DesktopRootWindowHostLinux::DesktopRootWindowHostLinux() {
+DesktopRootWindowHostLinux::DesktopRootWindowHostLinux()
+ : xdisplay_(base::MessagePumpAuraX11::GetDefaultXDisplay()),
+ xwindow_(0),
+ x_root_window_(DefaultRootWindow(xdisplay_)),
+ atom_cache_(xdisplay_, kAtomsToCache),
+ window_mapped_(false),
+ focus_when_shown_(false) {
}
DesktopRootWindowHostLinux::~DesktopRootWindowHostLinux() {
+ base::MessagePumpAuraX11::Current()->RemoveDispatcherForWindow(xwindow_);
+ XDestroyWindow(xdisplay_, xwindow_);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopRootWindowHostLinux, private:
+
+void DesktopRootWindowHostLinux::InitX11Window(const gfx::Rect& bounds) {
+ XSetWindowAttributes swa;
+ memset(&swa, 0, sizeof(swa));
+ swa.background_pixmap = None;
+ xwindow_ = XCreateWindow(
+ xdisplay_, x_root_window_,
+ bounds.x(), bounds.y(), bounds.width(), bounds.height(),
+ 0, // border width
+ CopyFromParent, // depth
+ InputOutput,
+ CopyFromParent, // visual
+ CWBackPixmap,
+ &swa);
+ base::MessagePumpAuraX11::Current()->AddDispatcherForWindow(this, xwindow_);
+
+ // TODO(erg): Maybe need to set a ViewProp here like in RWHL::RWHL().
+
+ long event_mask = ButtonPressMask | ButtonReleaseMask | FocusChangeMask |
+ KeyPressMask | KeyReleaseMask |
+ EnterWindowMask | LeaveWindowMask |
+ ExposureMask | VisibilityChangeMask |
+ StructureNotifyMask | PropertyChangeMask |
+ PointerMotionMask;
+ XSelectInput(xdisplay_, xwindow_, event_mask);
+ XFlush(xdisplay_);
+
+ // TODO(erg): Something about an invisible cursor here? Don't think I need
+ // it, but this is where it was.
+
+ // TODO(erg): We currently only request window deletion events. We also
+ // should listen for activation events and anything else that GTK+ listens
+ // for, and do something useful.
+ ::Atom protocols[2];
+ protocols[0] = atom_cache_.GetAtom("WM_DELETE_WINDOW");
+ protocols[1] = atom_cache_.GetAtom("_NET_WM_PING");
+ XSetWMProtocols(xdisplay_, xwindow_, protocols, 2);
+
+ // We need a WM_CLIENT_MACHINE and WM_LOCALE_NAME value so we integrate with
+ // the desktop environment.
+ XSetWMProperties(xdisplay_, xwindow_, NULL, NULL, NULL, 0, NULL, NULL, NULL);
+
+ // Likewise, the X server needs to know this window's pid so it knows which
+ // program to kill if the window hangs.
+ pid_t pid = getpid();
+ XChangeProperty(xdisplay_,
+ xwindow_,
+ atom_cache_.GetAtom("_NET_WM_PID"),
+ XA_CARDINAL,
+ 32,
+ PropModeReplace,
+ reinterpret_cast<unsigned char*>(&pid), 1);
+
+ // TODO(erg): Now that we're forked from RootWindowHostLinux, we should be
+ // doing a much better job about communicating things like the window title
+ // and icon to the window manager, which should replace this piece of copied
+ // code.
+ static int root_window_number = 0;
+ std::string name = StringPrintf("aura_root_%d", root_window_number++);
+ XStoreName(xdisplay_, xwindow_, name.c_str());
+}
+
+// TODO(erg): This method should basically be everything I need form
+// RootWindowHostLinux::RootWindowHostLinux().
+void DesktopRootWindowHostLinux::InitRootWindow(
+ const Widget::InitParams& params) {
+ aura::RootWindow::CreateParams rw_params(params.bounds);
+ rw_params.host = this;
+ root_window_.reset(new aura::RootWindow(rw_params));
+ root_window_->Init();
+ root_window_->AddChild(content_window_);
+ root_window_host_delegate_ = root_window_.get();
+
+ capture_client_.reset(new DesktopCaptureClient);
+ aura::client::SetCaptureClient(root_window_.get(), capture_client_.get());
+
+ root_window_->set_focus_manager(
+ X11DesktopHandler::get()->get_focus_manager());
+
+ aura::DesktopActivationClient* activation_client =
+ X11DesktopHandler::get()->get_activation_client();
+ aura::client::SetActivationClient(
+ root_window_.get(), activation_client);
+
+ dispatcher_client_.reset(new aura::DesktopDispatcherClient);
+ aura::client::SetDispatcherClient(root_window_.get(),
+ dispatcher_client_.get());
+
+ // No event filter for aura::Env. Create CompoundEvnetFilter per RootWindow.
+ root_window_event_filter_ = new aura::shared::CompoundEventFilter;
+ // Pass ownership of the filter to the root_window.
+ root_window_->SetEventFilter(root_window_event_filter_);
+
+ input_method_filter_.reset(new aura::shared::InputMethodEventFilter());
+ input_method_filter_->SetInputMethodPropertyInRootWindow(root_window_.get());
+ root_window_event_filter_->AddFilter(input_method_filter_.get());
+
+ // TODO(erg): Unify this code once the other consumer goes away.
+ x11_window_event_filter_.reset(
+ new X11WindowEventFilter(root_window_.get(), activation_client));
+ x11_window_event_filter_->SetUseHostWindowBorders(false);
+ root_window_event_filter_->AddFilter(x11_window_event_filter_.get());
+}
+
+bool DesktopRootWindowHostLinux::IsWindowManagerPresent() {
+ // Per ICCCM 2.8, "Manager Selections", window managers should take ownership
+ // of WM_Sn selections (where n is a screen number).
+ return XGetSelectionOwner(
+ xdisplay_, atom_cache_.GetAtom("WM_S0")) != None;
}
////////////////////////////////////////////////////////////////////////////////
@@ -22,8 +177,24 @@ DesktopRootWindowHostLinux::~DesktopRootWindowHostLinux() {
void DesktopRootWindowHostLinux::Init(aura::Window* content_window,
const Widget::InitParams& params) {
- // TODO(erg):
- NOTIMPLEMENTED();
+ content_window_ = content_window;
+
+ // TODO(erg): Check whether we *should* be building a RootWindowHost here, or
+ // whether we should be proxying requests to another DRWHL.
+
+ // TODO(erg): We can finally solve the role problem! Based on params, try to
+ // determine whether this is a utility window such as a menu.
+
+ InitX11Window(params.bounds);
+ InitRootWindow(params);
+
+ // TODO(erg): This should be done by a LayoutManager instead of being a
+ // one-off hack.
+ content_window_->SetBounds(params.bounds);
+
+ // This needs to be the intersection of:
+ // - NativeWidgetAura::InitNativeWidget()
+ // - DesktopNativeWidgetHelperAura::PreInitialize()
}
void DesktopRootWindowHostLinux::Close() {
@@ -32,20 +203,22 @@ void DesktopRootWindowHostLinux::Close() {
}
void DesktopRootWindowHostLinux::CloseNow() {
- // TODO(erg):
NOTIMPLEMENTED();
}
aura::RootWindowHost* DesktopRootWindowHostLinux::AsRootWindowHost() {
- // TODO(erg):
- NOTIMPLEMENTED();
- return NULL;
+ return this;
}
void DesktopRootWindowHostLinux::ShowWindowWithState(
ui::WindowShowState show_state) {
- // TODO(erg):
- NOTIMPLEMENTED();
+ if (show_state != ui::SHOW_STATE_DEFAULT &&
+ show_state != ui::SHOW_STATE_NORMAL) {
+ // Only forwarding to Show().
+ NOTIMPLEMENTED();
+ }
+
+ Show();
}
void DesktopRootWindowHostLinux::ShowMaximizedWithBounds(
@@ -55,9 +228,7 @@ void DesktopRootWindowHostLinux::ShowMaximizedWithBounds(
}
bool DesktopRootWindowHostLinux::IsVisible() const {
- // TODO(erg):
- NOTIMPLEMENTED();
- return true;
+ return window_mapped_;
}
void DesktopRootWindowHostLinux::SetSize(const gfx::Size& size) {
@@ -73,8 +244,8 @@ void DesktopRootWindowHostLinux::CenterWindow(const gfx::Size& size) {
void DesktopRootWindowHostLinux::GetWindowPlacement(
gfx::Rect* bounds,
ui::WindowShowState* show_state) const {
- // TODO(erg):
- NOTIMPLEMENTED();
+ // TODO(erg):
+ NOTIMPLEMENTED();
}
gfx::Rect DesktopRootWindowHostLinux::GetWindowBoundsInScreen() const {
@@ -177,6 +348,351 @@ void DesktopRootWindowHostLinux::SetWindowTitle(const string16& title) {
}
////////////////////////////////////////////////////////////////////////////////
+// DesktopRootWindowHostLinux, aura::RootWindowHost implementation:
+
+aura::RootWindow* DesktopRootWindowHostLinux::GetRootWindow() {
+ return root_window_.get();
+}
+
+gfx::AcceleratedWidget DesktopRootWindowHostLinux::GetAcceleratedWidget() {
+ return xwindow_;
+}
+
+void DesktopRootWindowHostLinux::Show() {
+ if (!window_mapped_) {
+ // Before we map the window, set size hints. Otherwise, some window managers
+ // will ignore toplevel XMoveWindow commands.
+ XSizeHints size_hints;
+ size_hints.flags = PPosition;
+ size_hints.x = bounds_.x();
+ size_hints.y = bounds_.y();
+ XSetWMNormalHints(xdisplay_, xwindow_, &size_hints);
+
+ XMapWindow(xdisplay_, xwindow_);
+
+ // We now block until our window is mapped. Some X11 APIs will crash and
+ // burn if passed |xwindow_| before the window is mapped, and XMapWindow is
+ // asynchronous.
+ base::MessagePumpAuraX11::Current()->BlockUntilWindowMapped(xwindow_);
+ window_mapped_ = true;
+ }
+}
+
+void DesktopRootWindowHostLinux::Hide() {
+ if (window_mapped_) {
+ XWithdrawWindow(xdisplay_, xwindow_, 0);
+ window_mapped_ = false;
+ }
+}
+
+void DesktopRootWindowHostLinux::ToggleFullScreen() {
+}
+
+gfx::Rect DesktopRootWindowHostLinux::GetBounds() const {
+ return gfx::Rect(100, 100);
+}
+
+void DesktopRootWindowHostLinux::SetBounds(const gfx::Rect& bounds) {
+}
+
+gfx::Point DesktopRootWindowHostLinux::GetLocationOnNativeScreen() const {
+ return gfx::Point(1, 1);
+}
+
+void DesktopRootWindowHostLinux::SetCapture() {
+}
+
+void DesktopRootWindowHostLinux::ReleaseCapture() {
+}
+
+void DesktopRootWindowHostLinux::SetCursor(gfx::NativeCursor cursor) {
+}
+
+void DesktopRootWindowHostLinux::ShowCursor(bool show) {
+}
+
+bool DesktopRootWindowHostLinux::QueryMouseLocation(
+ gfx::Point* location_return) {
+ return false;
+}
+
+bool DesktopRootWindowHostLinux::ConfineCursorToRootWindow() {
+ return false;
+}
+
+void DesktopRootWindowHostLinux::UnConfineCursor() {
+}
+
+void DesktopRootWindowHostLinux::MoveCursorTo(const gfx::Point& location) {
+}
+
+void DesktopRootWindowHostLinux::SetFocusWhenShown(bool focus_when_shown) {
+ static const char* k_NET_WM_USER_TIME = "_NET_WM_USER_TIME";
+ focus_when_shown_ = focus_when_shown;
+ if (IsWindowManagerPresent() && !focus_when_shown_) {
+ ui::SetIntProperty(xwindow_,
+ k_NET_WM_USER_TIME,
+ k_NET_WM_USER_TIME,
+ 0);
+ }
+}
+
+bool DesktopRootWindowHostLinux::GrabSnapshot(
+ const gfx::Rect& snapshot_bounds,
+ std::vector<unsigned char>* png_representation) {
+ return false;
+}
+
+void DesktopRootWindowHostLinux::PostNativeEvent(
+ const base::NativeEvent& native_event) {
+ DCHECK(xwindow_);
+ DCHECK(xdisplay_);
+ XEvent xevent = *native_event;
+ xevent.xany.display = xdisplay_;
+ xevent.xany.window = xwindow_;
+
+ switch (xevent.type) {
+ case EnterNotify:
+ case LeaveNotify:
+ case MotionNotify:
+ case KeyPress:
+ case KeyRelease:
+ case ButtonPress:
+ case ButtonRelease: {
+ // The fields used below are in the same place for all of events
+ // above. Using xmotion from XEvent's unions to avoid repeating
+ // the code.
+ xevent.xmotion.root = x_root_window_;
+ xevent.xmotion.time = CurrentTime;
+
+ gfx::Point point(xevent.xmotion.x, xevent.xmotion.y);
+ root_window_->ConvertPointToNativeScreen(&point);
+ xevent.xmotion.x_root = point.x();
+ xevent.xmotion.y_root = point.y();
+ }
+ default:
+ break;
+ }
+ XSendEvent(xdisplay_, xwindow_, False, 0, &xevent);
+}
+
+void DesktopRootWindowHostLinux::OnDeviceScaleFactorChanged(
+ float device_scale_factor) {
+}
+
+void DesktopRootWindowHostLinux::PrepareForShutdown() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopRootWindowHostLinux, MessageLoop::Dispatcher implementation:
+
+bool DesktopRootWindowHostLinux::Dispatch(const base::NativeEvent& event) {
+ XEvent* xev = event;
+
+ // May want to factor CheckXEventForConsistency(xev); into a common location
+ // since it is called here.
+ switch (xev->type) {
+ case Expose:
+ // TODO(erg): Can we only redraw the affected areas?
+ root_window_host_delegate_->OnHostPaint();
+ break;
+ case KeyPress: {
+ ui::KeyEvent keydown_event(xev, false);
+ root_window_host_delegate_->OnHostKeyEvent(&keydown_event);
+ break;
+ }
+ case KeyRelease: {
+ ui::KeyEvent keyup_event(xev, false);
+ root_window_host_delegate_->OnHostKeyEvent(&keyup_event);
+ break;
+ }
+ case ButtonPress: {
+ if (static_cast<int>(xev->xbutton.button) == kBackMouseButton ||
+ static_cast<int>(xev->xbutton.button) == kForwardMouseButton) {
+ aura::client::UserActionClient* gesture_client =
+ aura::client::GetUserActionClient(root_window_.get());
+ if (gesture_client) {
+ gesture_client->OnUserAction(
+ static_cast<int>(xev->xbutton.button) == kBackMouseButton ?
+ aura::client::UserActionClient::BACK :
+ aura::client::UserActionClient::FORWARD);
+ }
+ break;
+ }
+ } // fallthrough
+ case ButtonRelease: {
+ ui::MouseEvent mouseev(xev);
+ root_window_host_delegate_->OnHostMouseEvent(&mouseev);
+ break;
+ }
+ case FocusOut:
+ if (xev->xfocus.mode != NotifyGrab)
+ root_window_host_delegate_->OnHostLostCapture();
+ break;
+ case ConfigureNotify: {
+ DCHECK_EQ(xwindow_, xev->xconfigure.window);
+ DCHECK_EQ(xwindow_, xev->xconfigure.event);
+ // It's possible that the X window may be resized by some other means than
+ // from within aura (e.g. the X window manager can change the size). Make
+ // sure the root window size is maintained properly.
+ gfx::Rect bounds(xev->xconfigure.x, xev->xconfigure.y,
+ xev->xconfigure.width, xev->xconfigure.height);
+ bool size_changed = bounds_.size() != bounds.size();
+ bool origin_changed = bounds_.origin() != bounds.origin();
+ bounds_ = bounds;
+ if (size_changed)
+ root_window_host_delegate_->OnHostResized(bounds.size());
+ if (origin_changed)
+ root_window_host_delegate_->OnHostMoved(bounds_.origin());
+ break;
+ }
+ case GenericEvent: {
+ ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
+ if (!factory->ShouldProcessXI2Event(xev))
+ break;
+
+ ui::EventType type = ui::EventTypeFromNative(xev);
+ XEvent last_event;
+ int num_coalesced = 0;
+
+ switch (type) {
+ // case ui::ET_TOUCH_MOVED:
+ // num_coalesced = CoalescePendingMotionEvents(xev, &last_event);
+ // if (num_coalesced > 0)
+ // xev = &last_event;
+ // // fallthrough
+ // case ui::ET_TOUCH_PRESSED:
+ // case ui::ET_TOUCH_RELEASED: {
+ // ui::TouchEvent touchev(xev);
+ // root_window_host_delegate_->OnHostTouchEvent(&touchev);
+ // break;
+ // }
+ case ui::ET_MOUSE_MOVED:
+ case ui::ET_MOUSE_DRAGGED:
+ case ui::ET_MOUSE_PRESSED:
+ case ui::ET_MOUSE_RELEASED:
+ case ui::ET_MOUSE_ENTERED:
+ case ui::ET_MOUSE_EXITED: {
+ if (type == ui::ET_MOUSE_MOVED || type == ui::ET_MOUSE_DRAGGED) {
+ // If this is a motion event, we want to coalesce all pending motion
+ // events that are at the top of the queue.
+ // num_coalesced = CoalescePendingMotionEvents(xev, &last_event);
+ // if (num_coalesced > 0)
+ // xev = &last_event;
+ } else if (type == ui::ET_MOUSE_PRESSED) {
+ XIDeviceEvent* xievent =
+ static_cast<XIDeviceEvent*>(xev->xcookie.data);
+ int button = xievent->detail;
+ if (button == kBackMouseButton || button == kForwardMouseButton) {
+ aura::client::UserActionClient* gesture_client =
+ aura::client::GetUserActionClient(
+ root_window_host_delegate_->AsRootWindow());
+ if (gesture_client) {
+ bool reverse_direction =
+ ui::IsTouchpadEvent(xev) && ui::IsNaturalScrollEnabled();
+ gesture_client->OnUserAction(
+ (button == kBackMouseButton && !reverse_direction) ||
+ (button == kForwardMouseButton && reverse_direction) ?
+ aura::client::UserActionClient::BACK :
+ aura::client::UserActionClient::FORWARD);
+ }
+ break;
+ }
+ }
+ ui::MouseEvent mouseev(xev);
+ root_window_host_delegate_->OnHostMouseEvent(&mouseev);
+ break;
+ }
+ case ui::ET_MOUSEWHEEL: {
+ ui::MouseWheelEvent mouseev(xev);
+ root_window_host_delegate_->OnHostMouseEvent(&mouseev);
+ break;
+ }
+ case ui::ET_SCROLL_FLING_START:
+ case ui::ET_SCROLL_FLING_CANCEL:
+ case ui::ET_SCROLL: {
+ ui::ScrollEvent scrollev(xev);
+ root_window_host_delegate_->OnHostScrollEvent(&scrollev);
+ break;
+ }
+ case ui::ET_UNKNOWN:
+ break;
+ default:
+ NOTREACHED();
+ }
+
+ // If we coalesced an event we need to free its cookie.
+ if (num_coalesced > 0)
+ XFreeEventData(xev->xgeneric.display, &last_event.xcookie);
+ break;
+ }
+ case MapNotify: {
+ // If there's no window manager running, we need to assign the X input
+ // focus to our host window.
+ if (!IsWindowManagerPresent() && focus_when_shown_)
+ XSetInputFocus(xdisplay_, xwindow_, RevertToNone, CurrentTime);
+ break;
+ }
+ case ClientMessage: {
+ Atom message_type = static_cast<Atom>(xev->xclient.data.l[0]);
+ if (message_type == atom_cache_.GetAtom("WM_DELETE_WINDOW")) {
+ // We have received a close message from the window manager.
+ root_window_->OnRootWindowHostCloseRequested();
+ } else if (message_type == atom_cache_.GetAtom("_NET_WM_PING")) {
+ XEvent reply_event = *xev;
+ reply_event.xclient.window = x_root_window_;
+
+ XSendEvent(xdisplay_,
+ reply_event.xclient.window,
+ False,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ &reply_event);
+ }
+ break;
+ }
+ case MappingNotify: {
+ switch (xev->xmapping.request) {
+ case MappingModifier:
+ case MappingKeyboard:
+ XRefreshKeyboardMapping(&xev->xmapping);
+ root_window_->OnKeyboardMappingChanged();
+ break;
+ case MappingPointer:
+ ui::UpdateButtonMap();
+ break;
+ default:
+ NOTIMPLEMENTED() << " Unknown request: " << xev->xmapping.request;
+ break;
+ }
+ break;
+ }
+ case MotionNotify: {
+ // Discard all but the most recent motion event that targets the same
+ // window with unchanged state.
+ XEvent last_event;
+ while (XPending(xev->xany.display)) {
+ XEvent next_event;
+ XPeekEvent(xev->xany.display, &next_event);
+ if (next_event.type == MotionNotify &&
+ next_event.xmotion.window == xev->xmotion.window &&
+ next_event.xmotion.subwindow == xev->xmotion.subwindow &&
+ next_event.xmotion.state == xev->xmotion.state) {
+ XNextEvent(xev->xany.display, &last_event);
+ xev = &last_event;
+ } else {
+ break;
+ }
+ }
+
+ ui::MouseEvent mouseev(xev);
+ root_window_host_delegate_->OnHostMouseEvent(&mouseev);
+ break;
+ }
+ }
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
// DesktopRootWindowHost, public:
// static
« no previous file with comments | « ui/views/widget/desktop_root_window_host_linux.h ('k') | ui/views/widget/x11_window_event_filter.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698