OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/aura/desktop_host.h" | 5 #include "ui/aura/desktop_host.h" |
6 | 6 |
7 #include <X11/cursorfont.h> | 7 #include <X11/cursorfont.h> |
8 #include <X11/Xlib.h> | 8 #include <X11/Xlib.h> |
9 | 9 |
10 // Get rid of a macro from Xlib.h that conflicts with Aura's RootWindow class. | 10 // Get rid of a macro from Xlib.h that conflicts with Aura's RootWindow class. |
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
191 | 191 |
192 // DesktopHost Overrides. | 192 // DesktopHost Overrides. |
193 virtual void SetDesktop(Desktop* desktop) OVERRIDE; | 193 virtual void SetDesktop(Desktop* desktop) OVERRIDE; |
194 virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE; | 194 virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE; |
195 virtual void Show() OVERRIDE; | 195 virtual void Show() OVERRIDE; |
196 virtual gfx::Size GetSize() const OVERRIDE; | 196 virtual gfx::Size GetSize() const OVERRIDE; |
197 virtual void SetSize(const gfx::Size& size) OVERRIDE; | 197 virtual void SetSize(const gfx::Size& size) OVERRIDE; |
198 virtual void SetCursor(gfx::NativeCursor cursor_type) OVERRIDE; | 198 virtual void SetCursor(gfx::NativeCursor cursor_type) OVERRIDE; |
199 virtual gfx::Point QueryMouseLocation() OVERRIDE; | 199 virtual gfx::Point QueryMouseLocation() OVERRIDE; |
200 | 200 |
201 // Returns true if there's an X window manager present. | 201 // Returns true if there's an X window manager present... in most cases. Some |
| 202 // window managers (notably, ion3) don't implement enough of ICCCM for us to |
| 203 // detect that they're there. |
202 bool IsWindowManagerPresent(); | 204 bool IsWindowManagerPresent(); |
203 | 205 |
204 Desktop* desktop_; | 206 Desktop* desktop_; |
205 | 207 |
206 // The display and the native X window hosting the desktop. | 208 // The display and the native X window hosting the desktop. |
207 Display* xdisplay_; | 209 Display* xdisplay_; |
208 ::Window xwindow_; | 210 ::Window xwindow_; |
209 | 211 |
210 // Current Aura cursor. | 212 // Current Aura cursor. |
211 gfx::NativeCursor current_cursor_; | 213 gfx::NativeCursor current_cursor_; |
212 | 214 |
213 // The size of |xwindow_|. | 215 // The size of |xwindow_|. |
214 gfx::Rect bounds_; | 216 gfx::Size size_; |
215 | |
216 // True while we requested configure, but haven't recieved configure event | |
217 // yet. | |
218 bool expect_configure_event_; | |
219 | 217 |
220 DISALLOW_COPY_AND_ASSIGN(DesktopHostLinux); | 218 DISALLOW_COPY_AND_ASSIGN(DesktopHostLinux); |
221 }; | 219 }; |
222 | 220 |
223 DesktopHostLinux::DesktopHostLinux(const gfx::Rect& bounds) | 221 DesktopHostLinux::DesktopHostLinux(const gfx::Rect& bounds) |
224 : desktop_(NULL), | 222 : desktop_(NULL), |
225 xdisplay_(NULL), | 223 xdisplay_(base::MessagePumpX::GetDefaultXDisplay()), |
226 xwindow_(0), | 224 xwindow_(0), |
227 current_cursor_(aura::kCursorNull), | 225 current_cursor_(aura::kCursorNull), |
228 bounds_(bounds) { | 226 size_(bounds.size()) { |
229 // This assumes that the message-pump creates and owns the display. | |
230 xdisplay_ = base::MessagePumpX::GetDefaultXDisplay(); | |
231 | |
232 // Ingore the requested bounds and just cover the whole screen if there's no | |
233 // X window manager present. | |
234 if (!IsWindowManagerPresent()) | |
235 bounds_.SetRect( | |
236 0, 0, DisplayWidth(xdisplay_, 0), DisplayHeight(xdisplay_, 0)); | |
237 | |
238 xwindow_ = XCreateSimpleWindow(xdisplay_, DefaultRootWindow(xdisplay_), | 227 xwindow_ = XCreateSimpleWindow(xdisplay_, DefaultRootWindow(xdisplay_), |
239 bounds_.x(), bounds_.y(), | 228 bounds.x(), bounds.y(), |
240 bounds_.width(), bounds_.height(), | 229 bounds.width(), bounds.height(), |
241 0, 0, 0); | 230 0, 0, 0); |
242 | 231 |
243 long event_mask = ButtonPressMask | ButtonReleaseMask | | 232 long event_mask = ButtonPressMask | ButtonReleaseMask | |
244 KeyPressMask | KeyReleaseMask | | 233 KeyPressMask | KeyReleaseMask | |
245 ExposureMask | VisibilityChangeMask | | 234 ExposureMask | VisibilityChangeMask | |
246 StructureNotifyMask | PropertyChangeMask | | 235 StructureNotifyMask | PropertyChangeMask | |
247 PointerMotionMask; | 236 PointerMotionMask; |
248 XSelectInput(xdisplay_, xwindow_, event_mask); | 237 XSelectInput(xdisplay_, xwindow_, event_mask); |
249 XFlush(xdisplay_); | 238 XFlush(xdisplay_); |
250 | 239 |
(...skipping 24 matching lines...) Expand all Loading... |
275 KeyEvent keyup_event(xev, false); | 264 KeyEvent keyup_event(xev, false); |
276 handled = desktop_->DispatchKeyEvent(&keyup_event); | 265 handled = desktop_->DispatchKeyEvent(&keyup_event); |
277 break; | 266 break; |
278 } | 267 } |
279 case ButtonPress: | 268 case ButtonPress: |
280 case ButtonRelease: { | 269 case ButtonRelease: { |
281 MouseEvent mouseev(xev); | 270 MouseEvent mouseev(xev); |
282 handled = desktop_->DispatchMouseEvent(&mouseev); | 271 handled = desktop_->DispatchMouseEvent(&mouseev); |
283 break; | 272 break; |
284 } | 273 } |
285 case MotionNotify: { | |
286 // Discard all but the most recent motion event that targets the same | |
287 // window with unchanged state. | |
288 XEvent last_event; | |
289 while (XPending(xev->xany.display)) { | |
290 XEvent next_event; | |
291 XPeekEvent(xev->xany.display, &next_event); | |
292 if (next_event.type == MotionNotify && | |
293 next_event.xmotion.window == xev->xmotion.window && | |
294 next_event.xmotion.subwindow == xev->xmotion.subwindow && | |
295 next_event.xmotion.state == xev->xmotion.state) { | |
296 XNextEvent(xev->xany.display, &last_event); | |
297 xev = &last_event; | |
298 } else { | |
299 break; | |
300 } | |
301 } | |
302 | |
303 MouseEvent mouseev(xev); | |
304 handled = desktop_->DispatchMouseEvent(&mouseev); | |
305 break; | |
306 } | |
307 case ConfigureNotify: { | 274 case ConfigureNotify: { |
308 DCHECK_EQ(xdisplay_, xev->xconfigure.display); | 275 DCHECK_EQ(xdisplay_, xev->xconfigure.display); |
309 DCHECK_EQ(xwindow_, xev->xconfigure.window); | 276 DCHECK_EQ(xwindow_, xev->xconfigure.window); |
310 DCHECK_EQ(xwindow_, xev->xconfigure.event); | 277 DCHECK_EQ(xwindow_, xev->xconfigure.event); |
311 | 278 |
312 // It's possible that the X window may be resized by some other means than | 279 // It's possible that the X window may be resized by some other means than |
313 // from within aura (e.g. the X window manager can change the size). Make | 280 // from within aura (e.g. the X window manager can change the size). Make |
314 // sure the desktop size is maintained properly. | 281 // sure the desktop size is maintained properly. |
315 gfx::Size size(xev->xconfigure.width, xev->xconfigure.height); | 282 gfx::Size size(xev->xconfigure.width, xev->xconfigure.height); |
316 if (bounds_.size() != size || expect_configure_event_) { | 283 if (size_ != size) { |
317 expect_configure_event_ = false; | 284 size_ = size; |
318 bounds_.set_size(size); | |
319 desktop_->OnHostResized(size); | 285 desktop_->OnHostResized(size); |
320 } | 286 } |
321 handled = true; | 287 handled = true; |
322 break; | 288 break; |
323 } | 289 } |
324 | |
325 case GenericEvent: { | 290 case GenericEvent: { |
326 ui::TouchFactory* factory = ui::TouchFactory::GetInstance(); | 291 ui::TouchFactory* factory = ui::TouchFactory::GetInstance(); |
327 if (!factory->ShouldProcessXI2Event(xev)) | 292 if (!factory->ShouldProcessXI2Event(xev)) |
328 break; | 293 break; |
329 | 294 |
330 // If this is a motion event we want to coalesce all pending motion | 295 // If this is a motion event we want to coalesce all pending motion |
331 // events that are at the top of the queue. | 296 // events that are at the top of the queue. |
332 XEvent last_event; | 297 XEvent last_event; |
333 int num_coalesced = 0; | 298 int num_coalesced = 0; |
334 if (xev->xgeneric.evtype == XI_Motion) { | 299 if (xev->xgeneric.evtype == XI_Motion) { |
(...skipping 25 matching lines...) Expand all Loading... |
360 case ui::ET_UNKNOWN: | 325 case ui::ET_UNKNOWN: |
361 handled = false; | 326 handled = false; |
362 break; | 327 break; |
363 default: | 328 default: |
364 NOTREACHED(); | 329 NOTREACHED(); |
365 } | 330 } |
366 | 331 |
367 // If we coalesced an event we need to free its cookie. | 332 // If we coalesced an event we need to free its cookie. |
368 if (num_coalesced > 0) | 333 if (num_coalesced > 0) |
369 XFreeEventData(xev->xgeneric.display, &last_event.xcookie); | 334 XFreeEventData(xev->xgeneric.display, &last_event.xcookie); |
| 335 break; |
| 336 } |
| 337 case MapNotify: { |
| 338 // If there's no window manager running, we need to assign the X input |
| 339 // focus to our host window. |
| 340 if (!IsWindowManagerPresent()) |
| 341 XSetInputFocus(xdisplay_, xwindow_, RevertToNone, CurrentTime); |
| 342 handled = true; |
| 343 break; |
| 344 } |
| 345 case MotionNotify: { |
| 346 // Discard all but the most recent motion event that targets the same |
| 347 // window with unchanged state. |
| 348 XEvent last_event; |
| 349 while (XPending(xev->xany.display)) { |
| 350 XEvent next_event; |
| 351 XPeekEvent(xev->xany.display, &next_event); |
| 352 if (next_event.type == MotionNotify && |
| 353 next_event.xmotion.window == xev->xmotion.window && |
| 354 next_event.xmotion.subwindow == xev->xmotion.subwindow && |
| 355 next_event.xmotion.state == xev->xmotion.state) { |
| 356 XNextEvent(xev->xany.display, &last_event); |
| 357 xev = &last_event; |
| 358 } else { |
| 359 break; |
| 360 } |
| 361 } |
| 362 |
| 363 MouseEvent mouseev(xev); |
| 364 handled = desktop_->DispatchMouseEvent(&mouseev); |
| 365 break; |
370 } | 366 } |
371 } | 367 } |
372 return handled ? EVENT_PROCESSED : EVENT_IGNORED; | 368 return handled ? EVENT_PROCESSED : EVENT_IGNORED; |
373 } | 369 } |
374 | 370 |
375 void DesktopHostLinux::SetDesktop(Desktop* desktop) { | 371 void DesktopHostLinux::SetDesktop(Desktop* desktop) { |
376 desktop_ = desktop; | 372 desktop_ = desktop; |
377 } | 373 } |
378 | 374 |
379 gfx::AcceleratedWidget DesktopHostLinux::GetAcceleratedWidget() { | 375 gfx::AcceleratedWidget DesktopHostLinux::GetAcceleratedWidget() { |
380 return xwindow_; | 376 return xwindow_; |
381 } | 377 } |
382 | 378 |
383 void DesktopHostLinux::Show() { | 379 void DesktopHostLinux::Show() { |
384 XMapWindow(xdisplay_, xwindow_); | 380 XMapWindow(xdisplay_, xwindow_); |
385 | |
386 // If there's no window manager running, we need to assign the X input focus | |
387 // to our host window. (If there's no window manager running, it should also | |
388 // be safe to assume that the host window will have been mapped by the time | |
389 // that our SetInputFocus request is received.) | |
390 if (!IsWindowManagerPresent()) | |
391 XSetInputFocus(xdisplay_, xwindow_, RevertToNone, CurrentTime); | |
392 | |
393 XFlush(xdisplay_); | |
394 } | 381 } |
395 | 382 |
396 gfx::Size DesktopHostLinux::GetSize() const { | 383 gfx::Size DesktopHostLinux::GetSize() const { |
397 return bounds_.size(); | 384 return size_; |
398 } | 385 } |
399 | 386 |
400 void DesktopHostLinux::SetSize(const gfx::Size& size) { | 387 void DesktopHostLinux::SetSize(const gfx::Size& size) { |
401 if (bounds_.size() == size) | 388 if (size == size_) |
402 return; | 389 return; |
403 expect_configure_event_ = true; | 390 |
404 bounds_.set_size(size); | |
405 XResizeWindow(xdisplay_, xwindow_, size.width(), size.height()); | 391 XResizeWindow(xdisplay_, xwindow_, size.width(), size.height()); |
| 392 |
| 393 // Assume that the resize will go through as requested, which should be the |
| 394 // case if we're running without a window manager. If there's a window |
| 395 // manager, it can modify or ignore the request, but (per ICCCM) we'll get a |
| 396 // (possibly synthetic) ConfigureNotify about the actual size and correct |
| 397 // |size_| later. |
| 398 size_ = size; |
| 399 desktop_->OnHostResized(size); |
406 } | 400 } |
407 | 401 |
408 void DesktopHostLinux::SetCursor(gfx::NativeCursor cursor) { | 402 void DesktopHostLinux::SetCursor(gfx::NativeCursor cursor) { |
409 if (current_cursor_ == cursor) | 403 if (current_cursor_ == cursor) |
410 return; | 404 return; |
411 current_cursor_ = cursor; | 405 current_cursor_ = cursor; |
412 // Custom web cursors are handled directly. | 406 // Custom web cursors are handled directly. |
413 if (cursor == kCursorCustom) | 407 if (cursor == kCursorCustom) |
414 return; | 408 return; |
415 int cursor_shape = CursorShapeFromNative(cursor); | 409 int cursor_shape = CursorShapeFromNative(cursor); |
416 ::Cursor xcursor = ui::GetXCursor(cursor_shape); | 410 ::Cursor xcursor = ui::GetXCursor(cursor_shape); |
417 XDefineCursor(xdisplay_, xwindow_, xcursor); | 411 XDefineCursor(xdisplay_, xwindow_, xcursor); |
418 } | 412 } |
419 | 413 |
420 gfx::Point DesktopHostLinux::QueryMouseLocation() { | 414 gfx::Point DesktopHostLinux::QueryMouseLocation() { |
421 ::Window root_return, child_return; | 415 ::Window root_return, child_return; |
422 int root_x_return, root_y_return, win_x_return, win_y_return; | 416 int root_x_return, root_y_return, win_x_return, win_y_return; |
423 unsigned int mask_return; | 417 unsigned int mask_return; |
424 XQueryPointer(xdisplay_, | 418 XQueryPointer(xdisplay_, |
425 xwindow_, | 419 xwindow_, |
426 &root_return, | 420 &root_return, |
427 &child_return, | 421 &child_return, |
428 &root_x_return, &root_y_return, | 422 &root_x_return, &root_y_return, |
429 &win_x_return, &win_y_return, | 423 &win_x_return, &win_y_return, |
430 &mask_return); | 424 &mask_return); |
431 return gfx::Point(max(0, min(bounds_.width(), win_x_return)), | 425 return gfx::Point(max(0, min(size_.width(), win_x_return)), |
432 max(0, min(bounds_.height(), win_y_return))); | 426 max(0, min(size_.height(), win_y_return))); |
433 } | 427 } |
434 | 428 |
435 bool DesktopHostLinux::IsWindowManagerPresent() { | 429 bool DesktopHostLinux::IsWindowManagerPresent() { |
436 // Per ICCCM 2.8, "Manager Selections", window managers should take ownership | 430 // Per ICCCM 2.8, "Manager Selections", window managers should take ownership |
437 // of WM_Sn selections (where n is a screen number). | 431 // of WM_Sn selections (where n is a screen number). |
438 ::Atom wm_s0_atom = XInternAtom(xdisplay_, "WM_S0", False); | 432 ::Atom wm_s0_atom = XInternAtom(xdisplay_, "WM_S0", False); |
439 return XGetSelectionOwner(xdisplay_, wm_s0_atom) != None; | 433 return XGetSelectionOwner(xdisplay_, wm_s0_atom) != None; |
440 } | 434 } |
441 | 435 |
442 } // namespace | 436 } // namespace |
443 | 437 |
444 // static | 438 // static |
445 DesktopHost* DesktopHost::Create(const gfx::Rect& bounds) { | 439 DesktopHost* DesktopHost::Create(const gfx::Rect& bounds) { |
446 return new DesktopHostLinux(bounds); | 440 return new DesktopHostLinux(bounds); |
447 } | 441 } |
448 | 442 |
| 443 // static |
| 444 gfx::Size DesktopHost::GetNativeDisplaySize() { |
| 445 ::Display* xdisplay = base::MessagePumpX::GetDefaultXDisplay(); |
| 446 return gfx::Size(DisplayWidth(xdisplay, 0), DisplayHeight(xdisplay, 0)); |
| 447 } |
| 448 |
449 } // namespace aura | 449 } // namespace aura |
OLD | NEW |