Merge lp:~3v1n0/unity/decoration-edges-improvements into lp:unity
- decoration-edges-improvements
- Merge into trunk
Status: | Merged | ||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Approved by: | Marco Trevisan (Treviño) | ||||||||||||||||||||||||
Approved revision: | no longer in the source branch. | ||||||||||||||||||||||||
Merged at revision: | 3882 | ||||||||||||||||||||||||
Proposed branch: | lp:~3v1n0/unity/decoration-edges-improvements | ||||||||||||||||||||||||
Merge into: | lp:unity | ||||||||||||||||||||||||
Diff against target: |
1018 lines (+333/-177) 13 files modified
UnityCore/DesktopUtilities.cpp (+0/-2) decorations/DecoratedWindow.cpp (+139/-64) decorations/DecorationsEdgeBorders.cpp (+32/-19) decorations/DecorationsForceQuitDialog.cpp (+17/-3) decorations/DecorationsManager.cpp (+16/-25) decorations/DecorationsPriv.h (+11/-3) decorations/DecorationsTitle.cpp (+1/-0) decorations/DecorationsWidgets.cpp (+13/-1) decorations/DecorationsWidgets.h (+5/-0) plugins/unityshell/src/unityshell.cpp (+1/-0) unity-shared/CompizUtils.cpp (+73/-54) unity-shared/CompizUtils.h (+24/-5) unity-shared/XWindowManager.cpp (+1/-1) |
||||||||||||||||||||||||
To merge this branch: | bzr merge lp:~3v1n0/unity/decoration-edges-improvements | ||||||||||||||||||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot (community) | continuous-integration | Approve | |
Brandon Schaefer (community) | Approve | ||
Review via email: mp+236744@code.launchpad.net |
Commit message
DecoratedWindow: make edges independent from borders and properly update them on actions changed
Now windows can have edges (handles) also if they are not fully decorated, and
the other way around.
Improved the logic to detect which kind of decorations are supported by windows
(so now we add shadows to windows with borders, and we do not to shaped ones).
Removed a lot of duplicated matrix/region computations.
Properly rebuild decorations when _NET_WM_
Fixes to the ForceQuit dialog shadows (and support for backdrop mode).
Description of the change
PS Jenkins bot (ps-jenkins) wrote : | # |
Brandon Schaefer (brandontschaefer) wrote : | # |
LGTM
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:3836
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:3837
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Preview Diff
1 | === modified file 'UnityCore/DesktopUtilities.cpp' | |||
2 | --- UnityCore/DesktopUtilities.cpp 2014-08-26 22:59:57 +0000 | |||
3 | +++ UnityCore/DesktopUtilities.cpp 2014-10-10 14:56:03 +0000 | |||
4 | @@ -71,8 +71,6 @@ | |||
5 | 71 | const char *config_dir = g_get_user_config_dir(); | 71 | const char *config_dir = g_get_user_config_dir(); |
6 | 72 | auto unity_config = glib::gchar_to_string(config_dir).append(G_DIR_SEPARATOR_S "unity" G_DIR_SEPARATOR_S); | 72 | auto unity_config = glib::gchar_to_string(config_dir).append(G_DIR_SEPARATOR_S "unity" G_DIR_SEPARATOR_S); |
7 | 73 | 73 | ||
8 | 74 | printf("CONFIG %s\n", unity_config.c_str()); | ||
9 | 75 | |||
10 | 76 | if (g_mkdir_with_parents(unity_config.c_str(), 0700) >= 0) | 74 | if (g_mkdir_with_parents(unity_config.c_str(), 0700) >= 0) |
11 | 77 | return unity_config; | 75 | return unity_config; |
12 | 78 | 76 | ||
13 | 79 | 77 | ||
14 | === modified file 'decorations/DecoratedWindow.cpp' | |||
15 | --- decorations/DecoratedWindow.cpp 2014-07-30 00:49:35 +0000 | |||
16 | +++ decorations/DecoratedWindow.cpp 2014-10-10 14:56:03 +0000 | |||
17 | @@ -1,6 +1,6 @@ | |||
18 | 1 | // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- | 1 | // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- |
19 | 2 | /* | 2 | /* |
21 | 3 | * Copyright (C) 2013 Canonical Ltd | 3 | * Copyright (C) 2013-2014 Canonical Ltd |
22 | 4 | * | 4 | * |
23 | 5 | * This program is free software: you can redistribute it and/or modify | 5 | * This program is free software: you can redistribute it and/or modify |
24 | 6 | * it under the terms of the GNU General Public License version 3 as | 6 | * it under the terms of the GNU General Public License version 3 as |
25 | @@ -44,8 +44,12 @@ | |||
26 | 44 | , cwin_(CompositeWindow::get(win_)) | 44 | , cwin_(CompositeWindow::get(win_)) |
27 | 45 | , glwin_(GLWindow::get(win_)) | 45 | , glwin_(GLWindow::get(win_)) |
28 | 46 | , frame_(0) | 46 | , frame_(0) |
29 | 47 | , monitor_(0) | ||
30 | 47 | , dirty_geo_(true) | 48 | , dirty_geo_(true) |
32 | 48 | , monitor_(0) | 49 | , dirty_frame_(false) |
33 | 50 | , deco_elements_(cu::DecorationElement::NONE) | ||
34 | 51 | , last_mwm_decor_(win_->mwmDecor()) | ||
35 | 52 | , last_actions_(win_->actions()) | ||
36 | 49 | , cv_(Settings::Instance().em()) | 53 | , cv_(Settings::Instance().em()) |
37 | 50 | { | 54 | { |
38 | 51 | active.changed.connect([this] (bool active) { | 55 | active.changed.connect([this] (bool active) { |
39 | @@ -105,14 +109,27 @@ | |||
40 | 105 | 109 | ||
41 | 106 | void Window::Impl::Update() | 110 | void Window::Impl::Update() |
42 | 107 | { | 111 | { |
44 | 108 | ShouldBeDecorated() ? Decorate() : Undecorate(); | 112 | UpdateElements(); |
45 | 113 | (deco_elements_ & (cu::DecorationElement::EDGE | cu::DecorationElement::BORDER)) ? Decorate() : Undecorate(); | ||
46 | 114 | last_mwm_decor_ = win_->mwmDecor(); | ||
47 | 115 | last_actions_ = win_->actions(); | ||
48 | 109 | } | 116 | } |
49 | 110 | 117 | ||
50 | 111 | void Window::Impl::Decorate() | 118 | void Window::Impl::Decorate() |
51 | 112 | { | 119 | { |
52 | 113 | SetupExtents(); | 120 | SetupExtents(); |
53 | 114 | UpdateFrame(); | 121 | UpdateFrame(); |
55 | 115 | SetupWindowControls(); | 122 | SetupWindowEdges(); |
56 | 123 | |||
57 | 124 | if (deco_elements_ & cu::DecorationElement::BORDER) | ||
58 | 125 | { | ||
59 | 126 | SetupWindowControls(); | ||
60 | 127 | } | ||
61 | 128 | else | ||
62 | 129 | { | ||
63 | 130 | CleanupWindowControls(); | ||
64 | 131 | bg_textures_.clear(); | ||
65 | 132 | } | ||
66 | 116 | } | 133 | } |
67 | 117 | 134 | ||
68 | 118 | void Window::Impl::Undecorate() | 135 | void Window::Impl::Undecorate() |
69 | @@ -120,6 +137,7 @@ | |||
70 | 120 | UnsetExtents(); | 137 | UnsetExtents(); |
71 | 121 | UnsetFrame(); | 138 | UnsetFrame(); |
72 | 122 | CleanupWindowControls(); | 139 | CleanupWindowControls(); |
73 | 140 | CleanupWindowEdges(); | ||
74 | 123 | bg_textures_.clear(); | 141 | bg_textures_.clear(); |
75 | 124 | } | 142 | } |
76 | 125 | 143 | ||
77 | @@ -139,17 +157,27 @@ | |||
78 | 139 | if (win_->hasUnmapReference()) | 157 | if (win_->hasUnmapReference()) |
79 | 140 | return; | 158 | return; |
80 | 141 | 159 | ||
92 | 142 | auto const& sb = Style::Get()->Border(); | 160 | CompWindowExtents border; |
93 | 143 | CompWindowExtents border(cv_->CP(sb.left), | 161 | |
94 | 144 | cv_->CP(sb.right), | 162 | if (deco_elements_ & cu::DecorationElement::BORDER) |
95 | 145 | cv_->CP(sb.top), | 163 | { |
96 | 146 | cv_->CP(sb.bottom)); | 164 | auto const& sb = Style::Get()->Border(); |
97 | 147 | 165 | border.left = cv_->CP(sb.left); | |
98 | 148 | auto const& ib = Style::Get()->InputBorder(); | 166 | border.right = cv_->CP(sb.right); |
99 | 149 | CompWindowExtents input(cv_->CP(sb.left + ib.left), | 167 | border.top = cv_->CP(sb.top); |
100 | 150 | cv_->CP(sb.right + ib.right), | 168 | border.bottom = cv_->CP(sb.bottom); |
101 | 151 | cv_->CP(sb.top + ib.top), | 169 | } |
102 | 152 | cv_->CP(sb.bottom + ib.bottom)); | 170 | |
103 | 171 | CompWindowExtents input(border); | ||
104 | 172 | |||
105 | 173 | if (deco_elements_ & cu::DecorationElement::EDGE) | ||
106 | 174 | { | ||
107 | 175 | auto const& ib = Style::Get()->InputBorder(); | ||
108 | 176 | input.left += cv_->CP(ib.left); | ||
109 | 177 | input.right += cv_->CP(ib.right); | ||
110 | 178 | input.top += cv_->CP(ib.top); | ||
111 | 179 | input.bottom += cv_->CP(ib.bottom); | ||
112 | 180 | } | ||
113 | 153 | 181 | ||
114 | 154 | if (win_->border() != border || win_->input() != input) | 182 | if (win_->border() != border || win_->input() != input) |
115 | 155 | win_->setWindowFrameExtents(&border, &input); | 183 | win_->setWindowFrameExtents(&border, &input); |
116 | @@ -183,6 +211,15 @@ | |||
117 | 183 | UpdateFrameGeo(frame_geo); | 211 | UpdateFrameGeo(frame_geo); |
118 | 184 | } | 212 | } |
119 | 185 | 213 | ||
120 | 214 | void Window::Impl::UpdateFrameActions() | ||
121 | 215 | { | ||
122 | 216 | if (!dirty_frame_ && (win_->mwmDecor() != last_mwm_decor_ || win_->actions() != last_actions_)) | ||
123 | 217 | { | ||
124 | 218 | dirty_frame_ = true; | ||
125 | 219 | Damage(); | ||
126 | 220 | } | ||
127 | 221 | } | ||
128 | 222 | |||
129 | 186 | void Window::Impl::CreateFrame(nux::Geometry const& frame_geo) | 223 | void Window::Impl::CreateFrame(nux::Geometry const& frame_geo) |
130 | 187 | { | 224 | { |
131 | 188 | /* Since we're reparenting windows here, we need to grab the server | 225 | /* Since we're reparenting windows here, we need to grab the server |
132 | @@ -280,6 +317,42 @@ | |||
133 | 280 | win_->updateFrameRegion(); | 317 | win_->updateFrameRegion(); |
134 | 281 | } | 318 | } |
135 | 282 | 319 | ||
136 | 320 | void Window::Impl::SetupWindowEdges() | ||
137 | 321 | { | ||
138 | 322 | if (input_mixer_) | ||
139 | 323 | return; | ||
140 | 324 | |||
141 | 325 | dpi_changed_ = Settings::Instance().dpi_changed.connect([this] { | ||
142 | 326 | Update(); | ||
143 | 327 | edge_borders_->scale = cv_->DPIScale(); | ||
144 | 328 | if (top_layout_) top_layout_->scale = cv_->DPIScale(); | ||
145 | 329 | }); | ||
146 | 330 | |||
147 | 331 | input_mixer_ = std::make_shared<InputMixer>(); | ||
148 | 332 | edge_borders_ = std::make_shared<EdgeBorders>(win_); | ||
149 | 333 | edge_borders_->scale = cv_->DPIScale(); | ||
150 | 334 | input_mixer_->PushToFront(edge_borders_); | ||
151 | 335 | |||
152 | 336 | UpdateWindowEdgesGeo(); | ||
153 | 337 | } | ||
154 | 338 | |||
155 | 339 | void Window::Impl::UpdateWindowEdgesGeo() | ||
156 | 340 | { | ||
157 | 341 | if (!edge_borders_) | ||
158 | 342 | return; | ||
159 | 343 | |||
160 | 344 | auto const& input = win_->inputRect(); | ||
161 | 345 | edge_borders_->SetCoords(input.x(), input.y()); | ||
162 | 346 | edge_borders_->SetSize(input.width(), input.height()); | ||
163 | 347 | } | ||
164 | 348 | |||
165 | 349 | void Window::Impl::CleanupWindowEdges() | ||
166 | 350 | { | ||
167 | 351 | input_mixer_.reset(); | ||
168 | 352 | edge_borders_.reset(); | ||
169 | 353 | dpi_changed_->disconnect(); | ||
170 | 354 | } | ||
171 | 355 | |||
172 | 283 | void Window::Impl::SetupWindowControls() | 356 | void Window::Impl::SetupWindowControls() |
173 | 284 | { | 357 | { |
174 | 285 | if (top_layout_) | 358 | if (top_layout_) |
175 | @@ -291,26 +364,7 @@ | |||
176 | 291 | Decorate(); | 364 | Decorate(); |
177 | 292 | }); | 365 | }); |
178 | 293 | 366 | ||
199 | 294 | dpi_changed_ = Settings::Instance().dpi_changed.connect([this] { | 367 | grab_edge_ = std::static_pointer_cast<EdgeBorders>(edge_borders_)->GetEdge(Edge::Type::GRAB); |
180 | 295 | Update(); | ||
181 | 296 | top_layout_->scale = cv_->DPIScale(); | ||
182 | 297 | }); | ||
183 | 298 | |||
184 | 299 | input_mixer_ = std::make_shared<InputMixer>(); | ||
185 | 300 | |||
186 | 301 | if (win_->actions() & CompWindowActionResizeMask) | ||
187 | 302 | { | ||
188 | 303 | auto edges = std::make_shared<EdgeBorders>(win_); | ||
189 | 304 | grab_edge_ = edges->GetEdge(Edge::Type::GRAB); | ||
190 | 305 | edge_borders_ = edges; | ||
191 | 306 | } | ||
192 | 307 | else /*if (win_->actions() & CompWindowActionMoveMask)*/ | ||
193 | 308 | { | ||
194 | 309 | edge_borders_ = std::make_shared<GrabEdge>(win_); | ||
195 | 310 | grab_edge_ = edge_borders_; | ||
196 | 311 | } | ||
197 | 312 | |||
198 | 313 | input_mixer_->PushToFront(edge_borders_); | ||
200 | 314 | 368 | ||
201 | 315 | auto padding = style->Padding(Side::TOP); | 369 | auto padding = style->Padding(Side::TOP); |
202 | 316 | top_layout_ = std::make_shared<Layout>(); | 370 | top_layout_ = std::make_shared<Layout>(); |
203 | @@ -345,6 +399,7 @@ | |||
204 | 345 | top_layout_->Append(title_layout); | 399 | top_layout_->Append(title_layout); |
205 | 346 | 400 | ||
206 | 347 | input_mixer_->PushToFront(top_layout_); | 401 | input_mixer_->PushToFront(top_layout_); |
207 | 402 | dirty_frame_ = false; | ||
208 | 348 | 403 | ||
209 | 349 | SetupAppMenu(); | 404 | SetupAppMenu(); |
210 | 350 | RedrawDecorations(); | 405 | RedrawDecorations(); |
211 | @@ -355,12 +410,12 @@ | |||
212 | 355 | if (title_) | 410 | if (title_) |
213 | 356 | last_title_ = title_->text(); | 411 | last_title_ = title_->text(); |
214 | 357 | 412 | ||
215 | 413 | if (input_mixer_) | ||
216 | 414 | input_mixer_->Remove(top_layout_); | ||
217 | 415 | |||
218 | 358 | UnsetAppMenu(); | 416 | UnsetAppMenu(); |
219 | 359 | theme_changed_->disconnect(); | 417 | theme_changed_->disconnect(); |
220 | 360 | dpi_changed_->disconnect(); | ||
221 | 361 | top_layout_.reset(); | 418 | top_layout_.reset(); |
222 | 362 | input_mixer_.reset(); | ||
223 | 363 | edge_borders_.reset(); | ||
224 | 364 | } | 419 | } |
225 | 365 | 420 | ||
226 | 366 | bool Window::Impl::IsMaximized() const | 421 | bool Window::Impl::IsMaximized() const |
227 | @@ -368,26 +423,25 @@ | |||
228 | 368 | return (win_->state() & MAXIMIZE_STATE) == MAXIMIZE_STATE; | 423 | return (win_->state() & MAXIMIZE_STATE) == MAXIMIZE_STATE; |
229 | 369 | } | 424 | } |
230 | 370 | 425 | ||
231 | 426 | void Window::Impl::UpdateElements() | ||
232 | 427 | { | ||
233 | 428 | if (!parent_->scaled() && IsMaximized()) | ||
234 | 429 | { | ||
235 | 430 | deco_elements_ = cu::DecorationElement::NONE; | ||
236 | 431 | return; | ||
237 | 432 | } | ||
238 | 433 | |||
239 | 434 | deco_elements_ = cu::WindowDecorationElements(win_); | ||
240 | 435 | } | ||
241 | 436 | |||
242 | 371 | bool Window::Impl::ShadowDecorated() const | 437 | bool Window::Impl::ShadowDecorated() const |
243 | 372 | { | 438 | { |
251 | 373 | if (!parent_->scaled() && IsMaximized()) | 439 | return deco_elements_ & cu::DecorationElement::SHADOW; |
245 | 374 | return false; | ||
246 | 375 | |||
247 | 376 | if (!cu::IsWindowShadowDecorable(win_)) | ||
248 | 377 | return false; | ||
249 | 378 | |||
250 | 379 | return true; | ||
252 | 380 | } | 440 | } |
253 | 381 | 441 | ||
254 | 382 | bool Window::Impl::FullyDecorated() const | 442 | bool Window::Impl::FullyDecorated() const |
255 | 383 | { | 443 | { |
263 | 384 | if (!parent_->scaled() && IsMaximized()) | 444 | return deco_elements_ & cu::DecorationElement::BORDER; |
257 | 385 | return false; | ||
258 | 386 | |||
259 | 387 | if (!cu::IsWindowFullyDecorable(win_)) | ||
260 | 388 | return false; | ||
261 | 389 | |||
262 | 390 | return true; | ||
264 | 391 | } | 445 | } |
265 | 392 | 446 | ||
266 | 393 | bool Window::Impl::ShouldBeDecorated() const | 447 | bool Window::Impl::ShouldBeDecorated() const |
267 | @@ -429,6 +483,7 @@ | |||
268 | 429 | } | 483 | } |
269 | 430 | 484 | ||
270 | 431 | deco_tex.SetCoords(geo.x, geo.y); | 485 | deco_tex.SetCoords(geo.x, geo.y); |
271 | 486 | deco_tex.quad.region = deco_tex.quad.box; | ||
272 | 432 | } | 487 | } |
273 | 433 | 488 | ||
274 | 434 | void Window::Impl::UpdateDecorationTextures() | 489 | void Window::Impl::UpdateDecorationTextures() |
275 | @@ -440,7 +495,6 @@ | |||
276 | 440 | } | 495 | } |
277 | 441 | 496 | ||
278 | 442 | auto const& geo = win_->borderRect(); | 497 | auto const& geo = win_->borderRect(); |
279 | 443 | auto const& input = win_->inputRect(); | ||
280 | 444 | auto const& border = win_->border(); | 498 | auto const& border = win_->border(); |
281 | 445 | 499 | ||
282 | 446 | bg_textures_.resize(4); | 500 | bg_textures_.resize(4); |
283 | @@ -452,19 +506,18 @@ | |||
284 | 452 | top_layout_->SetCoords(geo.x(), geo.y()); | 506 | top_layout_->SetCoords(geo.x(), geo.y()); |
285 | 453 | top_layout_->SetSize(geo.width(), border.top); | 507 | top_layout_->SetSize(geo.width(), border.top); |
286 | 454 | 508 | ||
287 | 455 | if (edge_borders_) | ||
288 | 456 | { | ||
289 | 457 | edge_borders_->SetCoords(input.x(), input.y()); | ||
290 | 458 | edge_borders_->SetSize(input.width(), input.height()); | ||
291 | 459 | } | ||
292 | 460 | |||
293 | 461 | SyncMenusGeometries(); | 509 | SyncMenusGeometries(); |
294 | 462 | } | 510 | } |
295 | 463 | 511 | ||
296 | 464 | void Window::Impl::ComputeShadowQuads() | 512 | void Window::Impl::ComputeShadowQuads() |
297 | 465 | { | 513 | { |
299 | 466 | if (last_shadow_rect_.isEmpty() && !ShadowDecorated()) | 514 | if (!(deco_elements_ & cu::DecorationElement::SHADOW)) |
300 | 515 | { | ||
301 | 516 | if (!last_shadow_rect_.isEmpty()) | ||
302 | 517 | last_shadow_rect_.setGeometry(0, 0, 0, 0); | ||
303 | 518 | |||
304 | 467 | return; | 519 | return; |
305 | 520 | } | ||
306 | 468 | 521 | ||
307 | 469 | const auto* texture = ShadowTexture(); | 522 | const auto* texture = ShadowTexture(); |
308 | 470 | 523 | ||
309 | @@ -552,6 +605,12 @@ | |||
310 | 552 | 605 | ||
311 | 553 | if (shadows_rect != last_shadow_rect_) | 606 | if (shadows_rect != last_shadow_rect_) |
312 | 554 | { | 607 | { |
313 | 608 | auto const& win_region = win_->region(); | ||
314 | 609 | quads[Quads::Pos::TOP_LEFT].region = CompRegion(quads[Quads::Pos::TOP_LEFT].box) - win_region; | ||
315 | 610 | quads[Quads::Pos::TOP_RIGHT].region = CompRegion(quads[Quads::Pos::TOP_RIGHT].box) - win_region; | ||
316 | 611 | quads[Quads::Pos::BOTTOM_LEFT].region = CompRegion(quads[Quads::Pos::BOTTOM_LEFT].box) - win_region; | ||
317 | 612 | quads[Quads::Pos::BOTTOM_RIGHT].region = CompRegion(quads[Quads::Pos::BOTTOM_RIGHT].box) - win_region; | ||
318 | 613 | |||
319 | 555 | last_shadow_rect_ = shadows_rect; | 614 | last_shadow_rect_ = shadows_rect; |
320 | 556 | win_->updateWindowOutputExtents(); | 615 | win_->updateWindowOutputExtents(); |
321 | 557 | } | 616 | } |
322 | @@ -561,15 +620,26 @@ | |||
323 | 561 | GLWindowPaintAttrib const& attrib, | 620 | GLWindowPaintAttrib const& attrib, |
324 | 562 | CompRegion const& region, unsigned mask) | 621 | CompRegion const& region, unsigned mask) |
325 | 563 | { | 622 | { |
326 | 623 | if (win_->defaultViewport() != screen->vp()) | ||
327 | 624 | return; | ||
328 | 625 | |||
329 | 564 | if (dirty_geo_) | 626 | if (dirty_geo_) |
330 | 565 | parent_->UpdateDecorationPosition(); | 627 | parent_->UpdateDecorationPosition(); |
331 | 628 | |||
332 | 629 | if (dirty_frame_) | ||
333 | 630 | { | ||
334 | 631 | dirty_frame_ = false; | ||
335 | 632 | CleanupWindowControls(); | ||
336 | 633 | CleanupWindowEdges(); | ||
337 | 634 | Update(); | ||
338 | 635 | } | ||
339 | 566 | } | 636 | } |
340 | 567 | 637 | ||
341 | 568 | void Window::Impl::Draw(GLMatrix const& transformation, | 638 | void Window::Impl::Draw(GLMatrix const& transformation, |
342 | 569 | GLWindowPaintAttrib const& attrib, | 639 | GLWindowPaintAttrib const& attrib, |
343 | 570 | CompRegion const& region, unsigned mask) | 640 | CompRegion const& region, unsigned mask) |
344 | 571 | { | 641 | { |
346 | 572 | if (last_shadow_rect_.isEmpty()) | 642 | if (last_shadow_rect_.isEmpty() || win_->defaultViewport() != screen->vp()) |
347 | 573 | return; | 643 | return; |
348 | 574 | 644 | ||
349 | 575 | auto const& clip_region = (mask & PAINT_WINDOW_TRANSFORMED_MASK) ? infiniteRegion : region; | 645 | auto const& clip_region = (mask & PAINT_WINDOW_TRANSFORMED_MASK) ? infiniteRegion : region; |
350 | @@ -580,7 +650,7 @@ | |||
351 | 580 | for (unsigned i = 0; i < shadow_quads_.size(); ++i) | 650 | for (unsigned i = 0; i < shadow_quads_.size(); ++i) |
352 | 581 | { | 651 | { |
353 | 582 | auto& quad = shadow_quads_[Quads::Pos(i)]; | 652 | auto& quad = shadow_quads_[Quads::Pos(i)]; |
355 | 583 | glwin_->glAddGeometry({quad.matrix}, CompRegion(quad.box) - win_->region(), clip_region); | 653 | glwin_->glAddGeometry(quad.matrices, quad.region, clip_region); |
356 | 584 | } | 654 | } |
357 | 585 | 655 | ||
358 | 586 | if (glwin_->vertexBuffer()->end()) | 656 | if (glwin_->vertexBuffer()->end()) |
359 | @@ -592,7 +662,7 @@ | |||
360 | 592 | continue; | 662 | continue; |
361 | 593 | 663 | ||
362 | 594 | glwin_->vertexBuffer()->begin(); | 664 | glwin_->vertexBuffer()->begin(); |
364 | 595 | glwin_->glAddGeometry({dtex.quad.matrix}, dtex.quad.box, clip_region); | 665 | glwin_->glAddGeometry(dtex.quad.matrices, dtex.quad.region, clip_region); |
365 | 596 | 666 | ||
366 | 597 | if (glwin_->vertexBuffer()->end()) | 667 | if (glwin_->vertexBuffer()->end()) |
367 | 598 | glwin_->glDrawTexture(dtex, transformation, attrib, mask); | 668 | glwin_->glDrawTexture(dtex, transformation, attrib, mask); |
368 | @@ -705,6 +775,9 @@ | |||
369 | 705 | 775 | ||
370 | 706 | if (top_layout_) | 776 | if (top_layout_) |
371 | 707 | top_layout_->scale = cv_->DPIScale(); | 777 | top_layout_->scale = cv_->DPIScale(); |
372 | 778 | |||
373 | 779 | if (edge_borders_) | ||
374 | 780 | edge_borders_->scale = cv_->DPIScale(); | ||
375 | 708 | } | 781 | } |
376 | 709 | } | 782 | } |
377 | 710 | 783 | ||
378 | @@ -787,6 +860,7 @@ | |||
379 | 787 | { | 860 | { |
380 | 788 | impl_->UpdateMonitor(); | 861 | impl_->UpdateMonitor(); |
381 | 789 | impl_->ComputeShadowQuads(); | 862 | impl_->ComputeShadowQuads(); |
382 | 863 | impl_->UpdateWindowEdgesGeo(); | ||
383 | 790 | impl_->UpdateDecorationTextures(); | 864 | impl_->UpdateDecorationTextures(); |
384 | 791 | impl_->UpdateForceQuitDialogPosition(); | 865 | impl_->UpdateForceQuitDialogPosition(); |
385 | 792 | impl_->dirty_geo_ = false; | 866 | impl_->dirty_geo_ = false; |
386 | @@ -806,7 +880,8 @@ | |||
387 | 806 | { | 880 | { |
388 | 807 | data.add(impl_->win_->borderRect()) | 881 | data.add(impl_->win_->borderRect()) |
389 | 808 | .add("input_geo", impl_->win_->inputRect()) | 882 | .add("input_geo", impl_->win_->inputRect()) |
391 | 809 | .add("content_geo", impl_->win_->region().boundingRect()) | 883 | .add("content_geo", impl_->win_->geometry()) |
392 | 884 | .add("region", impl_->win_->region().boundingRect()) | ||
393 | 810 | .add("title", title()) | 885 | .add("title", title()) |
394 | 811 | .add("active", impl_->active()) | 886 | .add("active", impl_->active()) |
395 | 812 | .add("scaled", scaled()) | 887 | .add("scaled", scaled()) |
396 | 813 | 888 | ||
397 | === modified file 'decorations/DecorationsEdgeBorders.cpp' | |||
398 | --- decorations/DecorationsEdgeBorders.cpp 2014-02-18 23:01:33 +0000 | |||
399 | +++ decorations/DecorationsEdgeBorders.cpp 2014-10-10 14:56:03 +0000 | |||
400 | @@ -26,21 +26,31 @@ | |||
401 | 26 | { | 26 | { |
402 | 27 | namespace | 27 | namespace |
403 | 28 | { | 28 | { |
405 | 29 | const int MIN_CORNER_EDGE = 10; | 29 | const RawPixel MIN_CORNER_EDGE = 10_em; |
406 | 30 | } | 30 | } |
407 | 31 | 31 | ||
408 | 32 | EdgeBorders::EdgeBorders(CompWindow* win) | 32 | EdgeBorders::EdgeBorders(CompWindow* win) |
409 | 33 | { | 33 | { |
420 | 34 | items_.resize(size_t(Edge::Type::Size)); | 34 | scale.changed.connect(sigc::hide(sigc::mem_fun(this, &EdgeBorders::Relayout))); |
421 | 35 | 35 | ||
422 | 36 | for (unsigned i = 0; i < unsigned(Edge::Type::Size); ++i) | 36 | if (win->actions() & CompWindowActionResizeMask) |
423 | 37 | { | 37 | { |
424 | 38 | auto type = Edge::Type(i); | 38 | items_.resize(size_t(Edge::Type::Size)); |
425 | 39 | 39 | ||
426 | 40 | if (type == Edge::Type::GRAB) | 40 | for (unsigned i = 0; i < unsigned(Edge::Type::Size); ++i) |
427 | 41 | items_[i] = std::make_shared<GrabEdge>(win); | 41 | { |
428 | 42 | else | 42 | auto type = Edge::Type(i); |
429 | 43 | items_[i] = std::make_shared<Edge>(win, type); | 43 | |
430 | 44 | if (type == Edge::Type::GRAB) | ||
431 | 45 | items_[i] = std::make_shared<GrabEdge>(win); | ||
432 | 46 | else | ||
433 | 47 | items_[i] = std::make_shared<Edge>(win, type); | ||
434 | 48 | } | ||
435 | 49 | } | ||
436 | 50 | else /*if (win->actions() & CompWindowActionMoveMask)*/ | ||
437 | 51 | { | ||
438 | 52 | items_.resize(size_t(Edge::Type::GRAB) + 1); | ||
439 | 53 | items_[unsigned(Edge::Type::GRAB)] = std::make_shared<GrabEdge>(win); | ||
440 | 44 | } | 54 | } |
441 | 45 | 55 | ||
442 | 46 | Relayout(); | 56 | Relayout(); |
443 | @@ -54,10 +64,17 @@ | |||
444 | 54 | auto const& ib = win->input(); | 64 | auto const& ib = win->input(); |
445 | 55 | 65 | ||
446 | 56 | using namespace compiz::window::extents; | 66 | using namespace compiz::window::extents; |
451 | 57 | Extents edges(std::max(ib.left, MIN_CORNER_EDGE), | 67 | int min_corner_edge = MIN_CORNER_EDGE.CP(scale); |
452 | 58 | std::max(ib.right, MIN_CORNER_EDGE), | 68 | Extents edges(std::max(ib.left, min_corner_edge), |
453 | 59 | std::max(ib.top, MIN_CORNER_EDGE), | 69 | std::max(ib.right, min_corner_edge), |
454 | 60 | std::max(ib.bottom, MIN_CORNER_EDGE)); | 70 | std::max(ib.top, min_corner_edge), |
455 | 71 | std::max(ib.bottom, min_corner_edge)); | ||
456 | 72 | |||
457 | 73 | grab_edge->SetCoords(rect_.x() + ib.left, rect_.y() + ib.top - b.top); | ||
458 | 74 | grab_edge->SetSize(rect_.width() - ib.left - ib.right, b.top); | ||
459 | 75 | |||
460 | 76 | if (items_.size() != size_t(Edge::Type::Size)) | ||
461 | 77 | return; | ||
462 | 61 | 78 | ||
463 | 62 | auto item = items_[unsigned(Edge::Type::TOP)]; | 79 | auto item = items_[unsigned(Edge::Type::TOP)]; |
464 | 63 | item->SetCoords(rect_.x() + edges.left, rect_.y()); | 80 | item->SetCoords(rect_.x() + edges.left, rect_.y()); |
465 | @@ -90,10 +107,6 @@ | |||
466 | 90 | item = items_[unsigned(Edge::Type::BOTTOM_RIGHT)]; | 107 | item = items_[unsigned(Edge::Type::BOTTOM_RIGHT)]; |
467 | 91 | item->SetCoords(rect_.x2() - edges.right, rect_.y2() - edges.bottom); | 108 | item->SetCoords(rect_.x2() - edges.right, rect_.y2() - edges.bottom); |
468 | 92 | item->SetSize(edges.right, edges.bottom); | 109 | item->SetSize(edges.right, edges.bottom); |
469 | 93 | |||
470 | 94 | item = items_[unsigned(Edge::Type::GRAB)]; | ||
471 | 95 | item->SetCoords(rect_.x() + ib.left, rect_.y() + ib.top - b.top); | ||
472 | 96 | item->SetSize(rect_.width() - ib.left - ib.right, b.top); | ||
473 | 97 | } | 110 | } |
474 | 98 | 111 | ||
475 | 99 | Item::Ptr const& EdgeBorders::GetEdge(Edge::Type type) const | 112 | Item::Ptr const& EdgeBorders::GetEdge(Edge::Type type) const |
476 | 100 | 113 | ||
477 | === modified file 'decorations/DecorationsForceQuitDialog.cpp' | |||
478 | --- decorations/DecorationsForceQuitDialog.cpp 2014-06-13 15:23:12 +0000 | |||
479 | +++ decorations/DecorationsForceQuitDialog.cpp 2014-10-10 14:56:03 +0000 | |||
480 | @@ -141,7 +141,7 @@ | |||
481 | 141 | 141 | ||
482 | 142 | auto const& deco_style = decoration::Style::Get(); | 142 | auto const& deco_style = decoration::Style::Get(); |
483 | 143 | auto const& offset = deco_style->ShadowOffset(); | 143 | auto const& offset = deco_style->ShadowOffset(); |
485 | 144 | int max_offset = std::max(std::abs(offset.x), std::abs(offset.y)); | 144 | int max_offset = std::max(std::abs(offset.x * 4), std::abs(offset.y * 4)); |
486 | 145 | gtk_container_set_border_width(GTK_CONTAINER(self), deco_style->ActiveShadowRadius()+max_offset); | 145 | gtk_container_set_border_width(GTK_CONTAINER(self), deco_style->ActiveShadowRadius()+max_offset); |
487 | 146 | 146 | ||
488 | 147 | auto* screen = gtk_window_get_screen(self); | 147 | auto* screen = gtk_window_get_screen(self); |
489 | @@ -259,18 +259,32 @@ | |||
490 | 259 | auto const& radius = deco_style->CornerRadius(); | 259 | auto const& radius = deco_style->CornerRadius(); |
491 | 260 | auto const& offset = deco_style->ShadowOffset(); | 260 | auto const& offset = deco_style->ShadowOffset(); |
492 | 261 | auto const& color = deco_style->ActiveShadowColor(); | 261 | auto const& color = deco_style->ActiveShadowColor(); |
493 | 262 | auto const& backcolor = deco_style->InactiveShadowColor(); | ||
494 | 262 | int decoration_radius = std::max({radius.top, radius.left, radius.right, radius.bottom}); | 263 | int decoration_radius = std::max({radius.top, radius.left, radius.right, radius.bottom}); |
495 | 263 | 264 | ||
497 | 264 | gtk_css_provider_load_from_data(style, (R"(SheetStyleDialog { | 265 | gtk_css_provider_load_from_data(style, (R"( |
498 | 266 | SheetStyleDialog { | ||
499 | 265 | background-color: #f7f6f5; | 267 | background-color: #f7f6f5; |
500 | 266 | color: #4a4a4a; | 268 | color: #4a4a4a; |
501 | 267 | border-radius: )"+std::to_string(decoration_radius)+R"(px; | 269 | border-radius: )"+std::to_string(decoration_radius)+R"(px; |
503 | 268 | box-shadow: )"+std::to_string(offset.x)+"px "+std::to_string(offset.y)+"px "+ | 270 | box-shadow: )"+std::to_string(2 * offset.x)+"px "+std::to_string(2 * offset.y)+"px "+ |
504 | 269 | std::to_string(deco_style->ActiveShadowRadius())+"px "+ | 271 | std::to_string(deco_style->ActiveShadowRadius())+"px "+ |
505 | 270 | "rgba("+std::to_string(int(color.red * 255.0))+", "+ | 272 | "rgba("+std::to_string(int(color.red * 255.0))+", "+ |
506 | 271 | std::to_string(int(color.green * 255.0))+", "+ | 273 | std::to_string(int(color.green * 255.0))+", "+ |
507 | 272 | std::to_string(int(color.blue * 255.0))+", "+ | 274 | std::to_string(int(color.blue * 255.0))+", "+ |
508 | 273 | std::to_string(int(color.alpha))+'.'+std::to_string(int(color.alpha*10000.0))+')'+R"(; | 275 | std::to_string(int(color.alpha))+'.'+std::to_string(int(color.alpha*10000.0))+')'+R"(; |
509 | 276 | } | ||
510 | 277 | |||
511 | 278 | SheetStyleDialog:backdrop { | ||
512 | 279 | background-color: shade(#f7f6f5, 1.2); | ||
513 | 280 | color: shade(#4a4a4a, 1.5); | ||
514 | 281 | border-radius: )"+std::to_string(decoration_radius)+R"(px; | ||
515 | 282 | box-shadow: )"+std::to_string(2 * offset.x)+"px "+std::to_string(2 * offset.y)+"px "+ | ||
516 | 283 | std::to_string(deco_style->InactiveShadowRadius())+"px "+ | ||
517 | 284 | "rgba("+std::to_string(int(backcolor.red * 255.0))+", "+ | ||
518 | 285 | std::to_string(int(backcolor.green * 255.0))+", "+ | ||
519 | 286 | std::to_string(int(backcolor.blue * 255.0))+", "+ | ||
520 | 287 | std::to_string(int(backcolor.alpha))+'.'+std::to_string(int(backcolor.alpha*10000.0))+')'+R"(; | ||
521 | 274 | })").c_str(), -1, nullptr); | 288 | })").c_str(), -1, nullptr); |
522 | 275 | 289 | ||
523 | 276 | auto* style_ctx = gtk_widget_get_style_context(self); | 290 | auto* style_ctx = gtk_widget_get_style_context(self); |
524 | 277 | 291 | ||
525 | === modified file 'decorations/DecorationsManager.cpp' | |||
526 | --- decorations/DecorationsManager.cpp 2014-07-30 00:49:35 +0000 | |||
527 | +++ decorations/DecorationsManager.cpp 2014-10-10 14:56:03 +0000 | |||
528 | @@ -41,8 +41,7 @@ | |||
529 | 41 | } | 41 | } |
530 | 42 | 42 | ||
531 | 43 | Manager::Impl::Impl(decoration::Manager* parent, menu::Manager::Ptr const& menu) | 43 | Manager::Impl::Impl(decoration::Manager* parent, menu::Manager::Ptr const& menu) |
534 | 44 | : active_window_(0) | 44 | : enable_add_supported_atoms_(true) |
533 | 45 | , enable_add_supported_atoms_(true) | ||
535 | 46 | , data_pool_(DataPool::Get()) | 45 | , data_pool_(DataPool::Get()) |
536 | 47 | , menu_manager_(menu) | 46 | , menu_manager_(menu) |
537 | 48 | { | 47 | { |
538 | @@ -52,7 +51,6 @@ | |||
539 | 52 | Display* dpy = screen->dpy(); | 51 | Display* dpy = screen->dpy(); |
540 | 53 | atom::_NET_REQUEST_FRAME_EXTENTS = XInternAtom(dpy, "_NET_REQUEST_FRAME_EXTENTS", False); | 52 | atom::_NET_REQUEST_FRAME_EXTENTS = XInternAtom(dpy, "_NET_REQUEST_FRAME_EXTENTS", False); |
541 | 54 | atom::_NET_WM_VISIBLE_NAME = XInternAtom(dpy, "_NET_WM_VISIBLE_NAME", False); | 53 | atom::_NET_WM_VISIBLE_NAME = XInternAtom(dpy, "_NET_WM_VISIBLE_NAME", False); |
542 | 55 | screen->updateSupportedWmHints(); | ||
543 | 56 | 54 | ||
544 | 57 | auto rebuild_cb = sigc::mem_fun(this, &Impl::OnShadowOptionsChanged); | 55 | auto rebuild_cb = sigc::mem_fun(this, &Impl::OnShadowOptionsChanged); |
545 | 58 | manager_->active_shadow_color.changed.connect(sigc::hide(sigc::bind(rebuild_cb, true))); | 56 | manager_->active_shadow_color.changed.connect(sigc::hide(sigc::bind(rebuild_cb, true))); |
546 | @@ -205,8 +203,6 @@ | |||
547 | 205 | 203 | ||
548 | 206 | bool Manager::Impl::HandleEventBefore(XEvent* event) | 204 | bool Manager::Impl::HandleEventBefore(XEvent* event) |
549 | 207 | { | 205 | { |
550 | 208 | active_window_ = screen->activeWindow(); | ||
551 | 209 | |||
552 | 210 | switch (event->type) | 206 | switch (event->type) |
553 | 211 | { | 207 | { |
554 | 212 | case ClientMessage: | 208 | case ClientMessage: |
555 | @@ -251,31 +247,26 @@ | |||
556 | 251 | 247 | ||
557 | 252 | bool Manager::Impl::HandleEventAfter(XEvent* event) | 248 | bool Manager::Impl::HandleEventAfter(XEvent* event) |
558 | 253 | { | 249 | { |
559 | 254 | if (screen->activeWindow() != active_window_) | ||
560 | 255 | { | ||
561 | 256 | // Do this when _NET_ACTIVE_WINDOW changes on root! | ||
562 | 257 | if (active_deco_win_) | ||
563 | 258 | active_deco_win_->impl_->active = false; | ||
564 | 259 | |||
565 | 260 | active_window_ = screen->activeWindow(); | ||
566 | 261 | auto const& new_active = GetWindowByXid(active_window_); | ||
567 | 262 | active_deco_win_ = new_active; | ||
568 | 263 | |||
569 | 264 | if (new_active) | ||
570 | 265 | new_active->impl_->active = true; | ||
571 | 266 | } | ||
572 | 267 | |||
573 | 268 | switch (event->type) | 250 | switch (event->type) |
574 | 269 | { | 251 | { |
575 | 270 | case PropertyNotify: | 252 | case PropertyNotify: |
576 | 271 | { | 253 | { |
578 | 272 | if (event->xproperty.atom == Atoms::mwmHints) | 254 | if (event->xproperty.atom == Atoms::winActive) |
579 | 255 | { | ||
580 | 256 | if (active_deco_win_) | ||
581 | 257 | active_deco_win_->impl_->active = false; | ||
582 | 258 | |||
583 | 259 | auto const& new_active = GetWindowByXid(screen->activeWindow()); | ||
584 | 260 | active_deco_win_ = new_active; | ||
585 | 261 | |||
586 | 262 | if (new_active) | ||
587 | 263 | new_active->impl_->active = true; | ||
588 | 264 | } | ||
589 | 265 | else if (event->xproperty.atom == Atoms::mwmHints || | ||
590 | 266 | event->xproperty.atom == Atoms::wmAllowedActions) | ||
591 | 273 | { | 267 | { |
592 | 274 | if (Window::Ptr const& win = GetWindowByXid(event->xproperty.window)) | 268 | if (Window::Ptr const& win = GetWindowByXid(event->xproperty.window)) |
597 | 275 | { | 269 | win->impl_->UpdateFrameActions(); |
594 | 276 | win->impl_->CleanupWindowControls(); | ||
595 | 277 | win->Update(); | ||
596 | 278 | } | ||
598 | 279 | } | 270 | } |
599 | 280 | else if (event->xproperty.atom == XA_WM_NAME || | 271 | else if (event->xproperty.atom == XA_WM_NAME || |
600 | 281 | event->xproperty.atom == Atoms::wmName || | 272 | event->xproperty.atom == Atoms::wmName || |
601 | @@ -442,7 +433,7 @@ | |||
602 | 442 | .add("active_shadow_radius", active_shadow_radius()) | 433 | .add("active_shadow_radius", active_shadow_radius()) |
603 | 443 | .add("inactive_shadow_color", inactive_shadow_color()) | 434 | .add("inactive_shadow_color", inactive_shadow_color()) |
604 | 444 | .add("inactive_shadow_radius", inactive_shadow_radius()) | 435 | .add("inactive_shadow_radius", inactive_shadow_radius()) |
606 | 445 | .add("active_window", impl_->active_window_); | 436 | .add("active_window", screen->activeWindow()); |
607 | 446 | } | 437 | } |
608 | 447 | 438 | ||
609 | 448 | debug::Introspectable::IntrospectableList Manager::GetIntrospectableChildren() | 439 | debug::Introspectable::IntrospectableList Manager::GetIntrospectableChildren() |
610 | 449 | 440 | ||
611 | === modified file 'decorations/DecorationsPriv.h' | |||
612 | --- decorations/DecorationsPriv.h 2014-04-02 09:05:59 +0000 | |||
613 | +++ decorations/DecorationsPriv.h 2014-10-10 14:56:03 +0000 | |||
614 | @@ -1,6 +1,6 @@ | |||
615 | 1 | // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- | 1 | // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- |
616 | 2 | /* | 2 | /* |
618 | 3 | * Copyright (C) 2013 Canonical Ltd | 3 | * Copyright (C) 2013-2014 Canonical Ltd |
619 | 4 | * | 4 | * |
620 | 5 | * This program is free software: you can redistribute it and/or modify | 5 | * This program is free software: you can redistribute it and/or modify |
621 | 6 | * it under the terms of the GNU General Public License version 3 as | 6 | * it under the terms of the GNU General Public License version 3 as |
622 | @@ -92,11 +92,15 @@ | |||
623 | 92 | private: | 92 | private: |
624 | 93 | void UnsetExtents(); | 93 | void UnsetExtents(); |
625 | 94 | void SetupExtents(); | 94 | void SetupExtents(); |
626 | 95 | void UpdateElements(); | ||
627 | 95 | void UpdateMonitor(); | 96 | void UpdateMonitor(); |
628 | 96 | void UpdateFrame(); | 97 | void UpdateFrame(); |
629 | 97 | void CreateFrame(nux::Geometry const&); | 98 | void CreateFrame(nux::Geometry const&); |
630 | 98 | void UpdateFrameGeo(nux::Geometry const&); | 99 | void UpdateFrameGeo(nux::Geometry const&); |
631 | 100 | void UpdateFrameActions(); | ||
632 | 99 | void UnsetFrame(); | 101 | void UnsetFrame(); |
633 | 102 | void SetupWindowEdges(); | ||
634 | 103 | void CleanupWindowEdges(); | ||
635 | 100 | void SetupWindowControls(); | 104 | void SetupWindowControls(); |
636 | 101 | void CleanupWindowControls(); | 105 | void CleanupWindowControls(); |
637 | 102 | void UnsetAppMenu(); | 106 | void UnsetAppMenu(); |
638 | @@ -109,6 +113,7 @@ | |||
639 | 109 | 113 | ||
640 | 110 | void ComputeShadowQuads(); | 114 | void ComputeShadowQuads(); |
641 | 111 | void UpdateDecorationTextures(); | 115 | void UpdateDecorationTextures(); |
642 | 116 | void UpdateWindowEdgesGeo(); | ||
643 | 112 | void UpdateForceQuitDialogPosition(); | 117 | void UpdateForceQuitDialogPosition(); |
644 | 113 | void RenderDecorationTexture(Side, nux::Geometry const&); | 118 | void RenderDecorationTexture(Side, nux::Geometry const&); |
645 | 114 | void Paint(GLMatrix const&, GLWindowPaintAttrib const&, CompRegion const&, unsigned mask); | 119 | void Paint(GLMatrix const&, GLWindowPaintAttrib const&, CompRegion const&, unsigned mask); |
646 | @@ -122,8 +127,12 @@ | |||
647 | 122 | ::CompositeWindow* cwin_; | 127 | ::CompositeWindow* cwin_; |
648 | 123 | ::GLWindow* glwin_; | 128 | ::GLWindow* glwin_; |
649 | 124 | ::Window frame_; | 129 | ::Window frame_; |
650 | 130 | int monitor_; | ||
651 | 125 | bool dirty_geo_; | 131 | bool dirty_geo_; |
653 | 126 | int monitor_; | 132 | bool dirty_frame_; |
654 | 133 | unsigned deco_elements_; | ||
655 | 134 | unsigned last_mwm_decor_; | ||
656 | 135 | unsigned last_actions_; | ||
657 | 127 | 136 | ||
658 | 128 | CompRect last_shadow_rect_; | 137 | CompRect last_shadow_rect_; |
659 | 129 | Quads shadow_quads_; | 138 | Quads shadow_quads_; |
660 | @@ -176,7 +185,6 @@ | |||
661 | 176 | friend class Manager; | 185 | friend class Manager; |
662 | 177 | friend struct Window::Impl; | 186 | friend struct Window::Impl; |
663 | 178 | 187 | ||
664 | 179 | ::Window active_window_; | ||
665 | 180 | bool enable_add_supported_atoms_; | 188 | bool enable_add_supported_atoms_; |
666 | 181 | 189 | ||
667 | 182 | DataPool::Ptr data_pool_; | 190 | DataPool::Ptr data_pool_; |
668 | 183 | 191 | ||
669 | === modified file 'decorations/DecorationsTitle.cpp' | |||
670 | --- decorations/DecorationsTitle.cpp 2014-03-31 18:36:07 +0000 | |||
671 | +++ decorations/DecorationsTitle.cpp 2014-10-10 14:56:03 +0000 | |||
672 | @@ -80,6 +80,7 @@ | |||
673 | 80 | 80 | ||
674 | 81 | Style::Get()->DrawTitle(text(), state, text_ctx, texture_size_.width / scale(), texture_size_.height / scale(), bg_geo * (1.0/scale)); | 81 | Style::Get()->DrawTitle(text(), state, text_ctx, texture_size_.width / scale(), texture_size_.height / scale(), bg_geo * (1.0/scale)); |
675 | 82 | SetTexture(text_ctx); | 82 | SetTexture(text_ctx); |
676 | 83 | texture_.UpdateMatrix(); | ||
677 | 83 | } | 84 | } |
678 | 84 | 85 | ||
679 | 85 | void Title::SetX(int x) | 86 | void Title::SetX(int x) |
680 | 86 | 87 | ||
681 | === modified file 'decorations/DecorationsWidgets.cpp' | |||
682 | --- decorations/DecorationsWidgets.cpp 2014-02-27 07:10:31 +0000 | |||
683 | +++ decorations/DecorationsWidgets.cpp 2014-10-10 14:56:03 +0000 | |||
684 | @@ -226,6 +226,12 @@ | |||
685 | 226 | 226 | ||
686 | 227 | // | 227 | // |
687 | 228 | 228 | ||
688 | 229 | TexturedItem::TexturedItem() | ||
689 | 230 | : dirty_region_(false) | ||
690 | 231 | { | ||
691 | 232 | geo_parameters_changed.connect([this] { dirty_region_ = true; }); | ||
692 | 233 | } | ||
693 | 234 | |||
694 | 229 | void TexturedItem::SetTexture(cu::SimpleTexture::Ptr const& tex) | 235 | void TexturedItem::SetTexture(cu::SimpleTexture::Ptr const& tex) |
695 | 230 | { | 236 | { |
696 | 231 | auto prev_geo = Geometry(); | 237 | auto prev_geo = Geometry(); |
697 | @@ -254,8 +260,14 @@ | |||
698 | 254 | if (!visible || Geometry().isEmpty() || !texture_) | 260 | if (!visible || Geometry().isEmpty() || !texture_) |
699 | 255 | return; | 261 | return; |
700 | 256 | 262 | ||
701 | 263 | if (dirty_region_) | ||
702 | 264 | { | ||
703 | 265 | texture_.quad.region = texture_.quad.box; | ||
704 | 266 | dirty_region_ = false; | ||
705 | 267 | } | ||
706 | 268 | |||
707 | 257 | ctx->vertexBuffer()->begin(); | 269 | ctx->vertexBuffer()->begin(); |
709 | 258 | ctx->glAddGeometry({texture_.quad.matrix}, texture_.quad.box, clip); | 270 | ctx->glAddGeometry(texture_.quad.matrices, texture_.quad.region, clip); |
710 | 259 | 271 | ||
711 | 260 | if (ctx->vertexBuffer()->end()) | 272 | if (ctx->vertexBuffer()->end()) |
712 | 261 | ctx->glDrawTexture(texture_, transformation, attrib, mask); | 273 | ctx->glDrawTexture(texture_, transformation, attrib, mask); |
713 | 262 | 274 | ||
714 | === modified file 'decorations/DecorationsWidgets.h' | |||
715 | --- decorations/DecorationsWidgets.h 2014-02-27 07:10:31 +0000 | |||
716 | +++ decorations/DecorationsWidgets.h 2014-10-10 14:56:03 +0000 | |||
717 | @@ -121,6 +121,8 @@ | |||
718 | 121 | public: | 121 | public: |
719 | 122 | typedef std::shared_ptr<TexturedItem> Ptr; | 122 | typedef std::shared_ptr<TexturedItem> Ptr; |
720 | 123 | 123 | ||
721 | 124 | TexturedItem(); | ||
722 | 125 | |||
723 | 124 | void SetTexture(cu::SimpleTexture::Ptr const&); | 126 | void SetTexture(cu::SimpleTexture::Ptr const&); |
724 | 125 | void Draw(GLWindow*, GLMatrix const&, GLWindowPaintAttrib const&, CompRegion const&, unsigned mask); | 127 | void Draw(GLWindow*, GLMatrix const&, GLWindowPaintAttrib const&, CompRegion const&, unsigned mask); |
725 | 126 | void SetCoords(int x, int y); | 128 | void SetCoords(int x, int y); |
726 | @@ -133,6 +135,9 @@ | |||
727 | 133 | 135 | ||
728 | 134 | CompRect& InternalGeo(); | 136 | CompRect& InternalGeo(); |
729 | 135 | cu::SimpleTextureQuad texture_; | 137 | cu::SimpleTextureQuad texture_; |
730 | 138 | |||
731 | 139 | private: | ||
732 | 140 | bool dirty_region_; | ||
733 | 136 | }; | 141 | }; |
734 | 137 | 142 | ||
735 | 138 | 143 | ||
736 | 139 | 144 | ||
737 | === modified file 'plugins/unityshell/src/unityshell.cpp' | |||
738 | --- plugins/unityshell/src/unityshell.cpp 2014-09-04 22:12:01 +0000 | |||
739 | +++ plugins/unityshell/src/unityshell.cpp 2014-10-10 14:56:03 +0000 | |||
740 | @@ -281,6 +281,7 @@ | |||
741 | 281 | CompositeScreenInterface::setHandler(cScreen); | 281 | CompositeScreenInterface::setHandler(cScreen); |
742 | 282 | GLScreenInterface::setHandler(gScreen); | 282 | GLScreenInterface::setHandler(gScreen); |
743 | 283 | ScaleScreenInterface::setHandler(sScreen); | 283 | ScaleScreenInterface::setHandler(sScreen); |
744 | 284 | screen->updateSupportedWmHints(); | ||
745 | 284 | 285 | ||
746 | 285 | PluginAdapter::Initialize(screen); | 286 | PluginAdapter::Initialize(screen); |
747 | 286 | AddChild(&WindowManager::Default()); | 287 | AddChild(&WindowManager::Default()); |
748 | 287 | 288 | ||
749 | === modified file 'unity-shared/CompizUtils.cpp' | |||
750 | --- unity-shared/CompizUtils.cpp 2014-04-14 13:51:58 +0000 | |||
751 | +++ unity-shared/CompizUtils.cpp 2014-10-10 14:56:03 +0000 | |||
752 | @@ -1,6 +1,6 @@ | |||
753 | 1 | // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- | 1 | // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- |
754 | 2 | /* | 2 | /* |
756 | 3 | * Copyright (C) 2013 Canonical Ltd | 3 | * Copyright (C) 2013-2014 Canonical Ltd |
757 | 4 | * | 4 | * |
758 | 5 | * This program is free software: you can redistribute it and/or modify | 5 | * This program is free software: you can redistribute it and/or modify |
759 | 6 | * it under the terms of the GNU General Public License version 3 as | 6 | * it under the terms of the GNU General Public License version 3 as |
760 | @@ -30,6 +30,11 @@ | |||
761 | 30 | { | 30 | { |
762 | 31 | const unsigned PIXMAP_DEPTH = 32; | 31 | const unsigned PIXMAP_DEPTH = 32; |
763 | 32 | const float DEFAULT_SCALE = 1.0f; | 32 | const float DEFAULT_SCALE = 1.0f; |
764 | 33 | const unsigned DECORABLE_WINDOW_TYPES = CompWindowTypeDialogMask | | ||
765 | 34 | CompWindowTypeModalDialogMask | | ||
766 | 35 | CompWindowTypeUtilMask | | ||
767 | 36 | CompWindowTypeMenuMask | | ||
768 | 37 | CompWindowTypeNormalMask; | ||
769 | 33 | } | 38 | } |
770 | 34 | 39 | ||
771 | 35 | SimpleTexture::SimpleTexture(GLTexture::List const& tex) | 40 | SimpleTexture::SimpleTexture(GLTexture::List const& tex) |
772 | @@ -39,7 +44,7 @@ | |||
773 | 39 | // | 44 | // |
774 | 40 | 45 | ||
775 | 41 | SimpleTextureQuad::SimpleTextureQuad() | 46 | SimpleTextureQuad::SimpleTextureQuad() |
777 | 42 | : scale(DEFAULT_SCALE) | 47 | : scale_(DEFAULT_SCALE) |
778 | 43 | {} | 48 | {} |
779 | 44 | 49 | ||
780 | 45 | bool SimpleTextureQuad::SetTexture(SimpleTexture::Ptr const& simple_texture) | 50 | bool SimpleTextureQuad::SetTexture(SimpleTexture::Ptr const& simple_texture) |
781 | @@ -52,24 +57,27 @@ | |||
782 | 52 | if (st && st->texture()) | 57 | if (st && st->texture()) |
783 | 53 | { | 58 | { |
784 | 54 | auto* tex = st->texture(); | 59 | auto* tex = st->texture(); |
789 | 55 | CompPoint old_coords(quad.box.x(), quad.box.y()); | 60 | CompSize size(tex->width() * scale_, tex->height() * scale_); |
790 | 56 | short invalid = std::numeric_limits<short>::min(); | 61 | |
791 | 57 | quad.box.setGeometry(invalid, invalid, tex->width() * scale, tex->height() * scale); | 62 | if (quad.box.width() != size.width() || quad.box.height() != size.height()) |
792 | 58 | SetCoords(old_coords.x(), old_coords.y()); | 63 | { |
793 | 64 | quad.box.setSize(size); | ||
794 | 65 | UpdateMatrix(); | ||
795 | 66 | } | ||
796 | 59 | } | 67 | } |
797 | 60 | 68 | ||
798 | 61 | return true; | 69 | return true; |
799 | 62 | } | 70 | } |
800 | 63 | 71 | ||
802 | 64 | bool SimpleTextureQuad::SetScale(float s) | 72 | bool SimpleTextureQuad::SetScale(double s) |
803 | 65 | { | 73 | { |
805 | 66 | if (!st || scale == s) | 74 | if (!st || scale_ == s) |
806 | 67 | return false; | 75 | return false; |
807 | 68 | 76 | ||
809 | 69 | scale = s; | 77 | scale_ = s; |
810 | 70 | auto* tex = st->texture(); | 78 | auto* tex = st->texture(); |
813 | 71 | quad.box.setWidth(tex->width() * scale); | 79 | quad.box.setWidth(tex->width() * scale_); |
814 | 72 | quad.box.setHeight(tex->height() * scale); | 80 | quad.box.setHeight(tex->height() * scale_); |
815 | 73 | UpdateMatrix(); | 81 | UpdateMatrix(); |
816 | 74 | return true; | 82 | return true; |
817 | 75 | } | 83 | } |
818 | @@ -91,8 +99,8 @@ | |||
819 | 91 | int y = quad.box.y(); | 99 | int y = quad.box.y(); |
820 | 92 | 100 | ||
821 | 93 | quad.matrix = (st && st->texture()) ? st->texture()->matrix() : GLTexture::Matrix(); | 101 | quad.matrix = (st && st->texture()) ? st->texture()->matrix() : GLTexture::Matrix(); |
824 | 94 | quad.matrix.xx /= scale; | 102 | quad.matrix.xx /= scale_; |
825 | 95 | quad.matrix.yy /= scale; | 103 | quad.matrix.yy /= scale_; |
826 | 96 | quad.matrix.x0 = 0.0f - COMP_TEX_COORD_X(quad.matrix, x); | 104 | quad.matrix.x0 = 0.0f - COMP_TEX_COORD_X(quad.matrix, x); |
827 | 97 | quad.matrix.y0 = 0.0f - COMP_TEX_COORD_Y(quad.matrix, y); | 105 | quad.matrix.y0 = 0.0f - COMP_TEX_COORD_Y(quad.matrix, y); |
828 | 98 | } | 106 | } |
829 | @@ -166,57 +174,68 @@ | |||
830 | 166 | return cairo_xlib_surface_get_height(surface_); | 174 | return cairo_xlib_surface_get_height(surface_); |
831 | 167 | } | 175 | } |
832 | 168 | 176 | ||
834 | 169 | bool IsWindowShadowDecorable(CompWindow* win) | 177 | // |
835 | 178 | // | ||
836 | 179 | |||
837 | 180 | unsigned WindowDecorationElements(CompWindow* win) | ||
838 | 170 | { | 181 | { |
839 | 182 | unsigned elements = DecorationElement::NONE; | ||
840 | 183 | |||
841 | 171 | if (!win) | 184 | if (!win) |
843 | 172 | return false; | 185 | return elements; |
844 | 173 | 186 | ||
845 | 174 | if (!win->isViewable()) | 187 | if (!win->isViewable()) |
847 | 175 | return false; | 188 | return elements; |
848 | 176 | 189 | ||
849 | 177 | if (win->wmType() & (CompWindowTypeDockMask | CompWindowTypeDesktopMask)) | 190 | if (win->wmType() & (CompWindowTypeDockMask | CompWindowTypeDesktopMask)) |
859 | 178 | return false; | 191 | return elements; |
860 | 179 | 192 | ||
861 | 180 | if (win->region().numRects() != 1) // Non rectangular windows | 193 | if (win->inShowDesktopMode()) |
862 | 181 | return false; | 194 | return elements; |
863 | 182 | 195 | ||
864 | 183 | if (win->alpha()) | 196 | auto const& region = win->region(); |
865 | 184 | return WindowHasMotifDecorations(win); | 197 | bool rectangular = (region.numRects() == 1); |
866 | 185 | 198 | bool alpha = win->alpha(); | |
867 | 186 | return true; | 199 | |
868 | 200 | if (!rectangular && alpha) // Non-rectangular windows with alpha channel | ||
869 | 201 | return elements; | ||
870 | 202 | |||
871 | 203 | if (region.boundingRect() != win->geometry()) // Shaped windows | ||
872 | 204 | return elements; | ||
873 | 205 | |||
874 | 206 | if (rectangular) | ||
875 | 207 | elements |= DecorationElement::SHADOW; | ||
876 | 208 | |||
877 | 209 | if (!win->overrideRedirect() && | ||
878 | 210 | (win->type() & DECORABLE_WINDOW_TYPES) && | ||
879 | 211 | (win->frame() || win->hasUnmapReference())) | ||
880 | 212 | { | ||
881 | 213 | if (win->actions() & CompWindowActionResizeMask) | ||
882 | 214 | elements |= DecorationElement::EDGE; | ||
883 | 215 | |||
884 | 216 | if (rectangular && (win->mwmDecor() & (MwmDecorAll | MwmDecorTitle))) | ||
885 | 217 | elements |= DecorationElement::BORDER; | ||
886 | 218 | } | ||
887 | 219 | |||
888 | 220 | if (alpha && !(elements & DecorationElement::BORDER) && !(win->mwmDecor() & MwmDecorBorder)) | ||
889 | 221 | elements &= ~DecorationElement::SHADOW; | ||
890 | 222 | |||
891 | 223 | return elements; | ||
892 | 224 | } | ||
893 | 225 | |||
894 | 226 | bool IsWindowEdgeDecorable(CompWindow* win) | ||
895 | 227 | { | ||
896 | 228 | return WindowDecorationElements(win) & DecorationElement::EDGE; | ||
897 | 229 | } | ||
898 | 230 | |||
899 | 231 | bool IsWindowShadowDecorable(CompWindow* win) | ||
900 | 232 | { | ||
901 | 233 | return WindowDecorationElements(win) & DecorationElement::SHADOW; | ||
902 | 187 | } | 234 | } |
903 | 188 | 235 | ||
904 | 189 | bool IsWindowFullyDecorable(CompWindow* win) | 236 | bool IsWindowFullyDecorable(CompWindow* win) |
905 | 190 | { | 237 | { |
935 | 191 | if (!win) | 238 | return WindowDecorationElements(win) & DecorationElement::BORDER; |
907 | 192 | return false; | ||
908 | 193 | |||
909 | 194 | if (!IsWindowShadowDecorable(win)) | ||
910 | 195 | return false; | ||
911 | 196 | |||
912 | 197 | return WindowHasMotifDecorations(win); | ||
913 | 198 | } | ||
914 | 199 | |||
915 | 200 | bool WindowHasMotifDecorations(CompWindow* win) | ||
916 | 201 | { | ||
917 | 202 | if (!win) | ||
918 | 203 | return false; | ||
919 | 204 | |||
920 | 205 | if (win->overrideRedirect()) | ||
921 | 206 | return false; | ||
922 | 207 | |||
923 | 208 | switch (win->type()) | ||
924 | 209 | { | ||
925 | 210 | case CompWindowTypeDialogMask: | ||
926 | 211 | case CompWindowTypeModalDialogMask: | ||
927 | 212 | case CompWindowTypeUtilMask: | ||
928 | 213 | case CompWindowTypeMenuMask: | ||
929 | 214 | case CompWindowTypeNormalMask: | ||
930 | 215 | if (win->mwmDecor() & (MwmDecorAll | MwmDecorTitle)) | ||
931 | 216 | return true; | ||
932 | 217 | } | ||
933 | 218 | |||
934 | 219 | return false; | ||
936 | 220 | } | 239 | } |
937 | 221 | 240 | ||
938 | 222 | } // compiz_utils namespace | 241 | } // compiz_utils namespace |
939 | 223 | 242 | ||
940 | === modified file 'unity-shared/CompizUtils.h' | |||
941 | --- unity-shared/CompizUtils.h 2014-04-14 13:51:58 +0000 | |||
942 | +++ unity-shared/CompizUtils.h 2014-10-10 14:56:03 +0000 | |||
943 | @@ -31,8 +31,15 @@ | |||
944 | 31 | 31 | ||
945 | 32 | struct TextureQuad | 32 | struct TextureQuad |
946 | 33 | { | 33 | { |
947 | 34 | TextureQuad() | ||
948 | 35 | : matrices(1) | ||
949 | 36 | , matrix(matrices[0]) | ||
950 | 37 | {} | ||
951 | 38 | |||
952 | 34 | CompRect box; | 39 | CompRect box; |
954 | 35 | GLTexture::Matrix matrix; | 40 | CompRegion region; |
955 | 41 | GLTexture::MatrixList matrices; | ||
956 | 42 | GLTexture::Matrix& matrix; | ||
957 | 36 | }; | 43 | }; |
958 | 37 | 44 | ||
959 | 38 | struct SimpleTexture | 45 | struct SimpleTexture |
960 | @@ -59,11 +66,13 @@ | |||
961 | 59 | { | 66 | { |
962 | 60 | SimpleTextureQuad(); | 67 | SimpleTextureQuad(); |
963 | 61 | bool SetTexture(SimpleTexture::Ptr const&); | 68 | bool SetTexture(SimpleTexture::Ptr const&); |
965 | 62 | bool SetScale(float scale); | 69 | bool SetScale(double scale); |
966 | 63 | bool SetCoords(int x, int y); | 70 | bool SetCoords(int x, int y); |
967 | 64 | bool SetX(int x); | 71 | bool SetX(int x); |
968 | 65 | bool SetY(int y); | 72 | bool SetY(int y); |
969 | 66 | 73 | ||
970 | 74 | void UpdateMatrix(); | ||
971 | 75 | |||
972 | 67 | operator SimpleTexture::Ptr() const { return st; } | 76 | operator SimpleTexture::Ptr() const { return st; } |
973 | 68 | operator bool() const { return st && st->texture(); } | 77 | operator bool() const { return st && st->texture(); } |
974 | 69 | operator GLTexture*() const { return st ? st->texture() : nullptr; } | 78 | operator GLTexture*() const { return st ? st->texture() : nullptr; } |
975 | @@ -73,8 +82,7 @@ | |||
976 | 73 | TextureQuad quad; | 82 | TextureQuad quad; |
977 | 74 | 83 | ||
978 | 75 | private: | 84 | private: |
981 | 76 | void UpdateMatrix(); | 85 | double scale_; |
980 | 77 | float scale; | ||
982 | 78 | }; | 86 | }; |
983 | 79 | 87 | ||
984 | 80 | struct PixmapTexture : SimpleTexture | 88 | struct PixmapTexture : SimpleTexture |
985 | @@ -111,9 +119,20 @@ | |||
986 | 111 | cairo_t *cr_; | 119 | cairo_t *cr_; |
987 | 112 | }; | 120 | }; |
988 | 113 | 121 | ||
989 | 122 | enum DecorationElement | ||
990 | 123 | { | ||
991 | 124 | NONE = 0, | ||
992 | 125 | EDGE = (1 << 0), | ||
993 | 126 | SHADOW = (1 << 1), | ||
994 | 127 | BORDER = (1 << 2), | ||
995 | 128 | FULL = EDGE|SHADOW|BORDER | ||
996 | 129 | }; | ||
997 | 130 | |||
998 | 131 | unsigned WindowDecorationElements(CompWindow*); | ||
999 | 132 | |||
1000 | 133 | bool IsWindowEdgeDecorable(CompWindow*); | ||
1001 | 114 | bool IsWindowShadowDecorable(CompWindow*); | 134 | bool IsWindowShadowDecorable(CompWindow*); |
1002 | 115 | bool IsWindowFullyDecorable(CompWindow*); | 135 | bool IsWindowFullyDecorable(CompWindow*); |
1003 | 116 | bool WindowHasMotifDecorations(CompWindow*); | ||
1004 | 117 | 136 | ||
1005 | 118 | } // compiz_utils namespace | 137 | } // compiz_utils namespace |
1006 | 119 | } // unity namespace | 138 | } // unity namespace |
1007 | 120 | 139 | ||
1008 | === modified file 'unity-shared/XWindowManager.cpp' | |||
1009 | --- unity-shared/XWindowManager.cpp 2014-02-14 03:05:02 +0000 | |||
1010 | +++ unity-shared/XWindowManager.cpp 2014-10-10 14:56:03 +0000 | |||
1011 | @@ -83,7 +83,7 @@ | |||
1012 | 83 | { | 83 | { |
1013 | 84 | LOG_ERROR(logger) << "Impossible to get the property " << gdk_x11_get_xatom_name(atom) | 84 | LOG_ERROR(logger) << "Impossible to get the property " << gdk_x11_get_xatom_name(atom) |
1014 | 85 | << " for window " << window_id << ": invalid string type: " | 85 | << " for window " << window_id << ": invalid string type: " |
1016 | 86 | << gdk_x11_get_xatom_name(Atoms::utf8String); | 86 | << gdk_x11_get_xatom_name(type); |
1017 | 87 | return std::string(); | 87 | return std::string(); |
1018 | 88 | } | 88 | } |
1019 | 89 | 89 |
PASSED: Continuous integration, rev:3835 jenkins. qa.ubuntu. com/job/ unity-ci/ 1088/ jenkins. qa.ubuntu. com/job/ unity-utopic- amd64-ci/ 175 jenkins. qa.ubuntu. com/job/ unity-utopic- armhf-ci/ 175 jenkins. qa.ubuntu. com/job/ unity-utopic- i386-ci/ 175
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/unity- ci/1088/ rebuild
http://