summaryrefslogtreecommitdiff
diff options
authorIain Lane <iain@orangesquash.org.uk>2015-08-24 17:24:34 +0100
committerIain Lane <iain@orangesquash.org.uk>2015-08-24 17:24:34 +0100
commit26717828a63ad3d97dfd6e5a4933a922289db85d (patch)
treef518f1cc01e5d2d6979565163e478247fb01d4c1
parent60d495750881ce5833072d23a84028e835bcd616 (diff)
parent3dc35ae83a871b47ea25b9f0c9beb18a362e8aee (diff)
Merge archive upload
(bzr r3987.2.2)
-rw-r--r--dash/DashView.cpp34
-rw-r--r--dash/DashView.h2
-rwxr-xr-xdash/PlacesGroup.cpp28
-rw-r--r--dash/PlacesGroup.h2
-rw-r--r--dash/ResultViewGrid.cpp12
-rw-r--r--debian/changelog29
-rw-r--r--decorations/DecoratedWindow.cpp5
-rw-r--r--decorations/DecoratedWindow.h1
-rw-r--r--decorations/DecorationsForceQuitDialog.cpp8
-rw-r--r--decorations/DecorationsManager.cpp6
-rw-r--r--launcher/ApplicationLauncherIcon.cpp45
-rw-r--r--launcher/ApplicationLauncherIcon.h2
-rw-r--r--launcher/Launcher.cpp8
-rw-r--r--panel/PanelMenuView.cpp15
-rw-r--r--panel/PanelMenuView.h1
-rw-r--r--shutdown/SessionButton.cpp7
-rw-r--r--shutdown/SessionButton.h1
-rw-r--r--shutdown/SessionView.cpp2
-rw-r--r--tests/autopilot/unity/emulators/__init__.py24
-rw-r--r--tests/autopilot/unity/emulators/dash.py93
-rw-r--r--tests/autopilot/unity/emulators/hud.py4
-rw-r--r--tests/autopilot/unity/emulators/icons.py11
-rw-r--r--tests/autopilot/unity/emulators/launcher.py10
-rw-r--r--tests/autopilot/unity/emulators/panel.py80
-rw-r--r--tests/autopilot/unity/emulators/quicklist.py15
-rw-r--r--tests/autopilot/unity/emulators/screen.py9
-rw-r--r--tests/autopilot/unity/emulators/window_manager.py5
-rw-r--r--tests/autopilot/unity/tests/launcher/test_icon_behavior.py2
-rw-r--r--tests/autopilot/unity/tests/launcher/test_visual.py4
-rw-r--r--tests/autopilot/unity/tests/test_dash.py213
-rw-r--r--tests/autopilot/unity/tests/test_panel.py28
-rw-r--r--tests/autopilot/unity/tests/test_quicklist.py6
-rw-r--r--tests/autopilot/unity/tests/test_spread.py21
-rw-r--r--tests/autopilot/unity/tests/test_switcher.py11
-rw-r--r--tests/bamf-mock-application.c18
-rw-r--r--tests/mock-application.h7
-rw-r--r--tests/test_bamf_application.cpp5
-rw-r--r--unity-shared/ApplicationManager.h5
-rw-r--r--unity-shared/BamfApplicationManager.cpp116
-rw-r--r--unity-shared/BamfApplicationManager.h19
-rw-r--r--unity-shared/IconTexture.cpp4
-rw-r--r--unity-shared/PluginAdapter.cpp4
-rw-r--r--unity-shared/StandaloneAppManager.cpp30
-rw-r--r--unity-shared/WindowButtons.cpp16
44 files changed, 482 insertions, 486 deletions
diff --git a/dash/DashView.cpp b/dash/DashView.cpp
index 8afde747f..391ffe625 100644
--- a/dash/DashView.cpp
+++ b/dash/DashView.cpp
@@ -1547,6 +1547,32 @@ void DashView::ProcessDndEnter()
ubus_manager_.SendMessage(UBUS_OVERLAY_CLOSE_REQUEST);
}
+nux::Area* DashView::SkipUnexpandableHeaderKeyNav()
+{
+ PlacesGroup::Ptr prev_view;
+ auto category_views = active_scope_view_->GetOrderedCategoryViews();
+
+ for (auto category : category_views)
+ {
+ if (category->GetLayout() != nullptr)
+ {
+ auto header = category->GetHeaderFocusableView();
+ if (header && header->HasKeyFocus() && !category->IsExpandable())
+ {
+ if (prev_view)
+ return prev_view->GetChildView();
+ else
+ return search_bar_->text_entry();
+ }
+
+ if (category->IsVisible())
+ prev_view = category;
+ }
+ }
+
+ return nullptr;
+}
+
nux::Area* DashView::FindKeyFocusArea(unsigned int key_symbol,
unsigned long x11_key_code,
unsigned long special_keys_state)
@@ -1698,6 +1724,14 @@ nux::Area* DashView::FindKeyFocusArea(unsigned int key_symbol,
}
}
+ if (direction == KEY_NAV_UP)
+ {
+ if (auto skip_view = SkipUnexpandableHeaderKeyNav())
+ {
+ return skip_view;
+ }
+ }
+
bool search_key = false;
if (direction == KEY_NAV_NONE)
diff --git a/dash/DashView.h b/dash/DashView.h
index 5c7e5c0e6..cdcf70767 100644
--- a/dash/DashView.h
+++ b/dash/DashView.h
@@ -137,6 +137,8 @@ private:
nux::Area* KeyNavIteration(nux::KeyNavDirection direction);
+ nux::Area* SkipUnexpandableHeaderKeyNav();
+
UBusManager ubus_manager_;
Scopes::Ptr scopes_;
ScopeViews scope_views_;
diff --git a/dash/PlacesGroup.cpp b/dash/PlacesGroup.cpp
index 9d906100f..f0ba9087f 100755
--- a/dash/PlacesGroup.cpp
+++ b/dash/PlacesGroup.cpp
@@ -212,7 +212,12 @@ PlacesGroup::PlacesGroup(dash::StyleInterface& style)
if(direction == nux::KEY_NAV_UP)
nux::GetWindowCompositor().SetKeyFocusArea(_child_view, direction);
else
- nux::GetWindowCompositor().SetKeyFocusArea(GetHeaderFocusableView(), direction);
+ {
+ if (IsExpandable())
+ nux::GetWindowCompositor().SetKeyFocusArea(GetHeaderFocusableView(), direction);
+ else
+ nux::GetWindowCompositor().SetKeyFocusArea(_child_view, direction);
+ }
});
UpdatePlacesGroupSize();
@@ -343,15 +348,18 @@ PlacesGroup::SetChildView(dash::ResultView* view)
UpdateResultViewPadding();
_group_layout->AddLayout(_child_layout, 1);
- view->results_per_row.changed.connect([this] (int results_per_row)
- {
- _n_visible_items_in_unexpand_mode = results_per_row;
- RefreshLabel();
- });
+ UpdateVisibleItems(view->results_per_row());
+ view->results_per_row.changed.connect(sigc::mem_fun(this, &PlacesGroup::UpdateVisibleItems));
QueueDraw();
}
+void PlacesGroup::UpdateVisibleItems(int visible_items)
+{
+ _n_visible_items_in_unexpand_mode = visible_items;
+ RefreshLabel();
+}
+
dash::ResultView*
PlacesGroup::GetChildView()
{
@@ -567,6 +575,12 @@ PlacesGroup::SetCounts(unsigned n_total_items)
}
bool
+PlacesGroup::IsExpandable() const
+{
+ return (_n_visible_items_in_unexpand_mode < _n_total_items);
+}
+
+bool
PlacesGroup::GetExpanded() const
{
return _is_expanded;
@@ -649,7 +663,7 @@ nux::View* PlacesGroup::GetHeaderFocusableView() const
bool PlacesGroup::ShouldBeHighlighted() const
{
- return HeaderHasKeyFocus();
+ return (HeaderHasKeyFocus() && IsExpandable());
}
void PlacesGroup::SetResultsPreviewAnimationValue(float preview_animation)
diff --git a/dash/PlacesGroup.h b/dash/PlacesGroup.h
index d99883703..6b1295b95 100644
--- a/dash/PlacesGroup.h
+++ b/dash/PlacesGroup.h
@@ -77,6 +77,7 @@ public:
void SetCounts(unsigned n_total_items);
+ virtual bool IsExpandable() const;
virtual void SetExpanded(bool is_expanded);
virtual bool GetExpanded() const;
@@ -127,6 +128,7 @@ private:
void UpdatePlacesGroupSize();
void UpdateResultViewPadding();
void UpdateScale(double scale);
+ void UpdateVisibleItems(int visible_items);
private:
std::string _category_id;
diff --git a/dash/ResultViewGrid.cpp b/dash/ResultViewGrid.cpp
index ee3e3c286..78a01de9a 100644
--- a/dash/ResultViewGrid.cpp
+++ b/dash/ResultViewGrid.cpp
@@ -85,11 +85,11 @@ ResultViewGrid::ResultViewGrid(NUX_FILE_LINE_DECL)
EnableDoubleClick(true);
SetAcceptKeyNavFocusOnMouseDown(false);
- auto needredraw_lambda = [this](int value) { NeedRedraw(); };
- horizontal_spacing.changed.connect(needredraw_lambda);
- vertical_spacing.changed.connect(needredraw_lambda);
- padding.changed.connect(needredraw_lambda);
- selected_index_.changed.connect(needredraw_lambda);
+ auto queue_draw_cb = sigc::hide(sigc::mem_fun(this, &ResultViewGrid::QueueDraw));
+ horizontal_spacing.changed.connect(queue_draw_cb);
+ vertical_spacing.changed.connect(queue_draw_cb);
+ padding.changed.connect(queue_draw_cb);
+ selected_index_.changed.connect(queue_draw_cb);
expanded.changed.connect([this](bool value) { if (value) all_results_preloaded_ = false; });
results_per_row.changed.connect([this](int value) { if (value > 0) all_results_preloaded_ = false; });
scale.changed.connect(sigc::mem_fun(this, &ResultViewGrid::UpdateScale));
@@ -119,7 +119,7 @@ ResultViewGrid::ResultViewGrid(NUX_FILE_LINE_DECL)
NeedRedraw();
});
- WindowManager::Default().average_color.changed.connect(sigc::hide(sigc::mem_fun(this, &View::QueueDraw)));
+ WindowManager::Default().average_color.changed.connect(queue_draw_cb);
ubus_.RegisterInterest(UBUS_DASH_SIZE_CHANGED, [this] (GVariant* data) {
// on dash size changed, we update our stored values, this sucks
diff --git a/debian/changelog b/debian/changelog
index 468f7fe82..d3fb4e7d0 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,32 @@
+unity (7.3.2+15.10.20150819-0ubuntu1) wily; urgency=medium
+
+ [ Andrea Azzarone andrea.azzarone@canonical.com ]
+ * Do not handle events coming from viewports not actually containing
+ the window. (LP: #1449654)
+
+ [ Chris Townsend ]
+ * Also use the Compiz show() method when forcing an unmapped window to
+ be visible when clicking on it's active Launcher icon. (LP: #989588)
+ * When using keyboard navigation in the Dash, skip category headers
+ that are not expandable. Also, do not highlight the category header
+ when the mouse cursor is over it. (LP: #1045933)
+
+ [ Marco Trevisan (TreviƱo) ]
+ * ApplicationManager: rely on windows monitor property changes for
+ updating Pips (LP: #1027191)
+ * Autopilot: modernize some tests, use stronger methods to ensure
+ false positive
+ * DecorationsForceQuitDialog: override the background of the window
+ with transparent color (LP: #1470292)
+ * Launcher: Always unfold an active icon (LP: #1472339)
+ * PanelMenuView: ensure that we connect to window signals as soon as
+ the AppManager knows it (LP: #1472326)
+ * PlacesGroup: connect to view changes using a function instead of a
+ lambda (LP: #1470298)
+ * SessionButton: set button opacity to 75% when pressed (LP: #1301655)
+
+ -- CI Train Bot <ci-train-bot@canonical.com> Wed, 19 Aug 2015 14:45:18 +0000
+
unity (7.3.2+15.10.20150803.1-0ubuntu1) wily; urgency=medium
[ Andrea Azzarone andrea.azzarone@canonical.com ]
diff --git a/decorations/DecoratedWindow.cpp b/decorations/DecoratedWindow.cpp
index ea43f900a..b58a56c5a 100644
--- a/decorations/DecoratedWindow.cpp
+++ b/decorations/DecoratedWindow.cpp
@@ -842,6 +842,11 @@ Window::Window(CompWindow* cwin)
, impl_(new Impl(this, cwin))
{}
+CompWindow* Window::GetCompWindow()
+{
+ return impl_->win_;
+}
+
void Window::Update()
{
impl_->Update();
diff --git a/decorations/DecoratedWindow.h b/decorations/DecoratedWindow.h
index be49be600..893a6e0f3 100644
--- a/decorations/DecoratedWindow.h
+++ b/decorations/DecoratedWindow.h
@@ -45,6 +45,7 @@ public:
nux::Property<bool> scaled;
nux::ROProperty<double> dpi_scale;
+ CompWindow* GetCompWindow();
void Update();
void Undecorate();
void UpdateDecorationPosition();
diff --git a/decorations/DecorationsForceQuitDialog.cpp b/decorations/DecorationsForceQuitDialog.cpp
index 496803b0a..98b6349d7 100644
--- a/decorations/DecorationsForceQuitDialog.cpp
+++ b/decorations/DecorationsForceQuitDialog.cpp
@@ -169,6 +169,14 @@ GtkWidget* sheet_style_window_new(ForceQuitDialog* main_dialog, Window parent_xi
gtk_widget_set_visual(GTK_WIDGET(self), gdk_screen_get_rgba_visual(screen));
gtk_widget_realize(GTK_WIDGET(self));
+ glib::Object<GtkCssProvider> style(gtk_css_provider_new());
+ gtk_css_provider_load_from_data(style, R"(
+ * { background-color: transparent; }
+ )", -1, nullptr);
+
+ auto* style_ctx = gtk_widget_get_style_context(GTK_WIDGET(self));
+ gtk_style_context_add_provider(style_ctx, glib::object_cast<GtkStyleProvider>(style), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+
gtk_container_add(GTK_CONTAINER(self), sheet_style_dialog_new(main_dialog, parent_xid, parent_pid));
gtk_window_set_modal(self, TRUE);
diff --git a/decorations/DecorationsManager.cpp b/decorations/DecorationsManager.cpp
index 1b90d885f..e859850c9 100644
--- a/decorations/DecorationsManager.cpp
+++ b/decorations/DecorationsManager.cpp
@@ -172,7 +172,7 @@ bool Manager::Impl::UpdateWindow(::Window xid)
{
auto const& win = GetWindowByXid(xid);
- if (win && !win->impl_->win_->hasUnmapReference())
+ if (win && !win->GetCompWindow()->hasUnmapReference())
{
win->Update();
return true;
@@ -306,6 +306,10 @@ bool Manager::Impl::HandleFrameEvent(XEvent* event)
return false;
auto const& win = GetWindowByFrame(event->xany.window);
+ CompWindow* comp_window = win ? win->GetCompWindow() : nullptr;
+
+ if (comp_window && comp_window->defaultViewport() != screen->vp())
+ return false;
// ButtonRelease events might happen also outside the frame window, in this
// case we must unset the mouse owner, wherever the event happens.
diff --git a/launcher/ApplicationLauncherIcon.cpp b/launcher/ApplicationLauncherIcon.cpp
index e83621bdd..9010f3c02 100644
--- a/launcher/ApplicationLauncherIcon.cpp
+++ b/launcher/ApplicationLauncherIcon.cpp
@@ -48,7 +48,6 @@ DECLARE_LOGGER(logger, "unity.launcher.icon.application");
namespace
{
// We use the "bamf-" prefix since the manager is protected, to avoid name clash
-const std::string WINDOW_MOVE_TIMEOUT = "bamf-window-move";
const std::string ICON_REMOVE_TIMEOUT = "bamf-icon-remove";
const std::string ICON_DND_OVER_TIMEOUT = "bamf-icon-dnd-over";
const std::string DEFAULT_ICON = "application-default-icon";
@@ -87,12 +86,11 @@ ApplicationLauncherIcon::ApplicationLauncherIcon(ApplicationPtr const& app)
WindowManager& wm = WindowManager::Default();
wm.window_minimized.connect(sigc::mem_fun(this, &ApplicationLauncherIcon::OnWindowMinimized));
- wm.window_moved.connect(sigc::mem_fun(this, &ApplicationLauncherIcon::OnWindowMoved));
wm.screen_viewport_switch_ended.connect(sigc::mem_fun(this, &ApplicationLauncherIcon::EnsureWindowState));
wm.terminate_expo.connect(sigc::mem_fun(this, &ApplicationLauncherIcon::EnsureWindowState));
- UScreen::GetDefault()->changed.connect(sigc::hide(sigc::hide(sigc::mem_fun(this, &ApplicationLauncherIcon::EnsureWindowState))));
+ UScreen::GetDefault()->changed.connect(sigc::hide(sigc::hide(sigc::mem_fun(this, &ApplicationLauncherIcon::EnsureWindowsLocation))));
- EnsureWindowState();
+ EnsureWindowsLocation();
}
ApplicationLauncherIcon::~ApplicationLauncherIcon()
@@ -156,14 +154,16 @@ void ApplicationLauncherIcon::SetupApplicationSignalsConnections()
{
// Lambda functions should be fine here because when the application the icon
// is only ever removed when the application is closed.
- signals_conn_.Add(app_->window_opened.connect([this](ApplicationWindowPtr const&) {
- EnsureWindowState();
- UpdateIconGeometries(GetCenters());
+ signals_conn_.Add(app_->window_opened.connect([this](ApplicationWindowPtr const& win) {
+ signals_conn_.Add(win->monitor.changed.connect([this] (int) { EnsureWindowsLocation(); }));
+ EnsureWindowsLocation();
}));
- auto ensure_windows_cb = sigc::hide(sigc::mem_fun(this, &ApplicationLauncherIcon::EnsureWindowState));
- signals_conn_.Add(app_->window_closed.connect(ensure_windows_cb));
- signals_conn_.Add(app_->window_moved.connect(ensure_windows_cb));
+ auto ensure_win_location_cb = sigc::hide(sigc::mem_fun(this, &ApplicationLauncherIcon::EnsureWindowsLocation));
+ signals_conn_.Add(app_->window_closed.connect(ensure_win_location_cb));
+
+ for (auto& win : app_->GetWindows())
+ signals_conn_.Add(win->monitor.changed.connect(ensure_win_location_cb));
signals_conn_.Add(app_->urgent.changed.connect([this](bool const& urgent) {
LOG_DEBUG(logger) << tooltip_text() << " urgent now " << (urgent ? "true" : "false");
@@ -535,19 +535,6 @@ void ApplicationLauncherIcon::OnWindowMinimized(guint32 xid)
}
}
-void ApplicationLauncherIcon::OnWindowMoved(guint32 moved_win)
-{
- if (!app_->OwnsWindow(moved_win))
- return;
-
- _source_manager.AddTimeout(250, [this] {
- EnsureWindowState();
- UpdateIconGeometries(GetCenters());
-
- return false;
- }, WINDOW_MOVE_TIMEOUT);
-}
-
void ApplicationLauncherIcon::UpdateDesktopFile()
{
std::string const& filename = app_->desktop_file();
@@ -738,8 +725,8 @@ void ApplicationLauncherIcon::EnsureWindowState()
// If monitor is -1 (or negative), show on all monitors.
if (monitor < 0)
{
- for (unsigned j; j < monitors::MAX; j++)
- ++number_of_windows_on_monitor[j];
+ for (unsigned j; j < monitors::MAX; ++j)
+ ++number_of_windows_on_monitor[j];
}
else
{
@@ -748,12 +735,18 @@ void ApplicationLauncherIcon::EnsureWindowState()
}
}
- for (unsigned i = 0; i < monitors::MAX; i++)
+ for (unsigned i = 0; i < monitors::MAX; ++i)
SetNumberOfWindowsVisibleOnMonitor(number_of_windows_on_monitor[i], i);
WindowsChanged.emit();
}
+void ApplicationLauncherIcon::EnsureWindowsLocation()
+{
+ EnsureWindowState();
+ UpdateIconGeometries(GetCenters());
+}
+
void ApplicationLauncherIcon::UpdateDesktopQuickList()
{
std::string const& desktop_file = DesktopFile();
diff --git a/launcher/ApplicationLauncherIcon.h b/launcher/ApplicationLauncherIcon.h
index b92ad5e1f..2ea48c184 100644
--- a/launcher/ApplicationLauncherIcon.h
+++ b/launcher/ApplicationLauncherIcon.h
@@ -116,6 +116,7 @@ private:
void UnsetApplication();
void SetupApplicationSignalsConnections();
void EnsureWindowState();
+ void EnsureWindowsLocation();
void EnsureMenuItemsWindowsReady();
void EnsureMenuItemsDefaultReady();
void EnsureMenuItemsStaticQuicklist();
@@ -127,7 +128,6 @@ private:
bool Spread(bool current_desktop, int state, bool force);
void OnWindowMinimized(guint32 xid);
- void OnWindowMoved(guint32 xid);
WindowList GetWindows(WindowFilterMask filter = 0, int monitor = -1);
const std::set<std::string> GetSupportedTypes();
diff --git a/launcher/Launcher.cpp b/launcher/Launcher.cpp
index 1ea95e109..dc6b725ca 100644
--- a/launcher/Launcher.cpp
+++ b/launcher/Launcher.cpp
@@ -677,7 +677,9 @@ void Launcher::FillRenderArg(AbstractLauncherIcon::Ptr const& icon,
// goes for 0.0f when fully unfolded, to 1.0f folded
float folding_progress = CLAMP((center.y + c_icon_size - folding_threshold) / (float) c_icon_size, 0.0f, 1.0f);
float unfold_progress = icon->GetQuirkProgress(AbstractLauncherIcon::Quirk::UNFOLDED, monitor());
+ float active_progress = icon->GetQuirkProgress(AbstractLauncherIcon::Quirk::ACTIVE, monitor());
+ unfold_progress = CLAMP(unfold_progress + active_progress, 0.0f, 1.0f);
folding_progress *= 1.0f - unfold_progress;
float half_size = (folded_size / 2.0f) + (c_icon_size / 2.0f - folded_size / 2.0f) * (1.0f - folding_progress);
@@ -779,9 +781,12 @@ void Launcher::RenderArgs(std::list<RenderArg> &launcher_args,
sum += height;
// magic constant must some day be explained, for now suffice to say this constant prevents the bottom from "marching";
- float magic_constant = 1.3f;
+ const float magic_constant = 1.3f;
float unfold_progress = (*it)->GetQuirkProgress(AbstractLauncherIcon::Quirk::UNFOLDED, monitor());
+ float active_progress = (*it)->GetQuirkProgress(AbstractLauncherIcon::Quirk::ACTIVE, monitor());
+
+ unfold_progress = CLAMP(unfold_progress + active_progress, 0.0f, 1.0f);
folding_threshold -= CLAMP(sum - launcher_height, 0.0f, height * magic_constant) * (folding_constant + (1.0f - folding_constant) * unfold_progress);
}
@@ -1597,6 +1602,7 @@ void Launcher::SetupIconAnimations(AbstractLauncherIcon::Ptr const& icon)
{
icon->SetQuirkDuration(AbstractLauncherIcon::Quirk::VISIBLE, ANIM_DURATION_SHORT, monitor());
icon->SetQuirkDuration(AbstractLauncherIcon::Quirk::RUNNING, ANIM_DURATION_SHORT, monitor());
+ icon->SetQuirkDuration(AbstractLauncherIcon::Quirk::ACTIVE, ANIM_DURATION_SHORT, monitor());
icon->SetQuirkDuration(AbstractLauncherIcon::Quirk::STARTING, (ANIM_DURATION_LONG * MAX_STARTING_BLINKS * STARTING_BLINK_LAMBDA * 2), monitor());
icon->SetQuirkDuration(AbstractLauncherIcon::Quirk::PULSE_ONCE, (ANIM_DURATION_LONG * PULSE_BLINK_LAMBDA * 2), monitor());
icon->SetQuirkDuration(AbstractLauncherIcon::Quirk::PRESENTED, ANIM_DURATION, monitor());
diff --git a/panel/PanelMenuView.cpp b/panel/PanelMenuView.cpp
index 3ce44613a..56d8a397b 100644
--- a/panel/PanelMenuView.cpp
+++ b/panel/PanelMenuView.cpp
@@ -146,6 +146,8 @@ void PanelMenuView::SetupPanelMenuViewSignals()
am.active_application_changed.connect(sigc::mem_fun(this, &PanelMenuView::OnActiveAppChanged));
am.application_started.connect(sigc::mem_fun(this, &PanelMenuView::OnApplicationStarted));
am.application_stopped.connect(sigc::mem_fun(this, &PanelMenuView::OnApplicationClosed));
+ am.window_opened.connect(sigc::mem_fun(this, &PanelMenuView::OnWindowOpened));
+ am.window_closed.connect(sigc::mem_fun(this, &PanelMenuView::OnWindowClosed));
mouse_enter.connect(sigc::mem_fun(this, &PanelMenuView::OnPanelViewMouseEnter));
mouse_leave.connect(sigc::mem_fun(this, &PanelMenuView::OnPanelViewMouseLeave));
@@ -1028,6 +1030,19 @@ void PanelMenuView::OnApplicationClosed(ApplicationPtr const& app)
}
}
+void PanelMenuView::OnWindowOpened(ApplicationWindowPtr const& win)
+{
+ if (win->window_id() == window_buttons_->controlled_window() &&
+ win->title.changed.empty())
+ {
+ /* This is a not so nice workaround that we need to include here, since
+ * BAMF might be late in informing us about a new window, and thus we
+ * can't connect to it's signals (as not available in the App Manager). */
+ window_buttons_->controlled_window = 0;
+ UpdateTargetWindowItems();
+ }
+}
+
void PanelMenuView::OnWindowClosed(ApplicationWindowPtr const& win)
{
/* FIXME, this can be removed when window_unmapped WindowManager signal
diff --git a/panel/PanelMenuView.h b/panel/PanelMenuView.h
index ec0ce561a..7be902e85 100644
--- a/panel/PanelMenuView.h
+++ b/panel/PanelMenuView.h
@@ -89,6 +89,7 @@ private:
void OnEntryViewAdded(PanelIndicatorEntryView* view);
void OnApplicationStarted(ApplicationPtr const&);
void OnApplicationClosed(ApplicationPtr const&);
+ void OnWindowOpened(ApplicationWindowPtr const&);
void OnWindowClosed(ApplicationWindowPtr const&);
void OnActiveWindowChanged(ApplicationWindowPtr const&);
void OnActiveAppChanged(ApplicationPtr const&);
diff --git a/shutdown/SessionButton.cpp b/shutdown/SessionButton.cpp
index 06a8afa04..2e0eac9f9 100644
--- a/shutdown/SessionButton.cpp
+++ b/shutdown/SessionButton.cpp
@@ -40,6 +40,7 @@ Button::Button(Action action, NUX_FILE_LINE_DECL)
: nux::View(NUX_FILE_LINE_PARAM)
, scale(1.0)
, highlighted(false)
+ , pressed(false)
, action([this] { return action_; })
, label([this] { return label_view_->GetText(); })
, action_(action)
@@ -107,6 +108,8 @@ Button::Button(Action action, NUX_FILE_LINE_DECL)
mouse_enter.connect([this] (int, int, unsigned long, unsigned long) { highlighted = true; });
mouse_leave.connect([this] (int, int, unsigned long, unsigned long) { highlighted = false; });
mouse_click.connect([this] (int, int, unsigned long, unsigned long) { activated.emit(); });
+ mouse_down.connect([this] (int, int, unsigned long, unsigned long) { pressed = true; });
+ mouse_up.connect([this] (int, int, unsigned long, unsigned long) { pressed = false; });
begin_key_focus.connect([this] { highlighted = true; });
end_key_focus.connect([this] { highlighted = false; });
@@ -116,6 +119,10 @@ Button::Button(Action action, NUX_FILE_LINE_DECL)
image_view_->SetTexture(value ? highlight_tex_ : normal_tex_);
label_view_->SetTextColor(value ? nux::color::White : nux::color::Transparent);
});
+
+ pressed.changed.connect([this] (bool value) {
+ image_view_->SetOpacity(value ? 0.75 : 1.0);
+ });
}
void Button::UpdateTextures(std::string const& texture_prefix)
diff --git a/shutdown/SessionButton.h b/shutdown/SessionButton.h
index a25a65cdc..493113e8a 100644
--- a/shutdown/SessionButton.h
+++ b/shutdown/SessionButton.h
@@ -52,6 +52,7 @@ public:
nux::Property<double> scale;
nux::Property<bool> highlighted;
+ nux::Property<bool> pressed;
nux::ROProperty<Action> action;
nux::ROProperty<std::string> label;
diff --git a/shutdown/SessionView.cpp b/shutdown/SessionView.cpp
index 64aa4e96f..70534f0e7 100644
--- a/shutdown/SessionView.cpp
+++ b/shutdown/SessionView.cpp
@@ -236,7 +236,7 @@ void View::PopulateButtons()
{
if (mode() == Mode::FULL)
{
- if (manager_->CanLock())
+ if (manager_->CanLock() && !manager_->is_locked())
{
auto* button = new Button(Button::Action::LOCK, NUX_TRACKER_LOCATION);
button->activated.connect(sigc::mem_fun(manager_.get(), &Manager::LockScreen));
diff --git a/tests/autopilot/unity/emulators/__init__.py b/tests/autopilot/unity/emulators/__init__.py
index 998172b80..f10173c37 100644
--- a/tests/autopilot/unity/emulators/__init__.py
+++ b/tests/autopilot/unity/emulators/__init__.py
@@ -28,6 +28,30 @@ class UnityIntrospectionObject(CustomEmulatorBase):
_Backend = DBusAddress.SessionBus(DBUS_SERVICE, DBUS_OBJECT)
+ def _repr_string(self, obj_details=""):
+ geostr = ""
+ if hasattr(self, 'globalRect'):
+ geostr = " geo=[{r.x}x{r.y} {r.width}x{r.height}]".format(r=self.globalRect)
+
+ obj_details.strip()
+ obj_details = " "+obj_details if len(obj_details) else ""
+
+ return "<{cls} {addr} id={id}{geo}{details}>".format(cls=self.__class__.__name__,
+ addr=hex(id(self)),
+ id=self.id,
+ geo=geostr,
+ details=obj_details)
+
+ def __repr__(self):
+ with self.no_automatic_refreshing():
+ return self._repr_string()
+
+ def __eq__(self, other):
+ return isinstance(other, self.__class__) and self.id == other.id
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
def ensure_unity_is_running(timeout=300):
"""Poll the unity debug interface, and return when it's ready for use.
diff --git a/tests/autopilot/unity/emulators/dash.py b/tests/autopilot/unity/emulators/dash.py
index 58ba69790..8511d64a9 100644
--- a/tests/autopilot/unity/emulators/dash.py
+++ b/tests/autopilot/unity/emulators/dash.py
@@ -158,7 +158,7 @@ class DashController(UnityIntrospectionObject, KeybindingsHelper):
@property
def geometry(self):
- return (self.view.x, self.view.y, self.view.width, self.view.height)
+ return self.view.globalRect
class DashView(UnityIntrospectionObject):
@@ -225,10 +225,12 @@ class ScopeBarIcon(UnityIntrospectionObject):
class ScopeView(UnityIntrospectionObject):
"""A Scope View."""
- def get_groups(self):
+ def get_categories(self, only_visible=False):
"""Get a list of all groups within this scopeview. May return an empty list."""
- groups = self.get_children_by_type(PlacesGroup)
- return groups
+ if only_visible:
+ return self.get_children_by_type(PlacesGroup, is_visible=True)
+
+ return self.get_children_by_type(PlacesGroup)
def get_focused_category(self):
"""Return a PlacesGroup instance for the category whose header has keyboard focus.
@@ -236,30 +238,22 @@ class ScopeView(UnityIntrospectionObject):
Returns None if no category headers have keyboard focus.
"""
- categories = self.get_children_by_type(PlacesGroup)
- matches = [m for m in categories if m.header_has_keyfocus]
- if matches:
- return matches[0]
- return None
+ matches = self.get_children_by_type(PlacesGroup, header_has_keyfocus=True)
+ return matches[0] if matches else None
def get_category_by_name(self, category_name):
"""Return a PlacesGroup instance with the given name, or None."""
- categories = self.get_children_by_type(PlacesGroup)
- matches = [m for m in categories if m.name == category_name]
- if matches:
- return matches[0]
- return None
+ matches = self.get_children_by_type(PlacesGroup, name=category_name)
+ return matches[0] if matches else None
def get_num_visible_categories(self):
"""Get the number of visible categories in this scope."""
- return len([c for c in self.get_children_by_type(PlacesGroup) if c.is_visible])
+ return len(self.get_categories(only_visible=True))
def get_filterbar(self):
"""Get the filter bar for the current scope, or None if it doesn't have one."""
bars = self.get_children_by_type(FilterBar)
- if bars:
- return bars[0]
- return None
+ return bars[0] if bars else None
class PlacesGroup(UnityIntrospectionObject):
@@ -279,26 +273,16 @@ class Result(UnityIntrospectionObject):
"""A single result in the dash."""
def activate(self, double_click=True):
- tx = self.x + (self.width / 2)
- ty = self.y + (self.height / 2)
m = Mouse.create()
- m.move(tx, ty)
- m.click(1)
+ m.click_object(self, button=1)
if double_click:
- m.click(1)
+ m.click_object(self, button=1)
def preview(self, button=1):
- tx = self.x + (self.width / 2)
- ty = self.y + (self.height / 2)
- m = Mouse.create()
- m.move(tx, ty)
- m.click(button)
+ Mouse.create().click_object(self, button)
def preview_key(self):
- tx = self.x + (self.width / 2)
- ty = self.y + (self.height / 2)
- m = Mouse.create()
- m.move(tx, ty)
+ Mouse.create().move_to_object(self)
k = Keyboard.create()
k.press_and_release('Menu')
@@ -313,11 +297,8 @@ class FilterBar(UnityIntrospectionObject):
def get_focused_filter(self):
"""Returns the id of the focused filter widget."""
- filters = self.get_children_by_type(FilterExpanderLabel)
- for filter_label in filters:
- if filter_label.expander_has_focus:
- return filter_label
- return None
+ filters = self.get_children_by_type(FilterExpanderLabel, expander_has_focus=True)
+ return filters[0] if filters else None
@property
def expanded(self):
@@ -366,21 +347,13 @@ class FilterExpanderLabel(UnityIntrospectionObject):
def ensure_expanded(self):
"""Expand the filter expander label, if it's not already"""
if not self.expanded:
- tx = self.x + self.width / 2
- ty = self.y + self.height / 2
- m = Mouse.create()
- m.move(tx, ty)
- m.click()
+ Mouse.create().click_object(self)
self.expanded.wait_for(True)
def ensure_collapsed(self):
"""Collapse the filter expander label, if it's not already"""
if self.expanded:
- tx = self.x + self.width / 2
- ty = self.y + self.height / 2
- m = Mouse.create()
- m.move(tx, ty)
- m.click()
+ Mouse.create().click_object(self)
self.expanded.wait_for(False)
@@ -402,21 +375,14 @@ class Preview(UnityIntrospectionObject):
def get_action_by_id(self, action_id):
"""Returns the action given it's action hint."""
- actions = self.get_children_by_type(ActionButton)
- for action in actions:
- if action.action == action_id:
- return action
- return None
+ actions = self.get_children_by_type(ActionButton, action=action_id)
+ return actions[0] if actions else None
def execute_action_by_id(self, action_id):
"""Executes an action given by the id."""
action = self.get_action_by_id(action_id)
if action:
- tx = action.x + (action.width / 2)
- ty = action.y + (action.height / 2)
- m = Mouse.create()
- m.move(tx, ty)
- m.click()
+ Mouse.create().click_object(action)
@property
def cover_art(self):
@@ -495,12 +461,8 @@ class PreviewContainer(UnityIntrospectionObject):
def navigate_left(self, count=1):
"""Navigate preview left"""
- navigator = self.get_left_navigator()
-
- tx = navigator.button_x + (navigator.button_width / 2)
- ty = navigator.button_y + (navigator.button_height / 2)
m = Mouse.create()
- m.move(tx, ty)
+ m.move_to_object(self.get_left_navigator().button_geo)
old_preview_initiate_count = self.preview_initiate_count
@@ -512,12 +474,8 @@ class PreviewContainer(UnityIntrospectionObject):
def navigate_right(self, count=1):
"""Navigate preview right"""
- navigator = self.get_right_navigator()
-
- tx = navigator.button_x + (navigator.button_width / 2)
- ty = navigator.button_y + (navigator.button_height / 2)
m = Mouse.create()
- m.move(tx, ty)
+ m.move_to_object(self.get_right_navigator().button_geo)
old_preview_initiate_count = self.preview_initiate_count
@@ -607,3 +565,4 @@ class IconTexture(UnityIntrospectionObject):
class StaticCairoText(UnityIntrospectionObject):
"""Text boxes in the preview"""
+
diff --git a/tests/autopilot/unity/emulators/hud.py b/tests/autopilot/unity/emulators/hud.py
index bee29f54b..81e184c35 100644
--- a/tests/autopilot/unity/emulators/hud.py
+++ b/tests/autopilot/unity/emulators/hud.py
@@ -105,7 +105,7 @@ class HudController(UnityIntrospectionObject, KeybindingsHelper):
@property
def geometry(self):
- return (self.x, self.y, self.width, self.height)
+ return self.globalRect
@property
def selected_button(self):
@@ -156,7 +156,7 @@ class HudView(UnityIntrospectionObject):
@property
def geometry(self):
- return (self.x, self.y, self.width, self.height)
+ return self.globalRect
class HudButton(UnityIntrospectionObject):
diff --git a/tests/autopilot/unity/emulators/icons.py b/tests/autopilot/unity/emulators/icons.py
index 86cddfb0a..8230194dc 100644
--- a/tests/autopilot/unity/emulators/icons.py
+++ b/tests/autopilot/unity/emulators/icons.py
@@ -58,10 +58,6 @@ class SimpleLauncherIcon(UnityIntrospectionObject):
return self.xids.contains(xid)
- def __repr__(self):
- with self.no_automatic_refreshing():
- return "<%s id=%d>" % (self.__class__.__name__, self.id)
-
class BFBLauncherIcon(SimpleLauncherIcon):
"""Represents the BFB button in the launcher."""
@@ -80,10 +76,7 @@ class ApplicationLauncherIcon(SimpleLauncherIcon):
def __repr__(self):
with self.no_automatic_refreshing():
- return "<%s %s id=%d>" % (
- self.__class__.__name__,
- self.desktop_id,
- self.id)
+ return self._repr_string("{0.desktop_id}".format(self))
class TrashLauncherIcon(SimpleLauncherIcon):
"""Represents the trash launcher icon."""
@@ -110,7 +103,7 @@ class HudEmbeddedIcon(UnityIntrospectionObject):
@property
def geometry(self):
- return (self.x, self.y, self.width, self.height)
+ return self.globalRect
class LauncherEntry(UnityIntrospectionObject):
diff --git a/tests/autopilot/unity/emulators/launcher.py b/tests/autopilot/unity/emulators/launcher.py
index 5deb2fa18..361373395 100644
--- a/tests/autopilot/unity/emulators/launcher.py
+++ b/tests/autopilot/unity/emulators/launcher.py
@@ -118,12 +118,8 @@ class Launcher(UnityIntrospectionObject, KeybindingsHelper):
def move_mouse_over_launcher(self):
"""Move the mouse over this launcher."""
move_mouse_to_screen(self.monitor)
- (x, y, w, h) = self.geometry
- target_x = x + w / 2
- target_y = y + h / 2
-
logger.debug("Moving mouse to center of launcher.")
- self._mouse.move(target_x, target_y)
+ self._mouse.move_to_object(self)
def move_mouse_to_icon(self, icon, autoscroll_offset=0):
"""Move the mouse to a specific icon."""
@@ -438,8 +434,8 @@ class Launcher(UnityIntrospectionObject, KeybindingsHelper):
@property
def geometry(self):
- """Returns a tuple of (x,y,w,h) for the current launcher."""
- return (self.x, self.y, self.width, self.height)
+ """Returns a Rectangle (x,y,w,h) for the current launcher."""
+ return self.globalRect
class LauncherModel(UnityIntrospectionObject):
diff --git a/tests/autopilot/unity/emulators/panel.py b/tests/autopilot/unity/emulators/panel.py
index 5c196f6ca..78b10859d 100644
--- a/tests/autopilot/unity/emulators/panel.py
+++ b/tests/autopilot/unity/emulators/panel.py
@@ -14,6 +14,7 @@ from time import sleep
from autopilot.input import Mouse
from autopilot.keybindings import KeybindingsHelper
+from autopilot.introspection.types import Rectangle
from unity.emulators import UnityIntrospectionObject
logger = logging.getLogger(__name__)
@@ -107,30 +108,18 @@ class UnityPanel(UnityIntrospectionObject, KeybindingsHelper):
def move_mouse_over_grab_area(self):
"""Move the mouse over the grab area for this panel."""
- (x, y, w, h) = self.grab_area.geometry
- target_x = x + w / 2
- target_y = y + h / 2
-
logger.debug("Moving mouse to center of grab area.")
- self._mouse.move(target_x, target_y)
+ self._mouse.move_to_object(self.grab_area)
def move_mouse_over_window_buttons(self):
"""Move the mouse over the center of the window buttons area for this panel."""
- (x, y, w, h) = self.window_buttons.geometry
- target_x = x + w / 2
- target_y = y + h / 2
-
logger.debug("Moving mouse to center of the window buttons.")
- self._mouse.move(target_x, target_y)
+ self._mouse.move_to_object(self.window_buttons)
def move_mouse_over_indicators(self):
"""Move the mouse over the center of the indicators area for this panel."""
- (x, y, w, h) = self.indicators.geometry
- target_x = x + w / 2
- target_y = y + h / 2
-
logger.debug("Moving mouse to center of the indicators area.")
- self._mouse.move(target_x, target_y)
+ self._mouse.move_to_object(self.indicators)
def get_indicator_entries(self, visible_only=True, include_hidden_menus=False):
"""Returns a list of entries for this panel including both menus and indicators"""
@@ -192,8 +181,8 @@ class UnityPanel(UnityIntrospectionObject, KeybindingsHelper):
@property
def geometry(self):
- """Returns a tuple of (x,y,w,h) for the current panel."""
- return (self.x, self.y, self.width, self.height)
+ """Returns a Rectangle (x,y,w,h) for the current panel."""
+ return self.globalRect
class MenuView(UnityIntrospectionObject):
@@ -215,8 +204,8 @@ class MenuView(UnityIntrospectionObject):
@property
def geometry(self):
- """Returns a tuple of (x,y,w,h) for the current menu view."""
- return (self.x, self.y, self.width, self.height)
+ """Returns a Rectangle (x,y,w,h) for the current menu view."""
+ return self.globalRect
class WindowButtons(UnityIntrospectionObject):
@@ -256,8 +245,8 @@ class WindowButtons(UnityIntrospectionObject):
@property
def geometry(self):
- """Returns a tuple of (x,y,w,h) for the current panel."""
- return (self.x, self.y, self.width, self.height)
+ """Returns a Rectangle (x,y,w,h) for the current panel."""
+ return self.globalRect
class WindowButton(UnityIntrospectionObject):
@@ -268,20 +257,25 @@ class WindowButton(UnityIntrospectionObject):
self._mouse = Mouse.create()
def mouse_move_to(self):
- target_x = self.x + self.width / 2
- target_y = self.y + self.height / 2
- self._mouse.move(target_x, target_y, rate=20, time_between_events=0.005)
+ self._mouse.move_to_object(self)
def mouse_click(self):
- self.mouse_move_to()
- sleep(.2)
- self._mouse.click(press_duration=.1)
+ # Ignore buttons that are placed at 0x0, as they're invisible yet
+ if not self.x and not self.y and not self.visible:
+ return
+
+ self._mouse.click_object(self)
sleep(.01)
@property
def geometry(self):
- """Returns a tuple of (x,y,w,h) for the window button."""
- return (self.x, self.y, self.width, self.height)
+ """Returns a Rectangle (x,y,w,h) for the window button."""
+ return self.globalRect
+
+ def __repr__(self):
+ with self.no_automatic_refreshing():
+ details = "type={0.type} state={0.visual_state} sensitive={0.sensitive}".format(self)
+ return self._repr_string(details)
class GrabArea(UnityIntrospectionObject):
@@ -289,8 +283,8 @@ class GrabArea(UnityIntrospectionObject):
@property
def geometry(self):
- """Returns a tuple of (x,y,w,h) for the grab area."""
- return (self.x, self.y, self.width, self.height)
+ """Returns a Rectangle (x,y,w,h) for the grab area."""
+ return self.globalRect
class Indicators(UnityIntrospectionObject):
@@ -314,8 +308,8 @@ class Indicators(UnityIntrospectionObject):
@property
def geometry(self):
- """Returns a tuple of (x,y,w,h) for the indicators area."""
- return (self.x, self.y, self.width, self.height)
+ """Returns a Rectangle (x,y,w,h) for the indicators area."""
+ return self.globalRect
class IndicatorEntry(UnityIntrospectionObject):
@@ -326,30 +320,26 @@ class IndicatorEntry(UnityIntrospectionObject):
self._mouse = Mouse.create()
def mouse_move_to(self):
- target_x = self.x + self.width / 2
- target_y = self.y + self.height / 2
- self._mouse.move(target_x, target_y, rate=20, time_between_events=0.005)
+ self._mouse.move_to_object(self)
def mouse_click(self, button=1):
- self.mouse_move_to()
- sleep(.2)
- assert(self.visible)
- self._mouse.click(press_duration=.1)
+ self._mouse.click_object(self, button=button)
sleep(.01)
@property
def geometry(self):
- """Returns a tuple of (x,y,w,h) for the indicator entry."""
- return (self.x, self.y, self.width, self.height)
+ """Returns a Rectangle (x,y,w,h) for the indicator entry."""
+ return self.globalRect
@property
def menu_geometry(self):
- """Returns a tuple of (x,y,w,h) for the opened menu geometry."""
- return (self.menu_x, self.menu_y, self.menu_width, self.menu_height)
+ """Returns a Rectangle (x,y,w,h) for the opened menu geometry."""
+ return Rectangle(self.menu_x, self.menu_y, self.menu_width, self.menu_height)
def __repr__(self):
with self.no_automatic_refreshing():
- return "<IndicatorEntry 0x%x (%s)>" % (id(self), self.label)
+ details = "label={0.label}".format(self)
+ return self._repr_string(details)
class Tray(UnityIntrospectionObject):
diff --git a/tests/autopilot/unity/emulators/quicklist.py b/tests/autopilot/unity/emulators/quicklist.py
index a3e522600..42601bd3d 100644
--- a/tests/autopilot/unity/emulators/quicklist.py
+++ b/tests/autopilot/unity/emulators/quicklist.py
@@ -66,8 +66,8 @@ class Quicklist(UnityIntrospectionObject):
@property
def geometry(self):
- """Returns a tuple of (x,y,w,h) for the quicklist."""
- return (self.x, self.y, self.width, self.height)
+ """Returns a Rectangle (x,y,w,h) for the quicklist."""
+ return self.globalRect
class QuicklistMenuItem(UnityIntrospectionObject):
@@ -79,20 +79,17 @@ class QuicklistMenuItem(UnityIntrospectionObject):
@property
def geometry(self):
- """Returns a tuple of (x,y,w,h) for the quicklist item."""
- return (self.x, self.y, self.width, self.height)
+ """Returns a Rectangle (x,y,w,h) for the quicklist item."""
+ return self.globalRect
def mouse_move_to(self):
assert(self.visible)
logger.debug("Moving mouse over quicklist item %r", self)
- target_x = self.x + self.width / 2
- target_y = self.y + self.height / 2
- self._mouse.move(target_x, target_y, rate=20, time_between_events=0.005)
+ self._mouse.move_to_object(self)
def mouse_click(self, button=1):
logger.debug("Clicking on quicklist item %r", self)
- self.mouse_move_to()
- self._mouse.click()
+ self._mouse.click_object(self)
class QuicklistMenuItemLabel(QuicklistMenuItem):
diff --git a/tests/autopilot/unity/emulators/screen.py b/tests/autopilot/unity/emulators/screen.py
index 18dc90cc6..b9299a2b6 100644
--- a/tests/autopilot/unity/emulators/screen.py
+++ b/tests/autopilot/unity/emulators/screen.py
@@ -13,6 +13,7 @@ import logging
from unity.emulators import UnityIntrospectionObject
from testtools.matchers import GreaterThan
+from autopilot.introspection.types import Rectangle
from unity.emulators.dash import SearchBar
logger = logging.getLogger(__name__)
@@ -54,15 +55,15 @@ class Window(UnityIntrospectionObject):
@property
def geometry(self):
- """Returns a tuple of (x,y,w,h) for the current window."""
- return (self.x, self.y, self.width, self.height)
+ """Returns a Rectangle (x,y,w,h) for the current window."""
+ return self.globalRect
@property
def scale_close_geometry(self):
- """Returns a tuple of (x,y,w,h) for the scale close button."""
+ """Returns a Rectangle (x,y,w,h) for the scale close button."""
self.scaled_close_width.wait_for(GreaterThan(0))
self.scaled_close_height.wait_for(GreaterThan(0))
- return (self.scaled_close_x, self.scaled_close_y, self.scaled_close_width, self.scaled_close_height)
+ return Rectangle(self.scaled_close_x, self.scaled_close_y, self.scaled_close_width, self.scaled_close_height)
class SpreadFilter(UnityIntrospectionObject):
diff --git a/tests/autopilot/unity/emulators/window_manager.py b/tests/autopilot/unity/emulators/window_manager.py
index 4ce550386..d07fec8ed 100644
--- a/tests/autopilot/unity/emulators/window_manager.py
+++ b/tests/autopilot/unity/emulators/window_manager.py
@@ -10,6 +10,7 @@
from __future__ import absolute_import
import logging
+from autopilot.introspection.types import Rectangle
from autopilot.keybindings import KeybindingsHelper
from unity.emulators import UnityIntrospectionObject
@@ -22,8 +23,8 @@ class WindowManager(UnityIntrospectionObject, KeybindingsHelper):
@property
def screen_geometry(self):
- """Returns a tuple of (x,y,w,h) for the screen."""
- return (self.x, self.y, self.width, self.height)
+ """Returns a Rectangle (x,y,w,h) for the screen."""
+ return self.globalRect
def initiate_spread(self):
self.keybinding("spread/start")
diff --git a/tests/autopilot/unity/tests/launcher/test_icon_behavior.py b/tests/autopilot/unity/tests/launcher/test_icon_behavior.py
index 629e6ef3d..adadfbf91 100644
--- a/tests/autopilot/unity/tests/launcher/test_icon_behavior.py
+++ b/tests/autopilot/unity/tests/launcher/test_icon_behavior.py
@@ -384,7 +384,7 @@ class LauncherDragIconsBehavior(LauncherTestCase):
self.drag_type)
moved_icon = self.unity.launcher.model.\
get_launcher_icons_for_monitor(self.launcher_monitor)[1]
- self.assertThat(moved_icon.id, Equals(calc_icon.id))
+ self.assertThat(moved_icon, Equals(calc_icon))
def test_can_drag_icon_below_window_switcher(self):
"""Application icons must be dragable to below the workspace switcher icon."""
diff --git a/tests/autopilot/unity/tests/launcher/test_visual.py b/tests/autopilot/unity/tests/launcher/test_visual.py
index f7dc8b5b5..c44e9237d 100644
--- a/tests/autopilot/unity/tests/launcher/test_visual.py
+++ b/tests/autopilot/unity/tests/launcher/test_visual.py
@@ -71,14 +71,12 @@ class LauncherVisualTests(LauncherTestCase):
def test_mouse_over_with_dash_open_desaturates_icons(self):
"""Moving mouse over launcher with dash open must saturate icons."""
- launcher_instance = self.get_launcher()
self.unity.dash.ensure_visible()
current_monitor = self.unity.dash.monitor
self.addCleanup(self.unity.dash.ensure_hidden)
sleep(.5)
- x,y,w,h = launcher_instance.geometry
- self.mouse.move(x + w/2, y + h/2)
+ self.mouse.move_to_object(self.get_launcher())
sleep(.5)
for icon in self.unity.launcher.model.get_launcher_icons():
self.assertFalse(icon.monitors_desaturated[current_monitor])
diff --git a/tests/autopilot/unity/tests/test_dash.py b/tests/autopilot/unity/tests/test_dash.py
index 56b40cb09..26fb000f7 100644
--- a/tests/autopilot/unity/tests/test_dash.py
+++ b/tests/autopilot/unity/tests/test_dash.py
@@ -400,10 +400,11 @@ class DashKeyNavTests(DashTestCase):
# Test that tab cycles through the categories.
# + 1 is the filter bar
- for i in range(scope.get_num_visible_categories()):
+ for category in scope.get_categories(only_visible=True):
self.keyboard.press_and_release('Tab')
- category = scope.get_focused_category()
- self.assertIsNot(category, None)
+ selected = scope.get_focused_category()
+ expected = category if category.expand_label_is_visible else None
+ self.assertEqual(selected, expected)
def test_tab_with_filter_bar(self):
""" This test makes sure that Tab works well with the filter bara."""
@@ -544,10 +545,7 @@ class DashClipboardTests(DashTestCase):
self.unity.dash.ensure_visible()
- self.mouse.move(self.unity.dash.searchbar.x + self.unity.dash.searchbar.width / 2,
- self.unity.dash.searchbar.y + self.unity.dash.searchbar.height / 2)
-
- self.mouse.click(button=2)
+ self.mouse.click_object(self.unity.dash.searchbar, button=2)
self.assertThat(self.unity.dash.search_string, Eventually(Equals('ThirdButtonPaste')))
@@ -691,7 +689,7 @@ class DashVisualTests(DashTestCase):
self.unity.dash.ensure_visible()
- self.assertThat(self.unity.dash.geometry[0], Eventually(Equals(launcher.geometry[0] + launcher.geometry[2] - 1)))
+ self.assertThat(self.unity.dash.view.x, Eventually(Equals(launcher.geometry.x + launcher.geometry.width - 1)))
def test_see_more_result_alignment(self):
@@ -701,11 +699,9 @@ class DashVisualTests(DashTestCase):
self.unity.dash.reveal_application_scope()
scope = self.unity.dash.get_current_scope()
- self.assertThat(lambda: len(scope.get_groups()), Eventually(GreaterThan(0), timeout=20))
-
- groups = scope.get_groups()
+ self.assertThat(lambda: len(scope.get_categories()), Eventually(GreaterThan(0), timeout=20))
- for group in groups:
+ for group in scope.get_categories():
if (group.is_visible and group.expand_label_is_visible):
expand_label_y = group.expand_label_y + group.expand_label_baseline
name_label_y = group.name_label_y + group.name_label_baseline
@@ -725,10 +721,7 @@ class DashScopeBarTests(DashTestCase):
the rectangle outside of the icon.
"""
app_icon = self.scopebar.get_icon_by_name(u'applications.scope')
-
- self.mouse.move(app_icon.x + (app_icon.width / 2),
- app_icon.y + (app_icon.height / 2))
- self.mouse.click()
+ self.mouse.click_object(app_icon)
self.assertThat(self.scopebar.active_scope, Eventually(Equals('applications.scope')))
@@ -1119,10 +1112,7 @@ class PreviewNavigateTests(DashTestCase):
cover_art = self.get_current_preview().cover_art[0]
# click the cover-art (this will set focus)
- tx = cover_art.x + (cover_art.width / 2)
- ty = cover_art.y + (cover_art.height / 2)
- self.mouse.move(tx, ty)
- self.mouse.click()
+ self.mouse.click_object(cover_art)
self.keyboard.press_and_release("Escape")
@@ -1138,13 +1128,21 @@ class PreviewNavigateTests(DashTestCase):
class PreviewClickCancelTests(DashTestCase):
"""Tests that the preview closes when left, middle, and right clicking in the preview"""
+ scenarios = [('Left button', {'clicked_button': 1}),
+ ('Middle button', {'clicked_button': 2}),
+ ('Right button', {'clicked_button': 3})]
+
def setUp(self):
super(PreviewClickCancelTests, self).setUp()
gettext.install("unity-scope-applications")
- scope = self.unity.dash.reveal_application_scope()
+ scope = self.unity.dash.reveal_application_scope(clear_search=False)
self.addCleanup(self.unity.dash.ensure_hidden)
# Only testing an application preview for this test.
- self.keyboard.type("Software Updater")
+
+ search_string = "Software Updater"
+ if self.unity.dash.search_string != search_string:
+ self.unity.dash.clear_search()
+ self.keyboard.type(search_string)
# wait for "Installed" category
category = self.wait_for_category(scope, _("Installed"))
@@ -1159,183 +1157,43 @@ class PreviewClickCancelTests(DashTestCase):
self.preview_container = self.unity.dash.view.get_preview_container()
- def test_left_click_on_preview_icon_cancel_preview(self):
- """Left click on preview icon must close preview."""
- icon = self.get_current_preview().icon[0]
- self.assertThat(icon, NotEquals(None))
-
- tx = icon.x + icon.width
- ty = icon.y + (icon.height / 2)
- self.mouse.move(tx, ty)
- self.mouse.click(button=1)
-
- self.assertThat(self.unity.dash.preview_displaying, Eventually(Equals(False)))
-
- def test_middle_click_on_preview_icon_cancel_preview(self):
- """Middle click on preview icon must close preview."""
- icon = self.get_current_preview().icon[0]
- self.assertThat(icon, NotEquals(None))
-
- tx = icon.x + icon.width
- ty = icon.y + (icon.height / 2)
- self.mouse.move(tx, ty)
- self.mouse.click(button=2)
-
- self.assertThat(self.unity.dash.preview_displaying, Eventually(Equals(False)))
-
- def test_right_click_on_preview_icon_cancel_preview(self):
- """Right click on preview icon must close preview."""
+ def test_click_on_preview_icon_cancel_preview(self):
+ """Clicking with any button on preview icon must close preview."""
icon = self.get_current_preview().icon[0]
self.assertThat(icon, NotEquals(None))
- tx = icon.x + icon.width
- ty = icon.y + (icon.height / 2)
- self.mouse.move(tx, ty)
- self.mouse.click(button=3)
-
- self.assertThat(self.unity.dash.preview_displaying, Eventually(Equals(False)))
-
- def test_left_click_on_preview_image_cancel_preview(self):
- """Left click on preview image must cancel the preview."""
- cover_art = self.get_current_preview().cover_art[0]
- self.assertThat(cover_art, NotEquals(None))
-
- tx = cover_art.x + (cover_art.width / 2)
- ty = cover_art.y + (cover_art.height / 2)
- self.mouse.move(tx, ty)
- self.mouse.click(button=1)
-
+ self.mouse.click_object(icon, button=self.clicked_button)
self.assertThat(self.unity.dash.preview_displaying, Eventually(Equals(False)))
- def test_middle_click_on_preview_image_cancel_preview(self):
- """Middle click on preview image must cancel the preview."""
+ def test_click_on_preview_image_cancel_preview(self):
+ """Clicking with any button on preview image must cancel the preview."""
cover_art = self.get_current_preview().cover_art[0]
self.assertThat(cover_art, NotEquals(None))
- tx = cover_art.x + (cover_art.width / 2)
- ty = cover_art.y + (cover_art.height / 2)
- self.mouse.move(tx, ty)
- self.mouse.click(button=2)
-
- self.assertThat(self.unity.dash.preview_displaying, Eventually(Equals(False)))
-
- def test_right_click_on_preview_image_cancel_preview(self):
- """Right click on preview image must cancel the preview."""
- cover_art = self.get_current_preview().cover_art[0]
- self.assertThat(cover_art, NotEquals(None))
-
- tx = cover_art.x + (cover_art.width / 2)
- ty = cover_art.y + (cover_art.height / 2)
- self.mouse.move(tx, ty)
- self.mouse.click(button=3)
-
- self.assertThat(self.unity.dash.preview_displaying, Eventually(Equals(False)))
-
- def test_left_click_on_preview_text_cancel_preview(self):
- """Left click on some preview text must cancel the preview."""
- text = self.get_current_preview().text_boxes[0]
- self.assertThat(text, NotEquals(None))
-
- tx = text.x + (text.width / 2)
- ty = text.y + (text.height / 2)
- self.mouse.move(tx, ty)
- self.mouse.click(button=1)
-
- self.assertThat(self.unity.dash.preview_displaying, Eventually(Equals(False)))
-
- def test_middle_click_on_preview_text_cancel_preview(self):
- """Middle click on some preview text must cancel the preview."""
- text = self.get_current_preview().text_boxes[0]
- self.assertThat(text, NotEquals(None))
-
- tx = text.x + (text.width / 2)
- ty = text.y + (text.height / 2)
- self.mouse.move(tx, ty)
- self.mouse.click(button=2)
-
+ self.mouse.click_object(cover_art, button=self.clicked_button)
self.assertThat(self.unity.dash.preview_displaying, Eventually(Equals(False)))
- def test_right_click_on_preview_text_cancel_preview(self):
- """Right click on some preview text must cancel the preview."""
+ def test_click_on_preview_text_cancel_preview(self):
+ """Clicking with any button on some preview text must cancel the preview."""
text = self.get_current_preview().text_boxes[0]
self.assertThat(text, NotEquals(None))
-
- tx = text.x + (text.width / 2)
- ty = text.y + (text.height / 2)
- self.mouse.move(tx, ty)
- self.mouse.click(button=3)
-
- self.assertThat(self.unity.dash.preview_displaying, Eventually(Equals(False)))
-
- def test_left_click_on_preview_ratings_widget_cancel_preview(self):
- """Left click on the ratings widget must cancel the preview."""
- ratings_widget = self.get_current_preview().ratings_widget[0]
- self.assertThat(ratings_widget, NotEquals(None))
-
- tx = ratings_widget.x + (ratings_widget.width / 2)
- ty = ratings_widget.y + (ratings_widget.height / 2)
- self.mouse.move(tx, ty)
- self.mouse.click(button=1)
-
- self.assertThat(self.unity.dash.preview_displaying, Eventually(Equals(False)))
-
- def test_middle_click_on_preview_ratings_widget_cancel_preview(self):
- """Middle click on the ratings widget must cancel the preview."""
- ratings_widget = self.get_current_preview().ratings_widget[0]
- self.assertThat(ratings_widget, NotEquals(None))
-
- tx = ratings_widget.x + (ratings_widget.width / 2)
- ty = ratings_widget.y + (ratings_widget.height / 2)
- self.mouse.move(tx, ty)
- self.mouse.click(button=2)
+ self.mouse.click_object(text, button=self.clicked_button)
self.assertThat(self.unity.dash.preview_displaying, Eventually(Equals(False)))
- def test_right_click_on_preview_ratings_widget_cancel_preview(self):
- """Right click on the ratings widget must cancel the preview."""
+ def test_click_on_preview_ratings_widget_cancel_preview(self):
+ """Clicking with any button on the ratings widget must cancel the preview."""
ratings_widget = self.get_current_preview().ratings_widget[0]
self.assertThat(ratings_widget, NotEquals(None))
-
- tx = ratings_widget.x + (ratings_widget.width / 2)
- ty = ratings_widget.y + (ratings_widget.height / 2)
- self.mouse.move(tx, ty)
- self.mouse.click(button=3)
+ self.mouse.click_object(ratings_widget, button=self.clicked_button)
self.assertThat(self.unity.dash.preview_displaying, Eventually(Equals(False)))
- def test_left_click_on_preview_info_hint_cancel_preview(self):
- """Left click on the info hint must cancel the preview."""
+ def test_click_on_preview_info_hint_cancel_preview(self):
+ """Clicking with any button on the info hint must cancel the preview."""
info_hint = self.get_current_preview().info_hint_widget[0]
self.assertThat(info_hint, NotEquals(None))
-
- tx = info_hint.x + (info_hint.width / 2)
- ty = info_hint.y + (info_hint.height / 8)
- self.mouse.move(tx, ty)
- self.mouse.click(button=1)
-
- self.assertThat(self.unity.dash.preview_displaying, Eventually(Equals(False)))
-
- def test_middle_click_on_preview_info_hint_cancel_preview(self):
- """Middle click on the info hint must cancel the preview."""
- info_hint = self.get_current_preview().info_hint_widget[0]
- self.assertThat(info_hint, NotEquals(None))
-
- tx = info_hint.x + (info_hint.width / 2)
- ty = info_hint.y + (info_hint.height / 8)
- self.mouse.move(tx, ty)
- self.mouse.click(button=2)
-
- self.assertThat(self.unity.dash.preview_displaying, Eventually(Equals(False)))
-
- def test_right_click_on_preview_info_hint_cancel_preview(self):
- """Right click on the info hint must cancel the preview."""
- info_hint = self.get_current_preview().info_hint_widget[0]
- self.assertThat(info_hint, NotEquals(None))
-
- tx = info_hint.x + (info_hint.width / 2)
- ty = info_hint.y + (info_hint.height / 8)
- self.mouse.move(tx, ty)
- self.mouse.click(button=3)
+ self.mouse.click_object(info_hint, button=self.clicked_button)
self.assertThat(self.unity.dash.preview_displaying, Eventually(Equals(False)))
@@ -1401,3 +1259,4 @@ class DashCrossMonitorsTests(DashTestCase):
self.addCleanup(self.unity.dash.ensure_hidden)
self.assertThat(self.unity.dash.visible, Eventually(Equals(True)))
+
diff --git a/tests/autopilot/unity/tests/test_panel.py b/tests/autopilot/unity/tests/test_panel.py
index 77da6a5b3..e5359a87a 100644
--- a/tests/autopilot/unity/tests/test_panel.py
+++ b/tests/autopilot/unity/tests/test_panel.py
@@ -78,8 +78,7 @@ class PanelTestsBase(UnityTestCase):
self.keybinding("window/restore")
self.addCleanup(self.keybinding, "window/maximize")
- sleep(.25)
- self.assertProperty(win, is_maximized=maximized)
+ self.assertThat(lambda: win.is_maximized, Eventually(Equals(maximized)))
def open_new_application_window(self, app_name, maximized=False, move_to_monitor=True):
"""Opens a new instance of the requested application, ensuring that only
@@ -93,8 +92,8 @@ class PanelTestsBase(UnityTestCase):
app = app_win.application
app_win.set_focus()
- self.assertTrue(app.is_active)
- self.assertTrue(app_win.is_focused)
+ self.assertThat(lambda: app.is_active, Eventually(Equals(True)))
+ self.assertThat(lambda: app_win.is_focused, Eventually(Equals(True)))
self.assertThat(app.desktop_file, Equals(app_win.application.desktop_file))
if move_to_monitor:
@@ -431,7 +430,6 @@ class PanelWindowButtonsTests(PanelTestsBase):
self.addCleanup(self.unity.hud.ensure_hidden)
self.panel.window_buttons.maximize.mouse_click()
-
self.assertThat(self.unity.hud.visible, Eventually(Equals(True)))
def test_hud_maximize_button_does_not_change_dash_form_factor(self):
@@ -986,7 +984,7 @@ class PanelIndicatorEntryTests(PanelTestsBase):
def open_app_and_get_menu_entry(self):
"""Open the test app and wait for the menu entry to appear."""
- self.open_new_application_window("Remmina" if self.lim else "Calculator",
+ self.open_new_application_window("Text Editor" if self.lim else "Calculator",
maximized=self.lim)
refresh_fn = lambda: len(self.panel.menus.get_entries())
@@ -1043,7 +1041,8 @@ class PanelIndicatorEntryTests(PanelTestsBase):
self.assertThat(menu_entry.active, Eventually(Equals(True)))
self.open_new_application_window("Text Editor")
- self.assertThat(self.unity.panels.get_active_indicator, Eventually(Equals(None)))
+ get_active_indicator_fn = lambda: self.unity.panels.get_active_indicator()
+ self.assertThat(get_active_indicator_fn, Eventually(Equals(None)))
def test_indicator_opens_when_dash_is_open(self):
"""When the dash is open and a click is on an indicator the dash
@@ -1068,8 +1067,9 @@ class PanelKeyNavigationTests(PanelTestsBase):
This method will wait until the active indicator has been set.
"""
- self.assertThat(self.panel.get_active_indicator, Eventually(NotEquals(None)))
- return self.panel.get_active_indicator()
+ get_active_indicator_fn = lambda: self.panel.get_active_indicator()
+ self.assertThat(get_active_indicator_fn, Eventually(NotEquals(None)))
+ return get_active_indicator_fn()
def test_panel_first_menu_show_works(self):
"""Pressing the open-menus keybinding must open the first indicator."""
@@ -1185,9 +1185,7 @@ class PanelGrabAreaTests(PanelTestsBase):
self.assertProperty(text_win, is_focused=False)
self.assertProperty(calc_win, is_focused=True)
- self.move_mouse_over_grab_area()
- self.mouse.click()
-
+ self.mouse.click_object(self.panel.grab_area, button=1)
self.assertProperty(text_win, is_focused=True)
def test_lower_the_maximized_window_works(self):
@@ -1198,8 +1196,7 @@ class PanelGrabAreaTests(PanelTestsBase):
self.assertProperty(text_win, is_focused=True)
self.assertProperty(calc_win, is_focused=False)
- self.move_mouse_over_grab_area()
- self.mouse.click(2)
+ self.mouse.click_object(self.panel.grab_area, button=2)
self.assertProperty(calc_win, is_focused=True)
@@ -1209,8 +1206,7 @@ class PanelGrabAreaTests(PanelTestsBase):
self.addCleanup(self.unity.hud.ensure_hidden)
self.keyboard.type("Hello")
- self.move_mouse_over_grab_area()
- self.mouse.click()
+ self.mouse.click_object(self.panel.grab_area)
self.keyboard.type("World")
self.assertThat(self.unity.hud.search_string, Eventually(Equals("HelloWorld")))
diff --git a/tests/autopilot/unity/tests/test_quicklist.py b/tests/autopilot/unity/tests/test_quicklist.py
index 130b1636f..c54ccc3b8 100644
--- a/tests/autopilot/unity/tests/test_quicklist.py
+++ b/tests/autopilot/unity/tests/test_quicklist.py
@@ -269,7 +269,7 @@ class QuicklistKeyNavigationTests(UnityTestCase):
def assertCorrectItemSelected(self, item):
"""Ensure the item considers itself selected and that quicklist agrees."""
self.assertThat(item.selected, Eventually(Equals(True)))
- self.assertThat(self.quicklist.selected_item.id, Equals(item.id))
+ self.assertThat(self.quicklist.selected_item, Equals(item))
def test_keynav_selects_first_item_when_unselected(self):
"""Home key MUST select the first selectable item in a quicklist."""
@@ -402,11 +402,11 @@ class QuicklistKeyNavigationTests(UnityTestCase):
# Moving the mouse horizontally doesn't change the selection
self.mouse.move(mouse_item.x + mouse_item.width - 10, mouse_item.y + mouse_item.height / 2)
- self.assertThat(self.quicklist.selected_item.id, Equals(key_item.id))
+ self.assertThat(self.quicklist.selected_item, Equals(key_item))
# Moving the mouse outside doesn't change the selection
self.mouse.move(mouse_item.x + mouse_item.width + 50, mouse_item.y + mouse_item.height / 2)
- self.assertThat(self.quicklist.selected_item.id, Equals(key_item.id))
+ self.assertThat(self.quicklist.selected_item, Equals(key_item))
# Moving the mouse to another entry, changes the selection
mouse_item = self.quicklist.selectable_items[-2]
diff --git a/tests/autopilot/unity/tests/test_spread.py b/tests/autopilot/unity/tests/test_spread.py
index 2ced00ddd..c3c5b769d 100644
--- a/tests/autopilot/unity/tests/test_spread.py
+++ b/tests/autopilot/unity/tests/test_spread.py
@@ -114,11 +114,7 @@ class SpreadTests(UnityTestCase):
target_xid = not_focused.x_id
[target_win] = [w for w in self.unity.screen.scaled_windows if w.xid == target_xid]
- (x, y, w, h) = target_win.geometry
- self.mouse.move(x + w / 2, y + h / 2)
- sleep(.5)
- self.mouse.click()
-
+ self.mouse.click_object(target_win, button=1)
self.assertThat(lambda: not_focused.is_focused, Eventually(Equals(True)))
def test_scaled_window_closes_on_middle_click(self):
@@ -129,10 +125,8 @@ class SpreadTests(UnityTestCase):
target_xid = win.x_id
[target_win] = [w for w in self.unity.screen.scaled_windows if w.xid == target_xid]
- (x, y, w, h) = target_win.geometry
- self.mouse.move(x + w / 2, y + h / 2)
- sleep(.5)
- self.mouse.click(button=2)
+ sleep(1)
+ self.mouse.click_object(target_win, button=2)
self.assertWindowIsScaledEquals(target_xid, False)
self.assertWindowIsClosed(target_xid)
@@ -146,13 +140,8 @@ class SpreadTests(UnityTestCase):
[target_win] = [w for w in self.unity.screen.scaled_windows if w.xid == target_xid]
# Make sure mouse is over the test window
- (x1, y1, w1, h1) = target_win.geometry
- self.mouse.move(x1 + w1 / 2, y1 + h1 / 2)
-
- (x, y, w, h) = target_win.scale_close_geometry
- self.mouse.move(x + w / 2, y + h / 2)
- sleep(.5)
- self.mouse.click()
+ self.mouse.move_to_object(target_win)
+ self.mouse.click_object(target_win.scale_close_geometry)
self.assertWindowIsScaledEquals(target_xid, False)
self.assertWindowIsClosed(target_xid)
diff --git a/tests/autopilot/unity/tests/test_switcher.py b/tests/autopilot/unity/tests/test_switcher.py
index 4876e9eb1..d302db10f 100644
--- a/tests/autopilot/unity/tests/test_switcher.py
+++ b/tests/autopilot/unity/tests/test_switcher.py
@@ -629,6 +629,7 @@ class SwitcherDetailsMouseTests(SwitcherTestCase):
def setUp(self):
super(SwitcherDetailsMouseTests, self).setUp()
self.set_timeout_setting(False)
+ self.mouse.move(0, 0, animate=False)
def test_mouse_highlights_switcher_icons(self):
""" Tests that the mouse can hightlight all the switcher icons. """
@@ -653,7 +654,7 @@ class SwitcherDetailsMouseTests(SwitcherTestCase):
index = 0;
for cords in icon_cords:
self.mouse.move(cords[0], cords[1])
- self.assertThat(index, Equals(self.unity.switcher.selection_index))
+ self.assertThat(self.unity.switcher.selection_index, Eventually(Equals(index)))
index += 1
def test_mouse_clicks_activate_icon(self):
@@ -691,7 +692,7 @@ class SwitcherDetailsMouseTests(SwitcherTestCase):
mouse_index = self.unity.switcher.selection_index - 1
- self.unity.switcher.view.move_over_icon(mouse_index);
+ self.unity.switcher.view.move_over_icon(mouse_index)
# Assert we are over the icon we want to hover over.
self.assertThat(self.unity.switcher.view.last_icon_selected, Eventually(Equals(mouse_index)))
@@ -724,11 +725,9 @@ class SwitcherDetailsMouseTests(SwitcherTestCase):
self.unity.switcher.initiate(SwitcherMode.DETAIL)
self.addCleanup(self.unity.switcher.terminate)
- index = 0;
- for icon in self.unity.switcher.view.detail_icons:
+ for index in range(len(self.unity.switcher.view.detail_icons)):
self.unity.switcher.view.move_over_detail_icon(index)
- self.assertThat(index, Equals(self.unity.switcher.detail_selection_index))
- index += 1
+ self.assertThat(self.unity.switcher.detail_selection_index, Eventually(Equals(index)))
def test_mouse_click_will_activate_detail_icon(self):
"""
diff --git a/tests/bamf-mock-application.c b/tests/bamf-mock-application.c
index fd803324e..5d724716d 100644
--- a/tests/bamf-mock-application.c
+++ b/tests/bamf-mock-application.c
@@ -99,10 +99,24 @@ bamf_mock_application_set_icon (BamfMockApplication * self, const gchar * icon)
void
bamf_mock_application_set_children (BamfMockApplication * self, GList * children)
{
+ GList *l;
+
g_return_if_fail (BAMF_IS_MOCK_APPLICATION (self));
- g_list_free (self->priv->children);
- self->priv->children = g_list_copy (children);
+ for (l = self->priv->children; l;)
+ {
+ GList *next = l->next;
+ BamfView *view = l->data;
+ self->priv->children = g_list_delete_link (self->priv->children, l);
+ g_signal_emit_by_name (G_OBJECT (self), "child-removed", view);
+ l = next;
+ }
+
+ for (l = g_list_last (children); l; l = l->prev)
+ {
+ self->priv->children = g_list_prepend (self->priv->children, l->data);
+ g_signal_emit_by_name (G_OBJECT (self), "child-added", l->data);
+ }
}
static void
diff --git a/tests/mock-application.h b/tests/mock-application.h
index 5b53f5b0f..312168854 100644
--- a/tests/mock-application.h
+++ b/tests/mock-application.h
@@ -46,6 +46,7 @@ struct MockApplicationWindow : unity::ApplicationWindow
, active_(false)
, urgent_(false)
{
+ monitor.SetGetterFunction([this] { return monitor_; });
visible.SetGetterFunction([this] { return visible_; });
active.SetGetterFunction([this] { return active_; });
urgent.SetGetterFunction([this] { return urgent_; });
@@ -54,7 +55,6 @@ struct MockApplicationWindow : unity::ApplicationWindow
ON_CALL(*this, type()).WillByDefault(Invoke([this] { return type_; }));
ON_CALL(*this, window_id()).WillByDefault(Invoke([this] { return xid_; }));
- ON_CALL(*this, monitor()).WillByDefault(Invoke([this] { return monitor_; }));
ON_CALL(*this, Focus()).WillByDefault(Invoke([this] { return LocalFocus(); }));
ON_CALL(*this, application()).WillByDefault(Return(unity::ApplicationPtr()));
}
@@ -71,7 +71,6 @@ struct MockApplicationWindow : unity::ApplicationWindow
MOCK_CONST_METHOD0(type, unity::WindowType());
MOCK_CONST_METHOD0(window_id, Window());
- MOCK_CONST_METHOD0(monitor, int());
MOCK_CONST_METHOD0(application, unity::ApplicationPtr());
MOCK_CONST_METHOD0(Focus, bool());
MOCK_CONST_METHOD0(Quit, void());
@@ -144,7 +143,7 @@ struct MockApplication : unity::Application
ON_CALL(*this, type()).WillByDefault(Invoke([this] { return type_; }));
ON_CALL(*this, desktop_id()).WillByDefault(Invoke([this] { return desktop_file_; }));
ON_CALL(*this, repr()).WillByDefault(Return("MockApplication"));
- ON_CALL(*this, GetWindows()).WillByDefault(Invoke([this] { return windows_; }));
+ ON_CALL(*this, GetWindows()).WillByDefault(Invoke([this] () -> unity::WindowList const& { return windows_; }));
ON_CALL(*this, GetSupportedMimeTypes()).WillByDefault(Return(std::vector<std::string>()));
ON_CALL(*this, GetFocusableWindow()).WillByDefault(Return(unity::ApplicationWindowPtr()));
ON_CALL(*this, OwnsWindow(_)).WillByDefault(Invoke(this, &MockApplication::LocalOwnsWindow));
@@ -167,7 +166,7 @@ struct MockApplication : unity::Application
MOCK_CONST_METHOD0(type, unity::AppType());
MOCK_CONST_METHOD0(repr, std::string());
MOCK_CONST_METHOD0(desktop_id, std::string());
- MOCK_CONST_METHOD0(GetWindows, unity::WindowList());
+ MOCK_CONST_METHOD0(GetWindows, unity::WindowList const&());
MOCK_CONST_METHOD1(OwnsWindow, bool(Window));
MOCK_CONST_METHOD0(GetSupportedMimeTypes, std::vector<std::string>());
MOCK_CONST_METHOD0(GetFocusableWindow, unity::ApplicationWindowPtr());
diff --git a/tests/test_bamf_application.cpp b/tests/test_bamf_application.cpp
index fa0b72a0d..56b2052a6 100644
--- a/tests/test_bamf_application.cpp
+++ b/tests/test_bamf_application.cpp
@@ -56,6 +56,8 @@ struct TestBamfApplication : public testing::Test
TEST_F(TestBamfApplication, GetWindows)
{
+ ASSERT_EQ(application_.GetWindows().size(), 0);
+
GList* children = nullptr;
for (int i = 0; i<5; ++i)
{
@@ -71,8 +73,7 @@ TEST_F(TestBamfApplication, GetWindows)
AddFakeWindowToWM(3, true);
AddFakeWindowToWM(4, false);
- auto windows = application_.GetWindows();
- ASSERT_EQ(windows.size(), 5);
+ EXPECT_EQ(application_.GetWindows().size(), 5);
g_list_free_full(children, g_object_unref);
}
diff --git a/unity-shared/ApplicationManager.h b/unity-shared/ApplicationManager.h
index 24b97e5e9..c0f681a5e 100644
--- a/unity-shared/ApplicationManager.h
+++ b/unity-shared/ApplicationManager.h
@@ -80,7 +80,6 @@ public:
virtual WindowType type() const = 0;
virtual Window window_id() const = 0;
- virtual int monitor() const = 0;
// It is possible for this to be null, especially in situations where
// the application is starting up or shutting down.
@@ -101,6 +100,8 @@ public:
return !(operator==(other));
}
+ nux::ROProperty<int> monitor;
+
nux::ROProperty<std::string> title;
nux::ROProperty<std::string> icon;
@@ -121,7 +122,7 @@ public:
// A string representation of the object.
virtual std::string repr() const = 0;
- virtual WindowList GetWindows() const = 0;
+ virtual WindowList const& GetWindows() const = 0;
virtual bool OwnsWindow(Window window_id) const = 0;
virtual std::vector<std::string> GetSupportedMimeTypes() const = 0;
diff --git a/unity-shared/BamfApplicationManager.cpp b/unity-shared/BamfApplicationManager.cpp
index d96255af2..2a16228a7 100644
--- a/unity-shared/BamfApplicationManager.cpp
+++ b/unity-shared/BamfApplicationManager.cpp
@@ -145,6 +145,10 @@ WindowBase::WindowBase(ApplicationManager const& manager,
[this] (BamfView*, gboolean urgent) {
this->urgent.changed.emit(urgent);
});
+ signals_.Add<void, BamfView*>(bamf_view_, "closed",
+ [this] (BamfView* view) {
+ pool::wins_.erase(view);
+ });
}
bool WindowBase::Focus() const
@@ -170,7 +174,13 @@ AppWindow::AppWindow(ApplicationManager const& manager, glib::Object<BamfView> c
: WindowBase(manager, window)
, bamf_window_(glib::object_cast<BamfWindow>(window))
{
+ monitor.SetGetterFunction(std::bind(&AppWindow::GetMonitor, this));
maximized.SetGetterFunction(std::bind(&AppWindow::GetMaximized, this));
+
+ signals_.Add<void, BamfWindow*, gint, gint>(bamf_window_, "monitor-changed",
+ [this] (BamfWindow*, gint, gint monitor) {
+ this->monitor.changed.emit(monitor);
+ });
signals_.Add<void, BamfWindow*, gint, gint>(bamf_window_, "maximized-changed",
[this] (BamfWindow*, gint old_state, gint state) {
if ((old_state == BAMF_WINDOW_MAXIMIZED) != (state == BAMF_WINDOW_MAXIMIZED))
@@ -178,6 +188,11 @@ AppWindow::AppWindow(ApplicationManager const& manager, glib::Object<BamfView> c
});
}
+int AppWindow::GetMonitor() const
+{
+ return bamf_window_get_monitor(bamf_window_);
+}
+
bool AppWindow::GetMaximized() const
{
return bamf_window_maximized(bamf_window_) == BAMF_WINDOW_MAXIMIZED;
@@ -188,11 +203,6 @@ Window AppWindow::window_id() const
return bamf_window_get_xid(bamf_window_);
}
-int AppWindow::monitor() const
-{
- return bamf_window_get_monitor(bamf_window_);
-}
-
WindowType AppWindow::type() const
{
switch (bamf_window_get_window_type(bamf_window_))
@@ -231,14 +241,15 @@ void AppWindow::Quit() const
WindowManager::Default().Close(window_id());
}
-Tab::Tab(ApplicationManager const& manager, glib::Object<BamfView> const& tab)
- : WindowBase(manager, tab)
- , bamf_tab_(glib::object_cast<BamfTab>(tab))
-{}
-
Tab::Tab(ApplicationManager const& manager, glib::Object<BamfTab> const& tab)
: WindowBase(manager, glib::object_cast<BamfView>(tab))
, bamf_tab_(tab)
+{
+ monitor.SetGetterFunction([] { return -1; });
+}
+
+Tab::Tab(ApplicationManager const& manager, glib::Object<BamfView> const& tab)
+ : Tab(manager_, glib::object_cast<BamfTab>(tab))
{}
Window Tab::window_id() const
@@ -251,12 +262,6 @@ WindowType Tab::type() const
return WindowType::TAB;
}
-int Tab::monitor() const
-{
- // TODO, we could find the real window for the window_id, and get the monitor for that.
- return -1;
-}
-
ApplicationPtr Tab::application() const
{
// TODO, we could find the real window for the window_id, and return the application for that.
@@ -323,6 +328,7 @@ Application::Application(ApplicationManager const& manager, glib::Object<BamfApp
signals_.Add<void, BamfView*, gboolean>(bamf_view_, "running-changed",
[this] (BamfView*, gboolean running) {
LOG_TRACE(logger) << "running " << visible;
+ UpdateWindows();
this->running.changed.emit(running);
});
signals_.Add<void, BamfView*, gboolean>(bamf_view_, "urgent-changed",
@@ -330,21 +336,34 @@ Application::Application(ApplicationManager const& manager, glib::Object<BamfApp
this->urgent.changed.emit(urgent);
});
signals_.Add<void, BamfView*>(bamf_view_, "closed",
- [this] (BamfView*) {
+ [this] (BamfView* view) {
+ UpdateWindows();
this->closed.emit();
+
+ if (!sticky())
+ pool::apps_.erase(view);
});
signals_.Add<void, BamfView*, BamfView*>(bamf_view_, "child-added",
[this] (BamfView*, BamfView* child) {
// Ownership is not passed on signals
if (ApplicationWindowPtr const& win = pool::EnsureWindow(manager_, child))
- this->window_opened.emit(win);
+ {
+ if (std::find(windows_.begin(), windows_.end(), win) == windows_.end())
+ {
+ windows_.push_back(win);
+ this->window_opened.emit(win);
+ }
+ }
});
signals_.Add<void, BamfView*, BamfView*>(bamf_view_, "child-removed",
[this] (BamfView*, BamfView* child) {
if (ApplicationWindowPtr const& win = pool::EnsureWindow(manager_, child))
+ {
+ windows_.erase(std::remove(windows_.begin(), windows_.end(), win), windows_.end());
this->window_closed.emit(win);
+ }
});
signals_.Add<void, BamfView*, BamfView*>(bamf_view_, "child-moved",
@@ -353,6 +372,8 @@ Application::Application(ApplicationManager const& manager, glib::Object<BamfApp
if (ApplicationWindowPtr const& win = pool::EnsureWindow(manager_, child))
this->window_moved.emit(win);
});
+
+ UpdateWindows();
}
std::string Application::GetDesktopFile() const
@@ -384,20 +405,38 @@ std::string Application::repr() const
return sout.str();
}
-WindowList Application::GetWindows() const
+WindowList const& Application::GetWindows() const
{
- WindowList result;
+ return windows_;
+}
- if (!bamf_app_)
- return result;
+void Application::UpdateWindows()
+{
+ if (!bamf_app_ || !running() || bamf_view_is_closed(bamf_view_))
+ {
+ for (auto it = windows_.begin(); it != windows_.end();)
+ {
+ window_closed.emit(*it);
+ it = windows_.erase(it);
+ }
+
+ return;
+ }
+
+ bool was_empty = windows_.empty();
std::shared_ptr<GList> children(bamf_view_get_children(bamf_view_), g_list_free);
for (GList* l = children.get(); l; l = l->next)
{
if (ApplicationWindowPtr const& window = pool::EnsureWindow(manager_, static_cast<BamfView*>(l->data)))
- result.push_back(window);
+ {
+ if (was_empty || std::find(windows_.begin(), windows_.end(), window) == windows_.end())
+ {
+ windows_.push_back(window);
+ window_opened.emit(window);
+ }
+ }
}
- return result;
}
bool Application::OwnsWindow(Window window_id) const
@@ -405,15 +444,13 @@ bool Application::OwnsWindow(Window window_id) const
if (!window_id)
return false;
- bool owns = false;
- std::shared_ptr<GList> children(bamf_view_get_children(bamf_view_), g_list_free);
- for (GList* l = children.get(); l && !owns; l = l->next)
+ for (auto const& win : windows_)
{
- owns = BAMF_IS_WINDOW(l->data) &&
- bamf_window_get_xid(static_cast<BamfWindow*>(l->data)) == window_id;
+ if (win->window_id() == window_id)
+ return true;
}
- return owns;
+ return false;
}
std::vector<std::string> Application::GetSupportedMimeTypes() const
@@ -515,7 +552,7 @@ bool Application::GetSeen() const
g_quark_from_string(UNSEEN_QUARK));
}
-bool Application::SetSeen(bool const& param)
+bool Application::SetSeen(bool param)
{
bool is_seen = GetSeen();
if (param == is_seen)
@@ -533,12 +570,15 @@ bool Application::GetSticky() const
return bamf_view_is_sticky(bamf_view_);
}
-bool Application::SetSticky(bool const& param)
+bool Application::SetSticky(bool param)
{
bool is_sticky = GetSticky();
if (param == is_sticky)
return false; // unchanged
+ if (!param && bamf_view_is_closed(bamf_view_))
+ pool::apps_.erase(bamf_view_);
+
bamf_view_set_sticky(bamf_view_, param);
return true; // value updated
}
@@ -640,6 +680,12 @@ ApplicationWindowPtr Manager::GetWindowForId(Window xid) const
if (xid == 0)
return nullptr;
+ for (auto const& win_pair : pool::wins_)
+ {
+ if (win_pair.second->window_id() == xid)
+ return win_pair.second;
+ }
+
// TODO: use bamf_matcher_get_window_for_xid
auto* app = bamf_matcher_get_application_for_xid(matcher_, xid);
@@ -724,16 +770,14 @@ void Manager::OnViewClosed(BamfMatcher* matcher, BamfView* view)
{
if (ApplicationPtr const& app = pool::EnsureApplication(*this, view))
application_stopped.emit(app);
-
- pool::apps_.erase(view);
}
else if (BAMF_IS_WINDOW(view))
{
if (ApplicationWindowPtr const& win = pool::EnsureWindow(*this, view))
window_closed.emit(win);
-
- pool::wins_.erase(view);
}
+
+ /* No removal here, it's done inside views, as 'closed' signal arrives later */
}
} // namespace bamf
diff --git a/unity-shared/BamfApplicationManager.h b/unity-shared/BamfApplicationManager.h
index 6dacac12e..74503a9aa 100644
--- a/unity-shared/BamfApplicationManager.h
+++ b/unity-shared/BamfApplicationManager.h
@@ -49,6 +49,7 @@ public:
protected:
ApplicationManager const& manager_;
glib::Object<BamfView> bamf_view_;
+ glib::SignalManager signals_;
};
@@ -66,9 +67,6 @@ public:
return static_cast<WindowBase const*>(this)->bamf_view_ == static_cast<WindowBase const&>(other).bamf_view_;
}
bool operator!=(unity::ApplicationWindow const& other) const override { return !(operator==(other)); }
-
-protected:
- glib::SignalManager signals_;
};
// NOTE: Can't use Window as a type as there is a #define for Window to some integer value.
@@ -82,12 +80,13 @@ public:
WindowType type() const override;
Window window_id() const override;
- int monitor() const override;
ApplicationPtr application() const override;
void Quit() const override;
- bool GetMaximized() const;
private:
+ int GetMonitor() const;
+ bool GetMaximized() const;
+
glib::Object<BamfWindow> bamf_window_;
};
@@ -101,7 +100,6 @@ public:
WindowType type() const override;
Window window_id() const override;
- int monitor() const override;
ApplicationPtr application() const override;
bool Focus() const override;
void Quit() const override;
@@ -121,7 +119,7 @@ public:
virtual AppType type() const;
- virtual WindowList GetWindows() const;
+ virtual WindowList const& GetWindows() const;
virtual bool OwnsWindow(Window window_id) const;
virtual std::vector<std::string> GetSupportedMimeTypes() const;
@@ -145,13 +143,16 @@ private: // Property getters and setters
std::string GetDesktopFile() const;
bool GetSeen() const;
- bool SetSeen(bool const& param);
+ bool SetSeen(bool param);
bool GetSticky() const;
- bool SetSticky(bool const& param);
+ bool SetSticky(bool param);
+
+ void UpdateWindows();
private:
glib::Object<::BamfApplication> bamf_app_;
+ WindowList windows_;
glib::SignalManager signals_;
std::string type_;
};
diff --git a/unity-shared/IconTexture.cpp b/unity-shared/IconTexture.cpp
index 901228ccf..4b3cfa9eb 100644
--- a/unity-shared/IconTexture.cpp
+++ b/unity-shared/IconTexture.cpp
@@ -281,8 +281,10 @@ void IconTexture::GetTextureSize(int* width, int* height)
void IconTexture::SetOpacity(float opacity)
{
- _opacity = opacity;
+ if (_opacity == opacity)
+ return;
+ _opacity = opacity;
QueueDraw();
}
diff --git a/unity-shared/PluginAdapter.cpp b/unity-shared/PluginAdapter.cpp
index 189f9480c..8979fc785 100644
--- a/unity-shared/PluginAdapter.cpp
+++ b/unity-shared/PluginAdapter.cpp
@@ -781,7 +781,10 @@ void PluginAdapter::UnMinimize(Window window_id)
{
CompWindow* window = m_Screen->findWindow(window_id);
if (window && (window->actions() & CompWindowActionMinimizeMask))
+ {
window->unminimize();
+ window->show();
+ }
}
void PluginAdapter::Shade(Window window_id)
@@ -962,6 +965,7 @@ void PluginAdapter::FocusWindowGroup(std::vector<Window> const& window_ids,
if (forced_unminimize)
{
top_window->unminimize();
+ top_window->show();
}
top_window->raise();
diff --git a/unity-shared/StandaloneAppManager.cpp b/unity-shared/StandaloneAppManager.cpp
index 388ada139..f3978e75a 100644
--- a/unity-shared/StandaloneAppManager.cpp
+++ b/unity-shared/StandaloneAppManager.cpp
@@ -81,6 +81,22 @@ std::ostream& operator<<(std::ostream &os, WindowType wt)
return os;
}
+void connect_window_events(ApplicationWindowPtr const& win)
+{
+ win->title.changed.connect([win] (std::string const& t) {
+ std::cout << "Window "<< win->window_id()<< " title changed to "<< t << endl;
+ });
+ win->maximized.changed.connect([win] (bool m) {
+ std::cout << "Window "<< win->window_id()<< " maximized changed to "<< m << endl;
+ });
+ win->monitor.changed.connect([win] (int m) {
+ std::cout << "Window "<< win->window_id()<< " monitor changed to "<< m << endl;
+ });
+ win->active.changed.connect([win] (bool a) {
+ std::cout << "Window "<< win->window_id()<< " active changed to "<< a << endl;
+ });
+}
+
void dump_app(ApplicationPtr const& app, std::string const& prefix = "")
{
if (app)
@@ -153,6 +169,7 @@ void connect_events(ApplicationPtr const& app)
});
app->window_opened.connect([idx](ApplicationWindowPtr const& window) {
cout << "** " << names[idx] << " window opened: " << window->title() << endl;
+ connect_window_events(window);
});
app->window_closed.connect([idx](ApplicationWindowPtr const& window) {
cout << "** " << names[idx] << " window closed: " << window->title() << endl;
@@ -163,21 +180,10 @@ void connect_events(ApplicationPtr const& app)
app->seen = true;
for (auto win : app->GetWindows())
- {
- win->title.changed.connect([win] (std::string const& t) {
- std::cout << "Window "<< win->window_id()<< " title changed to "<< t << endl;
- });
- win->maximized.changed.connect([win] (bool m) {
- std::cout << "Window "<< win->window_id()<< " maximized changed to "<< m << endl;
- });
- win->active.changed.connect([win] (bool a) {
- std::cout << "Window "<< win->window_id()<< " active changed to "<< a << endl;
- });
- }
+ connect_window_events(win);
}
-
nux::logging::Level glog_level_to_nux(GLogLevelFlags log_level)
{
// For some weird reason, ERROR is more critical than CRITICAL in gnome.
diff --git a/unity-shared/WindowButtons.cpp b/unity-shared/WindowButtons.cpp
index 613fdb1dc..6ddbc59ab 100644
--- a/unity-shared/WindowButtons.cpp
+++ b/unity-shared/WindowButtons.cpp
@@ -234,14 +234,14 @@ void WindowButton::AddProperties(debug::IntrospectionData& introspection)
}
introspection.add(GetAbsoluteGeometry())
- .add("type", type_name)
- .add("visible", IsVisible() && Parent()->opacity() != 0.0f)
- .add("sensitive", Parent()->GetInputEventSensitivity())
- .add("enabled", enabled())
- .add("visual_state", state_name)
- .add("opacity", Parent()->opacity())
- .add("focused", Parent()->focused())
- .add("overlay_mode", overlay_mode());
+ .add("type", type_name)
+ .add("visible", IsVisible() && Parent()->opacity() != 0.0f)
+ .add("sensitive", Parent()->GetInputEventSensitivity())
+ .add("enabled", enabled())
+ .add("visual_state", state_name)
+ .add("opacity", Parent()->opacity())
+ .add("focused", Parent()->focused())
+ .add("overlay_mode", overlay_mode());
}
} // Internal Namespace