Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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/views/widget/desktop_aura/desktop_window_tree_host_x11.h" | 5 #include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h" |
| 6 | 6 |
| 7 #include <X11/extensions/shape.h> | 7 #include <X11/extensions/shape.h> |
| 8 #include <X11/extensions/XInput2.h> | 8 #include <X11/extensions/XInput2.h> |
| 9 #include <X11/Xatom.h> | 9 #include <X11/Xatom.h> |
| 10 #include <X11/Xregion.h> | 10 #include <X11/Xregion.h> |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 70 | 70 |
| 71 // Constants that are part of EWMH. | 71 // Constants that are part of EWMH. |
| 72 const int k_NET_WM_STATE_ADD = 1; | 72 const int k_NET_WM_STATE_ADD = 1; |
| 73 const int k_NET_WM_STATE_REMOVE = 0; | 73 const int k_NET_WM_STATE_REMOVE = 0; |
| 74 | 74 |
| 75 const char* kAtomsToCache[] = { | 75 const char* kAtomsToCache[] = { |
| 76 "UTF8_STRING", | 76 "UTF8_STRING", |
| 77 "WM_DELETE_WINDOW", | 77 "WM_DELETE_WINDOW", |
| 78 "WM_PROTOCOLS", | 78 "WM_PROTOCOLS", |
| 79 "WM_S0", | 79 "WM_S0", |
| 80 "_NET_FRAME_EXTENTS", | |
| 80 "_NET_WM_CM_S0", | 81 "_NET_WM_CM_S0", |
| 81 "_NET_WM_ICON", | 82 "_NET_WM_ICON", |
| 82 "_NET_WM_NAME", | 83 "_NET_WM_NAME", |
| 83 "_NET_WM_PID", | 84 "_NET_WM_PID", |
| 84 "_NET_WM_PING", | 85 "_NET_WM_PING", |
| 85 "_NET_WM_STATE", | 86 "_NET_WM_STATE", |
| 86 "_NET_WM_STATE_ABOVE", | 87 "_NET_WM_STATE_ABOVE", |
| 87 "_NET_WM_STATE_FULLSCREEN", | 88 "_NET_WM_STATE_FULLSCREEN", |
| 88 "_NET_WM_STATE_HIDDEN", | 89 "_NET_WM_STATE_HIDDEN", |
| 89 "_NET_WM_STATE_MAXIMIZED_HORZ", | 90 "_NET_WM_STATE_MAXIMIZED_HORZ", |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 134 is_fullscreen_(false), | 135 is_fullscreen_(false), |
| 135 is_always_on_top_(false), | 136 is_always_on_top_(false), |
| 136 use_native_frame_(false), | 137 use_native_frame_(false), |
| 137 use_argb_visual_(false), | 138 use_argb_visual_(false), |
| 138 drag_drop_client_(NULL), | 139 drag_drop_client_(NULL), |
| 139 current_cursor_(ui::kCursorNull), | 140 current_cursor_(ui::kCursorNull), |
| 140 native_widget_delegate_(native_widget_delegate), | 141 native_widget_delegate_(native_widget_delegate), |
| 141 desktop_native_widget_aura_(desktop_native_widget_aura), | 142 desktop_native_widget_aura_(desktop_native_widget_aura), |
| 142 content_window_(NULL), | 143 content_window_(NULL), |
| 143 window_parent_(NULL), | 144 window_parent_(NULL), |
| 144 custom_window_shape_(NULL), | 145 window_shape_(NULL), |
| 146 custom_window_shape_(false), | |
| 145 urgency_hint_set_(false) { | 147 urgency_hint_set_(false) { |
| 146 } | 148 } |
| 147 | 149 |
| 148 DesktopWindowTreeHostX11::~DesktopWindowTreeHostX11() { | 150 DesktopWindowTreeHostX11::~DesktopWindowTreeHostX11() { |
| 149 window()->ClearProperty(kHostForRootWindow); | 151 window()->ClearProperty(kHostForRootWindow); |
| 150 aura::client::SetWindowMoveClient(window(), NULL); | 152 aura::client::SetWindowMoveClient(window(), NULL); |
| 151 desktop_native_widget_aura_->OnDesktopWindowTreeHostDestroyed(this); | 153 desktop_native_widget_aura_->OnDesktopWindowTreeHostDestroyed(this); |
| 152 if (custom_window_shape_) | 154 if (window_shape_) |
| 153 XDestroyRegion(custom_window_shape_); | 155 XDestroyRegion(window_shape_); |
| 154 DestroyDispatcher(); | 156 DestroyDispatcher(); |
| 155 } | 157 } |
| 156 | 158 |
| 157 // static | 159 // static |
| 158 aura::Window* DesktopWindowTreeHostX11::GetContentWindowForXID(XID xid) { | 160 aura::Window* DesktopWindowTreeHostX11::GetContentWindowForXID(XID xid) { |
| 159 aura::WindowTreeHost* host = | 161 aura::WindowTreeHost* host = |
| 160 aura::WindowTreeHost::GetForAcceleratedWidget(xid); | 162 aura::WindowTreeHost::GetForAcceleratedWidget(xid); |
| 161 return host ? host->window()->GetProperty(kViewsWindowForRootWindow) : NULL; | 163 return host ? host->window()->GetProperty(kViewsWindowForRootWindow) : NULL; |
| 162 } | 164 } |
| 163 | 165 |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 175 open_windows().end(), | 177 open_windows().end(), |
| 176 windows.begin(), | 178 windows.begin(), |
| 177 GetContentWindowForXID); | 179 GetContentWindowForXID); |
| 178 return windows; | 180 return windows; |
| 179 } | 181 } |
| 180 | 182 |
| 181 gfx::Rect DesktopWindowTreeHostX11::GetX11RootWindowBounds() const { | 183 gfx::Rect DesktopWindowTreeHostX11::GetX11RootWindowBounds() const { |
| 182 return bounds_; | 184 return bounds_; |
| 183 } | 185 } |
| 184 | 186 |
| 187 gfx::Rect DesktopWindowTreeHostX11::GetX11RootWindowOuterBounds() const { | |
| 188 gfx::Rect outer_bounds(bounds_); | |
| 189 outer_bounds.Inset(-native_window_frame_borders_); | |
| 190 return outer_bounds; | |
| 191 } | |
| 192 | |
| 193 ::Region DesktopWindowTreeHostX11::GetWindowShape() const { | |
| 194 return window_shape_; | |
| 195 } | |
| 196 | |
| 185 void DesktopWindowTreeHostX11::HandleNativeWidgetActivationChanged( | 197 void DesktopWindowTreeHostX11::HandleNativeWidgetActivationChanged( |
| 186 bool active) { | 198 bool active) { |
| 187 if (active) { | 199 if (active) { |
| 188 FlashFrame(false); | 200 FlashFrame(false); |
| 189 OnHostActivated(); | 201 OnHostActivated(); |
| 190 open_windows().remove(xwindow_); | 202 open_windows().remove(xwindow_); |
| 191 open_windows().insert(open_windows().begin(), xwindow_); | 203 open_windows().insert(open_windows().begin(), xwindow_); |
| 192 } | 204 } |
| 193 | 205 |
| 194 desktop_native_widget_aura_->HandleActivationChanged(active); | 206 desktop_native_widget_aura_->HandleActivationChanged(active); |
| (...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 458 if (!XGetGeometry(xdisplay_, x_root_window_, &root, &x, &y, | 470 if (!XGetGeometry(xdisplay_, x_root_window_, &root, &x, &y, |
| 459 &width, &height, &border_width, &depth)) { | 471 &width, &height, &border_width, &depth)) { |
| 460 NOTIMPLEMENTED(); | 472 NOTIMPLEMENTED(); |
| 461 return gfx::Rect(0, 0, 10, 10); | 473 return gfx::Rect(0, 0, 10, 10); |
| 462 } | 474 } |
| 463 | 475 |
| 464 return gfx::Rect(x, y, width, height); | 476 return gfx::Rect(x, y, width, height); |
| 465 } | 477 } |
| 466 | 478 |
| 467 void DesktopWindowTreeHostX11::SetShape(gfx::NativeRegion native_region) { | 479 void DesktopWindowTreeHostX11::SetShape(gfx::NativeRegion native_region) { |
| 468 if (custom_window_shape_) | 480 if (window_shape_) |
| 469 XDestroyRegion(custom_window_shape_); | 481 XDestroyRegion(window_shape_); |
| 470 custom_window_shape_ = gfx::CreateRegionFromSkRegion(*native_region); | 482 custom_window_shape_ = true; |
| 483 window_shape_ = gfx::CreateRegionFromSkRegion(*native_region); | |
| 471 ResetWindowRegion(); | 484 ResetWindowRegion(); |
| 472 delete native_region; | 485 delete native_region; |
| 473 } | 486 } |
| 474 | 487 |
| 475 void DesktopWindowTreeHostX11::Activate() { | 488 void DesktopWindowTreeHostX11::Activate() { |
| 476 if (!window_mapped_) | 489 if (!window_mapped_) |
| 477 return; | 490 return; |
| 478 | 491 |
| 479 X11DesktopHandler::get()->ActivateWindow(xwindow_); | 492 X11DesktopHandler::get()->ActivateWindow(xwindow_); |
| 480 } | 493 } |
| (...skipping 630 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1111 CreateCompositor(GetAcceleratedWidget()); | 1124 CreateCompositor(GetAcceleratedWidget()); |
| 1112 } | 1125 } |
| 1113 | 1126 |
| 1114 bool DesktopWindowTreeHostX11::IsWindowManagerPresent() { | 1127 bool DesktopWindowTreeHostX11::IsWindowManagerPresent() { |
| 1115 // Per ICCCM 2.8, "Manager Selections", window managers should take ownership | 1128 // Per ICCCM 2.8, "Manager Selections", window managers should take ownership |
| 1116 // of WM_Sn selections (where n is a screen number). | 1129 // of WM_Sn selections (where n is a screen number). |
| 1117 return XGetSelectionOwner( | 1130 return XGetSelectionOwner( |
| 1118 xdisplay_, atom_cache_.GetAtom("WM_S0")) != None; | 1131 xdisplay_, atom_cache_.GetAtom("WM_S0")) != None; |
| 1119 } | 1132 } |
| 1120 | 1133 |
| 1134 void DesktopWindowTreeHostX11::OnWMStateUpdated() { | |
| 1135 std::vector< ::Atom> atom_list; | |
| 1136 if (ui::GetAtomArrayProperty(xwindow_, "_NET_WM_STATE", &atom_list)) { | |
|
sadrul
2014/05/08 18:53:29
Early out instead if this is false?
| |
| 1137 window_properties_.clear(); | |
| 1138 std::copy(atom_list.begin(), atom_list.end(), | |
| 1139 inserter(window_properties_, window_properties_.begin())); | |
| 1140 | |
| 1141 if (!restored_bounds_.IsEmpty() && !IsMaximized()) { | |
| 1142 // If we have restored bounds, but WM_STATE no longer claims to be | |
| 1143 // maximized, we should clear our restored bounds. | |
| 1144 restored_bounds_ = gfx::Rect(); | |
| 1145 } else if (IsMaximized() && restored_bounds_.IsEmpty()) { | |
| 1146 // The request that we become maximized originated from a different | |
| 1147 // process. |bounds_| already contains our maximized bounds. Do a | |
| 1148 // best effort attempt to get restored bounds by setting it to our | |
| 1149 // previously set bounds (and if we get this wrong, we aren't any | |
| 1150 // worse off since we'd otherwise be returning our maximized bounds). | |
| 1151 restored_bounds_ = previous_bounds_; | |
| 1152 } | |
| 1153 | |
| 1154 is_fullscreen_ = HasWMSpecProperty("_NET_WM_STATE_FULLSCREEN"); | |
| 1155 is_always_on_top_ = HasWMSpecProperty("_NET_WM_STATE_ABOVE"); | |
| 1156 | |
| 1157 // Now that we have different window properties, we may need to | |
| 1158 // relayout the window. (The windows code doesn't need this because | |
| 1159 // their window change is synchronous.) | |
| 1160 // | |
| 1161 // TODO(erg): While this does work, there's a quick flash showing the | |
| 1162 // tabstrip/toolbar/etc. when going into fullscreen mode before hiding | |
| 1163 // those parts of the UI because we receive the sizing event from the | |
| 1164 // window manager before we receive the event that changes the | |
| 1165 // fullscreen state. Unsure what to do about that. | |
| 1166 Widget* widget = native_widget_delegate_->AsWidget(); | |
| 1167 NonClientView* non_client_view = widget->non_client_view(); | |
| 1168 // non_client_view may be NULL, especially during creation. | |
| 1169 if (non_client_view) { | |
| 1170 non_client_view->client_view()->InvalidateLayout(); | |
| 1171 non_client_view->InvalidateLayout(); | |
| 1172 } | |
| 1173 widget->GetRootView()->Layout(); | |
| 1174 // Refresh the window's border, which may need to be updated if we have | |
| 1175 // changed the window's maximization state. | |
| 1176 ResetWindowRegion(); | |
| 1177 } | |
| 1178 } | |
| 1179 | |
| 1180 void DesktopWindowTreeHostX11::OnFrameExtentsUpdated() { | |
| 1181 std::vector<int> insets; | |
| 1182 if (ui::GetIntArrayProperty(xwindow_, "_NET_FRAME_EXTENTS", &insets) && | |
|
sadrul
2014/05/08 18:53:29
Add a comment about the ordering in _NET_FRAME_EXT
| |
| 1183 insets.size() == 4) { | |
| 1184 native_window_frame_borders_ = gfx::Insets( | |
| 1185 insets[2], | |
| 1186 insets[0], | |
| 1187 insets[3], | |
| 1188 insets[1]); | |
| 1189 } else { | |
| 1190 native_window_frame_borders_ = gfx::Insets(); | |
| 1191 } | |
| 1192 } | |
| 1193 | |
| 1121 void DesktopWindowTreeHostX11::SetWMSpecState(bool enabled, | 1194 void DesktopWindowTreeHostX11::SetWMSpecState(bool enabled, |
| 1122 ::Atom state1, | 1195 ::Atom state1, |
| 1123 ::Atom state2) { | 1196 ::Atom state2) { |
| 1124 XEvent xclient; | 1197 XEvent xclient; |
| 1125 memset(&xclient, 0, sizeof(xclient)); | 1198 memset(&xclient, 0, sizeof(xclient)); |
| 1126 xclient.type = ClientMessage; | 1199 xclient.type = ClientMessage; |
| 1127 xclient.xclient.window = xwindow_; | 1200 xclient.xclient.window = xwindow_; |
| 1128 xclient.xclient.message_type = atom_cache_.GetAtom("_NET_WM_STATE"); | 1201 xclient.xclient.message_type = atom_cache_.GetAtom("_NET_WM_STATE"); |
| 1129 xclient.xclient.format = 32; | 1202 xclient.xclient.format = 32; |
| 1130 xclient.xclient.data.l[0] = | 1203 xclient.xclient.data.l[0] = |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1204 g_current_capture->SendEventToProcessor(event); | 1277 g_current_capture->SendEventToProcessor(event); |
| 1205 } else { | 1278 } else { |
| 1206 SendEventToProcessor(event); | 1279 SendEventToProcessor(event); |
| 1207 } | 1280 } |
| 1208 } | 1281 } |
| 1209 | 1282 |
| 1210 void DesktopWindowTreeHostX11::ResetWindowRegion() { | 1283 void DesktopWindowTreeHostX11::ResetWindowRegion() { |
| 1211 // If a custom window shape was supplied then apply it. | 1284 // If a custom window shape was supplied then apply it. |
| 1212 if (custom_window_shape_) { | 1285 if (custom_window_shape_) { |
| 1213 XShapeCombineRegion( | 1286 XShapeCombineRegion( |
| 1214 xdisplay_, xwindow_, ShapeBounding, 0, 0, custom_window_shape_, false); | 1287 xdisplay_, xwindow_, ShapeBounding, 0, 0, window_shape_, false); |
| 1215 return; | 1288 return; |
| 1216 } | 1289 } |
| 1217 | 1290 |
| 1291 if (window_shape_) | |
| 1292 XDestroyRegion(window_shape_); | |
| 1293 window_shape_ = NULL; | |
| 1294 | |
| 1218 if (!IsMaximized()) { | 1295 if (!IsMaximized()) { |
| 1219 gfx::Path window_mask; | 1296 gfx::Path window_mask; |
| 1220 views::Widget* widget = native_widget_delegate_->AsWidget(); | 1297 views::Widget* widget = native_widget_delegate_->AsWidget(); |
| 1221 if (widget->non_client_view()) { | 1298 if (widget->non_client_view()) { |
| 1222 // Some frame views define a custom (non-rectangular) window mask. If | 1299 // Some frame views define a custom (non-rectangular) window mask. If |
| 1223 // so, use it to define the window shape. If not, fall through. | 1300 // so, use it to define the window shape. If not, fall through. |
| 1224 widget->non_client_view()->GetWindowMask(bounds_.size(), &window_mask); | 1301 widget->non_client_view()->GetWindowMask(bounds_.size(), &window_mask); |
| 1225 if (window_mask.countPoints() > 0) { | 1302 if (window_mask.countPoints() > 0) { |
| 1226 Region region = gfx::CreateRegionFromSkPath(window_mask); | 1303 window_shape_ = gfx::CreateRegionFromSkPath(window_mask); |
| 1227 XShapeCombineRegion(xdisplay_, xwindow_, ShapeBounding, | 1304 XShapeCombineRegion(xdisplay_, xwindow_, ShapeBounding, |
| 1228 0, 0, region, false); | 1305 0, 0, window_shape_, false); |
|
sadrul
2014/05/08 18:53:29
Interesting. Can there be a test for this case?
| |
| 1229 XDestroyRegion(region); | |
| 1230 return; | 1306 return; |
| 1231 } | 1307 } |
| 1232 } | 1308 } |
| 1233 } | 1309 } |
| 1234 | 1310 |
| 1235 // If we didn't set the shape for any reason, reset the shaping information. | 1311 // If we didn't set the shape for any reason, reset the shaping information. |
| 1236 // How this is done depends on the border style, due to quirks and bugs in | 1312 // How this is done depends on the border style, due to quirks and bugs in |
| 1237 // various window managers. | 1313 // various window managers. |
| 1238 if (ShouldUseNativeFrame()) { | 1314 if (ShouldUseNativeFrame()) { |
| 1239 // If the window has system borders, the mask must be set to null (not a | 1315 // If the window has system borders, the mask must be set to null (not a |
| (...skipping 362 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1602 } else { | 1678 } else { |
| 1603 break; | 1679 break; |
| 1604 } | 1680 } |
| 1605 } | 1681 } |
| 1606 | 1682 |
| 1607 ui::MouseEvent mouseev(xev); | 1683 ui::MouseEvent mouseev(xev); |
| 1608 DispatchMouseEvent(&mouseev); | 1684 DispatchMouseEvent(&mouseev); |
| 1609 break; | 1685 break; |
| 1610 } | 1686 } |
| 1611 case PropertyNotify: { | 1687 case PropertyNotify: { |
| 1612 // Get our new window property state if the WM has told us its changed. | 1688 ::Atom changed_atom = xev->xproperty.atom; |
| 1613 ::Atom state = atom_cache_.GetAtom("_NET_WM_STATE"); | 1689 if (changed_atom == atom_cache_.GetAtom("_NET_WM_STATE")) |
| 1614 | 1690 OnWMStateUpdated(); |
| 1615 std::vector< ::Atom> atom_list; | 1691 else if (changed_atom == atom_cache_.GetAtom("_NET_FRAME_EXTENTS")) |
| 1616 if (xev->xproperty.atom == state && | 1692 OnFrameExtentsUpdated(); |
| 1617 ui::GetAtomArrayProperty(xwindow_, "_NET_WM_STATE", &atom_list)) { | |
| 1618 window_properties_.clear(); | |
| 1619 std::copy(atom_list.begin(), atom_list.end(), | |
| 1620 inserter(window_properties_, window_properties_.begin())); | |
| 1621 | |
| 1622 if (!restored_bounds_.IsEmpty() && !IsMaximized()) { | |
| 1623 // If we have restored bounds, but WM_STATE no longer claims to be | |
| 1624 // maximized, we should clear our restored bounds. | |
| 1625 restored_bounds_ = gfx::Rect(); | |
| 1626 } else if (IsMaximized() && restored_bounds_.IsEmpty()) { | |
| 1627 // The request that we become maximized originated from a different | |
| 1628 // process. |bounds_| already contains our maximized bounds. Do a | |
| 1629 // best effort attempt to get restored bounds by setting it to our | |
| 1630 // previously set bounds (and if we get this wrong, we aren't any | |
| 1631 // worse off since we'd otherwise be returning our maximized bounds). | |
| 1632 restored_bounds_ = previous_bounds_; | |
| 1633 } | |
| 1634 | |
| 1635 is_fullscreen_ = HasWMSpecProperty("_NET_WM_STATE_FULLSCREEN"); | |
| 1636 is_always_on_top_ = HasWMSpecProperty("_NET_WM_STATE_ABOVE"); | |
| 1637 | |
| 1638 // Now that we have different window properties, we may need to | |
| 1639 // relayout the window. (The windows code doesn't need this because | |
| 1640 // their window change is synchronous.) | |
| 1641 // | |
| 1642 // TODO(erg): While this does work, there's a quick flash showing the | |
| 1643 // tabstrip/toolbar/etc. when going into fullscreen mode before hiding | |
| 1644 // those parts of the UI because we receive the sizing event from the | |
| 1645 // window manager before we receive the event that changes the | |
| 1646 // fullscreen state. Unsure what to do about that. | |
| 1647 Widget* widget = native_widget_delegate_->AsWidget(); | |
| 1648 NonClientView* non_client_view = widget->non_client_view(); | |
| 1649 // non_client_view may be NULL, especially during creation. | |
| 1650 if (non_client_view) { | |
| 1651 non_client_view->client_view()->InvalidateLayout(); | |
| 1652 non_client_view->InvalidateLayout(); | |
| 1653 } | |
| 1654 widget->GetRootView()->Layout(); | |
| 1655 // Refresh the window's border, which may need to be updated if we have | |
| 1656 // changed the window's maximization state. | |
| 1657 ResetWindowRegion(); | |
| 1658 } | |
| 1659 break; | 1693 break; |
| 1660 } | 1694 } |
| 1661 case SelectionNotify: { | 1695 case SelectionNotify: { |
| 1662 drag_drop_client_->OnSelectionNotify(xev->xselection); | 1696 drag_drop_client_->OnSelectionNotify(xev->xselection); |
| 1663 break; | 1697 break; |
| 1664 } | 1698 } |
| 1665 } | 1699 } |
| 1666 return ui::POST_DISPATCH_STOP_PROPAGATION; | 1700 return ui::POST_DISPATCH_STOP_PROPAGATION; |
| 1667 } | 1701 } |
| 1668 | 1702 |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 1683 if (linux_ui) { | 1717 if (linux_ui) { |
| 1684 ui::NativeTheme* native_theme = linux_ui->GetNativeTheme(window); | 1718 ui::NativeTheme* native_theme = linux_ui->GetNativeTheme(window); |
| 1685 if (native_theme) | 1719 if (native_theme) |
| 1686 return native_theme; | 1720 return native_theme; |
| 1687 } | 1721 } |
| 1688 | 1722 |
| 1689 return ui::NativeTheme::instance(); | 1723 return ui::NativeTheme::instance(); |
| 1690 } | 1724 } |
| 1691 | 1725 |
| 1692 } // namespace views | 1726 } // namespace views |
| OLD | NEW |