Supervised user whitelists: Cleanup
[chromium-blink-merge.git] / ui / platform_window / x11 / x11_window.cc
blob14e6fdf0b282421af5e88e7bf8c6c27032543337
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.
5 #include "ui/platform_window/x11/x11_window.h"
7 #include <X11/extensions/XInput2.h>
8 #include <X11/Xatom.h>
9 #include <X11/Xlib.h>
10 #include <X11/Xutil.h>
12 #include "ui/events/devices/x11/touch_factory_x11.h"
13 #include "ui/events/event.h"
14 #include "ui/events/event_utils.h"
15 #include "ui/events/platform/platform_event_dispatcher.h"
16 #include "ui/events/platform/platform_event_source.h"
17 #include "ui/events/platform/x11/x11_event_source.h"
18 #include "ui/gfx/geometry/rect.h"
19 #include "ui/gfx/x/x11_atom_cache.h"
20 #include "ui/gfx/x/x11_types.h"
21 #include "ui/platform_window/platform_window_delegate.h"
23 namespace ui {
25 namespace {
27 const char* kAtomsToCache[] = {
28 "WM_DELETE_WINDOW",
29 "_NET_WM_PING",
30 "_NET_WM_PID",
31 NULL
34 XID FindXEventTarget(XEvent* xevent) {
35 XID target = xevent->xany.window;
36 if (xevent->type == GenericEvent)
37 target = static_cast<XIDeviceEvent*>(xevent->xcookie.data)->event;
38 return target;
41 } // namespace
43 X11Window::X11Window(PlatformWindowDelegate* delegate)
44 : delegate_(delegate),
45 xdisplay_(gfx::GetXDisplay()),
46 xwindow_(None),
47 xroot_window_(DefaultRootWindow(xdisplay_)),
48 atom_cache_(xdisplay_, kAtomsToCache),
49 window_mapped_(false) {
50 CHECK(delegate_);
51 TouchFactory::SetTouchDeviceListFromCommandLine();
54 X11Window::~X11Window() {
55 Destroy();
58 void X11Window::Destroy() {
59 delegate_->OnClosed();
60 if (xwindow_ == None)
61 return;
63 // Stop processing events.
64 PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
65 XDestroyWindow(xdisplay_, xwindow_);
66 xwindow_ = None;
69 void X11Window::ProcessXInput2Event(XEvent* xev) {
70 if (!TouchFactory::GetInstance()->ShouldProcessXI2Event(xev))
71 return;
72 EventType event_type = EventTypeFromNative(xev);
73 switch (event_type) {
74 case ET_KEY_PRESSED:
75 case ET_KEY_RELEASED: {
76 KeyEvent key_event(xev);
77 delegate_->DispatchEvent(&key_event);
78 break;
80 case ET_MOUSE_PRESSED:
81 case ET_MOUSE_MOVED:
82 case ET_MOUSE_DRAGGED:
83 case ET_MOUSE_RELEASED: {
84 MouseEvent mouse_event(xev);
85 delegate_->DispatchEvent(&mouse_event);
86 break;
88 case ET_MOUSEWHEEL: {
89 MouseWheelEvent wheel_event(xev);
90 delegate_->DispatchEvent(&wheel_event);
91 break;
93 case ET_SCROLL_FLING_START:
94 case ET_SCROLL_FLING_CANCEL:
95 case ET_SCROLL: {
96 ScrollEvent scroll_event(xev);
97 delegate_->DispatchEvent(&scroll_event);
98 break;
100 case ET_TOUCH_MOVED:
101 case ET_TOUCH_PRESSED:
102 case ET_TOUCH_CANCELLED:
103 case ET_TOUCH_RELEASED: {
104 TouchEvent touch_event(xev);
105 delegate_->DispatchEvent(&touch_event);
106 break;
108 default:
109 break;
113 void X11Window::Show() {
114 if (window_mapped_)
115 return;
117 CHECK(PlatformEventSource::GetInstance());
118 PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
120 XSetWindowAttributes swa;
121 memset(&swa, 0, sizeof(swa));
122 swa.background_pixmap = None;
123 swa.override_redirect = False;
124 xwindow_ = XCreateWindow(xdisplay_,
125 xroot_window_,
126 requested_bounds_.x(),
127 requested_bounds_.y(),
128 requested_bounds_.width(),
129 requested_bounds_.height(),
130 0, // border width
131 CopyFromParent, // depth
132 InputOutput,
133 CopyFromParent, // visual
134 CWBackPixmap | CWOverrideRedirect,
135 &swa);
137 long event_mask = ButtonPressMask | ButtonReleaseMask | FocusChangeMask |
138 KeyPressMask | KeyReleaseMask | EnterWindowMask |
139 LeaveWindowMask | ExposureMask | VisibilityChangeMask |
140 StructureNotifyMask | PropertyChangeMask |
141 PointerMotionMask;
142 XSelectInput(xdisplay_, xwindow_, event_mask);
144 unsigned char mask[XIMaskLen(XI_LASTEVENT)];
145 memset(mask, 0, sizeof(mask));
147 XISetMask(mask, XI_TouchBegin);
148 XISetMask(mask, XI_TouchUpdate);
149 XISetMask(mask, XI_TouchEnd);
150 XISetMask(mask, XI_ButtonPress);
151 XISetMask(mask, XI_ButtonRelease);
152 XISetMask(mask, XI_Motion);
153 XISetMask(mask, XI_KeyPress);
154 XISetMask(mask, XI_KeyRelease);
156 XIEventMask evmask;
157 evmask.deviceid = XIAllDevices;
158 evmask.mask_len = sizeof(mask);
159 evmask.mask = mask;
160 XISelectEvents(xdisplay_, xwindow_, &evmask, 1);
161 XFlush(xdisplay_);
163 ::Atom protocols[2];
164 protocols[0] = atom_cache_.GetAtom("WM_DELETE_WINDOW");
165 protocols[1] = atom_cache_.GetAtom("_NET_WM_PING");
166 XSetWMProtocols(xdisplay_, xwindow_, protocols, 2);
168 // We need a WM_CLIENT_MACHINE and WM_LOCALE_NAME value so we integrate with
169 // the desktop environment.
170 XSetWMProperties(
171 xdisplay_, xwindow_, NULL, NULL, NULL, 0, NULL, NULL, NULL);
173 // Likewise, the X server needs to know this window's pid so it knows which
174 // program to kill if the window hangs.
175 // XChangeProperty() expects "pid" to be long.
176 static_assert(sizeof(long) >= sizeof(pid_t),
177 "pid_t should not be larger than long");
178 long pid = getpid();
179 XChangeProperty(xdisplay_,
180 xwindow_,
181 atom_cache_.GetAtom("_NET_WM_PID"),
182 XA_CARDINAL,
184 PropModeReplace,
185 reinterpret_cast<unsigned char*>(&pid),
187 // Before we map the window, set size hints. Otherwise, some window managers
188 // will ignore toplevel XMoveWindow commands.
189 XSizeHints size_hints;
190 size_hints.flags = PPosition | PWinGravity;
191 size_hints.x = requested_bounds_.x();
192 size_hints.y = requested_bounds_.y();
193 // Set StaticGravity so that the window position is not affected by the
194 // frame width when running with window manager.
195 size_hints.win_gravity = StaticGravity;
196 XSetWMNormalHints(xdisplay_, xwindow_, &size_hints);
198 delegate_->OnAcceleratedWidgetAvailable(xwindow_);
200 XMapWindow(xdisplay_, xwindow_);
202 // We now block until our window is mapped. Some X11 APIs will crash and
203 // burn if passed |xwindow_| before the window is mapped, and XMapWindow is
204 // asynchronous.
205 if (X11EventSource::GetInstance())
206 X11EventSource::GetInstance()->BlockUntilWindowMapped(xwindow_);
207 window_mapped_ = true;
210 void X11Window::Hide() {
211 if (!window_mapped_)
212 return;
213 XWithdrawWindow(xdisplay_, xwindow_, 0);
214 window_mapped_ = false;
217 void X11Window::Close() {
218 Destroy();
221 void X11Window::SetBounds(const gfx::Rect& bounds) {
222 requested_bounds_ = bounds;
223 if (!window_mapped_)
224 return;
225 XWindowChanges changes = {0};
226 unsigned value_mask = CWX | CWY | CWWidth | CWHeight;
227 changes.x = bounds.x();
228 changes.y = bounds.y();
229 changes.width = bounds.width();
230 changes.height = bounds.height();
231 XConfigureWindow(xdisplay_, xwindow_, value_mask, &changes);
234 gfx::Rect X11Window::GetBounds() {
235 return confirmed_bounds_;
238 void X11Window::SetCapture() {}
240 void X11Window::ReleaseCapture() {}
242 void X11Window::ToggleFullscreen() {}
244 void X11Window::Maximize() {}
246 void X11Window::Minimize() {}
248 void X11Window::Restore() {}
250 void X11Window::SetCursor(PlatformCursor cursor) {}
252 void X11Window::MoveCursorTo(const gfx::Point& location) {}
254 void X11Window::ConfineCursorToBounds(const gfx::Rect& bounds) {
257 bool X11Window::CanDispatchEvent(const PlatformEvent& event) {
258 return FindXEventTarget(event) == xwindow_;
261 uint32_t X11Window::DispatchEvent(const PlatformEvent& event) {
262 XEvent* xev = event;
263 switch (xev->type) {
264 case EnterNotify: {
265 // EnterNotify creates ET_MOUSE_MOVED. Mark as synthesized as this is
266 // not real mouse move event.
267 MouseEvent mouse_event(xev);
268 CHECK_EQ(ET_MOUSE_MOVED, mouse_event.type());
269 mouse_event.set_flags(mouse_event.flags() | EF_IS_SYNTHESIZED);
270 delegate_->DispatchEvent(&mouse_event);
271 break;
273 case LeaveNotify: {
274 MouseEvent mouse_event(xev);
275 delegate_->DispatchEvent(&mouse_event);
276 break;
279 case Expose: {
280 gfx::Rect damage_rect(xev->xexpose.x,
281 xev->xexpose.y,
282 xev->xexpose.width,
283 xev->xexpose.height);
284 delegate_->OnDamageRect(damage_rect);
285 break;
288 case KeyPress:
289 case KeyRelease: {
290 KeyEvent key_event(xev);
291 delegate_->DispatchEvent(&key_event);
292 break;
295 case ButtonPress:
296 case ButtonRelease: {
297 switch (EventTypeFromNative(xev)) {
298 case ET_MOUSEWHEEL: {
299 MouseWheelEvent mouseev(xev);
300 delegate_->DispatchEvent(&mouseev);
301 break;
303 case ET_MOUSE_PRESSED:
304 case ET_MOUSE_RELEASED: {
305 MouseEvent mouseev(xev);
306 delegate_->DispatchEvent(&mouseev);
307 break;
309 case ET_UNKNOWN:
310 // No event is created for X11-release events for mouse-wheel
311 // buttons.
312 break;
313 default:
314 NOTREACHED();
316 break;
319 case FocusOut:
320 if (xev->xfocus.mode != NotifyGrab)
321 delegate_->OnLostCapture();
322 break;
324 case ConfigureNotify: {
325 DCHECK_EQ(xwindow_, xev->xconfigure.event);
326 DCHECK_EQ(xwindow_, xev->xconfigure.window);
327 gfx::Rect bounds(xev->xconfigure.x,
328 xev->xconfigure.y,
329 xev->xconfigure.width,
330 xev->xconfigure.height);
331 if (confirmed_bounds_ != bounds) {
332 confirmed_bounds_ = bounds;
333 delegate_->OnBoundsChanged(confirmed_bounds_);
335 break;
338 case ClientMessage: {
339 Atom message = static_cast<Atom>(xev->xclient.data.l[0]);
340 if (message == atom_cache_.GetAtom("WM_DELETE_WINDOW")) {
341 delegate_->OnCloseRequest();
342 } else if (message == atom_cache_.GetAtom("_NET_WM_PING")) {
343 XEvent reply_event = *xev;
344 reply_event.xclient.window = xroot_window_;
346 XSendEvent(xdisplay_,
347 reply_event.xclient.window,
348 False,
349 SubstructureRedirectMask | SubstructureNotifyMask,
350 &reply_event);
351 XFlush(xdisplay_);
353 break;
356 case GenericEvent: {
357 ProcessXInput2Event(xev);
358 break;
361 return POST_DISPATCH_STOP_PROPAGATION;
364 } // namespace ui