Merge lp:~3v1n0/unity/scale-close-middle-click-6.0 into lp:unity/6.0
- scale-close-middle-click-6.0
- Merge into 6.0
Proposed by
Marco Trevisan (Treviño)
Status: | Merged |
---|---|
Approved by: | Brandon Schaefer |
Approved revision: | no longer in the source branch. |
Merged at revision: | 2737 |
Proposed branch: | lp:~3v1n0/unity/scale-close-middle-click-6.0 |
Merge into: | lp:unity/6.0 |
Diff against target: |
1018 lines (+472/-175) 6 files modified
plugins/unityshell/src/ScreenIntrospection.h (+48/-0) plugins/unityshell/src/unityshell.cpp (+223/-156) plugins/unityshell/src/unityshell.h (+23/-19) tests/autopilot/unity/emulators/screen.py (+42/-0) tests/autopilot/unity/tests/__init__.py (+12/-0) tests/autopilot/unity/tests/test_spread.py (+124/-0) |
To merge this branch: | bzr merge lp:~3v1n0/unity/scale-close-middle-click-6.0 |
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Brandon Schaefer (community) | Approve | ||
Review via email: mp+126077@code.launchpad.net |
Commit message
UnityShell: enable closing on middle-click, fix scaled decoration sizes, fix theming issues, added scale autopilot tests
Description of the change
Backporting branch lp:~3v1n0/unity/scale-close-middle-click/+merge/126044
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added file 'plugins/unityshell/src/ScreenIntrospection.h' |
2 | --- plugins/unityshell/src/ScreenIntrospection.h 1970-01-01 00:00:00 +0000 |
3 | +++ plugins/unityshell/src/ScreenIntrospection.h 2012-09-24 19:39:25 +0000 |
4 | @@ -0,0 +1,48 @@ |
5 | +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- |
6 | +/* |
7 | + * Copyright (C) 2012 Canonical Ltd |
8 | + * |
9 | + * This program is free software: you can redistribute it and/or modify |
10 | + * it under the terms of the GNU General Public License version 3 as |
11 | + * published by the Free Software Foundation. |
12 | + * |
13 | + * This program is distributed in the hope that it will be useful, |
14 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | + * GNU General Public License for more details. |
17 | + * |
18 | + * You should have received a copy of the GNU General Public License |
19 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
20 | + * |
21 | + * Authored by: Marco Trevisan (Treviño) <marco.trevisan@canonical.com> |
22 | + */ |
23 | + |
24 | +#ifndef SCREEN_INTROSPECTION_H |
25 | +#define SCREEN_INTROSPECTION_H |
26 | + |
27 | +#include "Introspectable.h" |
28 | +#include <core/core.h> |
29 | + |
30 | +namespace unity |
31 | +{ |
32 | +namespace debug |
33 | +{ |
34 | + |
35 | +class ScreenIntrospection : public Introspectable |
36 | +{ |
37 | +public: |
38 | + ScreenIntrospection(CompScreen* screen); |
39 | + |
40 | +protected: |
41 | + std::string GetName() const; |
42 | + void AddProperties(GVariantBuilder* builder); |
43 | + IntrospectableList GetIntrospectableChildren(); |
44 | + |
45 | +private: |
46 | + CompScreen* screen_; |
47 | +}; |
48 | + |
49 | +} |
50 | +} |
51 | + |
52 | +#endif |
53 | |
54 | === modified file 'plugins/unityshell/src/unityshell.cpp' |
55 | --- plugins/unityshell/src/unityshell.cpp 2012-09-19 13:58:01 +0000 |
56 | +++ plugins/unityshell/src/unityshell.cpp 2012-09-24 19:39:25 +0000 |
57 | @@ -26,6 +26,8 @@ |
58 | #include <Nux/WindowCompositor.h> |
59 | #include <Nux/NuxTimerTickSource.h> |
60 | |
61 | +#include <UnityCore/Variant.h> |
62 | + |
63 | #include "BaseWindowRaiserImp.h" |
64 | #include "IconRenderer.h" |
65 | #include "Launcher.h" |
66 | @@ -125,7 +127,6 @@ |
67 | , allowWindowPaint(false) |
68 | , _key_nav_mode_requested(false) |
69 | , _last_output(nullptr) |
70 | - , _bghash(NULL) |
71 | , grab_index_ (0) |
72 | , painting_tray_ (false) |
73 | , last_scroll_event_(0) |
74 | @@ -133,7 +134,7 @@ |
75 | , panel_texture_has_changed_(true) |
76 | , paint_panel_(false) |
77 | , scale_just_activated_(false) |
78 | - , minimize_speed_controller(new WindowMinimizeSpeedController()) |
79 | + , screen_introspection_(screen) |
80 | { |
81 | Timer timer; |
82 | #ifndef USE_GLES |
83 | @@ -244,7 +245,7 @@ |
84 | // _bghash is a pointer. We don't want it to be created before Nux system has had a chance |
85 | // to start. BGHash relies on animations. Nux animation system starts after the WindowThread |
86 | // has been created. |
87 | - _bghash = new BGHash(); |
88 | + _bghash.reset(new BGHash()); |
89 | |
90 | unity_a11y_init(wt.get()); |
91 | |
92 | @@ -375,13 +376,15 @@ |
93 | Display* display = gdk_x11_display_get_xdisplay(gdk_display_get_default());; |
94 | XSelectInput(display, GDK_ROOT_WINDOW(), PropertyChangeMask); |
95 | LOG_INFO(logger) << "UnityScreen constructed: " << timer.ElapsedSeconds() << "s"; |
96 | + |
97 | + panel::Style::Instance().changed.connect(sigc::mem_fun(this, &UnityScreen::OnPanelStyleChanged)); |
98 | + |
99 | + minimize_speed_controller_.DurationChanged.connect( |
100 | + sigc::mem_fun(this, &UnityScreen::OnMinimizeDurationChanged) |
101 | + ); |
102 | + |
103 | + AddChild(&screen_introspection_); |
104 | } |
105 | - |
106 | - panel::Style::Instance().changed.connect(sigc::mem_fun(this, &UnityScreen::OnPanelStyleChanged)); |
107 | - |
108 | - minimize_speed_controller->DurationChanged.connect( |
109 | - sigc::mem_fun(this, &UnityScreen::OnMinimizeDurationChanged) |
110 | - ); |
111 | } |
112 | |
113 | UnityScreen::~UnityScreen() |
114 | @@ -391,7 +394,6 @@ |
115 | unity_a11y_finalize(); |
116 | ::unity::ui::IconRenderer::DestroyTextures(); |
117 | QuicklistManager::Destroy(); |
118 | - delete _bghash; |
119 | |
120 | reset_glib_logging(); |
121 | } |
122 | @@ -659,10 +661,15 @@ |
123 | wy = y + (last_bound.height - height) / 2; |
124 | } |
125 | |
126 | -void |
127 | -UnityScreen::OnPanelStyleChanged() |
128 | +void UnityScreen::OnPanelStyleChanged() |
129 | { |
130 | panel_texture_has_changed_ = true; |
131 | + |
132 | + // Reload the windows themed textures |
133 | + UnityWindow::CleanupSharedTextures(); |
134 | + |
135 | + if (WindowManager::Default()->IsScaleActive()) |
136 | + UnityWindow::SetupSharedTextures(); |
137 | } |
138 | |
139 | void UnityScreen::paintDisplay() |
140 | @@ -1136,6 +1143,12 @@ |
141 | DoAddDamage(); |
142 | handled = true; |
143 | } |
144 | + else if (event->xbutton.button == Button2 && |
145 | + GetScaledGeometry().IsPointInside(event->xbutton.x_root, event->xbutton.y_root)) |
146 | + { |
147 | + middle_clicked_ = true; |
148 | + handled = true; |
149 | + } |
150 | break; |
151 | |
152 | case ButtonRelease: |
153 | @@ -1155,6 +1168,18 @@ |
154 | |
155 | handled = true; |
156 | } |
157 | + |
158 | + if (middle_clicked_) |
159 | + { |
160 | + if (event->xbutton.button == Button2 && |
161 | + GetScaledGeometry().IsPointInside(event->xbutton.x_root, event->xbutton.y_root)) |
162 | + { |
163 | + window->close(0); |
164 | + } |
165 | + |
166 | + middle_clicked_ = false; |
167 | + handled = true; |
168 | + } |
169 | } |
170 | break; |
171 | |
172 | @@ -2277,8 +2302,7 @@ |
173 | } |
174 | |
175 | void UnityScreen::AddProperties(GVariantBuilder* builder) |
176 | -{ |
177 | -} |
178 | +{} |
179 | |
180 | std::string UnityScreen::GetName() const |
181 | { |
182 | @@ -2469,10 +2493,10 @@ |
183 | CompOption::Value& value = o.value(); |
184 | CompOption::Value::Vector& list = value.list(); |
185 | CompOption::Value::Vector::iterator i = list.begin(); |
186 | - if (i != list.end()) { |
187 | - i->set(minimize_speed_controller->getDuration()); |
188 | - } |
189 | - value.set(list); |
190 | + if (i != list.end()) |
191 | + i->set(minimize_speed_controller_.getDuration()); |
192 | + |
193 | + value.set(list); |
194 | screen->setOptionForPlugin(p->vTable->name().c_str(), |
195 | o.name().c_str(), value); |
196 | break; |
197 | @@ -2603,7 +2627,7 @@ |
198 | case CompWindowNotifyMinimize: |
199 | /* Updating the count in dconf will trigger a "changed" signal to which |
200 | * the method setting the new animation speed is attached */ |
201 | - UnityScreen::get(screen)->minimize_speed_controller->UpdateCount(); |
202 | + UnityScreen::get(screen)->minimize_speed_controller_.UpdateCount(); |
203 | break; |
204 | default: |
205 | break; |
206 | @@ -3458,107 +3482,117 @@ |
207 | WindowManager::Default()->terminate_spread.connect(sigc::mem_fun(this, &UnityWindow::OnTerminateSpreed)); |
208 | } |
209 | |
210 | -void |
211 | -UnityWindow::DrawTexture(GLTexture* icon, |
212 | - const GLWindowPaintAttrib& attrib, |
213 | - const GLMatrix& transform, |
214 | - unsigned int mask, |
215 | - float x, float y, |
216 | - int &maxWidth, int &maxHeight) |
217 | -{ |
218 | - if (icon) |
219 | +void UnityWindow::AddProperties(GVariantBuilder* builder) |
220 | +{ |
221 | + Window xid = window->id(); |
222 | + auto const& swins = ScaleScreen::get(screen)->getWindows(); |
223 | + bool scaled = std::find(swins.begin(), swins.end(), ScaleWindow::get(window)) != swins.end(); |
224 | + auto wm = WindowManager::Default(); |
225 | + |
226 | + variant::BuilderWrapper(builder) |
227 | + .add(scaled ? GetScaledGeometry() : wm->GetWindowGeometry(xid)) |
228 | + .add("xid", xid) |
229 | + .add("title", wm->GetWindowName(xid)) |
230 | + .add("scaled", scaled) |
231 | + .add("scaled_close_x", close_button_geo_.x) |
232 | + .add("scaled_close_y", close_button_geo_.y) |
233 | + .add("scaled_close_width", close_button_geo_.width) |
234 | + .add("scaled_close_height", close_button_geo_.height); |
235 | +} |
236 | + |
237 | +std::string UnityWindow::GetName() const |
238 | +{ |
239 | + return "Window"; |
240 | +} |
241 | + |
242 | +void UnityWindow::DrawTexture(GLTexture::List const& textures, GLWindowPaintAttrib const& attrib, |
243 | + GLMatrix const& transform, unsigned int mask, int x, int y) |
244 | +{ |
245 | + for (auto const& texture : textures) |
246 | { |
247 | - int width, height; |
248 | - width = icon->width(); |
249 | - height = icon->height(); |
250 | - |
251 | - if (height > maxHeight) |
252 | - maxHeight = height; |
253 | - |
254 | - if (width > maxWidth) |
255 | - maxWidth = width; |
256 | - |
257 | - CompRegion iconReg(0, 0, width, height); |
258 | - GLTexture::MatrixList ml(1); |
259 | - |
260 | - ml[0] = icon->matrix(); |
261 | + if (!texture) |
262 | + continue; |
263 | + |
264 | gWindow->vertexBuffer()->begin(); |
265 | - if (width && height) |
266 | - gWindow->glAddGeometry(ml, iconReg, iconReg); |
267 | + |
268 | + if (texture->width() && texture->height()) |
269 | + { |
270 | + GLTexture::MatrixList ml(1); |
271 | + ml[0] = texture->matrix(); |
272 | + CompRegion texture_region(0, 0, texture->width(), texture->height()); |
273 | + gWindow->glAddGeometry(ml, texture_region, texture_region); |
274 | + } |
275 | |
276 | if (gWindow->vertexBuffer()->end()) |
277 | { |
278 | GLMatrix wTransform(transform); |
279 | - |
280 | wTransform.translate(x, y, 0.0f); |
281 | |
282 | - gWindow->glDrawTexture(icon, wTransform, attrib, mask); |
283 | + gWindow->glDrawTexture(texture, wTransform, attrib, mask); |
284 | } |
285 | } |
286 | } |
287 | |
288 | -void |
289 | -UnityWindow::RenderText(UnityWindow::CairoContext const& context, |
290 | - float x, float y, |
291 | - float maxWidth, float maxHeight) |
292 | +void UnityWindow::RenderText(CairoContext const& context, int x, int y, int width, int height) |
293 | { |
294 | panel::Style& style = panel::Style::Instance(); |
295 | - std::string fontDescription(style.GetFontDescription(panel::PanelItem::TITLE)); |
296 | + std::string const& font_desc = style.GetFontDescription(panel::PanelItem::TITLE); |
297 | |
298 | glib::Object<PangoLayout> layout(pango_cairo_create_layout(context.cr_)); |
299 | - std::shared_ptr<PangoFontDescription> font(pango_font_description_from_string(fontDescription.c_str()), |
300 | + std::shared_ptr<PangoFontDescription> font(pango_font_description_from_string(font_desc.c_str()), |
301 | pango_font_description_free); |
302 | |
303 | pango_layout_set_font_description(layout, font.get()); |
304 | |
305 | - GdkScreen* gdkScreen = gdk_screen_get_default(); |
306 | - PangoContext* pCxt = pango_layout_get_context(layout); |
307 | + GdkScreen* gdk_screen = gdk_screen_get_default(); |
308 | + PangoContext* pango_ctx = pango_layout_get_context(layout); |
309 | int dpi = style.GetTextDPI(); |
310 | |
311 | - pango_cairo_context_set_font_options(pCxt, gdk_screen_get_font_options(gdkScreen)); |
312 | - pango_cairo_context_set_resolution(pCxt, dpi / static_cast<float>(PANGO_SCALE)); |
313 | + pango_cairo_context_set_font_options(pango_ctx, gdk_screen_get_font_options(gdk_screen)); |
314 | + pango_cairo_context_set_resolution(pango_ctx, dpi / static_cast<float>(PANGO_SCALE)); |
315 | pango_layout_context_changed(layout); |
316 | |
317 | - pango_layout_set_height(layout, maxHeight); |
318 | + std::string const& win_title = WindowManager::Default()->GetWindowName(window->id()); |
319 | + pango_layout_set_height(layout, height); |
320 | pango_layout_set_width(layout, -1); //avoid wrap lines |
321 | pango_layout_set_auto_dir(layout, false); |
322 | - pango_layout_set_text(layout, |
323 | - WindowManager::Default()->GetWindowName(window->id()).c_str(), |
324 | - -1); |
325 | + pango_layout_set_text(layout, win_title.c_str(), -1); |
326 | |
327 | /* update the size of the pango layout */ |
328 | pango_cairo_update_layout(context.cr_, layout); |
329 | - cairo_set_operator(context.cr_, CAIRO_OPERATOR_OVER); |
330 | - cairo_set_source_rgba(context.cr_, |
331 | - 1.0, |
332 | - 1.0, |
333 | - 1.0, |
334 | - 1.0); |
335 | + |
336 | + GtkStyleContext* style_context = style.GetStyleContext(); |
337 | + gtk_style_context_save(style_context); |
338 | + |
339 | + std::shared_ptr<GtkWidgetPath> widget_path(gtk_widget_path_new(), gtk_widget_path_free); |
340 | + gtk_widget_path_append_type(widget_path.get(), GTK_TYPE_MENU_BAR); |
341 | + gtk_widget_path_append_type(widget_path.get(), GTK_TYPE_MENU_ITEM); |
342 | + gtk_widget_path_iter_set_name(widget_path.get(), -1 , "UnityPanelWidget"); |
343 | + |
344 | + gtk_style_context_set_path(style_context, widget_path.get()); |
345 | + gtk_style_context_add_class(style_context, GTK_STYLE_CLASS_MENUBAR); |
346 | + gtk_style_context_add_class(style_context, GTK_STYLE_CLASS_MENUITEM); |
347 | |
348 | // alignment |
349 | PangoRectangle lRect; |
350 | - int textWidth, textHeight; |
351 | - |
352 | - pango_layout_get_extents(layout, NULL, &lRect); |
353 | - textWidth = lRect.width / PANGO_SCALE; |
354 | - textHeight = lRect.height / PANGO_SCALE; |
355 | - |
356 | - y = ((maxHeight - textHeight) / 2.0) + y; |
357 | - cairo_translate(context.cr_, x, y); |
358 | - |
359 | - if (textWidth > maxWidth) |
360 | + pango_layout_get_extents(layout, nullptr, &lRect); |
361 | + int text_width = lRect.width / PANGO_SCALE; |
362 | + int text_height = lRect.height / PANGO_SCALE; |
363 | + y += (height - text_height) / 2.0f; |
364 | + int text_space = width - x; |
365 | + |
366 | + if (text_width > text_space) |
367 | { |
368 | - // apply a fade effect in the right corner |
369 | - const int outPixels = textWidth - maxWidth; |
370 | - const int fadingPixels = 35; |
371 | - const int fadingWidth = outPixels < fadingPixels ? outPixels : fadingPixels; |
372 | + // Cut the text with fade |
373 | + int out_pixels = text_width - text_space; |
374 | + const int fading_pixels = 35; |
375 | + int fading_width = (out_pixels < fading_pixels) ? out_pixels : fading_pixels; |
376 | |
377 | cairo_push_group(context.cr_); |
378 | - pango_cairo_show_layout(context.cr_, layout); |
379 | + gtk_render_layout(style_context, context.cr_, x, y, layout); |
380 | cairo_pop_group_to_source(context.cr_); |
381 | |
382 | - std::shared_ptr<cairo_pattern_t> linpat(cairo_pattern_create_linear(maxWidth - fadingWidth, |
383 | - y, maxWidth, y), |
384 | + std::shared_ptr<cairo_pattern_t> linpat(cairo_pattern_create_linear(width - fading_width, y, width, y), |
385 | cairo_pattern_destroy); |
386 | cairo_pattern_add_color_stop_rgba(linpat.get(), 0, 0, 0, 0, 1); |
387 | cairo_pattern_add_color_stop_rgba(linpat.get(), 1, 0, 0, 0, 0); |
388 | @@ -3566,61 +3600,55 @@ |
389 | } |
390 | else |
391 | { |
392 | - pango_cairo_show_layout(context.cr_, layout); |
393 | + gtk_render_layout(style_context, context.cr_, x, y, layout); |
394 | } |
395 | + |
396 | + gtk_style_context_restore(style_context); |
397 | } |
398 | |
399 | -void |
400 | -UnityWindow::DrawWindowDecoration(GLWindowPaintAttrib const& attrib, |
401 | - GLMatrix const& transform, |
402 | - unsigned int mask, |
403 | - bool highlighted, |
404 | - int x, int y, unsigned width, unsigned height) |
405 | +void UnityWindow::DrawWindowDecoration(GLWindowPaintAttrib const& attrib, |
406 | + GLMatrix const& transform, |
407 | + unsigned int mask, |
408 | + bool highlighted, |
409 | + int x, int y, unsigned width, unsigned height) |
410 | { |
411 | // Paint a fake window decoration |
412 | CairoContext context(width, height); |
413 | |
414 | cairo_save(context.cr_); |
415 | + |
416 | + // Draw window decoration based on gtk style |
417 | cairo_push_group(context.cr_); |
418 | + auto& style = panel::Style::Instance(); |
419 | + gtk_render_background(style.GetStyleContext(), context.cr_, 0, 0, width, height); |
420 | + gtk_render_frame(style.GetStyleContext(), context.cr_, 0, 0, width, height); |
421 | + cairo_pop_group_to_source(context.cr_); |
422 | |
423 | // Round window decoration top border |
424 | - const double aspect = 1.0; |
425 | - const double corner_radius = height / 10.0; |
426 | - const double radius = corner_radius / aspect; |
427 | - const double degrees = M_PI / 180.0; |
428 | + const double aspect = ScaleWindow::get(window)->getCurrentPosition().scale; |
429 | + const double radius = 8.0 * aspect; |
430 | |
431 | cairo_new_sub_path(context.cr_); |
432 | - |
433 | - cairo_arc(context.cr_, radius, radius, radius, 180 * degrees, 270 * degrees); |
434 | - cairo_arc(context.cr_, width - radius, radius, radius, -90 * degrees, 0 * degrees); |
435 | + cairo_line_to(context.cr_, 0, height); |
436 | + cairo_arc(context.cr_, radius, radius, radius, M_PI, -M_PI * 0.5f); |
437 | + cairo_line_to(context.cr_, width - radius, 0); |
438 | + cairo_arc(context.cr_, width - radius, radius, radius, M_PI * 0.5f, 0); |
439 | cairo_line_to(context.cr_, width, height); |
440 | - cairo_line_to(context.cr_, 0, height); |
441 | - |
442 | cairo_close_path(context.cr_); |
443 | - cairo_clip(context.cr_); |
444 | - |
445 | - // Draw window decoration based on gtk style |
446 | - auto& style = panel::Style::Instance(); |
447 | - gtk_render_background(style.GetStyleContext(), context.cr_, 0, 0, width, height); |
448 | - gtk_render_frame(style.GetStyleContext(), context.cr_, 0, 0, width, height); |
449 | - |
450 | - cairo_pop_group_to_source(context.cr_); |
451 | - |
452 | - cairo_paint_with_alpha(context.cr_, 1.0); |
453 | + |
454 | + cairo_fill(context.cr_); |
455 | + |
456 | cairo_restore(context.cr_); |
457 | |
458 | if (highlighted) |
459 | { |
460 | // Draw windows title |
461 | const float xText = SCALE_ITEMS_PADDING * 2 + SCALE_CLOSE_ICON_SIZE; |
462 | - RenderText(context, xText, 0.0, width - xText - SCALE_ITEMS_PADDING, height); |
463 | + RenderText(context, xText, 0.0, width - SCALE_ITEMS_PADDING, height); |
464 | } |
465 | |
466 | mask |= PAINT_WINDOW_BLEND_MASK; |
467 | - int maxWidth, maxHeight; |
468 | - |
469 | - for (GLTexture *icon : context.texture_) |
470 | - DrawTexture(icon, attrib, transform, mask, x, y, maxWidth , maxHeight); |
471 | + DrawTexture(context.texture_, attrib, transform, mask, x, y); |
472 | } |
473 | |
474 | void UnityWindow::LoadCloseIcon(panel::WindowState state, GLTexture::List& texture) |
475 | @@ -3631,12 +3659,12 @@ |
476 | auto& style = panel::Style::Instance(); |
477 | auto const& files = style.GetWindowButtonFileNames(panel::WindowButtonType::CLOSE, state); |
478 | |
479 | - CompString pName("unityshell"); |
480 | + CompString plugin("unityshell"); |
481 | for (std::string const& file : files) |
482 | { |
483 | - CompString fileName(file.c_str()); |
484 | + CompString file_name = file; |
485 | CompSize size(SCALE_CLOSE_ICON_SIZE, SCALE_CLOSE_ICON_SIZE); |
486 | - texture = GLTexture::readImageToTexture(fileName, pName, size); |
487 | + texture = GLTexture::readImageToTexture(file_name, plugin, size); |
488 | if (!texture.empty()) |
489 | break; |
490 | } |
491 | @@ -3649,49 +3677,57 @@ |
492 | else if (state == panel::WindowState::PRESSED) |
493 | suffix = "_pressed"; |
494 | |
495 | - CompString fileName((PKGDATADIR"/close_dash" + suffix + ".png").c_str()); |
496 | + CompString file_name(PKGDATADIR"/close_dash" + suffix + ".png"); |
497 | CompSize size(SCALE_CLOSE_ICON_SIZE, SCALE_CLOSE_ICON_SIZE); |
498 | - texture = GLTexture::readImageToTexture(fileName, pName, size); |
499 | + texture = GLTexture::readImageToTexture(file_name, plugin, size); |
500 | } |
501 | } |
502 | |
503 | -void UnityWindow::SetupScaleHeaderStyle() |
504 | +void UnityWindow::SetupSharedTextures() |
505 | { |
506 | LoadCloseIcon(panel::WindowState::NORMAL, close_normal_tex_); |
507 | LoadCloseIcon(panel::WindowState::PRELIGHT, close_prelight_tex_); |
508 | LoadCloseIcon(panel::WindowState::PRESSED, close_pressed_tex_); |
509 | } |
510 | |
511 | +void UnityWindow::CleanupSharedTextures() |
512 | +{ |
513 | + close_normal_tex_.clear(); |
514 | + close_prelight_tex_.clear(); |
515 | + close_pressed_tex_.clear(); |
516 | +} |
517 | + |
518 | void UnityWindow::scalePaintDecoration(GLWindowPaintAttrib const& attrib, |
519 | GLMatrix const& transform, |
520 | CompRegion const& region, |
521 | unsigned int mask) |
522 | { |
523 | ScaleWindow *scale_win = ScaleWindow::get(window); |
524 | - if (!scale_win) |
525 | - return; |
526 | - |
527 | scale_win->scalePaintDecoration(attrib, transform, region, mask); |
528 | |
529 | if (!scale_win->hasSlot()) // animation not finished |
530 | return; |
531 | |
532 | ScaleScreen* ss = ScaleScreen::get(screen); |
533 | + auto state = ss->getState(); |
534 | + |
535 | + if (state != ScaleScreen::Wait && state != ScaleScreen::Out) |
536 | + return; |
537 | + |
538 | + auto const& scaled_geo = GetScaledGeometry(); |
539 | + auto const& decoration_extents = window->border(); |
540 | + auto const& pos = scale_win->getCurrentPosition(); |
541 | + |
542 | const bool highlighted = (ss->getSelectedWindow() == window->id()); |
543 | - |
544 | - ScalePosition const& pos = scale_win->getCurrentPosition(); |
545 | - auto const& border_rect = window->borderRect(); |
546 | - auto const& deco_ext = window->border(); |
547 | - |
548 | - const unsigned decoration_height = deco_ext.top; |
549 | - unsigned width = (border_rect.width() + deco_ext.left + deco_ext.right) * pos.scale; |
550 | - unsigned height = decoration_height * pos.scale; |
551 | - int x = pos.x() + border_rect.x(); |
552 | - int y = pos.y() + border_rect.y() + decoration_height - height - 1; |
553 | - |
554 | - // If window is highlighted, we draw the decoration at full size |
555 | - if (highlighted) |
556 | - height = decoration_height; |
557 | + int width = scaled_geo.width; |
558 | + int height = decoration_extents.top; |
559 | + int x = scaled_geo.x; |
560 | + int y = scaled_geo.y; |
561 | + |
562 | + |
563 | + // If window is not highlighted, we draw the decoration at scaled size |
564 | + if (!highlighted) |
565 | + height *= pos.scale; |
566 | |
567 | DrawWindowDecoration(attrib, transform, mask, highlighted, x, y, width, height); |
568 | |
569 | @@ -3699,30 +3735,25 @@ |
570 | { |
571 | x += SCALE_ITEMS_PADDING; |
572 | y += (height - SCALE_CLOSE_ICON_SIZE) / 2.0f; |
573 | - int max_height = 0; |
574 | - int max_width = 0; |
575 | mask |= PAINT_WINDOW_BLEND_MASK; |
576 | |
577 | - switch(close_icon_state_) |
578 | + switch (close_icon_state_) |
579 | { |
580 | case panel::WindowState::NORMAL: |
581 | default: |
582 | - for (GLTexture *icon : close_normal_tex_) |
583 | - DrawTexture(icon, attrib, transform, mask, x, y, max_width , max_height); |
584 | + DrawTexture(close_normal_tex_, attrib, transform, mask, x, y); |
585 | break; |
586 | |
587 | case panel::WindowState::PRELIGHT: |
588 | - for (GLTexture *icon : close_prelight_tex_) |
589 | - DrawTexture(icon, attrib, transform, mask, x, y, max_width , max_height); |
590 | + DrawTexture(close_prelight_tex_, attrib, transform, mask, x, y); |
591 | break; |
592 | |
593 | case panel::WindowState::PRESSED: |
594 | - for (GLTexture *icon : close_pressed_tex_) |
595 | - DrawTexture(icon, attrib, transform, mask, x, y, max_width , max_height); |
596 | + DrawTexture(close_pressed_tex_, attrib, transform, mask, x, y); |
597 | break; |
598 | } |
599 | |
600 | - close_button_geo_.Set(x, y, max_height, max_width); |
601 | + close_button_geo_.Set(x, y, SCALE_CLOSE_ICON_SIZE, SCALE_CLOSE_ICON_SIZE); |
602 | } |
603 | else if (!close_button_geo_.IsNull()) |
604 | { |
605 | @@ -3730,14 +3761,27 @@ |
606 | } |
607 | } |
608 | |
609 | +nux::Geometry UnityWindow::GetScaledGeometry() |
610 | +{ |
611 | + ScaleWindow *scale_win = ScaleWindow::get(window); |
612 | + |
613 | + ScalePosition const& pos = scale_win->getCurrentPosition(); |
614 | + auto const& border_rect = window->borderRect(); |
615 | + auto const& deco_ext = window->border(); |
616 | + |
617 | + const unsigned width = std::floor(border_rect.width() * pos.scale); |
618 | + const unsigned height = std::floor(border_rect.height() * pos.scale); |
619 | + const int x = pos.x() + window->x() - std::floor(deco_ext.left * pos.scale); |
620 | + const int y = pos.y() + window->y() - std::floor(deco_ext.top * pos.scale); |
621 | + |
622 | + return nux::Geometry(x, y, width, height); |
623 | +} |
624 | + |
625 | void UnityWindow::OnInitiateSpreed() |
626 | { |
627 | - auto const& windows = screen->windows(); |
628 | - if (std::find(windows.begin(), windows.end(), window) == windows.end()) |
629 | - return; |
630 | - |
631 | close_icon_state_ = panel::WindowState::NORMAL; |
632 | - SetupScaleHeaderStyle(); |
633 | + middle_clicked_ = false; |
634 | + SetupSharedTextures(); |
635 | |
636 | WindowManager *wm = WindowManager::Default(); |
637 | Window xid = window->id(); |
638 | @@ -3748,10 +3792,6 @@ |
639 | |
640 | void UnityWindow::OnTerminateSpreed() |
641 | { |
642 | - auto const& windows = screen->windows(); |
643 | - if (std::find(windows.begin(), windows.end(), window) == windows.end()) |
644 | - return; |
645 | - |
646 | WindowManager *wm = WindowManager::Default(); |
647 | Window xid = window->id(); |
648 | |
649 | @@ -3813,6 +3853,33 @@ |
650 | return true; |
651 | } |
652 | |
653 | +namespace debug |
654 | +{ |
655 | + |
656 | +ScreenIntrospection::ScreenIntrospection(CompScreen* screen) |
657 | + : screen_(screen) |
658 | +{} |
659 | + |
660 | +std::string ScreenIntrospection::GetName() const |
661 | +{ |
662 | + return "Screen"; |
663 | +} |
664 | + |
665 | +void ScreenIntrospection::AddProperties(GVariantBuilder* builder) |
666 | +{} |
667 | + |
668 | +Introspectable::IntrospectableList ScreenIntrospection::GetIntrospectableChildren() |
669 | +{ |
670 | + IntrospectableList children; |
671 | + |
672 | + for (auto const& win : screen_->windows()) |
673 | + children.push_back(UnityWindow::get(win)); |
674 | + |
675 | + return children; |
676 | +} |
677 | + |
678 | +} // debug namespace |
679 | + |
680 | namespace |
681 | { |
682 | |
683 | |
684 | === modified file 'plugins/unityshell/src/unityshell.h' |
685 | --- plugins/unityshell/src/unityshell.h 2012-09-19 16:57:39 +0000 |
686 | +++ plugins/unityshell/src/unityshell.h 2012-09-24 19:39:25 +0000 |
687 | @@ -27,7 +27,6 @@ |
688 | #include <Nux/WindowThread.h> |
689 | #include <NuxCore/Property.h> |
690 | #include <sigc++/sigc++.h> |
691 | -#include <boost/shared_ptr.hpp> |
692 | |
693 | #include <scale/scale.h> |
694 | #include <core/core.h> |
695 | @@ -50,6 +49,7 @@ |
696 | #include "PanelStyle.h" |
697 | #include "UScreen.h" |
698 | #include "DebugDBusInterface.h" |
699 | +#include "ScreenIntrospection.h" |
700 | #include "SwitcherController.h" |
701 | #include "UBusWrapper.h" |
702 | #include "UnityshellPrivate.h" |
703 | @@ -69,7 +69,7 @@ |
704 | |
705 | /* base screen class */ |
706 | class UnityScreen : |
707 | - public unity::debug::Introspectable, |
708 | + public debug::Introspectable, |
709 | public sigc::trackable, |
710 | public ScreenInterface, |
711 | public CompositeScreenInterface, |
712 | @@ -307,7 +307,7 @@ |
713 | |
714 | nux::Property<nux::Geometry> primary_monitor_; |
715 | |
716 | - BGHash* _bghash; |
717 | + std::unique_ptr<BGHash> _bghash; |
718 | |
719 | ::GLFramebufferObject *oldFbo; |
720 | |
721 | @@ -329,11 +329,13 @@ |
722 | nux::ObjectPtr<nux::IOpenGLBaseTexture> panel_texture_; |
723 | |
724 | bool scale_just_activated_; |
725 | + WindowMinimizeSpeedController minimize_speed_controller_; |
726 | + |
727 | + debug::ScreenIntrospection screen_introspection_; |
728 | |
729 | UBusManager ubus_manager_; |
730 | glib::SourceManager sources_; |
731 | |
732 | - WindowMinimizeSpeedController* minimize_speed_controller; |
733 | friend class UnityWindow; |
734 | }; |
735 | |
736 | @@ -345,6 +347,7 @@ |
737 | public WrapableHandler<ScaleWindowInterface, 4>, |
738 | public BaseSwitchWindow, |
739 | public PluginClassHandler <UnityWindow, CompWindow>, |
740 | + public debug::Introspectable, |
741 | public sigc::trackable |
742 | { |
743 | public: |
744 | @@ -391,6 +394,7 @@ |
745 | |
746 | bool place(CompPoint& pos); |
747 | CompPoint tryNotIntersectUI(CompPoint& pos); |
748 | + nux::Geometry GetScaledGeometry(); |
749 | |
750 | void paintThumbnail (nux::Geometry const& bounding, float alpha); |
751 | |
752 | @@ -413,6 +417,10 @@ |
753 | const CompRegion &, |
754 | unsigned int); |
755 | |
756 | +protected: |
757 | + std::string GetName() const; |
758 | + void AddProperties(GVariantBuilder* builder); |
759 | + |
760 | private: |
761 | struct CairoContext; |
762 | |
763 | @@ -449,23 +457,16 @@ |
764 | |
765 | compiz::WindowInputRemoverLock::Ptr GetInputRemover (); |
766 | |
767 | - void DrawWindowDecoration(GLWindowPaintAttrib const& attrib, |
768 | - GLMatrix const& transform, |
769 | - unsigned int mask, |
770 | - bool highlighted, |
771 | + void DrawWindowDecoration(GLWindowPaintAttrib const& attrib, GLMatrix const& transform, |
772 | + unsigned int mask, bool highlighted, |
773 | int x, int y, unsigned width, unsigned height); |
774 | - void DrawTexture(GLTexture *icon, |
775 | - const GLWindowPaintAttrib& attrib, |
776 | - const GLMatrix& transform, |
777 | - unsigned int mask, |
778 | - float x, float y, |
779 | - int &maxWidth, int &maxHeight); |
780 | - void RenderText(CairoContext const& context, |
781 | - float x, float y, |
782 | - float maxWidth, float maxHeight); |
783 | + void DrawTexture(GLTexture::List const& textures, GLWindowPaintAttrib const& attrib, |
784 | + GLMatrix const& transform, unsigned int mask, int x, int y); |
785 | + void RenderText(CairoContext const& context, int x, int y, int width, int height); |
786 | |
787 | - void SetupScaleHeaderStyle(); |
788 | - void LoadCloseIcon(panel::WindowState state, GLTexture::List& texture); |
789 | + static void SetupSharedTextures(); |
790 | + static void CleanupSharedTextures(); |
791 | + static void LoadCloseIcon(panel::WindowState state, GLTexture::List& texture); |
792 | |
793 | static GLTexture::List close_normal_tex_; |
794 | static GLTexture::List close_prelight_tex_; |
795 | @@ -473,7 +474,10 @@ |
796 | compiz::WindowInputRemoverLock::Weak input_remover_; |
797 | panel::WindowState close_icon_state_; |
798 | nux::Geometry close_button_geo_; |
799 | + bool middle_clicked_; |
800 | glib::Source::UniquePtr focus_desktop_timeout_; |
801 | + |
802 | + friend class UnityScreen; |
803 | }; |
804 | |
805 | |
806 | |
807 | === added file 'tests/autopilot/unity/emulators/screen.py' |
808 | --- tests/autopilot/unity/emulators/screen.py 1970-01-01 00:00:00 +0000 |
809 | +++ tests/autopilot/unity/emulators/screen.py 2012-09-24 19:39:25 +0000 |
810 | @@ -0,0 +1,42 @@ |
811 | +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
812 | +# Copyright 2012 Canonical |
813 | +# Author: Marco Trevisan (Treviño) |
814 | +# |
815 | +# This program is free software: you can redistribute it and/or modify it |
816 | +# under the terms of the GNU General Public License version 3, as published |
817 | +# by the Free Software Foundation. |
818 | +# |
819 | + |
820 | +from __future__ import absolute_import |
821 | + |
822 | +import logging |
823 | +from unity.emulators import UnityIntrospectionObject |
824 | +logger = logging.getLogger(__name__) |
825 | + |
826 | + |
827 | +class Screen(UnityIntrospectionObject): |
828 | + """The Screen class.""" |
829 | + |
830 | + @property |
831 | + def windows(self): |
832 | + """Return the available windows, or None.""" |
833 | + return self.get_children_by_type(Window) |
834 | + |
835 | + @property |
836 | + def scaled_windows(self): |
837 | + """Return the available scaled windows, or None.""" |
838 | + return self.get_children_by_type(Window, scaled=True) |
839 | + |
840 | + |
841 | +class Window(UnityIntrospectionObject): |
842 | + """An individual window.""" |
843 | + |
844 | + @property |
845 | + def geometry(self): |
846 | + """Returns a tuple of (x,y,w,h) for the current window.""" |
847 | + return (self.x, self.y, self.width, self.height) |
848 | + |
849 | + @property |
850 | + def scale_close_geometry(self): |
851 | + """Returns a tuple of (x,y,w,h) for the scale close button.""" |
852 | + return (self.scaled_close_x, self.scaled_close_y, self.scaled_close_width, self.scaled_close_height) |
853 | |
854 | === modified file 'tests/autopilot/unity/tests/__init__.py' |
855 | --- tests/autopilot/unity/tests/__init__.py 2012-07-12 20:54:59 +0000 |
856 | +++ tests/autopilot/unity/tests/__init__.py 2012-09-24 19:39:25 +0000 |
857 | @@ -20,6 +20,7 @@ |
858 | from testtools.content import text_content |
859 | from testtools.matchers import Equals |
860 | |
861 | +from unity.emulators.screen import Screen |
862 | from unity.emulators.dash import Dash |
863 | from unity.emulators.hud import Hud |
864 | from unity.emulators.launcher import LauncherController |
865 | @@ -114,6 +115,12 @@ |
866 | return True |
867 | |
868 | @property |
869 | + def screen(self): |
870 | + if not getattr(self, '__screen', None): |
871 | + self.__screen = self._get_screen() |
872 | + return self.__screen |
873 | + |
874 | + @property |
875 | def dash(self): |
876 | if not getattr(self, '__dash', None): |
877 | self.__dash = Dash() |
878 | @@ -155,6 +162,11 @@ |
879 | self.__workspace = WorkspaceManager() |
880 | return self.__workspace |
881 | |
882 | + def _get_screen(self): |
883 | + screens = Screen.get_all_instances() |
884 | + self.assertThat(len(screens), Equals(1)) |
885 | + return screens[0] |
886 | + |
887 | def _get_launcher_controller(self): |
888 | controllers = LauncherController.get_all_instances() |
889 | self.assertThat(len(controllers), Equals(1)) |
890 | |
891 | === added file 'tests/autopilot/unity/tests/test_spread.py' |
892 | --- tests/autopilot/unity/tests/test_spread.py 1970-01-01 00:00:00 +0000 |
893 | +++ tests/autopilot/unity/tests/test_spread.py 2012-09-24 19:39:25 +0000 |
894 | @@ -0,0 +1,124 @@ |
895 | +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
896 | +# Copyright 2012 Canonical |
897 | +# Author: Marco Trevisan (Treviño) |
898 | +# |
899 | +# This program is free software: you can redistribute it and/or modify it |
900 | +# under the terms of the GNU General Public License version 3, as published |
901 | +# by the Free Software Foundation. |
902 | + |
903 | +from __future__ import absolute_import |
904 | + |
905 | +from autopilot.matchers import Eventually |
906 | +import logging |
907 | +from time import sleep |
908 | +from testtools.matchers import Equals, NotEquals |
909 | + |
910 | +from unity.tests import UnityTestCase |
911 | +from unity.emulators.screen import Screen |
912 | + |
913 | + |
914 | +class SpreadTests(UnityTestCase): |
915 | + """Spread tests""" |
916 | + |
917 | + def start_test_application_windows(self, app_name, num_windows=2): |
918 | + """Start a given number of windows of the requested application""" |
919 | + self.close_all_app(app_name) |
920 | + windows = [] |
921 | + |
922 | + for i in range(num_windows): |
923 | + win = self.start_app_window(app_name) |
924 | + if len(windows): |
925 | + self.assertThat(win.application, Equals(windows[-1].application)) |
926 | + |
927 | + windows.append(win) |
928 | + |
929 | + self.assertThat(len(windows), Equals(num_windows)) |
930 | + |
931 | + return windows |
932 | + |
933 | + def initiate_spread_for_screen(self): |
934 | + """Initiate the Spread for all windows""" |
935 | + self.addCleanup(self.keybinding, "spread/cancel") |
936 | + self.keybinding("spread/start") |
937 | + sleep(1) |
938 | + self.assertThat(self.window_manager.scale_active, Eventually(Equals(True))) |
939 | + |
940 | + |
941 | + def initiate_spread_for_application(self, desktop_id): |
942 | + """Initiate the Spread for windows of the given app""" |
943 | + icon = self.launcher.model.get_icon(desktop_id=desktop_id) |
944 | + self.assertThat(lambda: icon, Eventually(NotEquals(None))) |
945 | + launcher = self.launcher.get_launcher_for_monitor(self.screen_geo.get_primary_monitor()) |
946 | + |
947 | + self.addCleanup(self.keybinding, "spread/cancel") |
948 | + launcher.click_launcher_icon(icon) |
949 | + self.assertThat(self.window_manager.scale_active_for_group, Eventually(Equals(True))) |
950 | + |
951 | + def assertWindowIsNotScaled(self, xid): |
952 | + """Assert that a window is not scaled""" |
953 | + refresh_fn = lambda: xid in [w.xid for w in self.screen.scaled_windows] |
954 | + self.assertThat(refresh_fn, Eventually(Equals(False))) |
955 | + |
956 | + def assertWindowIsClosed(self, xid): |
957 | + """Assert that a window is not in the list of the open windows""" |
958 | + refresh_fn = lambda: xid in [w.x_id for w in self.bamf.get_open_windows()] |
959 | + self.assertThat(refresh_fn, Eventually(Equals(False))) |
960 | + |
961 | + |
962 | + def test_scale_application_windows(self): |
963 | + """Test if all the windows of an application are scaled when application spread is initiated""" |
964 | + [win1, win2] = self.start_test_application_windows("Calculator") |
965 | + self.initiate_spread_for_application(win1.application.desktop_file) |
966 | + |
967 | + self.assertThat(lambda: len(self.screen.scaled_windows), Eventually(Equals(2))) |
968 | + self.assertThat(lambda: (win1.x_id and win2.x_id) in [w.xid for w in self.screen.scaled_windows], |
969 | + Eventually(Equals(True))) |
970 | + |
971 | + def test_scaled_window_is_focused_on_click(self): |
972 | + """Test that a window is focused when clicked in spread""" |
973 | + windows = self.start_test_application_windows("Calculator", 3) |
974 | + self.initiate_spread_for_application(windows[0].application.desktop_file) |
975 | + |
976 | + not_focused = [w for w in windows if not w.is_focused][0] |
977 | + |
978 | + target_xid = not_focused.x_id |
979 | + [target_win] = [w for w in self.screen.scaled_windows if w.xid == target_xid] |
980 | + |
981 | + (x, y, w, h) = target_win.geometry |
982 | + self.mouse.move(x + w / 2, y + h / 2) |
983 | + sleep(.5) |
984 | + self.mouse.click() |
985 | + |
986 | + self.assertThat(lambda: not_focused.is_focused, Eventually(Equals(True))) |
987 | + |
988 | + def test_scaled_window_closes_on_middle_click(self): |
989 | + """Test that a window is closed when middle-clicked in spread""" |
990 | + win = self.start_test_application_windows("Calculator", 2)[0] |
991 | + self.initiate_spread_for_application(win.application.desktop_file) |
992 | + |
993 | + target_xid = win.x_id |
994 | + [target_win] = [w for w in self.screen.scaled_windows if w.xid == target_xid] |
995 | + |
996 | + (x, y, w, h) = target_win.geometry |
997 | + self.mouse.move(x + w / 2, y + h / 2) |
998 | + sleep(.5) |
999 | + self.mouse.click(button=2) |
1000 | + |
1001 | + self.assertWindowIsNotScaled(target_xid) |
1002 | + self.assertWindowIsClosed(target_xid) |
1003 | + |
1004 | + def test_scaled_window_closes_on_close_button_click(self): |
1005 | + """Test that a window is closed when its close button is clicked in spread""" |
1006 | + win = self.start_test_application_windows("Calculator", 1)[0] |
1007 | + self.initiate_spread_for_screen() |
1008 | + |
1009 | + target_xid = win.x_id |
1010 | + [target_win] = [w for w in self.screen.scaled_windows if w.xid == target_xid] |
1011 | + |
1012 | + (x, y, w, h) = target_win.scale_close_geometry |
1013 | + self.mouse.move(x + w / 2, y + h / 2) |
1014 | + sleep(.5) |
1015 | + self.mouse.click() |
1016 | + |
1017 | + self.assertWindowIsNotScaled(target_xid) |
1018 | + self.assertWindowIsClosed(target_xid) |
Confirmed still working :)