Merge lp:~3v1n0/unity/scale-close-middle-click-6.0 into lp:unity/6.0

Proposed by Marco Trevisan (Treviño) on 2012-09-24
Status: Merged
Approved by: Brandon Schaefer on 2012-09-24
Approved revision: 2737
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
Reviewer Review Type Date Requested Status
Brandon Schaefer (community) 2012-09-24 Approve on 2012-09-24
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

To post a comment you must log in.
2737. By Marco Trevisan (Treviño) on 2012-09-24

UnityShell: enable closing on middle-click, fix scaled decoration sizes, fix theming issues, added scale autopilot tests

Brandon Schaefer (brandontschaefer) wrote :

Confirmed still working :)

review: Approve

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)

Subscribers

People subscribed via source and target branches