summaryrefslogtreecommitdiff
diff options
authorMarco Trevisan (TreviƱo) <mail@3v1n0.net>2014-02-18 16:52:35 +0000
committerCI bot <ps-jenkins@lists.canonical.com>2014-02-18 16:52:35 +0000
commit5552af01f7a0d146fdf92a7c1c9181c90ac116f0 (patch)
tree2a830786d7145179f22af886a20167d37d48b0e1
parent4a7c9922101362e50ef439d63ee4735264bd1251 (diff)
parent7784579293f26ca8e83f9c934ad814cce8d8fede (diff)
UnityScreen: add a SpreadFilter when in Scale mode, when updated it filters the scale results
The SpreadFilter is a BaseWindow with a SearchBar shown on the top-left corner of the active workspace that is hidden by default monitoring key-presses; when some content is written, the bar is shown, while is hidden when empty. Thanks to this we can finally filter the windows by name in the unity spread! Fixes: 1281257 (bzr r3668)
-rw-r--r--plugins/unityshell/src/unityshell.cpp90
-rw-r--r--plugins/unityshell/src/unityshell.h4
-rw-r--r--plugins/unityshell/unityshell.xml.in1
-rw-r--r--shutdown/SessionController.h1
-rw-r--r--tests/CMakeLists.txt1
-rw-r--r--tests/autopilot/unity/emulators/screen.py23
-rw-r--r--tests/autopilot/unity/tests/test_spread.py57
-rw-r--r--tests/test_spread_filter.cpp116
-rw-r--r--unity-shared/CMakeLists.txt1
-rw-r--r--unity-shared/PluginAdapter.cpp10
-rw-r--r--unity-shared/SearchBar.cpp69
-rw-r--r--unity-shared/SearchBar.h3
-rw-r--r--unity-shared/SpreadFilter.cpp121
-rw-r--r--unity-shared/SpreadFilter.h64
14 files changed, 476 insertions, 85 deletions
diff --git a/plugins/unityshell/src/unityshell.cpp b/plugins/unityshell/src/unityshell.cpp
index cdaa6dcd9..340844006 100644
--- a/plugins/unityshell/src/unityshell.cpp
+++ b/plugins/unityshell/src/unityshell.cpp
@@ -137,10 +137,8 @@ const unsigned int SCROLL_DOWN_BUTTON = 6;
const unsigned int SCROLL_UP_BUTTON = 7;
const int MAX_BUFFER_AGE = 11;
const int FRAMES_TO_REDRAW_ON_RESUME = 10;
-
const std::string RELAYOUT_TIMEOUT = "relayout-timeout";
} // namespace local
-
} // anon namespace
UnityScreen::UnityScreen(CompScreen* screen)
@@ -149,6 +147,7 @@ UnityScreen::UnityScreen(CompScreen* screen)
, screen(screen)
, cScreen(CompositeScreen::get(screen))
, gScreen(GLScreen::get(screen))
+ , sScreen(ScaleScreen::get(screen))
, menus_(std::make_shared<menu::Manager>(std::make_shared<indicator::DBusIndicators>(), std::make_shared<key::GnomeGrabber>()))
, deco_manager_(std::make_shared<decoration::Manager>())
, debugger_(this)
@@ -511,13 +510,28 @@ void UnityScreen::initAltTabNextWindow()
void UnityScreen::OnInitiateSpread()
{
- for (auto const& swin : ScaleScreen::get(screen)->getWindows())
+ spread_filter_ = std::make_shared<spread::Filter>();
+ spread_filter_->text.changed.connect([this] (std::string const& filter) {
+ if (filter.empty())
+ {
+ sScreen->relayoutSlots(CompMatch::emptyMatch);
+ }
+ else
+ {
+ auto match = sScreen->getCustomMatch();
+ sScreen->relayoutSlots(match & ("ititle="+filter));
+ }
+ });
+
+ for (auto const& swin : sScreen->getWindows())
UnityWindow::get(swin->window)->OnInitiateSpread();
}
void UnityScreen::OnTerminateSpread()
{
- for (auto const& swin : ScaleScreen::get(screen)->getWindows())
+ spread_filter_.reset();
+
+ for (auto const& swin : sScreen->getWindows())
UnityWindow::get(swin->window)->OnTerminateSpread();
}
@@ -1680,8 +1694,7 @@ void UnityScreen::handleEvent(XEvent* event)
case MotionNotify:
if (wm.IsScaleActive())
{
- ScaleScreen* ss = ScaleScreen::get(screen);
- if (CompWindow *w = screen->findWindow(ss->getSelectedWindow()))
+ if (CompWindow *w = screen->findWindow(sScreen->getSelectedWindow()))
skip_other_plugins = UnityWindow::get(w)->handleEvent(event);
}
else if (switcher_controller_->IsDetailViewShown())
@@ -1706,9 +1719,14 @@ void UnityScreen::handleEvent(XEvent* event)
}
if (wm.IsScaleActive())
{
- ScaleScreen* ss = ScaleScreen::get(screen);
- if (CompWindow *w = screen->findWindow(ss->getSelectedWindow()))
- skip_other_plugins = UnityWindow::get(w)->handleEvent(event);
+ if (spread_filter_ && spread_filter_->Visible())
+ skip_other_plugins = spread_filter_->GetAbsoluteGeometry().IsPointInside(event->xbutton.x_root, event->xbutton.y_root);
+
+ if (!skip_other_plugins)
+ {
+ if (CompWindow *w = screen->findWindow(sScreen->getSelectedWindow()))
+ skip_other_plugins = UnityWindow::get(w)->handleEvent(event);
+ }
}
else if (switcher_controller_->IsDetailViewShown())
{
@@ -1782,9 +1800,14 @@ void UnityScreen::handleEvent(XEvent* event)
}
else if (wm.IsScaleActive())
{
- ScaleScreen* ss = ScaleScreen::get(screen);
- if (CompWindow *w = screen->findWindow(ss->getSelectedWindow()))
- skip_other_plugins = UnityWindow::get(w)->handleEvent(event);
+ if (spread_filter_ && spread_filter_->Visible())
+ skip_other_plugins = spread_filter_->GetAbsoluteGeometry().IsPointInside(event->xbutton.x_root, event->xbutton.y_root);
+
+ if (!skip_other_plugins)
+ {
+ if (CompWindow *w = screen->findWindow(sScreen->getSelectedWindow()))
+ skip_other_plugins = skip_other_plugins || UnityWindow::get(w)->handleEvent(event);
+ }
}
break;
case KeyPress:
@@ -1853,6 +1876,16 @@ void UnityScreen::handleEvent(XEvent* event)
EnableCancelAction(CancelActionTarget::LAUNCHER_SWITCHER, false);
}
}
+
+ if (spread_filter_ && spread_filter_->Visible())
+ {
+ if (key_sym == XK_Escape)
+ {
+ skip_other_plugins = true;
+ spread_filter_->text = "";
+ }
+ }
+
break;
}
case MapRequest:
@@ -1866,22 +1899,21 @@ void UnityScreen::handleEvent(XEvent* event)
}
break;
default:
- if (screen->shapeEvent () + ShapeNotify == event->type)
+ if (screen->shapeEvent() + ShapeNotify == event->type)
{
Window xid = event->xany.window;
CompWindow *w = screen->findWindow(xid);
if (w)
{
- UnityWindow *uw = UnityWindow::get (w);
-
+ UnityWindow *uw = UnityWindow::get(w);
uw->handleEvent(event);
}
}
break;
}
- compiz::CompizMinimizedWindowHandler<UnityScreen, UnityWindow>::handleEvent (event);
+ compiz::CompizMinimizedWindowHandler<UnityScreen, UnityWindow>::handleEvent(event);
// avoid further propagation (key conflict for instance)
if (!skip_other_plugins)
@@ -1890,19 +1922,18 @@ void UnityScreen::handleEvent(XEvent* event)
if (deco_manager_->HandleEventAfter(event))
return;
- switch (event->type)
- {
- case MapRequest:
- ShowdesktopHandler::AllowLeaveShowdesktopMode(event->xmaprequest.window);
- break;
- }
+ if (event->type == MapRequest)
+ ShowdesktopHandler::AllowLeaveShowdesktopMode(event->xmaprequest.window);
- if ((event->type == MotionNotify || event->type == ButtonPress || event->type == ButtonRelease) &&
- switcher_controller_->IsMouseDisabled() && switcher_controller_->Visible())
+ if (switcher_controller_->IsMouseDisabled() && switcher_controller_->Visible() &&
+ (event->type == MotionNotify || event->type == ButtonPress || event->type == ButtonRelease))
{
skip_other_plugins = true;
}
+ if (spread_filter_ && spread_filter_->Visible())
+ skip_other_plugins = false;
+
if (!skip_other_plugins &&
screen->otherGrabExist("deco", "move", "switcher", "resize", nullptr))
{
@@ -2786,7 +2817,7 @@ bool UnityWindow::glPaint(const GLWindowPaintAttrib& attrib,
}
if (WindowManager::Default().IsScaleActive() &&
- ScaleScreen::get(screen)->getSelectedWindow() == window->id())
+ uScreen->sScreen->getSelectedWindow() == window->id())
{
nux::Geometry const& scaled_geo = GetScaledGeometry();
paintInnerGlow(scaled_geo, matrix, attrib, mask);
@@ -3737,7 +3768,7 @@ UnityWindow::UnityWindow(CompWindow* window)
void UnityWindow::AddProperties(debug::IntrospectionData& introspection)
{
Window xid = window->id();
- auto const& swins = ScaleScreen::get(screen)->getWindows();
+ auto const& swins = uScreen->sScreen->getWindows();
bool scaled = std::find(swins.begin(), swins.end(), ScaleWindow::get(window)) != swins.end();
WindowManager& wm = WindowManager::Default();
@@ -3942,8 +3973,7 @@ void UnityWindow::scalePaintDecoration(GLWindowPaintAttrib const& attrib,
if (!scale_win->hasSlot()) // animation not finished
return;
- ScaleScreen* ss = ScaleScreen::get(screen);
- auto state = ss->getState();
+ auto state = uScreen->sScreen->getState();
if (state != ScaleScreen::Wait && state != ScaleScreen::Out)
return;
@@ -3953,7 +3983,7 @@ void UnityWindow::scalePaintDecoration(GLWindowPaintAttrib const& attrib,
auto deco_attrib = attrib;
deco_attrib.opacity = COMPIZ_COMPOSITE_OPAQUE;
- bool highlighted = (ss->getSelectedWindow() == window->id());
+ bool highlighted = (uScreen->sScreen->getSelectedWindow() == window->id());
paintFakeDecoration(scale_geo, deco_attrib, transform, mask, highlighted, pos.scale);
}
@@ -4130,7 +4160,7 @@ void ScreenIntrospection::AddProperties(debug::IntrospectionData& introspection)
Introspectable::IntrospectableList ScreenIntrospection::GetIntrospectableChildren()
{
- IntrospectableList children;
+ IntrospectableList children({uScreen->spread_filter_.get()});
for (auto const& win : screen_->windows())
children.push_back(UnityWindow::get(win));
diff --git a/plugins/unityshell/src/unityshell.h b/plugins/unityshell/src/unityshell.h
index bbb94ece4..a9594f7c2 100644
--- a/plugins/unityshell/src/unityshell.h
+++ b/plugins/unityshell/src/unityshell.h
@@ -65,6 +65,7 @@
#include "ScreenIntrospection.h"
#include "SwitcherController.h"
#include "SessionController.h"
+#include "SpreadFilter.h"
#include "UBusWrapper.h"
#include "UnityshellPrivate.h"
#include "UnityShowdesktopHandler.h"
@@ -118,6 +119,7 @@ public:
CompScreen* screen;
CompositeScreen* cScreen;
GLScreen* gScreen;
+ ScaleScreen* sScreen;
/* prepares nux for drawing */
void nuxPrologue();
@@ -327,6 +329,7 @@ private:
session::Controller::Ptr session_controller_;
debug::DebugDBusInterface debugger_;
std::unique_ptr<BGHash> bghash_;
+ spread::Filter::Ptr spread_filter_;
/* Subscription for gestures that manipulate Unity launcher */
std::unique_ptr<nux::GesturesSubscription> gestures_sub_launcher_;
@@ -407,6 +410,7 @@ private:
bool is_desktop_active_;
friend class UnityWindow;
+ friend class debug::ScreenIntrospection;
friend class decoration::Manager;
};
diff --git a/plugins/unityshell/unityshell.xml.in b/plugins/unityshell/unityshell.xml.in
index ac484f319..87e8d618e 100644
--- a/plugins/unityshell/unityshell.xml.in
+++ b/plugins/unityshell/unityshell.xml.in
@@ -43,6 +43,7 @@
</requirement>
<conflict>
<plugin>decor</plugin>
+ <plugin>scalefilter</plugin>
</conflict>
</deps>
diff --git a/shutdown/SessionController.h b/shutdown/SessionController.h
index 3c5ab97ce..59fe6a9c7 100644
--- a/shutdown/SessionController.h
+++ b/shutdown/SessionController.h
@@ -25,7 +25,6 @@
#include <Nux/Nux.h>
#include <Nux/BaseWindow.h>
#include <Nux/HLayout.h>
-#include <NuxCore/Color.h>
#include <NuxCore/Animation.h>
#include <UnityCore/SessionManager.h>
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 770ed22b0..86f88a772 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -278,6 +278,7 @@ if (ENABLE_X_SUPPORT)
test_single_monitor_launcher_icon.cpp
test_showdesktop_handler.cpp
test_software_center_launcher_icon.cpp
+ test_spread_filter.cpp
test_static_cairo_text.cpp
test_switcher_controller.cpp
test_switcher_controller_class.cpp
diff --git a/tests/autopilot/unity/emulators/screen.py b/tests/autopilot/unity/emulators/screen.py
index 94179ef67..29f2e37e5 100644
--- a/tests/autopilot/unity/emulators/screen.py
+++ b/tests/autopilot/unity/emulators/screen.py
@@ -28,6 +28,15 @@ class Screen(UnityIntrospectionObject):
"""Return the available scaled windows, or None."""
return self.get_children_by_type(Window, scaled=True)
+ @property
+ def spread_filter(self):
+ """Return the spread filter, or None."""
+ filter = self.get_children_by_type(SpreadFilter)
+ if len(filter):
+ return filter[0]
+
+ return None
+
def window(self, xid):
"""Return the window with given xid."""
windows = self.get_children_by_type(Window, xid=xid)
@@ -51,3 +60,17 @@ class Window(UnityIntrospectionObject):
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)
+
+
+class SpreadFilter(UnityIntrospectionObject):
+ """The spread filter."""
+
+ @property
+ def search_bar(self):
+ """Return the search bar."""
+ [search_bar] = self.get_children_by_type(SearchBar)
+ return search_bar
+
+
+class SearchBar(UnityIntrospectionObject):
+ """The search bar for the spread filter.""" \ No newline at end of file
diff --git a/tests/autopilot/unity/tests/test_spread.py b/tests/autopilot/unity/tests/test_spread.py
index 7c7887f47..c6e5b73ec 100644
--- a/tests/autopilot/unity/tests/test_spread.py
+++ b/tests/autopilot/unity/tests/test_spread.py
@@ -12,7 +12,6 @@ from autopilot.display import Display
from autopilot.matchers import Eventually
from testtools.matchers import Equals, NotEquals
from time import sleep
-from unity.emulators.icons import BFBLauncherIcon
from unity.tests import UnityTestCase
@@ -56,10 +55,14 @@ class SpreadTests(UnityTestCase):
self.launcher.click_launcher_icon(icon, move_mouse_after=False)
self.assertThat(self.unity.window_manager.scale_active_for_group, Eventually(Equals(True)))
- def assertWindowIsNotScaled(self, window):
- """Assert that a window is not scaled"""
- refresh_fn = lambda: window.id in [w.id for w in self.unity.screen.scaled_windows]
- self.assertThat(refresh_fn, Eventually(Equals(False)))
+ def get_spread_filter(self):
+ self.assertThat(lambda: self.unity.screen.spread_filter, Eventually(NotEquals(None)))
+ return self.unity.screen.spread_filter
+
+ def assertWindowIsScaledEquals(self, xid, scaled):
+ """Assert weather a window is scaled"""
+ refresh_fn = lambda: xid in [w.xid for w in self.unity.screen.scaled_windows]
+ self.assertThat(refresh_fn, Eventually(Equals(scaled)))
def assertWindowIsClosed(self, xid):
"""Assert that a window is not in the list of the open windows"""
@@ -72,7 +75,7 @@ class SpreadTests(UnityTestCase):
def assertLauncherIconsDesaturated(self, also_active=True):
for icon in self.unity.launcher.model.get_launcher_icons():
- if isinstance(icon, BFBLauncherIcon) or (not also_active and icon.active):
+ if not also_active and icon.active:
self.assertFalse(icon.monitors_desaturated[self.monitor])
else:
self.assertTrue(icon.monitors_desaturated[self.monitor])
@@ -119,7 +122,7 @@ class SpreadTests(UnityTestCase):
sleep(.5)
self.mouse.click(button=2)
- self.assertWindowIsNotScaled(target_win)
+ self.assertWindowIsScaledEquals(target_xid, False)
self.assertWindowIsClosed(target_xid)
def test_scaled_window_closes_on_close_button_click(self):
@@ -135,7 +138,7 @@ class SpreadTests(UnityTestCase):
sleep(.5)
self.mouse.click()
- self.assertWindowIsNotScaled(target_win)
+ self.assertWindowIsScaledEquals(target_xid, False)
self.assertWindowIsClosed(target_xid)
def test_spread_desaturate_launcher_icons(self):
@@ -191,3 +194,41 @@ class SpreadTests(UnityTestCase):
self.initiate_spread_for_screen()
self.assertThat(icon.get_tooltip().active, Eventually(Equals(False)))
+
+ def test_spread_puts_panel_in_overlay_mode(self):
+ """Test that the panel is in overlay mode when in spread"""
+ self.start_test_application_windows("Calculator", 1)
+ self.initiate_spread_for_screen()
+ self.assertThat(self.unity.panels.get_active_panel().in_overlay_mode, Eventually(Equals(True)))
+ self.unity.window_manager.terminate_spread()
+ self.assertThat(self.unity.panels.get_active_panel().in_overlay_mode, Eventually(Equals(False)))
+
+ def test_panel_close_window_button_terminates_spread(self):
+ """Test that the panel close window button terminates the spread"""
+ self.start_test_application_windows("Calculator", 1)
+ self.initiate_spread_for_screen()
+ self.unity.panels.get_active_panel().window_buttons.close.mouse_click();
+ self.assertThat(self.unity.window_manager.scale_active, Eventually(Equals(False)))
+
+ def test_spread_filter(self):
+ """Test spread filter"""
+ cal_wins = self.start_test_application_windows("Calculator", 2)
+ char_wins = self.start_test_application_windows("Character Map", 2)
+ self.initiate_spread_for_screen()
+ spread_filter = self.get_spread_filter()
+ self.assertThat(spread_filter.visible, Eventually(Equals(False)))
+
+ self.addCleanup(self.keyboard.press_and_release, "Escape")
+ self.keyboard.type(cal_wins[0].title)
+ self.assertThat(spread_filter.visible, Eventually(Equals(True)))
+ self.assertThat(spread_filter.search_bar.search_string, Eventually(Equals(cal_wins[0].title)))
+
+ for w in cal_wins + char_wins:
+ self.assertWindowIsScaledEquals(w.x_id, (w in cal_wins))
+
+ self.keyboard.press_and_release("Escape")
+ self.assertThat(spread_filter.visible, Eventually(Equals(False)))
+ self.assertThat(spread_filter.search_bar.search_string, Eventually(Equals("")))
+
+ for w in cal_wins + char_wins:
+ self.assertWindowIsScaledEquals(w.x_id, True)
diff --git a/tests/test_spread_filter.cpp b/tests/test_spread_filter.cpp
new file mode 100644
index 000000000..f4fd1e064
--- /dev/null
+++ b/tests/test_spread_filter.cpp
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2014 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 3 along with this program. If not, see
+ * <http://www.gnu.org/licenses/>
+ *
+ * Authored by: Marco Trevisan <marco.trevisan@canonical.com>
+ *
+ */
+
+#include <gmock/gmock.h>
+#include <Nux/NuxTimerTickSource.h>
+#include <NuxCore/AnimationController.h>
+
+#include "SpreadFilter.h"
+#include "UnitySettings.h"
+#include "DashStyle.h"
+#include "test_utils.h"
+
+namespace unity
+{
+namespace spread
+{
+namespace
+{
+using namespace testing;
+
+const unsigned ANIMATION_DURATION = 100 * 1000; // in microseconds
+
+struct SigReceiver : sigc::trackable
+{
+ typedef NiceMock<SigReceiver> Nice;
+
+ SigReceiver(Filter const& const_filter)
+ {
+ auto& filter = const_cast<Filter&>(const_filter);
+ filter.text.changed.connect(sigc::mem_fun(this, &SigReceiver::TextChanged));
+ }
+
+ MOCK_CONST_METHOD1(TextChanged, void(std::string const&));
+};
+
+struct TestSpreadFilter : Test
+{
+ TestSpreadFilter()
+ : animation_controller(tick_source)
+ , big_tick_(0)
+ , sig_receiver(filter)
+ {}
+
+ void Tick()
+ {
+ big_tick_ += ANIMATION_DURATION;
+ tick_source.tick(big_tick_);
+ }
+
+ Settings settings_;
+ dash::Style style_;
+ nux::NuxTimerTickSource tick_source;
+ nux::animation::AnimationController animation_controller;
+ uint64_t big_tick_;
+ Filter filter;
+ SigReceiver::Nice sig_receiver;
+};
+
+TEST_F(TestSpreadFilter, Construction)
+{
+ EXPECT_FALSE(filter.Visible());
+ EXPECT_TRUE(filter.text().empty());
+}
+
+TEST_F(TestSpreadFilter, VisibleWithText)
+{
+ std::string filter_string = "Unity is cool!";
+ EXPECT_CALL(sig_receiver, TextChanged(_)).Times(0);
+
+ filter.text = filter_string;
+ Tick();
+
+ EXPECT_TRUE(filter.Visible());
+ EXPECT_FALSE(filter.text().empty());
+
+ EXPECT_CALL(sig_receiver, TextChanged(filter_string));
+ Utils::WaitForTimeoutMSec();
+
+ EXPECT_EQ(filter_string, filter.text());
+}
+
+TEST_F(TestSpreadFilter, InVisibleWithoutText)
+{
+ filter.text = "Really, Unity is cool!";
+ Utils::WaitForTimeoutMSec();
+ Tick();
+
+ ASSERT_TRUE(filter.Visible());
+
+ EXPECT_CALL(sig_receiver, TextChanged(""));
+ filter.text = "";
+ EXPECT_TRUE(filter.text().empty());
+ Tick();
+ EXPECT_FALSE(filter.Visible());
+}
+
+} // anonymous namespace
+} // spread namespace
+} // unity namespace
diff --git a/unity-shared/CMakeLists.txt b/unity-shared/CMakeLists.txt
index c6b20fb66..5fca6ab17 100644
--- a/unity-shared/CMakeLists.txt
+++ b/unity-shared/CMakeLists.txt
@@ -55,6 +55,7 @@ set (UNITY_SHARED_SOURCES
ResizingBaseWindow.cpp
SearchBar.cpp
SearchBarSpinner.cpp
+ SpreadFilter.cpp
StaticCairoText.cpp
TextureCache.cpp
TextInput.cpp
diff --git a/unity-shared/PluginAdapter.cpp b/unity-shared/PluginAdapter.cpp
index 0a4611116..dc2c3b29a 100644
--- a/unity-shared/PluginAdapter.cpp
+++ b/unity-shared/PluginAdapter.cpp
@@ -24,6 +24,7 @@
#include "PluginAdapter.h"
#include "CompizUtils.h"
+#include <scale/scale.h>
#include <NuxCore/Logger.h>
namespace unity
@@ -288,7 +289,7 @@ void MultiActionList::TerminateAll(CompOption::Vector const& extra_args) const
if (primary_action_)
{
- primary_action_->terminate()(primary_action_, 0, argument);
+ primary_action_->terminate()(primary_action_, CompAction::StateCancel, argument);
return;
}
@@ -337,13 +338,8 @@ std::string PluginAdapter::MatchStringForXids(std::vector<Window> const& windows
{
std::ostringstream sout;
- sout << "any & (";
-
for (auto const& window : windows)
- {
- sout << "| xid=" << window << " ";
- }
- sout << ")";
+ sout << "xid=" << window << " | ";
return sout.str();
}
diff --git a/unity-shared/SearchBar.cpp b/unity-shared/SearchBar.cpp
index f82cd39dd..12f055636 100644
--- a/unity-shared/SearchBar.cpp
+++ b/unity-shared/SearchBar.cpp
@@ -33,8 +33,8 @@
namespace
{
-const float kExpandDefaultIconOpacity = 1.0f;
-const int LIVE_SEARCH_TIMEOUT = 40;
+const float DEFAULT_ICON_OPACITY = 1.0f;
+const int DEFAULT_LIVE_SEARCH_TIMEOUT = 40;
const int SPINNER_TIMEOUT = 100;
const int SPACE_BETWEEN_SPINNER_AND_TEXT = 5;
@@ -105,35 +105,20 @@ namespace unity
NUX_IMPLEMENT_OBJECT_TYPE(SearchBar);
SearchBar::SearchBar(NUX_FILE_LINE_DECL)
- : View(NUX_FILE_LINE_PARAM)
- , search_hint("")
- , showing_filters(false)
- , can_refine_search(false)
- , show_filter_hint_(true)
- , expander_view_(nullptr)
- , show_filters_(nullptr)
- , last_width_(-1)
- , last_height_(-1)
-{
- Init();
-}
+ : SearchBar(false)
+{}
-SearchBar::SearchBar(bool show_filter_hint_, NUX_FILE_LINE_DECL)
+SearchBar::SearchBar(bool show_filter_hint, NUX_FILE_LINE_DECL)
: View(NUX_FILE_LINE_PARAM)
- , search_hint("")
, showing_filters(false)
, can_refine_search(false)
- , show_filter_hint_(show_filter_hint_)
+ , live_search_wait(DEFAULT_LIVE_SEARCH_TIMEOUT)
+ , show_filter_hint_(show_filter_hint)
, expander_view_(nullptr)
, show_filters_(nullptr)
, last_width_(-1)
, last_height_(-1)
{
- Init();
-}
-
-void SearchBar::Init()
-{
dash::Style& style = dash::Style::Instance();
nux::BaseTexture* icon = style.GetSearchMagnifyIcon();
@@ -199,7 +184,7 @@ void SearchBar::Init()
expand_icon_ = new IconTexture(arrow,
arrow->GetWidth(),
arrow->GetHeight());
- expand_icon_->SetOpacity(kExpandDefaultIconOpacity);
+ expand_icon_->SetOpacity(DEFAULT_ICON_OPACITY);
expand_icon_->SetMinimumSize(arrow->GetWidth(), arrow->GetHeight());
expand_icon_->SetVisible(false);
@@ -294,10 +279,13 @@ void SearchBar::OnFontChanged(GtkSettings* settings, GParamSpec* pspec)
font_desc << pango_font_description_get_family(desc) << " " << HINT_LABEL_FONT_STYLE << " " << HINT_LABEL_FONT_SIZE;
hint_->SetFont(font_desc.str().c_str());
- font_desc.str("");
- font_desc.clear();
- font_desc << pango_font_description_get_family(desc) << " " << SHOW_FILTERS_LABEL_FONT_STYLE << " " << SHOW_FILTERS_LABEL_FONT_SIZE;
- show_filters_->SetFont(font_desc.str().c_str());
+ if (show_filter_hint_)
+ {
+ font_desc.str("");
+ font_desc.clear();
+ font_desc << pango_font_description_get_family(desc) << " " << SHOW_FILTERS_LABEL_FONT_STYLE << " " << SHOW_FILTERS_LABEL_FONT_SIZE;
+ show_filters_->SetFont(font_desc.str().c_str());
+ }
pango_font_description_free(desc);
}
@@ -317,7 +305,7 @@ void SearchBar::OnSearchChanged(nux::TextEntry* text_entry)
// We don't want to set a new search string on every new character, so we add a sma
// timeout to see if the user is typing a sentence. If more characters are added, we
// keep restarting the timeout unti the user has actuay paused.
- live_search_timeout_.reset(new glib::Timeout(LIVE_SEARCH_TIMEOUT));
+ live_search_timeout_.reset(new glib::Timeout(live_search_wait()));
live_search_timeout_->Run(sigc::mem_fun(this, &SearchBar::OnLiveSearchTimeout));
// Don't animate the spinner immediately, the searches are fast and
@@ -428,6 +416,9 @@ void SearchBar::DrawContent(nux::GraphicsEngine& graphics_engine, bool force_dra
nux::GetPainter().PushPaintLayerStack();
}
+ if (!IsFullRedraw())
+ graphics::ClearGeometry(pango_entry_->GetGeometry());
+
layout_->ProcessDraw(graphics_engine, force_draw);
if (IsFullRedraw())
@@ -455,7 +446,7 @@ void SearchBar::OnEntryActivated()
void SearchBar::ForceLiveSearch()
{
- live_search_timeout_.reset(new glib::Timeout(LIVE_SEARCH_TIMEOUT));
+ live_search_timeout_.reset(new glib::Timeout(live_search_wait()));
live_search_timeout_->Run(sigc::mem_fun(this, &SearchBar::OnLiveSearchTimeout));
start_spinner_timeout_.reset(new glib::Timeout(SPINNER_TIMEOUT));
@@ -466,8 +457,7 @@ void SearchBar::SetSearchFinished()
{
start_spinner_timeout_.reset();
- bool is_empty = pango_entry_->im_active() ?
- false : pango_entry_->GetText() == "";
+ bool is_empty = pango_entry_->im_active() ? false : pango_entry_->GetText().empty();
spinner_->SetState(is_empty ? STATE_READY : STATE_CLEAR);
}
@@ -609,14 +599,19 @@ void SearchBar::AddProperties(debug::IntrospectionData& introspection)
.add(GetAbsoluteGeometry())
.add("has_focus", pango_entry_->HasKeyFocus())
.add("search_string", pango_entry_->GetText())
- .add("expander-has-focus", expander_view_->HasKeyFocus())
.add("showing-filters", showing_filters)
- .add("filter-label-x", show_filters_->GetAbsoluteX())
- .add("filter-label-y", show_filters_->GetAbsoluteY())
- .add("filter-label-width", show_filters_->GetAbsoluteWidth())
- .add("filter-label-height", show_filters_->GetAbsoluteHeight())
- .add("filter-label-geo", show_filters_->GetAbsoluteGeometry())
.add("im_active", pango_entry_->im_active());
+
+ if (show_filter_hint_)
+ {
+ introspection
+ .add("expander-has-focus", expander_view_->HasKeyFocus())
+ .add("filter-label-x", show_filters_->GetAbsoluteX())
+ .add("filter-label-y", show_filters_->GetAbsoluteY())
+ .add("filter-label-width", show_filters_->GetAbsoluteWidth())
+ .add("filter-label-height", show_filters_->GetAbsoluteHeight())
+ .add("filter-label-geo", show_filters_->GetAbsoluteGeometry());
+ }
}
} // namespace unity
diff --git a/unity-shared/SearchBar.h b/unity-shared/SearchBar.h
index 18f8e34a3..e4f1505fa 100644
--- a/unity-shared/SearchBar.h
+++ b/unity-shared/SearchBar.h
@@ -63,14 +63,13 @@ public:
nux::Property<bool> can_refine_search;
nux::ROProperty<bool> im_active;
nux::ROProperty<bool> im_preedit;
+ nux::Property<unsigned> live_search_wait;
sigc::signal<void> activated;
sigc::signal<void, std::string const&> search_changed;
sigc::signal<void, std::string const&> live_search_reached;
private:
- void Init();
-
void OnFontChanged(GtkSettings* settings, GParamSpec* pspec=NULL);
void OnSearchHintChanged();
diff --git a/unity-shared/SpreadFilter.cpp b/unity-shared/SpreadFilter.cpp
new file mode 100644
index 000000000..ddbd99696
--- /dev/null
+++ b/unity-shared/SpreadFilter.cpp
@@ -0,0 +1,121 @@
+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
+/*
+* Copyright (C) 2014 Canonical Ltd
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 3 as
+* published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*
+* Authored by: Marco Trevisan <marco@ubuntu.com>
+*/
+
+#include "SpreadFilter.h"
+
+#include <Nux/HLayout.h>
+#include "AnimationUtils.h"
+#include "SearchBar.h"
+#include "WindowManager.h"
+
+namespace unity
+{
+namespace spread
+{
+namespace
+{
+const unsigned FADE_DURATION = 100;
+const unsigned DEFAULT_SEARCH_WAIT = 300;
+const nux::Point OFFSET(10, 15);
+const nux::Size SIZE(620, 42);
+}
+
+Filter::Filter()
+ : fade_animator_(FADE_DURATION)
+{
+ search_bar_ = SearchBar::Ptr(new SearchBar());
+ search_bar_->SetMinMaxSize(SIZE.width, SIZE.height);
+ search_bar_->live_search_wait = DEFAULT_SEARCH_WAIT;
+ text.SetGetterFunction([this] { return search_bar_->search_string(); });
+ text.SetSetterFunction([this] (std::string const& t) { search_bar_->search_string = t; return false; });
+ debug::Introspectable::AddChild(search_bar_.GetPointer());
+
+ auto layout = new nux::HLayout(NUX_TRACKER_LOCATION);
+ layout->SetVerticalExternalMargin(0);
+ layout->SetHorizontalExternalMargin(0);
+ layout->AddView(search_bar_.GetPointer());
+
+ auto const& work_area = WindowManager::Default().GetWorkAreaGeometry(0);
+ view_window_ = new nux::BaseWindow(GetName().c_str());
+ view_window_->SetLayout(layout);
+ view_window_->SetBackgroundColor(nux::color::Transparent);
+ view_window_->SetWindowSizeMatchLayout(true);
+ view_window_->ShowWindow(true);
+ view_window_->PushToFront();
+ view_window_->SetOpacity(0.0f);
+ view_window_->SetEnterFocusInputArea(search_bar_.GetPointer());
+ view_window_->SetInputFocus();
+ view_window_->SetXY(OFFSET.x + work_area.x, OFFSET.y + work_area.y);
+ fade_animator_.updated.connect([this] (double opacity) { view_window_->SetOpacity(opacity); });
+
+ nux::GetWindowCompositor().SetKeyFocusArea(search_bar_->text_entry());
+
+ search_bar_->search_changed.connect([this] (std::string const& search) {
+ if (!Visible())
+ animation::StartOrReverse(fade_animator_, animation::Direction::FORWARD);
+
+ if (search.empty())
+ {
+ text.changed.emit(search);
+ animation::StartOrReverse(fade_animator_, animation::Direction::BACKWARD);
+ }
+ });
+
+ search_bar_->live_search_reached.connect([this] (std::string const& search) {
+ if (!search.empty())
+ {
+ text.changed.emit(search);
+ search_bar_->SetSearchFinished();
+ }
+ });
+}
+
+Filter::~Filter()
+{
+ nux::GetWindowCompositor().SetKeyFocusArea(nullptr);
+ nux::GetWindowThread()->RemoveObjectFromLayoutQueue(view_window_.GetPointer());
+}
+
+bool Filter::Visible() const
+{
+ return (view_window_->GetOpacity() != 0.0f);
+}
+
+nux::Geometry const& Filter::GetAbsoluteGeometry() const
+{
+ return view_window_->GetGeometry();
+}
+
+//
+// Introspection
+//
+std::string Filter::GetName() const
+{
+ return "SpreadFilter";
+}
+
+void Filter::AddProperties(debug::IntrospectionData& introspection)
+{
+ introspection
+ .add(GetAbsoluteGeometry())
+ .add("visible", Visible());
+}
+
+} // namespace spread
+} // namespace unity
diff --git a/unity-shared/SpreadFilter.h b/unity-shared/SpreadFilter.h
new file mode 100644
index 000000000..2709315a5
--- /dev/null
+++ b/unity-shared/SpreadFilter.h
@@ -0,0 +1,64 @@
+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
+/*
+* Copyright (C) 2014 Canonical Ltd
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 3 as
+* published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*
+* Authored by: Marco Trevisan <marco@ubuntu.com>
+*/
+
+#ifndef UNITYSHELL_SPREAD_FILTER_H
+#define UNITYSHELL_SPREAD_FILTER_H
+
+#include <memory>
+
+#include <Nux/Nux.h>
+#include <Nux/BaseWindow.h>
+#include <NuxCore/Animation.h>
+#include "Introspectable.h"
+
+namespace unity
+{
+class SearchBar;
+
+namespace spread
+{
+
+class Filter : public debug::Introspectable, public sigc::trackable
+{
+public:
+ typedef std::shared_ptr<Filter> Ptr;
+
+ Filter();
+ virtual ~Filter();
+
+ nux::RWProperty<std::string> text;
+
+ bool Visible() const;
+ nux::Geometry const& GetAbsoluteGeometry() const;
+
+protected:
+ // Introspectable
+ std::string GetName() const;
+ void AddProperties(debug::IntrospectionData&);
+
+private:
+ nux::ObjectPtr<SearchBar> search_bar_;
+ nux::ObjectPtr<nux::BaseWindow> view_window_;
+ nux::animation::AnimateValue<double> fade_animator_;
+};
+
+} // namespace spread
+} // namespace unity
+
+#endif