summaryrefslogtreecommitdiff
diff options
authorRudra Saraswat <rs2009@ubuntu.com>2023-02-22 18:37:59 +0000
committerBileto Bot <ci-train-bot@canonical.com>2023-02-22 18:37:59 +0000
commit4bc29d53573b0943a77f56772fb0f4b183192cad (patch)
tree89a975ff9b07e1c9e594bf633f34d34765d79b8e
parentcd0e7d8f64a348def9f05853921f76737157db78 (diff)
parent9e2b1125105ee5deb6291c1046491795e59d0a6b (diff)
* Added UWidgets, a new widget system for Unity based on Blighty
* Made the dash vertical and moved the scope bar to the top * Increased the panel height to 30 * Added indicator-notifications as a Recommend
-rw-r--r--.gitignore86
-rw-r--r--CMakeLists.txt2
-rw-r--r--README4
-rw-r--r--dash/DashView.cpp166
-rwxr-xr-xdash/PlacesGroup.cpp4
-rw-r--r--dash/ResultViewGrid.cpp2
-rw-r--r--dash/ScopeBar.cpp2
-rw-r--r--dash/StandaloneDash.cpp6
-rw-r--r--debian/changelog9
-rw-r--r--debian/control35
-rwxr-xr-xdebian/rules9
-rw-r--r--debian/unity-uwidgets.install3
-rw-r--r--debian/unity.install2
-rw-r--r--launcher/BFBLauncherIcon.cpp4
-rw-r--r--launcher/FileManagerLauncherIcon.cpp2
-rw-r--r--launcher/Launcher.cpp318
-rw-r--r--launcher/StandaloneLauncher.cpp2
-rw-r--r--launcher/TrashLauncherIcon.cpp2
-rw-r--r--lockscreen/LockScreenPanel.cpp4
-rw-r--r--panel/PanelController.cpp2
-rw-r--r--panel/PanelIndicatorsView.cpp1
-rw-r--r--panel/PanelIndicatorsView.h2
-rw-r--r--panel/PanelMenuView.cpp4
-rw-r--r--panel/PanelTray.cpp6
-rw-r--r--panel/PanelView.cpp4
-rw-r--r--panel/StandalonePanel.cpp2
-rw-r--r--plugins/unityshell/src/unityshell.cpp64
-rw-r--r--plugins/unityshell/unityshell.xml.in8
-rw-r--r--resources/dash_sheen.pngbin5222 -> 272 bytes
-rw-r--r--resources/empty.pngbin0 -> 272 bytes
-rw-r--r--resources/launcher_bfb.svg137
-rw-r--r--resources/panel_shadow.pngbin159 -> 272 bytes
-rw-r--r--resources/refine_gradient_dash.pngbin15080 -> 272 bytes
-rw-r--r--resources/refine_gradient_panel.pngbin1691 -> 272 bytes
-rw-r--r--resources/refine_gradient_panel_single_column.pngbin115 -> 272 bytes
-rw-r--r--shutdown/SessionButton.cpp4
-rw-r--r--shutdown/SessionView.cpp2
-rw-r--r--tests/CMakeLists.txt10
-rw-r--r--tests/mock_key_grabber.h2
-rw-r--r--tests/test_error_preview.cpp109
-rw-r--r--tests/test_launcher.cpp58
-rw-r--r--tests/test_launcher_controller.cpp121
-rw-r--r--tests/test_preview_player.cpp230
-rw-r--r--tests/test_previews.cpp230
-rw-r--r--tests/test_previews_application.cpp142
-rw-r--r--tests/test_previews_generic.cpp129
-rw-r--r--tests/test_previews_movie.cpp149
-rw-r--r--tests/test_previews_music.cpp131
-rw-r--r--tests/test_previews_music_payment.cpp150
-rw-r--r--tests/test_previews_payment.cpp184
-rw-r--r--tests/test_previews_social.cpp107
-rw-r--r--unity-shared/BackgroundEffectHelper.cpp2
-rw-r--r--unity-shared/CMakeLists.txt2
-rwxr-xr-xunity-shared/DashStyle.cpp56
-rwxr-xr-xunity-shared/DashStyle.h2
-rw-r--r--unity-shared/FileManager.cpp2
-rw-r--r--unity-shared/FileManager.h2
-rw-r--r--unity-shared/GnomeFileManager.h2
-rw-r--r--unity-shared/NemoFileManager.cpp66
-rw-r--r--unity-shared/NemoFileManager.h2
-rw-r--r--unity-shared/OverlayRenderer.cpp52
-rw-r--r--unity-shared/OverlayWindowButtons.cpp2
-rw-r--r--unity-shared/PanelStyle.cpp4
-rw-r--r--unity-shared/SearchBar.cpp66
-rw-r--r--unity-shared/SearchBar.h1
-rw-r--r--unity-standalone/StandaloneUnity.cpp3
-rw-r--r--uwidgets/LICENCE636
-rw-r--r--uwidgets/MANIFEST.in3
-rwxr-xr-xuwidgets/official-widgets/clock/clock.py104
-rw-r--r--uwidgets/official-widgets/clock/settings.ini7
-rw-r--r--uwidgets/official-widgets/clock/widget.ini5
-rwxr-xr-xuwidgets/official-widgets/cpu/cpu.py169
-rw-r--r--uwidgets/official-widgets/cpu/settings.ini5
-rw-r--r--uwidgets/official-widgets/cpu/widget.ini5
-rw-r--r--uwidgets/official-widgets/spotify/settings.ini5
-rwxr-xr-xuwidgets/official-widgets/spotify/spotify.py176
-rw-r--r--uwidgets/official-widgets/spotify/widget.ini5
-rw-r--r--uwidgets/official-widgets/unsplash-background/settings.ini5
-rwxr-xr-xuwidgets/official-widgets/unsplash-background/unsplash-background.py96
-rw-r--r--uwidgets/official-widgets/unsplash-background/widget.ini5
-rwxr-xr-xuwidgets/setup.py64
-rwxr-xr-xuwidgets/uwidgets-runner24
-rw-r--r--uwidgets/uwidgets-runner.desktop9
-rw-r--r--uwidgets/uwidgets/__init__.py77
-rw-r--r--uwidgets/uwidgets/_brush.py163
-rw-r--r--uwidgets/uwidgets/_extended_context.py72
-rw-r--r--uwidgets/uwidgets/legacy.py73
-rw-r--r--uwidgets/uwidgets/settings/__init__.py4
-rw-r--r--uwidgets/uwidgets/settings/launcher.py18
-rw-r--r--uwidgets/uwidgets/settings/wallpaper.py27
-rw-r--r--uwidgets/uwidgets/x11/__init__.py31
-rw-r--r--uwidgets/uwidgets/x11/_x11module.c71
-rw-r--r--uwidgets/uwidgets/x11/atelier.c265
-rw-r--r--uwidgets/uwidgets/x11/atelier.h63
-rw-r--r--uwidgets/uwidgets/x11/base_canvas.c445
-rw-r--r--uwidgets/uwidgets/x11/base_canvas.h163
-rw-r--r--uwidgets/uwidgets/x11/canvas.py407
-rwxr-xr-xuwidgets/uwidgets/x11/pycairo.h280
-rw-r--r--uwidgets/widget.ini4
99 files changed, 3916 insertions, 2484 deletions
diff --git a/.gitignore b/.gitignore
index d58747cbb..da7cffb1d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,16 +1,90 @@
build
-services/panel-marshal.c
-services/panel-marshal.h
.AUTHORS.sed
-tests/autopilot/dist
-tests/autopilot/unity.egg-info
*.log
*.debhelper
*.substvars
*.swp
+.vscode/
debian/tmp
debian/files
obj-*/
-debian/libunity-core-*/
-debian/unity-*/
+debian/libunity-core-6.0-9/
+debian/libunity-core-6.0-dev/
+debian/unity-autopilot/
+debian/unity-uwidgets/
+debian/unity-services/
+debian/unity-schemas/
debian/unity/
+
+### UWidgets
+
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+.hypothesis/
+.pytest_cache/
+
+# Translations
+*.mo
+*.pot
+
+# Sphinx documentation
+docs/*build/
+
+# PyBuilder
+target/
+
+# pyenv
+.python-version
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1d58a4619..bd237ca47 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -10,7 +10,7 @@ include (GNUInstallDirs)
#
set (PROJECT_NAME "unity")
set (UNITY_MAJOR 7)
-set (UNITY_MINOR 6)
+set (UNITY_MINOR 7)
set (UNITY_MICRO 0)
set (UNITY_VERSION "${UNITY_MAJOR}.${UNITY_MINOR}.${UNITY_MICRO}")
set (UNITY_API_VERSION "6.0")
diff --git a/README b/README
index 801461a13..131489c64 100644
--- a/README
+++ b/README
@@ -19,3 +19,7 @@
D-Bus activation. This is used for testing how the panel reacts when it
starts before the service does.
+ Credits
+--------------------------------------------------------------------------------
+
+UWidgets is based on the Blighty project. \ No newline at end of file
diff --git a/dash/DashView.cpp b/dash/DashView.cpp
index dc4e1b2d8..0fd05974d 100644
--- a/dash/DashView.cpp
+++ b/dash/DashView.cpp
@@ -39,6 +39,7 @@
#include "unity-shared/UBusMessages.h"
#include "unity-shared/UnitySettings.h"
#include "unity-shared/WindowManager.h"
+#include "unity-shared/FileManager.h"
namespace unity
{
@@ -231,83 +232,12 @@ void DashView::OnResultActivated(ResultView::ActivateType type, LocalResult cons
void DashView::BuildPreview(Preview::Ptr model)
{
- if (!preview_displaying_)
- {
- StartPreviewAnimation();
-
- content_view_->SetPresentRedirectedView(false);
- preview_scope_view_ = active_scope_view_;
- if (preview_scope_view_)
- {
- preview_scope_view_->ForceCategoryExpansion(stored_activated_unique_id_, true);
- preview_scope_view_->EnableResultTextures(true);
- preview_scope_view_->PushFilterExpansion(false);
- }
-
- if (!preview_container_)
- {
- preview_container_ = new previews::PreviewContainer();
- preview_container_->SetRedirectRenderingToTexture(true);
- AddChild(preview_container_.GetPointer());
- preview_container_->SetParentObject(this);
- }
- preview_container_->Preview(model, previews::Navigation::NONE); // no swipe left or right
- preview_container_->scale = scale();
- preview_container_->SetGeometry(scopes_layout_->GetGeometry());
- preview_displaying_ = true;
-
- // connect to nav left/right signals to request nav left/right movement.
- preview_container_->navigate_left.connect([this] () {
- preview_navigation_mode_ = previews::Navigation::LEFT;
-
- // sends a message to all result views, sending the the uri of the current preview result
- // and the unique id of the result view that should be handling the results
- ubus_manager_.SendMessage(UBUS_DASH_PREVIEW_NAVIGATION_REQUEST, g_variant_new("(ivs)", -1, g_variant_ref(last_activated_result_.Variant()), stored_activated_unique_id_.c_str()));
- });
-
- preview_container_->navigate_right.connect([this] () {
- preview_navigation_mode_ = previews::Navigation::RIGHT;
-
- // sends a message to all result views, sending the the uri of the current preview result
- // and the unique id of the result view that should be handling the results
- ubus_manager_.SendMessage(UBUS_DASH_PREVIEW_NAVIGATION_REQUEST, g_variant_new("(ivs)", 1, g_variant_ref(last_activated_result_.Variant()), stored_activated_unique_id_.c_str()));
- });
-
- preview_container_->request_close.connect([this] () { ClosePreview(); });
- }
- else
- {
- // got a new preview whilst already displaying, we probably clicked a navigation button.
- preview_container_->Preview(model, preview_navigation_mode_); // TODO
- preview_container_->scale = scale();
- }
-
- if (G_LIKELY(preview_state_machine_.left_results() > 0 && preview_state_machine_.right_results() > 0))
- preview_container_->DisableNavButton(previews::Navigation::NONE);
- else if (preview_state_machine_.left_results() > 0)
- preview_container_->DisableNavButton(previews::Navigation::RIGHT);
- else if (preview_state_machine_.right_results() > 0)
- preview_container_->DisableNavButton(previews::Navigation::LEFT);
- else
- preview_container_->DisableNavButton(previews::Navigation::BOTH);
-
- QueueDraw();
+ // Previews have been removed, so this function has been left blank until we eliminate all of the preview-related code.
}
void DashView::ClosePreview()
{
- if (preview_displaying_)
- {
- EndPreviewAnimation();
-
- preview_displaying_ = false;
- }
-
- preview_navigation_mode_ = previews::Navigation::NONE;
-
- // re-focus dash view component.
- nux::GetWindowCompositor().SetKeyFocusArea(default_focus());
- QueueDraw();
+ // Previews have been removed, so this function has been left blank until we eliminate all of the preview-related code.
}
void DashView::StartPreviewAnimation()
@@ -555,6 +485,11 @@ void DashView::SetupViews()
content_view_->SetLayout(content_layout_);
layout_->AddView(content_view_, 1, nux::MINOR_POSITION_START, nux::MINOR_SIZE_FULL);
+ scope_bar_ = new ScopeBar();
+ AddChild(scope_bar_);
+ scope_bar_->scope_activated.connect(sigc::mem_fun(this, &DashView::OnScopeBarActivated));
+ content_layout_->AddView(scope_bar_, 0, nux::MINOR_POSITION_CENTER);
+
search_bar_layout_ = new nux::HLayout();
content_layout_->AddLayout(search_bar_layout_, 0, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FULL);
@@ -578,11 +513,6 @@ void DashView::SetupViews()
scopes_layout_ = new nux::VLayout();
content_layout_->AddLayout(scopes_layout_, 1, nux::MINOR_POSITION_START);
- scope_bar_ = new ScopeBar();
- AddChild(scope_bar_);
- scope_bar_->scope_activated.connect(sigc::mem_fun(this, &DashView::OnScopeBarActivated));
- content_layout_->AddView(scope_bar_, 0, nux::MINOR_POSITION_CENTER);
-
OnDPIChanged();
}
@@ -701,24 +631,24 @@ nux::Geometry DashView::GetBestFitGeometry(nux::Geometry const& for_geo)
style.GetPlacesGroupResultTopPadding().CP(scale) +
style.GetTileHeight().CP(scale));
- int half = for_geo.width / 2;
-
- // if default dash size is bigger than half a screens worth of items, go for that.
- while ((width += tile_width) < half);
+ // let's show five tiles per row
+ width = tile_width * 5;
- width = std::max(width, tile_width * DASH_TILE_HORIZONTAL_COUNT);
width += style.GetVSeparatorSize().CP(scale);
width += style.GetPlacesGroupResultLeftPadding().CP(scale) + DASH_RESULT_RIGHT_PAD.CP(scale);
- height = style.GetHSeparatorSize().CP(scale);
- height += style.GetDashViewTopPadding().CP(scale);
- height += search_bar_->GetGeometry().height;
- height += category_height * DASH_DEFAULT_CATEGORY_COUNT; // adding three categories
- height += scope_bar_->GetGeometry().height;
-
- // width/height shouldn't be bigger than the geo available.
+ // width shouldn't be bigger than the geo available.
width = std::min(width, for_geo.width); // launcher width is taken into account in for_geo.
- height = std::min(height, for_geo.height - vertical_offset); // panel height is not taken into account in for_geo.
+ height = for_geo.height - vertical_offset;
+
+ if (Settings::Instance().launcher_position() == LauncherPosition::BOTTOM) {
+ height = style.GetHSeparatorSize().CP(scale);
+ height += style.GetDashViewTopPadding().CP(scale);
+ height += search_bar_->GetGeometry().height;
+ height += category_height * 3;
+ height += scope_bar_->GetGeometry().height;
+ height = std::min(height, for_geo.height - vertical_offset);
+ }
return nux::Geometry(0, vertical_offset, width, height);
}
@@ -1091,59 +1021,7 @@ void DashView::DrawPreviewResultTextures(nux::GraphicsEngine& graphics_engine, b
}
void DashView::DrawPreview(nux::GraphicsEngine& graphics_engine, bool force_draw)
-{
- if (animate_preview_value_ > 0.0f)
- {
- bool animating = animate_split_value_ != 1.0f || animate_preview_value_ < 1.0f;
- bool preview_force_draw = force_draw || animating || IsFullRedraw();
-
- if (preview_force_draw)
- nux::GetPainter().PushBackgroundStack();
-
- if (animate_preview_value_ < 1.0f && preview_container_->RedirectRenderingToTexture())
- {
- preview_container_->SetPresentRedirectedView(false);
- preview_container_->ProcessDraw(graphics_engine, preview_force_draw);
-
- unsigned int alpha, src, dest = 0;
- graphics_engine.GetRenderStates().GetBlend(alpha, src, dest);
- graphics_engine.GetRenderStates().SetBlend(true, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
-
- nux::ObjectPtr<nux::IOpenGLBaseTexture> preview_texture = preview_container_->BackupTexture();
- if (preview_texture)
- {
- nux::TexCoordXForm texxform;
- texxform.FlipVCoord(true);
- texxform.uoffset = 0.0f;
- texxform.voffset = 0.0f;
- texxform.SetTexCoordType(nux::TexCoordXForm::OFFSET_COORD);
-
- nux::Geometry const& geo_preview = preview_container_->GetGeometry();
- graphics_engine.QRP_1Tex
- (
- geo_preview.x,
- geo_preview.y,
- geo_preview.width,
- geo_preview.height,
- preview_texture,
- texxform,
- nux::Color(animate_preview_value_, animate_preview_value_, animate_preview_value_, animate_preview_value_)
- );
- }
-
- preview_container_->SetPresentRedirectedView(true);
-
- graphics_engine.GetRenderStates().SetBlend(alpha, src, dest);
- }
- else
- {
- preview_container_->ProcessDraw(graphics_engine, preview_force_draw);
- }
-
- if (preview_force_draw)
- nux::GetPainter().PopBackgroundStack();
- }
-}
+{ }
void DashView::OnActivateRequest(GVariant* args)
{
diff --git a/dash/PlacesGroup.cpp b/dash/PlacesGroup.cpp
index 7a1f8dbf0..b83be9b34 100755
--- a/dash/PlacesGroup.cpp
+++ b/dash/PlacesGroup.cpp
@@ -52,6 +52,9 @@ namespace
const nux::Color EXPAND_DEFAULT_TEXT_COLOR(1.0f, 1.0f, 1.0f, 0.5f);
const float EXPAND_DEFAULT_ICON_OPACITY = 0.5f;
+// Category heading
+const RawPixel HEADER_VERTICAL_MARGIN = 10_em;
+
// Category highlight
const RawPixel HIGHLIGHT_RIGHT_PADDING = 10_em;
const RawPixel HIGHLIGHT_HEIGHT = 24_em;
@@ -229,6 +232,7 @@ PlacesGroup::UpdatePlacesGroupSize()
_header_layout->SetSpaceBetweenChildren(SPACE_BETWEEN_CHILDREN.CP(scale()));
_header_layout->SetLeftAndRightPadding(_style.GetCategoryHeaderLeftPadding().CP(scale), 0);
+ _header_layout->SetVerticalExternalMargin(HEADER_VERTICAL_MARGIN);
_icon->SetMinMaxSize(icon_size, icon_size);
diff --git a/dash/ResultViewGrid.cpp b/dash/ResultViewGrid.cpp
index 78a01de9a..16692607b 100644
--- a/dash/ResultViewGrid.cpp
+++ b/dash/ResultViewGrid.cpp
@@ -55,7 +55,7 @@ namespace
const int DOUBLE_CLICK_SPEED = 500; //500 ms (double-click speed hardcoded to 400 ms in nux)
- const RawPixel WIDTH_PADDING = 25_em;
+ const RawPixel WIDTH_PADDING = 25_em;
const RawPixel SCROLLBAR_WIDTH = 3_em;
const std::string APPLICATION_URI_PREFIX = "application://";
diff --git a/dash/ScopeBar.cpp b/dash/ScopeBar.cpp
index 027675c5a..5bba47719 100644
--- a/dash/ScopeBar.cpp
+++ b/dash/ScopeBar.cpp
@@ -58,7 +58,7 @@ void ScopeBar::SetupBackground()
rop.Blend = true;
rop.SrcBlend = GL_ONE;
rop.DstBlend = GL_ONE_MINUS_SRC_ALPHA;
- bg_layer_.reset(new nux::ColorLayer(nux::Color(0.0f, 0.0f, 0.0f, 0.2f), true, rop));
+ bg_layer_.reset(new nux::ColorLayer(nux::Color(0.0f, 0.0f, 0.0f, 0.0f), true, rop));
}
void ScopeBar::UpdateScale(double scale)
diff --git a/dash/StandaloneDash.cpp b/dash/StandaloneDash.cpp
index e869aced4..b14d36040 100644
--- a/dash/StandaloneDash.cpp
+++ b/dash/StandaloneDash.cpp
@@ -41,8 +41,8 @@
#include <UnityCore/GSettingsScopes.h>
#include <UnityCore/ScopeProxyInterface.h>
-const unity::RawPixel WIDTH(1024);
-const unity::RawPixel HEIGHT(768);
+const unity::RawPixel WIDTH(1280);
+const unity::RawPixel HEIGHT(720);
using namespace unity::dash;
@@ -126,7 +126,7 @@ int main(int argc, char **argv)
0, &TestRunner::InitWindowThread, test_runner));
nux::ObjectPtr<nux::BaseTexture> background_tex;
- background_tex.Adopt(nux::CreateTextureFromFile("/usr/share/backgrounds/warty-final-ubuntu.png"));
+ background_tex.Adopt(nux::CreateTextureFromFile("/usr/share/backgrounds/ubuntu-unity/ubuntu-unity-default.png"));
nux::TexCoordXForm texxform;
auto tex_layer = std::make_shared<nux::TextureLayer>(background_tex->GetDeviceTexture(), texxform, nux::color::White);
wt->SetWindowBackgroundPaintLayer(tex_layer.get());
diff --git a/debian/changelog b/debian/changelog
index a3a4d5d4d..1767d6dcd 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,12 @@
+unity (7.7.0+23.04.20230222-0ubuntu1) lunar; urgency=medium
+
+ * Added UWidgets, a new widget system for Unity based on Blighty
+ * Made the dash vertical and moved the scope bar to the top
+ * Increased the panel height to 30
+ * Added indicator-notifications as a Recommend
+
+ -- Rudra Saraswat <ruds@ruds.io> Tue, 21 Feb 2022 15:38:23 +0530
+
unity (7.6.0+22.10.20220913-0ubuntu1) kinetic; urgency=medium
[ Rudra Saraswat ]
diff --git a/debian/control b/debian/control
index c61edb5fe..2484f2227 100644
--- a/debian/control
+++ b/debian/control
@@ -11,6 +11,8 @@ Build-Depends: cmake (>= 3.17.0),
dh-translations (>= 94),
dh-python,
google-mock (>= 1.6.0+svn437),
+ gir1.2-gtk-3.0,
+ gir1.2-glib-2.0,
gsettings-desktop-schemas-dev,
gsettings-ubuntu-schemas (>= 0.0.7+17.10.20170922),
intltool (>= 0.35.0),
@@ -48,17 +50,21 @@ Build-Depends: cmake (>= 3.17.0),
libxcb-icccm4-dev,
libxfixes-dev (>= 1:5.0.1),
libxi-dev (>= 2:1.7.1.901),
+ libxinerama-dev,
libxpathselect-dev (>=1.4),
libxtst-dev,
libzeitgeist-2.0-dev,
pkg-config,
python3-all (>= 3.4),
+ python3-dev,
+ python3-gi,
python3-setuptools,
quilt,
systemd,
+ xorg,
xserver-xorg-video-dummy,
xsltproc,
- yaru-theme-icon,
+ yaru-theme-icon
Standards-Version: 3.9.5
Homepage: https://launchpad.net/unity
# If you aren't a member of ~unity-team but need to upload packaging changes,
@@ -95,6 +101,8 @@ Recommends: unity-control-center,
hud,
session-shortcuts,
unity-session,
+ unity-uwidgets,
+ indicator-notifications
Breaks: unity-lens-applications (<< 5.12.0-0ubuntu2),
unity-lens-files (<< 5.10.0-0ubuntu2),
unity-lens-music (<< 6.0.0),
@@ -220,3 +228,28 @@ Description: Autopiloted tests for Unity
bindings to be able to write tests in python as well as the full test suite
for Unity.
+Package: unity-uwidgets
+Section: python
+Architecture: all
+Depends: ${misc:Depends},
+ ${python3:Depends},
+ python3,
+ xorg,
+ libxinerama-dev,
+ libcairo2-dev,
+ python3-gi,
+ python3-pil,
+ python3-pydbus,
+ python3-psutil,
+ gir1.2-gtk-3.0,
+ gir1.2-glib-2.0,
+Description: Widgets for Unity
+ Unity is a desktop experience that sings. Designed by Canonical and the Ayatana
+ community, Unity is all about the combination of familiarity and the future. We
+ bring together visual design, analysis of user experience testing, modern
+ graphics technologies and a deep understanding of the free software landscape
+ to produce what we hope will be the lightest, most elegant and most delightful
+ way to use your PC.
+ .
+ This package contains support for widgets for Unity, based on Blighty.
+
diff --git a/debian/rules b/debian/rules
index 4b29c43fb..038698489 100755
--- a/debian/rules
+++ b/debian/rules
@@ -35,13 +35,12 @@ override_dh_auto_configure:
override_dh_install:
# install autopilot tests
- cd tests/autopilot; \
- set -ex; for python in $(shell py3versions -r); do \
- $$python setup.py install --root=$(CURDIR)/debian/tmp --install-layout=deb; \
- done; \
- cd $(CURDIR)
+ cd tests/autopilot; python3 setup.py install --root=$(CURDIR)/debian/tmp --install-layout=deb;
find debian/tmp/usr/lib -name \*.*a -exec rm {} \;
rm -rf debian/tmp/usr/share/gconf/schemas
+ # install uwidgets
+ cd uwidgets; python3 setup.py install --root=$(CURDIR)/debian/tmp --install-layout=deb
+ install -Dm755 uwidgets/uwidgets-runner.desktop $(CURDIR)/debian/tmp/etc/xdg/autostart/uwidgets-runner.desktop
dh_install --fail-missing
override_dh_gencontrol:
diff --git a/debian/unity-uwidgets.install b/debian/unity-uwidgets.install
new file mode 100644
index 000000000..5bbbd8873
--- /dev/null
+++ b/debian/unity-uwidgets.install
@@ -0,0 +1,3 @@
+usr/lib/python*/*/uwidgets*
+usr/bin/uwidgets-runner
+etc/xdg/autostart/uwidgets-runner.desktop \ No newline at end of file
diff --git a/debian/unity.install b/debian/unity.install
index b60c76294..224959ec9 100644
--- a/debian/unity.install
+++ b/debian/unity.install
@@ -1,6 +1,6 @@
etc/compizconfig
etc/pam.d
-usr/bin
+usr/bin/unity
usr/lib/*/compiz/libunity*.so
usr/lib/*/unity/unity-active-plugins-safety-check
usr/lib/*/unity/compiz-config-profile-setter
diff --git a/launcher/BFBLauncherIcon.cpp b/launcher/BFBLauncherIcon.cpp
index 68ff72dad..eece73a88 100644
--- a/launcher/BFBLauncherIcon.cpp
+++ b/launcher/BFBLauncherIcon.cpp
@@ -143,9 +143,7 @@ void BFBLauncherIcon::UpdateDefaultSearchText()
{
auto home_scope = reader_->GetScopeDataById("home.scope");
- tooltip_text = ((Settings::Instance().remote_content) ?
- _("Search your computer and online sources") :
- _("Search your computer"));
+ tooltip_text = _("Search your computer");
if (home_scope)
{
diff --git a/launcher/FileManagerLauncherIcon.cpp b/launcher/FileManagerLauncherIcon.cpp
index 019c5507e..7e1560a95 100644
--- a/launcher/FileManagerLauncherIcon.cpp
+++ b/launcher/FileManagerLauncherIcon.cpp
@@ -23,7 +23,7 @@
#include <NuxCore/Logger.h>
#include <UnityCore/DesktopUtilities.h>
-#include "unity-shared/FileManager.h"
+#include "unity-shared/GnomeFileManager.h"
namespace unity
{
diff --git a/launcher/Launcher.cpp b/launcher/Launcher.cpp
index e744757b2..a4f880af0 100644
--- a/launcher/Launcher.cpp
+++ b/launcher/Launcher.cpp
@@ -562,10 +562,8 @@ void Launcher::SetupRenderArg(AbstractLauncherIcon::Ptr const& icon, RenderArg&
arg.progress_bias = IconProgressBias(icon);
arg.progress = CLAMP(icon->GetProgress(), 0.0f, 1.0f);
arg.draw_shortcut = shortcuts_shown_ && !hide_machine_.GetQuirk(LauncherHideMachine::PLACES_VISIBLE);
- arg.system_item = icon->GetIconType() == AbstractLauncherIcon::IconType::HOME ||
- icon->GetIconType() == AbstractLauncherIcon::IconType::HUD;
- arg.colorify_background = icon->GetIconType() == AbstractLauncherIcon::IconType::HOME ||
- icon->GetIconType() == AbstractLauncherIcon::IconType::HUD ||
+ arg.system_item = icon->GetIconType() == AbstractLauncherIcon::IconType::HUD;
+ arg.colorify_background = icon->GetIconType() == AbstractLauncherIcon::IconType::HUD ||
icon->GetIconType() == AbstractLauncherIcon::IconType::TRASH ||
icon->GetIconType() == AbstractLauncherIcon::IconType::DESKTOP ||
icon->GetIconType() == AbstractLauncherIcon::IconType::DEVICE ||
@@ -1113,13 +1111,6 @@ void Launcher::OnOverlayShown(GVariant* data)
bg_effect_helper_.enabled = true;
- // Don't desaturate icons if the mouse is over the launcher:
- if (!hovered_)
- {
- LOG_DEBUG(logger) << "Desaturate on monitor " << monitor();
- DesaturateIcons();
- }
-
if (icon_under_mouse_)
icon_under_mouse_->HideTooltip();
}
@@ -2769,242 +2760,22 @@ bool Launcher::DndIsSpecialRequest(std::string const& uri) const
}
void Launcher::ProcessDndEnter()
-{
-#ifdef USE_X11
- SetStateMouseOverLauncher(true);
-
- dnd_data_.Reset();
- drag_action_ = nux::DNDACTION_NONE;
- steal_drag_ = false;
- data_checked_ = false;
- dnd_hovered_icon_ = nullptr;
- drag_edge_touching_ = false;
- dnd_hide_animation_.Stop();
-#endif
-}
+{ }
void Launcher::DndReset()
-{
-#ifdef USE_X11
- dnd_data_.Reset();
-
- bool is_overlay_open = IsOverlayOpen();
-
- for (auto it : *model_)
- {
- auto icon_type = it->GetIconType();
- bool desaturate = false;
-
- if (icon_type != AbstractLauncherIcon::IconType::HOME &&
- icon_type != AbstractLauncherIcon::IconType::HUD)
- {
- desaturate = is_overlay_open && !hovered_;
- }
-
- it->SetQuirk(AbstractLauncherIcon::Quirk::DESAT, desaturate, monitor());
- it->SetQuirk(AbstractLauncherIcon::Quirk::UNFOLDED, false, monitor());
- }
-
- DndHoveredIconReset();
-#endif
-}
+{ }
void Launcher::DndHoveredIconReset()
-{
-#ifdef USE_X11
- SetActionState(ACTION_NONE);
-
- if (steal_drag_ && dnd_hovered_icon_)
- {
- dnd_hovered_icon_->SetQuirk(AbstractLauncherIcon::Quirk::VISIBLE, false, monitor());
- dnd_hovered_icon_->remove.emit(dnd_hovered_icon_);
- }
-
- if (!steal_drag_ && dnd_hovered_icon_)
- {
- dnd_hovered_icon_->SendDndLeave();
- dnd_hovered_icon_->SetQuirk(AbstractLauncherIcon::Quirk::GLOW, false, monitor());
- }
-
- steal_drag_ = false;
- drag_edge_touching_ = false;
- dnd_hovered_icon_ = nullptr;
-#endif
-}
+{ }
void Launcher::ProcessDndLeave()
-{
-#ifdef USE_X11
- SetStateMouseOverLauncher(false);
- DndHoveredIconReset();
-#endif
-}
+{ }
void Launcher::ProcessDndMove(int x, int y, std::list<char*> mimes)
-{
-#ifdef USE_X11
- if (!data_checked_)
- {
- const std::string uri_list = "text/uri-list";
- data_checked_ = true;
- dnd_data_.Reset();
- auto& display = nux::GetWindowThread()->GetGraphicsDisplay();
-
- // get the data
- for (auto const& mime : mimes)
- {
- if (mime != uri_list)
- continue;
-
- dnd_data_.Fill(display.GetDndData(const_cast<char*>(uri_list.c_str())));
- break;
- }
-
- // see if the launcher wants this one
- auto const& uris = dnd_data_.Uris();
- if (std::find_if(uris.begin(), uris.end(), [this] (std::string const& uri)
- {return DndIsSpecialRequest(uri);}) != uris.end())
- {
- steal_drag_ = true;
- }
-
- // only set hover once we know our first x/y
- SetActionState(ACTION_DRAG_EXTERNAL);
- SetStateMouseOverLauncher(true);
- }
-
- SetMousePosition(x - parent_->GetGeometry().x, y - parent_->GetGeometry().y);
-
- if (options()->hide_mode != LAUNCHER_HIDE_NEVER)
- {
- if ((monitor() == 0 && !IsOverlayOpen() && mouse_position_.x == 0 && !drag_edge_touching_) &&
- ((launcher_position_ == LauncherPosition::LEFT &&
- mouse_position_.y <= (parent_->GetGeometry().height - icon_size_.CP(cv_) - 2 * SPACE_BETWEEN_ICONS.CP(cv_))) ||
- (launcher_position_ == LauncherPosition::BOTTOM &&
- mouse_position_.x <= (parent_->GetGeometry().width - icon_size_.CP(cv_) - 2 * SPACE_BETWEEN_ICONS.CP(cv_)))))
- {
- if (dnd_hovered_icon_)
- {
- dnd_hovered_icon_->SendDndLeave();
- dnd_hovered_icon_->SetQuirk(AbstractLauncherIcon::Quirk::GLOW, false, monitor());
- }
-
- animation::StartOrReverse(dnd_hide_animation_, animation::Direction::FORWARD);
- drag_edge_touching_ = true;
- }
- else if (drag_edge_touching_ &&
- ((launcher_position_ == LauncherPosition::LEFT && mouse_position_.x != 0) ||
- (launcher_position_ == LauncherPosition::BOTTOM && mouse_position_.y != 0)))
- {
- animation::StartOrReverse(dnd_hide_animation_, animation::Direction::BACKWARD);
- drag_edge_touching_ = false;
- }
- }
-
- EventLogic();
- auto const& hovered_icon = MouseIconIntersection(mouse_position_.x, mouse_position_.y);
-
- bool hovered_icon_is_appropriate = false;
- if (hovered_icon)
- {
- if (hovered_icon->GetIconType() == AbstractLauncherIcon::IconType::TRASH)
- steal_drag_ = false;
-
- if (hovered_icon->position() == AbstractLauncherIcon::Position::FLOATING)
- hovered_icon_is_appropriate = true;
- }
-
- if (steal_drag_)
- {
- drag_action_ = nux::DNDACTION_COPY;
- if (!dnd_hovered_icon_ && hovered_icon_is_appropriate)
- {
- dnd_hovered_icon_ = new SpacerLauncherIcon(monitor());
- model_->AddIcon(dnd_hovered_icon_);
- model_->ReorderBefore(dnd_hovered_icon_, hovered_icon, true);
- }
- else if (dnd_hovered_icon_)
- {
- if (hovered_icon)
- {
- if (hovered_icon_is_appropriate)
- {
- model_->ReorderSmart(dnd_hovered_icon_, hovered_icon, true);
- }
- else
- {
- dnd_hovered_icon_->SetQuirk(AbstractLauncherIcon::Quirk::VISIBLE, false, monitor());
- dnd_hovered_icon_->remove.emit(dnd_hovered_icon_);
- dnd_hovered_icon_ = nullptr;
- }
- }
- }
- }
- else
- {
- if (!drag_edge_touching_ && hovered_icon != dnd_hovered_icon_)
- {
- if (hovered_icon)
- {
- hovered_icon->SendDndEnter();
- drag_action_ = hovered_icon->QueryAcceptDrop(dnd_data_);
-
- if (drag_action_ != nux::DNDACTION_NONE)
- hovered_icon->SetQuirk(AbstractLauncherIcon::Quirk::GLOW, true, monitor());
- }
- else
- {
- drag_action_ = nux::DNDACTION_NONE;
- }
-
- if (dnd_hovered_icon_)
- {
- dnd_hovered_icon_->SendDndLeave();
- dnd_hovered_icon_->SetQuirk(AbstractLauncherIcon::Quirk::GLOW, false, monitor());
- }
-
- dnd_hovered_icon_ = hovered_icon;
- }
- }
-
- bool accept;
- if (drag_action_ != nux::DNDACTION_NONE)
- accept = true;
- else
- accept = false;
-
- SendDndStatus(accept, drag_action_, nux::Geometry(x, y, 1, 1));
-#endif
-}
+{ }
void Launcher::ProcessDndDrop(int x, int y)
-{
-#ifdef USE_X11
- if (steal_drag_)
- {
- for (auto const& uri : dnd_data_.Uris())
- {
- if (DndIsSpecialRequest(uri))
- add_request.emit(uri, dnd_hovered_icon_);
- }
- }
- else if (dnd_hovered_icon_ && drag_action_ != nux::DNDACTION_NONE)
- {
- if (IsOverlayOpen())
- ubus_.SendMessage(UBUS_OVERLAY_CLOSE_REQUEST);
-
- dnd_hovered_icon_->AcceptDrop(dnd_data_);
- }
-
- if (drag_action_ != nux::DNDACTION_NONE)
- SendDndFinished(true, drag_action_);
- else
- SendDndFinished(false, drag_action_);
-
- // reset our shiz
- DndReset();
-#endif
-}
+{ }
/*
* Returns the current selected icon if it is in keynavmode
@@ -3035,81 +2806,16 @@ int Launcher::GetDragDelta() const
}
void Launcher::DndStarted(std::string const& data)
-{
-#ifdef USE_X11
- SetDndQuirk();
-
- dnd_data_.Fill(data.c_str());
-
- auto const& uris = dnd_data_.Uris();
- if (std::find_if(uris.begin(), uris.end(), [this] (std::string const& uri)
- {return DndIsSpecialRequest(uri);}) != uris.end())
- {
- steal_drag_ = true;
-
- if (IsOverlayOpen())
- SaturateIcons();
- }
- else
- {
- for (auto const& it : *model_)
- {
- if (it->ShouldHighlightOnDrag(dnd_data_))
- {
- it->SetQuirk(AbstractLauncherIcon::Quirk::DESAT, false, monitor());
- it->SetQuirk(AbstractLauncherIcon::Quirk::UNFOLDED, true, monitor());
- }
- else
- {
- it->SetQuirk(AbstractLauncherIcon::Quirk::DESAT, true, monitor());
- it->SetQuirk(AbstractLauncherIcon::Quirk::UNFOLDED, false, monitor());
- }
- }
- }
-#endif
-}
+{ }
void Launcher::DndFinished()
-{
-#ifdef USE_X11
- UnsetDndQuirk();
-
- data_checked_ = false;
-
- DndReset();
-#endif
-}
+{ }
void Launcher::SetDndQuirk()
-{
-#ifdef USE_X11
- hide_machine_.SetQuirk(LauncherHideMachine::EXTERNAL_DND_ACTIVE, true);
-#endif
-}
+{ }
void Launcher::UnsetDndQuirk()
-{
-#ifdef USE_X11
-
- if (IsOverlayOpen() && !hovered_)
- {
- DesaturateIcons();
- }
- else
- {
- for (auto const& it : *model_)
- {
- it->SetQuirk(AbstractLauncherIcon::Quirk::DESAT, false, monitor());
- it->SetQuirk(AbstractLauncherIcon::Quirk::UNFOLDED, false, monitor());
- }
- }
-
-
- hide_machine_.SetQuirk(LauncherHideMachine::MT_DRAG_OUT, drag_out_delta_x_ >= DRAG_OUT_PIXELS - 90.0f);
- hide_machine_.SetQuirk(LauncherHideMachine::EXTERNAL_DND_ACTIVE, false);
- animation::SetValue(dnd_hide_animation_, animation::Direction::BACKWARD);
-#endif
-}
+{ }
} // namespace launcher
} // namespace unity
diff --git a/launcher/StandaloneLauncher.cpp b/launcher/StandaloneLauncher.cpp
index 0af7d0c1b..779528357 100644
--- a/launcher/StandaloneLauncher.cpp
+++ b/launcher/StandaloneLauncher.cpp
@@ -40,7 +40,7 @@ using namespace unity;
namespace
{
-const nux::Size win_size(1024, 768);
+const nux::Size win_size(1280, 720);
const nux::Color bg_color(95/255.0f, 18/255.0f, 45/255.0f, 1.0f);
}
diff --git a/launcher/TrashLauncherIcon.cpp b/launcher/TrashLauncherIcon.cpp
index 15dc9a611..edf5eea34 100644
--- a/launcher/TrashLauncherIcon.cpp
+++ b/launcher/TrashLauncherIcon.cpp
@@ -29,7 +29,7 @@
#include "QuicklistMenuItemLabel.h"
#include "unity-shared/DesktopApplicationManager.h"
-#include "unity-shared/FileManager.h"
+#include "unity-shared/GnomeFileManager.h"
namespace unity
{
diff --git a/lockscreen/LockScreenPanel.cpp b/lockscreen/LockScreenPanel.cpp
index e54e2f1b4..b3087a5cc 100644
--- a/lockscreen/LockScreenPanel.cpp
+++ b/lockscreen/LockScreenPanel.cpp
@@ -37,8 +37,8 @@ namespace lockscreen
{
namespace
{
-const RawPixel PADDING = 5_em;
-const nux::Color BG_COLOR(0.1, 0.1, 0.1, 0.4);
+const RawPixel PADDING = 14_em;
+nux::Color BG_COLOR(0.1, 0.1, 0.1, 0.9);
}
using namespace indicator;
diff --git a/panel/PanelController.cpp b/panel/PanelController.cpp
index f24eb460b..c6496b790 100644
--- a/panel/PanelController.cpp
+++ b/panel/PanelController.cpp
@@ -66,7 +66,7 @@ Controller::Impl::Impl(Controller* parent, menu::Manager::Ptr const& indicators,
: parent_(parent)
, indicators_(indicators)
, edge_barriers_(edge_barriers)
- , opacity_(1.0f)
+ , opacity_(0.7f)
, opacity_maximized_toggle_(false)
{
UScreen* screen = UScreen::GetDefault();
diff --git a/panel/PanelIndicatorsView.cpp b/panel/PanelIndicatorsView.cpp
index 20f06381c..8bf3c8009 100644
--- a/panel/PanelIndicatorsView.cpp
+++ b/panel/PanelIndicatorsView.cpp
@@ -46,6 +46,7 @@ PanelIndicatorsView::PanelIndicatorsView()
{
opacity.DisableNotifications();
layout_->SetContentDistribution(nux::MAJOR_POSITION_END);
+ layout_->SetLeftAndRightPadding(layout_->GetLeftPadding(), 6);
SetLayout(layout_);
LOG_DEBUG(logger) << "Indicators View Added: ";
diff --git a/panel/PanelIndicatorsView.h b/panel/PanelIndicatorsView.h
index bb11df48b..8e3a1ec4c 100644
--- a/panel/PanelIndicatorsView.h
+++ b/panel/PanelIndicatorsView.h
@@ -52,7 +52,7 @@ public:
typedef PanelIndicatorEntryView::IndicatorEntryType IndicatorEntryType;
PanelIndicatorEntryView* AddEntry(indicator::Entry::Ptr const& entry,
- int padding = 5,
+ int padding = 9,
IndicatorEntryPosition pos = AUTO,
IndicatorEntryType type = IndicatorEntryType::INDICATOR);
void RemoveEntry(indicator::Entry::Ptr const&);
diff --git a/panel/PanelMenuView.cpp b/panel/PanelMenuView.cpp
index 2bcdd494c..abaa420b4 100644
--- a/panel/PanelMenuView.cpp
+++ b/panel/PanelMenuView.cpp
@@ -45,8 +45,8 @@ DECLARE_LOGGER(logger, "unity.panel.menu");
namespace
{
- const RawPixel MAIN_LEFT_PADDING = 4_em;
- const RawPixel TITLE_PADDING = 2_em;
+ const RawPixel MAIN_LEFT_PADDING = 13_em;
+ const RawPixel TITLE_PADDING = 1_em;
const RawPixel MENUBAR_PADDING = 4_em;
const int MENU_ENTRIES_PADDING = 6;
diff --git a/panel/PanelTray.cpp b/panel/PanelTray.cpp
index 20be87f5a..afdf7d4f9 100644
--- a/panel/PanelTray.cpp
+++ b/panel/PanelTray.cpp
@@ -29,7 +29,7 @@ DECLARE_LOGGER(logger, "unity.panel.tray");
namespace
{
const std::string SETTINGS_NAME = "com.canonical.Unity.Panel";
-const int PADDING = 3;
+const int PADDING = 12;
const std::array<std::string, 2> WHITELIST {{ "JavaEmbeddedFrame", "Wine" }};
}
@@ -63,7 +63,7 @@ PanelTray::PanelTray(int monitor)
GTK_ORIENTATION_HORIZONTAL,
(NaTrayFilterCallback)FilterTrayCallback,
this);
- na_tray_set_icon_size(tray_, panel_height);
+ na_tray_set_icon_size(tray_, panel_height-6);
icon_removed_signal_.Connect(na_tray_get_manager(tray_), "tray_icon_removed",
sigc::mem_fun(this, &PanelTray::OnTrayIconRemoved));
@@ -97,7 +97,7 @@ Window PanelTray::xid()
void PanelTray::Draw(nux::GraphicsEngine& gfx_context, bool force_draw)
{
- nux::Geometry const& geo = GetAbsoluteGeometry();
+ nux::Geometry geo = GetAbsoluteGeometry();
gfx_context.PushClippingRectangle(geo);
nux::GetPainter().PaintBackground(gfx_context, geo);
diff --git a/panel/PanelView.cpp b/panel/PanelView.cpp
index fd492b62e..1a54ab1a0 100644
--- a/panel/PanelView.cpp
+++ b/panel/PanelView.cpp
@@ -58,7 +58,7 @@ PanelView::PanelView(MockableBaseWindow* parent, menu::Manager::Ptr const& menus
, opacity_maximized_toggle_(false)
, needs_geo_sync_(false)
, overlay_is_open_(false)
- , opacity_(1.0f)
+ , opacity_(0.7f)
, monitor_(0)
, stored_dash_width_(0)
, bg_effect_helper_(this)
@@ -539,7 +539,7 @@ PanelView::UpdateBackground()
if (overlay_is_open_ || wm.IsScaleActive())
{
- bg_layer_.reset(new nux::ColorLayer(wm.average_color(), true, rop));
+ // bg_layer_.reset(new nux::ColorLayer(wm.average_color(), true, rop));
}
else
{
diff --git a/panel/StandalonePanel.cpp b/panel/StandalonePanel.cpp
index e13460240..76b4c0e06 100644
--- a/panel/StandalonePanel.cpp
+++ b/panel/StandalonePanel.cpp
@@ -41,7 +41,7 @@ using namespace unity::panel;
struct PanelWindow
{
PanelWindow()
- : wt(nux::CreateGUIThread("Unity Panel", 1024, 24, 0, &PanelWindow::ThreadWidgetInit, this))
+ : wt(nux::CreateGUIThread("Unity Panel", 1024, 30, 0, &PanelWindow::ThreadWidgetInit, this))
, animation_controller(tick_source)
{}
diff --git a/plugins/unityshell/src/unityshell.cpp b/plugins/unityshell/src/unityshell.cpp
index ff739f6d6..38f433aaf 100644
--- a/plugins/unityshell/src/unityshell.cpp
+++ b/plugins/unityshell/src/unityshell.cpp
@@ -3157,73 +3157,9 @@ bool UnityWindow::glDraw(const GLMatrix& matrix,
auto draw_panel_shadow = DrawPanelShadow::NO;
- if (!(mask & PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK))
- {
- Window active_window = screen->activeWindow();
-
- if (G_UNLIKELY(window_type == CompWindowTypeDesktopMask))
- {
- uScreen->setPanelShadowMatrix(matrix);
-
- if (active_window == 0 || active_window == window->id())
- {
- if (PluginAdapter::Default().IsWindowOnTop(window->id()))
- {
- draw_panel_shadow = DrawPanelShadow::OVER_WINDOW;
- }
- uScreen->is_desktop_active_ = true;
- }
- }
- else
- {
- if (window->id() == active_window)
- {
- draw_panel_shadow = DrawPanelShadow::BELOW_WINDOW;
- uScreen->is_desktop_active_ = false;
-
- if (!(window_state & CompWindowStateMaximizedVertMask) &&
- !(window_state & CompWindowStateFullscreenMask) &&
- !(window_type & CompWindowTypeFullscreenMask))
- {
- auto const& output = uScreen->screen->currentOutputDev();
- int monitor = uScreen->WM.MonitorGeometryIn(NuxGeometryFromCompRect(output));
-
- if (window->y() - window->border().top < output.y() + uScreen->panel_style_.PanelHeight(monitor))
- {
- draw_panel_shadow = DrawPanelShadow::OVER_WINDOW;
- }
- }
- }
- else if (uScreen->menus_->integrated_menus())
- {
- draw_panel_shadow = DrawPanelShadow::BELOW_WINDOW;
- }
- else
- {
- if (uScreen->is_desktop_active_)
- {
- if (PluginAdapter::Default().IsWindowOnTop(window->id()))
- {
- draw_panel_shadow = DrawPanelShadow::OVER_WINDOW;
- uScreen->panelShadowPainted = CompRegion();
- }
- }
- }
- }
- }
-
- if (locked)
- draw_panel_shadow = DrawPanelShadow::NO;
-
- if (draw_panel_shadow == DrawPanelShadow::BELOW_WINDOW)
- uScreen->paintPanelShadow(region);
-
deco_win_->Draw(matrix, attrib, region, mask);
bool ret = gWindow->glDraw(matrix, attrib, region, mask);
- if (draw_panel_shadow == DrawPanelShadow::OVER_WINDOW)
- uScreen->paintPanelShadow(region);
-
return ret;
}
diff --git a/plugins/unityshell/unityshell.xml.in b/plugins/unityshell/unityshell.xml.in
index 9294c5b26..61afdeac4 100644
--- a/plugins/unityshell/unityshell.xml.in
+++ b/plugins/unityshell/unityshell.xml.in
@@ -104,8 +104,8 @@
<option name="panel_opacity" type="float">
<_short>Panel Opacity</_short>
<_long>The opacity of the Panel background.</_long>
- <default>1.0</default>
- <min>0.0</min>
+ <default>0.75</default>
+ <min>0.1</min>
<max>1.0</max>
<precision>0.01</precision>
</option>
@@ -419,7 +419,7 @@
<option name="icon_size" type="int">
<_short>Launcher Icon Size</_short>
<_long>The size of the icons in the Launcher.</_long>
- <default>48</default>
+ <default>44</default>
<min>8</min>
<max>64</max>
<precision>1</precision>
@@ -430,7 +430,7 @@
<_long>Change how the icons in the Launcher are backlit.</_long>
<min>0</min>
<max>4</max>
- <default>1</default>
+ <default>4</default>
<desc>
<value>0</value>
<_name>Backlight Always On</_name>
diff --git a/resources/dash_sheen.png b/resources/dash_sheen.png
index fb31cdb6e..7cceadb76 100644
--- a/resources/dash_sheen.png
+++ b/resources/dash_sheen.png
Binary files differ
diff --git a/resources/empty.png b/resources/empty.png
new file mode 100644
index 000000000..7cceadb76
--- /dev/null
+++ b/resources/empty.png
Binary files differ
diff --git a/resources/launcher_bfb.svg b/resources/launcher_bfb.svg
index 74e60e9c8..b6f1ccb0a 100644
--- a/resources/launcher_bfb.svg
+++ b/resources/launcher_bfb.svg
@@ -1,13 +1,126 @@
-<svg version="1.1" viewBox="0 0 136.53 136.53" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
- <defs>
- <filter id="a" x="-.075" y="-.075" width="1.15" height="1.15" color-interpolation-filters="sRGB">
- <feGaussianBlur stdDeviation="2.4999998"/>
- </filter>
- </defs>
- <image width="136.53" height="136.53" preserveAspectRatio="none" xlink:href="data:image/png;base64,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 4K+6lV/77/8DTX3gKAGJXUUAAAAASUVORK5CYII= "/>
- <g>
- <ellipse cx="68.267" cy="68.267" rx="40" ry="40" fill="#9005d5"/>
- <path d="m68.244 28.267a40 40 0 0 0-39.978 40 40 40 0 0 0 40 40 40 40 0 0 0 40-40 40 40 0 0 0-40-40 40 40 0 0 0-0.0223 0zm0.43912 12.8a27.2 27.2 0 0 1 5.2476 0.51106l-3.8886 6.7353a20 20 0 0 0-1.359-0.04632 20 20 0 0 0-1.3588 0.04608l-3.4e-4 -5.52e-4a20 20 0 0 0-8.6411 2.6333 20 20 0 0 0-2e-3 8e-4 20 20 0 0 0-6.5993 6.1657l4.9e-4 5.44e-4a20 20 0 0 0-1.359 2.3538l-7.7772 9.6e-5a27.2 27.2 0 0 1 5.2474-9.0889l-5.5e-4 -5.52e-4a27.2 27.2 0 0 1 5.4498-4.7744l1.9133 3.314 2.933-1.6933-1.9133-3.3139a27.2 27.2 0 0 1 6.8594-2.332l4.4e-4 5.44e-4a27.2 27.2 0 0 1 5.2474-0.51097zm8.6027 1.4841 5.7186 9.6e-5c0.38588 7.2e-5 0.73999 0.20394 0.93828 0.5309l2.8616 4.7698c0.0837 0.12732 0.17604 0.33828 0.16272 0.60168-8e-3 0.15803-0.0538 0.33549-0.16272 0.52421l-2.8616 4.7756c-0.19839 0.32682-0.55229 0.53025-0.9382 0.53024l-5.7186-8e-5c-0.19298 1.28e-4 -0.37827-0.04912-0.53974-0.14023-0.16143-0.09116-0.29882-0.22444-0.39836-0.39034l-2.862-4.7755c-0.20902-0.34837-0.20905-0.77678 0-1.1251l2.862-4.7706c0.0992-0.16344 0.23645-0.29694 0.39854-0.38769 0.16151-0.09178 0.34654-0.14284 0.53949-0.14288zm-11.115 3.7637c0.0455 0.08294 0.0932 0.16574 0.14346 0.24846zm23.002 4.0632v1.76e-4a27.2 27.2 0 0 1 5.2475 9.0889h-5e-3a27.2 27.2 0 0 1 1.41 7.1068h-3.8789v3.3867h3.8793a27.2 27.2 0 0 1-1.4101 7.1067h4e-3a27.2 27.2 0 0 1-5.2475 9.089l-3.8886-6.7352a20 20 0 0 0 1.359-2.3536h-4e-3a20 20 0 0 0 2.0401-8.8 20 20 0 0 0-5.6e-4 -0.0024 20 20 0 0 0-2.0399-8.7985l5e-3 8e-5a20 20 0 0 0-1.3584-2.3536zm-46.255 11.84 5.5666 0.09045c0.38224 0.0084 0.73533 0.21324 0.92828 0.54744l2.8592 4.9525c0.0966 0.16707 0.14668 0.3521 0.1485 0.53751l-9e-5 -8e-5c2e-3 0.18537-0.045 0.37099-0.1389 0.54017l-2.7046 4.8664c-0.19718 0.35519-0.5682 0.56943-0.9744 0.56257l-5.5624-0.09335c-0.19113-4e-3 -0.3754-0.05632-0.53504-0.1513-0.16024-0.09399-0.29698-0.22863-0.39349-0.39572l-2.8592-4.9525c-0.19287-0.33421-0.19334-0.7428-9e-3 -1.078l2.6999-4.8631c0.0684-0.13618 0.20503-0.3216 0.43979-0.44177 0.14087-0.07208 0.31738-0.12122 0.53528-0.12122zm0.0284 14.849h7.7773a20 20 0 0 0 1.3589 2.3536l-6e-3 0.0097a20 20 0 0 0 15.242 8.8l-3.883 6.7258 3.8886-6.7352a20 20 0 0 0 1.3588 0.04608 20 20 0 0 0 1.3591-0.04664l3.8885 6.7354a27.2 27.2 0 0 1-5.2475 0.51106 27.2 27.2 0 0 1-5.2476-0.51106l-6e-3 9e-3a27.2 27.2 0 0 1-6.8595-2.332l1.9133-3.314-2.933-1.6934-1.9134 3.314a27.2 27.2 0 0 1-5.4496-4.7746l6e-3 -0.0094a27.2 27.2 0 0 1-5.2475-9.089zm40.045 5.0986c0.40294-0.0064 0.77107 0.20574 0.96664 0.55811l2.6786 4.8249c0.0913 0.16622 0.13786 0.35033 0.13544 0.53461-8e-4 0.18428-0.0492 0.36861-0.14487 0.53439l-2.8364 4.9126c-0.19146 0.33149-0.5422 0.5345-0.92142 0.54266l-5.5169 0.0926c-0.1509 9e-3 -0.37795-0.0166-0.59762-0.15867-0.13179-0.0853-0.26151-0.2125-0.36958-0.39967l-2.6833-4.827c-0.18236-0.33255-0.18149-0.7375 0.01-1.069l2.8364-4.9127c0.0956-0.16586 0.22973-0.30062 0.38811-0.39414 0.15837-0.09346 0.34107-0.14544 0.53297-0.14866z" filter="url(#a)" opacity=".5" style="mix-blend-mode:normal;paint-order:stroke markers fill"/>
- <path d="m68.244 28.267a40 40 0 0 0-39.978 40 40 40 0 0 0 40 40 40 40 0 0 0 40-40 40 40 0 0 0-40-40 40 40 0 0 0-0.0223 0zm0.43913 12.8a27.2 27.2 0 0 1 5.2476 0.51106l-3.8886 6.7353a20 20 0 0 0-1.359-0.04632 20 20 0 0 0-1.3588 0.04608l-3.4e-4 -5.52e-4a20 20 0 0 0-8.6411 2.6333 20 20 0 0 0-2e-3 8e-4 20 20 0 0 0-6.5993 6.1657l4.9e-4 5.44e-4a20 20 0 0 0-1.359 2.3538l-7.7773 9.6e-5a27.2 27.2 0 0 1 5.2474-9.0889l-5.5e-4 -5.52e-4a27.2 27.2 0 0 1 5.4498-4.7744l1.9133 3.314 2.933-1.6933-1.9133-3.3139a27.2 27.2 0 0 1 6.8594-2.332l4.3e-4 5.44e-4a27.2 27.2 0 0 1 5.2474-0.51097zm8.6027 1.4841 5.7186 9.6e-5c0.38587 7.2e-5 0.73998 0.20394 0.93827 0.5309l2.8616 4.7698c0.0837 0.12732 0.17603 0.33828 0.16272 0.60168-8e-3 0.15803-0.0538 0.33549-0.16272 0.52421l-2.8616 4.7756c-0.19839 0.32682-0.55229 0.53025-0.9382 0.53024l-5.7186-8e-5c-0.19299 1.28e-4 -0.37827-0.04912-0.53975-0.14023-0.16143-0.09116-0.29881-0.22444-0.39836-0.39034l-2.862-4.7755c-0.20903-0.34837-0.20906-0.77678 0-1.1251l2.862-4.7706c0.0992-0.16344 0.23644-0.29694 0.39853-0.38769 0.16151-0.09178 0.34655-0.14284 0.5395-0.14288zm-11.115 3.7637c0.0455 0.08294 0.0932 0.16574 0.14346 0.24846zm23.002 4.0632v1.76e-4a27.2 27.2 0 0 1 5.2475 9.0889h-5e-3a27.2 27.2 0 0 1 1.41 7.1068h-3.8789v3.3867h3.8793a27.2 27.2 0 0 1-1.4102 7.1067h4e-3a27.2 27.2 0 0 1-5.2475 9.089l-3.8886-6.7352a20 20 0 0 0 1.359-2.3536h-4e-3a20 20 0 0 0 2.0401-8.8 20 20 0 0 0-5.5e-4 -0.0024 20 20 0 0 0-2.0399-8.7985l5e-3 8e-5a20 20 0 0 0-1.3584-2.3536zm-46.255 11.84 5.5666 0.09045c0.38223 0.0084 0.73532 0.21324 0.92828 0.54744l2.8592 4.9525c0.0966 0.16707 0.14668 0.3521 0.1485 0.53751l-9e-5 -8e-5c2e-3 0.18537-0.045 0.37099-0.1389 0.54017l-2.7046 4.8664c-0.19719 0.35519-0.5682 0.56943-0.97441 0.56257l-5.5624-0.09335c-0.19113-4e-3 -0.3754-0.05632-0.53504-0.1513-0.16024-0.09399-0.29697-0.22863-0.39349-0.39572l-2.8592-4.9525c-0.19287-0.33421-0.19333-0.7428-9e-3 -1.078l2.6999-4.8631c0.0684-0.13618 0.20502-0.3216 0.43978-0.44177 0.14087-0.07208 0.31738-0.12122 0.53529-0.12122zm0.0284 14.849h7.7773a20 20 0 0 0 1.3589 2.3536l-6e-3 0.0097a20 20 0 0 0 15.242 8.8l-3.883 6.7258 3.8886-6.7352a20 20 0 0 0 1.3588 0.0461 20 20 0 0 0 1.3591-0.0466l3.8885 6.7354a27.2 27.2 0 0 1-5.2475 0.51106 27.2 27.2 0 0 1-5.2476-0.51106l-6e-3 9e-3a27.2 27.2 0 0 1-6.8595-2.332l1.9133-3.314-2.933-1.6934-1.9134 3.3141a27.2 27.2 0 0 1-5.4496-4.7746l6e-3 -9e-3a27.2 27.2 0 0 1-5.2475-9.0889zm40.045 5.0986c0.40295-0.0064 0.77107 0.20574 0.96664 0.55811l2.6786 4.8249c0.0913 0.16621 0.13786 0.35032 0.13544 0.5346-8e-4 0.18428-0.0492 0.36861-0.14486 0.5344l-2.8364 4.9126c-0.19146 0.3315-0.54219 0.53451-0.92142 0.54267l-5.5169 0.0926c-0.15091 9e-3 -0.37795-0.0166-0.59763-0.15868-0.13179-0.0853-0.26151-0.21249-0.36958-0.39967l-2.6833-4.827c-0.18236-0.33255-0.18148-0.73749 0.01-1.069l2.8364-4.9127c0.0956-0.16586 0.22974-0.30062 0.38811-0.39414 0.15838-0.09346 0.34107-0.14544 0.53297-0.14866z" fill="#fff" style="paint-order:stroke markers fill"/>
- </g>
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ version="1.1"
+ id="svg2"
+ width="136.53333"
+ height="136.53333"
+ viewBox="0 0 136.53333 136.53333"
+ sodipodi:docname="launcher_bfb.svg"
+ inkscape:export-filename="/home/muqtadir/Desktop/unity-orb1.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <metadata
+ id="metadata8">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs6">
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient927"
+ id="linearGradient1686-0"
+ x1="321.99991"
+ y1="84.000153"
+ x2="365.99991"
+ y2="84.000153"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0,2.9046321,-2.9677501,0,317.55806,-932.37102)" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient927">
+ <stop
+ style="stop-color:#f3e6fa;stop-opacity:1"
+ offset="0"
+ id="stop923" />
+ <stop
+ id="stop933"
+ offset="0.125"
+ style="stop-color:#f3e6fa;stop-opacity:0.09803922" />
+ <stop
+ id="stop931"
+ offset="0.92500001"
+ style="stop-color:#f3e6fa;stop-opacity:0.09803922" />
+ <stop
+ style="stop-color:#f3e6fa;stop-opacity:0.49803922"
+ offset="1"
+ id="stop925" />
+ </linearGradient>
+ </defs>
+ <sodipodi:namedview
+ pagecolor="#3d3d3d"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1920"
+ inkscape:window-height="965"
+ id="namedview4"
+ showgrid="false"
+ units="px"
+ inkscape:zoom="2.5"
+ inkscape:cx="80.2"
+ inkscape:cy="76.6"
+ inkscape:window-x="0"
+ inkscape:window-y="36"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg2"
+ inkscape:document-rotation="0"
+ inkscape:pagecheckerboard="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5.87204361;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 37.573433,2.9202406 c -7.781739,0 -13.909103,0.1455247 -18.950896,0.8328467 C 13.580716,4.4404388 9.4550382,5.7297171 6.4329484,8.1783524 3.4108883,10.626984 1.8158115,13.976199 0.97739229,18.072688 0.13894348,22.169208 -0.02472795,27.156491 0.01340764,33.491722 v 36.234721 36.252077 c -0.03769042,6.32548 0.12642616,11.31024 0.96398465,15.40234 0.83841921,4.09652 2.43349601,7.44572 5.45555611,9.89435 3.0220898,2.44864 7.1477676,3.73791 12.1895886,4.42524 5.041852,0.68739 11.169157,0.83288 18.950896,0.83288 h 61.391416 c 7.781821,0 13.905931,-0.14514 18.937331,-0.83288 5.03135,-0.68762 9.14441,-1.98125 12.15534,-4.4308 3.01099,-2.44948 4.5966,-5.79631 5.44188,-9.88879 0.8453,-4.09242 1.02547,-9.06961 1.02547,-15.40234 V 69.726443 33.475042 c 0,-6.332726 -0.18044,-11.309873 -1.02547,-15.402354 -0.84528,-4.092451 -2.43092,-7.439254 -5.44191,-9.8887903 C 127.04657,5.7343641 122.9335,4.4407284 117.90212,3.7530873 112.87078,3.0654433 106.74662,2.9202406 98.964849,2.9202406 Z"
+ id="path1020"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sccsccccccsscccscsccsss" />
+ <path
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.93602157;marker:none;enable-background:accumulate;opacity:0.05"
+ d="m 36.616066,1.46807 c -29.710622,0 -35.2766675,2.6326143 -35.1205639,28.315452 v 37.038633 37.039335 c -0.1564004,25.68283 5.4099419,28.31544 35.1205639,28.31544 h 63.304487 c 29.703207,0 35.120497,-2.63232 35.120497,-28.31544 V 66.822155 29.783522 c 0,-25.6831304 -5.41729,-28.315452 -35.120527,-28.315452 z"
+ id="path964"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="scccssscsss" />
+ <path
+ style="display:inline;opacity:0.2;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:5.87204313;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;enable-background:new"
+ d="M 122.82763,7.1410191 4.1773923,118.58086 v 0 c 0,0 2.7330968,13.59552 32.4363287,13.59552 h 63.30235 c 29.710619,0 35.276429,-2.63162 35.120329,-28.31451 V 66.822155 29.78238 C 133.55543,5.2605566 129.804,6.4966209 122.82763,7.1410191 Z"
+ id="path962"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccssscccc" />
+ <path
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.4;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:2.93602157;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 36.616066,1.4680407 c -29.710622,0 -35.2766675,2.6326143 -35.1205639,28.3154523 v 37.038662 37.039335 c -0.1564004,25.68283 5.4099419,28.31544 35.1205639,28.31544 h 63.304487 c 29.703207,0 35.120497,-2.63232 35.120497,-28.31544 V 66.822155 29.783493 c 0,-25.6831306 -5.41729,-28.3154523 -35.120527,-28.3154523 z"
+ id="path958"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="scccssscsss" />
+ <path
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:url(#linearGradient1686-0);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.93602157;marker:none;enable-background:accumulate"
+ d="m 36.618351,2.9202406 c -14.810527,0 -23.357707,0.8024923 -27.8516528,4.2207785 C 6.5197254,8.8501622 5.0937808,11.21773 4.1817615,14.867805 3.2697718,18.517883 2.9433191,23.40751 2.9819001,29.776733 v 37.045422 37.045395 c -0.038878,6.36922 0.2878717,11.25888 1.1998614,14.90894 0.9120193,3.65006 2.3379639,6.0176 4.5849367,7.72679 4.4939748,3.41826 13.0411258,4.2208 27.8516528,4.2208 h 63.302351 c 14.806778,0 23.311728,-0.80368 27.787868,-4.2208 2.23804,-1.70861 3.65904,-4.07987 4.57915,-7.73244 0.9201,-3.65257 1.2694,-8.53814 1.2694,-14.90897 V 66.822155 29.78238 c 0,-6.370773 -0.3493,-11.256335 -1.2694,-14.90891 -0.92011,-3.652576 -2.34108,-6.0238287 -4.57915,-7.7324509 C 123.23243,3.7238069 114.72752,2.9202406 99.920702,2.9202406 Z m 7.129545,3.1882707 c 20.618059,0.00241 41.283276,0.00878 61.876434,0.1588686 6.35977,0.2408047 13.24896,-0.4290153 19.06432,2.70607 3.84648,2.0193891 4.59592,6.5363811 5.25152,10.3534451 0.52087,6.398586 0.27156,12.903067 0.41154,19.37366 0.0674,24.629916 0.22852,49.288685 -0.23771,73.914945 -0.47932,4.30826 -1.13175,9.6021 -5.33845,12.03266 -4.76473,2.4071 -10.31445,2.63285 -15.5749,2.76847 -28.192857,0.19695 -56.459373,0.24494 -84.650447,-0.0512 -4.683585,-0.3315 -9.706116,-0.69753 -13.749023,-3.25637 C 7.1522717,121.21787 6.7626061,116.18701 6.3379507,111.92893 5.9604529,85.791447 6.0898469,59.632601 6.1815503,33.481246 6.477435,26.564529 5.4533237,19.248544 8.2740517,12.68364 10.267341,8.2984563 15.591723,7.2811389 19.965355,6.709856 27.864557,5.790309 35.818602,6.282816 43.747926,6.1085113 Z"
+ id="path964-3"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path12"
+ style="fill:#4d4d4d;fill-opacity:1;stroke:none;stroke-width:0.0633053;stroke-linejoin:round;paint-order:stroke markers fill"
+ d="M 68.386946,28.008705 A 46.000001,45.999994 0 0 0 22.412573,74.008748 46.000001,45.999994 0 0 0 68.412617,120.0087 46.000001,45.999994 0 0 0 114.41258,74.008748 46.000001,45.999994 0 0 0 68.412617,28.008705 a 46.000001,45.999994 0 0 0 -0.02568,0 z m 0.504997,14.719959 a 31.280001,31.279996 0 0 1 6.034734,0.587714 l -4.471922,7.745593 a 22.999998,22.999995 0 0 0 -1.562812,-0.05322 22.999998,22.999995 0 0 0 -1.562626,0.05296 l -3.9e-4,-6.39e-4 a 22.999996,22.999993 0 0 0 -9.93729,3.028352 22.999996,22.999993 0 0 0 -0.0019,0.0013 22.999996,22.999993 0 0 0 -7.589182,7.090553 l 5.69e-4,6.39e-4 a 22.999998,22.999995 0 0 0 -1.562812,2.70687 l -8.94385,1.02e-4 a 31.280001,31.279996 0 0 1 6.034544,-10.452199 l -6.39e-4,-6.39e-4 a 31.279999,31.279994 0 0 1 6.267219,-5.490949 l 2.200263,3.811087 3.372937,-1.947333 -2.200263,-3.810991 a 31.279999,31.279994 0 0 1 7.888316,-2.681863 l 4.92e-4,6.39e-4 a 31.280001,31.279996 0 0 1 6.034542,-0.587624 z m 9.893081,1.70667 6.576339,1.02e-4 c 0.443759,9.6e-5 0.85098,0.234549 1.079019,0.610535 l 3.290878,5.485244 c 0.09631,0.146414 0.202439,0.389025 0.187131,0.691929 -0.0092,0.181745 -0.06185,0.385818 -0.187131,0.602836 l -3.290878,5.491901 c -0.228147,0.375839 -0.635132,0.609781 -1.07893,0.609774 l -6.576428,-9.5e-5 c -0.221931,1.47e-4 -0.435013,-0.05648 -0.620713,-0.161262 v 0 c -0.185648,-0.104836 -0.343634,-0.258105 -0.458116,-0.448896 l -3.291262,-5.491805 c -0.240375,-0.400615 -0.240407,-0.893301 0,-1.29391 l 3.291351,-5.486195 c 0.114023,-0.187967 0.271913,-0.341486 0.458315,-0.445848 0.185738,-0.105545 0.398526,-0.164265 0.620425,-0.16431 z m -12.782417,4.328254 c 0.05232,0.09538 0.10718,0.190606 0.164967,0.28573 z m 26.452543,4.672647 v 1.98e-4 a 31.280001,31.279996 0 0 1 6.034644,10.452272 h -0.0051 a 31.279997,31.279992 0 0 1 1.621486,8.172806 h -4.460725 v 3.894666 h 4.461185 a 31.279997,31.279992 0 0 1 -1.621669,8.172716 h 0.0045 a 31.280001,31.279996 0 0 1 -6.034666,10.452354 l -4.471928,-7.745485 a 22.999998,22.999995 0 0 0 1.562812,-2.706582 h -0.0045 a 22.999995,22.999991 0 0 0 2.346115,-10.119953 22.999995,22.999991 0 0 0 -6.38e-4,-0.0026 22.999995,22.999991 0 0 0 -2.345917,-10.118247 l 0.0051,1.02e-4 a 22.999998,22.999995 0 0 0 -1.562167,-2.706684 z m -53.193199,13.616503 6.401571,0.104017 c 0.439568,0.0096 0.845627,0.245225 1.067519,0.629555 l 3.288118,5.69538 c 0.11109,0.192133 0.16868,0.404928 0.170775,0.618144 l -1e-4,-9.6e-5 c 0.0019,0.213185 -0.05175,0.42665 -0.159741,0.621192 l -3.110315,5.596397 c -0.226761,0.408474 -0.653437,0.654848 -1.120573,0.646958 l -6.396818,-0.107352 c -0.219797,-0.0045 -0.43171,-0.06476 -0.615294,-0.174008 -0.184275,-0.108081 -0.341525,-0.262928 -0.452506,-0.455074 L 35.046462,74.53247 c -0.221803,-0.384342 -0.222333,-0.854226 -0.01073,-1.239712 l 3.104891,-5.59259 c 0.07864,-0.15661 0.235782,-0.36984 0.505757,-0.508038 0.161997,-0.0829 0.364985,-0.139399 0.615576,-0.139392 z m 0.03265,17.075772 h 8.94385 a 22.999998,22.999995 0 0 0 1.562716,2.706677 l -0.0065,0.01112 a 22.999998,22.999995 0 0 0 17.528377,10.119981 l -4.465457,7.734642 4.471922,-7.745439 a 22.999998,22.999995 0 0 0 1.56262,0.05303 22.999998,22.999995 0 0 0 1.563004,-0.05367 l 4.471736,7.745699 a 31.280001,31.279996 0 0 1 -6.034644,0.58771 31.280001,31.279996 0 0 1 -6.034733,-0.58771 l -0.0064,0.0109 a 31.279999,31.279994 0 0 1 -7.888357,-2.68187 l 2.200352,-3.811096 -3.372937,-1.947399 -2.200353,3.811165 a 31.279999,31.279994 0 0 1 -6.267033,-5.490739 l 0.0065,-0.01086 a 31.280001,31.279996 0 0 1 -6.034638,-10.45228 z m 46.05177,5.863389 c 0.463386,-0.0078 0.886733,0.236599 1.111641,0.641821 l 3.080454,5.548583 c 0.104918,0.191155 0.15854,0.402883 0.155748,0.614804 -0.0013,0.21192 -0.05654,0.423903 -0.16659,0.614547 l -3.261873,5.649506 c -0.22018,0.38122 -0.623523,0.61467 -1.059629,0.62406 l -6.344429,0.10651 c -0.173541,0.0102 -0.434642,-0.0192 -0.687271,-0.18247 -0.151558,-0.0981 -0.300738,-0.24438 -0.425023,-0.45962 l -3.085788,-5.551047 c -0.209715,-0.382439 -0.208706,-0.848127 0.01144,-1.229351 l 3.26188,-5.649566 c 0.109953,-0.190734 0.264194,-0.345709 0.446328,-0.453266 v 0 c 0.182135,-0.107487 0.39224,-0.167248 0.612918,-0.17096 z" />
+ <path
+ id="path12-3"
+ style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.0633053;stroke-linejoin:round;paint-order:stroke markers fill"
+ d="M 68.38737,22.009002 A 46.000001,45.999994 0 0 0 22.413,68.009045 46.000001,45.999994 0 0 0 68.41304,114.009 46.000001,45.999994 0 0 0 114.413,68.009045 46.000001,45.999994 0 0 0 68.41304,22.009002 a 46.000001,45.999994 0 0 0 -0.0257,0 z m 0.505,14.719959 a 31.280001,31.279996 0 0 1 6.03473,0.587714 l -4.47192,7.745593 a 22.999998,22.999995 0 0 0 -1.56281,-0.05322 22.999998,22.999995 0 0 0 -1.56263,0.05296 l -3.9e-4,-6.39e-4 a 22.999996,22.999993 0 0 0 -9.93729,3.028352 22.999996,22.999993 0 0 0 -0.002,0.0013 22.999996,22.999993 0 0 0 -7.58918,7.090553 l 5.7e-4,6.39e-4 a 22.999998,22.999995 0 0 0 -1.56281,2.70687 l -8.94385,1.02e-4 a 31.280001,31.279996 0 0 1 6.03454,-10.452199 l -6.4e-4,-6.39e-4 a 31.279999,31.279994 0 0 1 6.26722,-5.490949 l 2.20026,3.811087 3.37294,-1.947333 -2.20026,-3.810991 a 31.279999,31.279994 0 0 1 7.88831,-2.681863 l 5e-4,6.39e-4 a 31.280001,31.279996 0 0 1 6.03454,-0.587624 z m 9.89308,1.70667 6.57634,1.02e-4 c 0.44376,9.6e-5 0.85098,0.234549 1.07902,0.610535 l 3.29087,5.485244 c 0.0963,0.146414 0.20244,0.389025 0.18714,0.691929 -0.009,0.181745 -0.0618,0.385818 -0.18714,0.602836 l -3.29087,5.491901 c -0.22815,0.375839 -0.63513,0.609781 -1.07893,0.609774 l -6.57643,-9.5e-5 c -0.22193,1.47e-4 -0.43501,-0.05648 -0.62071,-0.161262 v 0 C 77.97909,51.661759 77.8211,51.50849 77.70662,51.317699 l -3.29126,-5.491805 c -0.24038,-0.400615 -0.24041,-0.893301 0,-1.29391 l 3.29135,-5.486195 c 0.11402,-0.187967 0.27191,-0.341486 0.45831,-0.445848 0.18574,-0.105545 0.39853,-0.164265 0.62043,-0.16431 z m -12.78242,4.328254 c 0.0523,0.09538 0.10718,0.190606 0.16497,0.28573 z m 26.45255,4.672647 v 1.98e-4 a 31.280001,31.279996 0 0 1 6.03464,10.452272 h -0.005 a 31.279997,31.279992 0 0 1 1.62148,8.172806 h -4.46072 v 3.894666 h 4.46118 A 31.279997,31.279992 0 0 1 98.4855,78.12919 h 0.004 A 31.280001,31.279996 0 0 1 92.45483,88.581544 L 87.9829,80.836059 a 22.999998,22.999995 0 0 0 1.56281,-2.706582 h -0.005 a 22.999995,22.999991 0 0 0 2.34612,-10.119953 22.999995,22.999991 0 0 0 -6.4e-4,-0.0026 22.999995,22.999991 0 0 0 -2.34592,-10.118247 l 0.005,1.02e-4 a 22.999998,22.999995 0 0 0 -1.56216,-2.706684 z m -53.1932,13.616503 6.40157,0.104017 c 0.43956,0.0096 0.84562,0.245225 1.06752,0.629555 l 3.28811,5.69538 c 0.11109,0.192133 0.16868,0.404928 0.17078,0.618144 l -10e-5,-9.6e-5 c 0.002,0.213185 -0.0517,0.42665 -0.15974,0.621192 l -3.11032,5.596397 c -0.22676,0.408474 -0.65343,0.654848 -1.12057,0.646958 L 39.40281,74.85723 c -0.2198,-0.0045 -0.43171,-0.06476 -0.61529,-0.174008 -0.18428,-0.108081 -0.34153,-0.262928 -0.45251,-0.455074 l -3.28812,-5.695381 c -0.22181,-0.384342 -0.22234,-0.854226 -0.0107,-1.239712 l 3.10489,-5.59259 c 0.0786,-0.15661 0.23578,-0.36984 0.50575,-0.508038 0.162,-0.0829 0.36499,-0.139399 0.61558,-0.139392 z m 0.0327,17.075772 h 8.94385 a 22.999998,22.999995 0 0 0 1.56271,2.706677 l -0.006,0.01112 A 22.999998,22.999995 0 0 0 67.32402,90.96658 l -4.46546,7.73465 4.47192,-7.74544 a 22.999998,22.999995 0 0 0 1.56262,0.053 22.999998,22.999995 0 0 0 1.56301,-0.0537 l 4.47173,7.74569 A 31.280001,31.279996 0 0 1 68.8932,99.2885 31.280001,31.279996 0 0 1 62.85847,98.70078 l -0.006,0.0109 a 31.279999,31.279994 0 0 1 -7.88836,-2.68186 l 2.20035,-3.8111 -3.37294,-1.9474 -2.20035,3.81117 a 31.279999,31.279994 0 0 1 -6.26703,-5.490742 l 0.007,-0.01086 A 31.280001,31.279996 0 0 1 39.2965,78.128668 Z m 46.05177,5.863389 c 0.46338,-0.0078 0.88673,0.236599 1.11164,0.641821 l 3.08045,5.548583 c 0.10492,0.19115 0.15854,0.40288 0.15575,0.6148 -10e-4,0.21192 -0.0565,0.42391 -0.16659,0.61455 l -3.26187,5.6495 c -0.22018,0.38123 -0.62353,0.61468 -1.05963,0.62407 l -6.34443,0.1065 c -0.17354,0.0102 -0.43464,-0.0192 -0.68727,-0.18246 -0.15156,-0.0981 -0.30074,-0.24438 -0.42503,-0.45962 l -3.08578,-5.55105 c -0.20972,-0.38244 -0.20871,-0.84813 0.0114,-1.22935 l 3.26188,-5.649567 c 0.10995,-0.190734 0.26419,-0.345709 0.44632,-0.453266 v 0 c 0.18214,-0.107487 0.39224,-0.167248 0.61292,-0.17096 z" />
</svg>
diff --git a/resources/panel_shadow.png b/resources/panel_shadow.png
index d76818a65..7cceadb76 100644
--- a/resources/panel_shadow.png
+++ b/resources/panel_shadow.png
Binary files differ
diff --git a/resources/refine_gradient_dash.png b/resources/refine_gradient_dash.png
index 17214cc5f..7cceadb76 100644
--- a/resources/refine_gradient_dash.png
+++ b/resources/refine_gradient_dash.png
Binary files differ
diff --git a/resources/refine_gradient_panel.png b/resources/refine_gradient_panel.png
index 0b58160ae..7cceadb76 100644
--- a/resources/refine_gradient_panel.png
+++ b/resources/refine_gradient_panel.png
Binary files differ
diff --git a/resources/refine_gradient_panel_single_column.png b/resources/refine_gradient_panel_single_column.png
index 38b9b4956..7cceadb76 100644
--- a/resources/refine_gradient_panel_single_column.png
+++ b/resources/refine_gradient_panel_single_column.png
Binary files differ
diff --git a/shutdown/SessionButton.cpp b/shutdown/SessionButton.cpp
index 61a6e8e11..6762c888e 100644
--- a/shutdown/SessionButton.cpp
+++ b/shutdown/SessionButton.cpp
@@ -132,11 +132,11 @@ void Button::UpdateTextures(std::string const& texture_prefix)
{
auto const& theme = theme::Settings::Get();
auto texture_path = theme->ThemedFilePath(texture_prefix, {PKGDATADIR});
- RawPixel const texture_size = GetDefaultMaxTextureSize(texture_path);
+ RawPixel const texture_size = GetDefaultMaxTextureSize(texture_path) * 0.8;
normal_tex_.Adopt(nux::CreateTexture2DFromFile(texture_path.c_str(), texture_size.CP(scale), true));
auto texture_highlight_path = theme->ThemedFilePath(texture_prefix + "_highlight", {PKGDATADIR});
- RawPixel const texture_highlight_size = GetDefaultMaxTextureSize(texture_path);
+ RawPixel const texture_highlight_size = GetDefaultMaxTextureSize(texture_path) * 0.8;
highlight_tex_.Adopt(nux::CreateTexture2DFromFile(texture_highlight_path.c_str(), texture_highlight_size.CP(scale), true));
}
diff --git a/shutdown/SessionView.cpp b/shutdown/SessionView.cpp
index 422e3c934..a5667c2c2 100644
--- a/shutdown/SessionView.cpp
+++ b/shutdown/SessionView.cpp
@@ -39,7 +39,7 @@ namespace style
RawPixel const LEFT_RIGHT_PADDING = 30_em;
RawPixel const TOP_PADDING = 19_em;
RawPixel const BOTTOM_PADDING = 12_em;
- RawPixel const MAIN_SPACE = 10_em;
+ RawPixel const MAIN_SPACE = 17_em;
RawPixel const BUTTONS_SPACE = 20_em;
}
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 58a8b1089..82d92aaaf 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -281,7 +281,6 @@ if (GMOCK_LIB AND
add_unity_test_xless (launcher-options)
add_unity_test_xless (layout-system)
add_unity_test_xless (model-iterator)
- add_unity_test_xless (previews)
add_unity_test_xless (raw-pixel)
add_unity_test_xless (scope-data)
add_unity_test_xless (time-util)
@@ -382,7 +381,6 @@ if (ENABLE_X_SUPPORT)
add_unity_test (dash-controller)
add_unity_test (desktop-launcher-icon)
add_unity_test (device-launcher-section)
- add_unity_test (error-preview)
add_unity_test (edge-barrier-controller)
add_unity_test (expo-launcher-icon)
add_unity_test (file-manager-launcher-icon)
@@ -418,14 +416,6 @@ if (ENABLE_X_SUPPORT)
add_unity_test (panel-tray)
add_unity_test (panel-view)
add_unity_test (places-group)
- add_unity_test (preview-player)
- add_unity_test (previews-application)
- add_unity_test (previews-generic)
- add_unity_test (previews-movie)
- add_unity_test (previews-music)
- add_unity_test (previews-music-payment)
- add_unity_test (previews-payment)
- add_unity_test (previews-social)
add_unity_test (quicklist-manager)
add_unity_test (quicklist-menu-item)
add_unity_test (quicklist-view)
diff --git a/tests/mock_key_grabber.h b/tests/mock_key_grabber.h
index 2c271ca56..27bccd181 100644
--- a/tests/mock_key_grabber.h
+++ b/tests/mock_key_grabber.h
@@ -18,7 +18,7 @@
*
*/
-#include "KeyGrabber.h"
+#include "unity-shared/KeyGrabber.h"
#include <gmock/gmock.h>
namespace unity
diff --git a/tests/test_error_preview.cpp b/tests/test_error_preview.cpp
deleted file mode 100644
index a339e0d2c..000000000
--- a/tests/test_error_preview.cpp
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright 2012-2013 Canonical Ltd.
- *
- * This program is free software: you can redistribute it and/or modify it
- * under the terms of the GNU Lesser 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 applicable version of the GNU Lesser General Public
- * License for more details.
- *
- * You should have received a copy of both the GNU Lesser General Public
- * License version 3 along with this program. If not, see
- * <http://www.gnu.org/licenses/>
- *
- * Authored by: Diego Sarmentero <diego.sarmentero@canonical.com>
- *
- */
-#include <list>
-#include <gmock/gmock.h>
-using namespace testing;
-
-#include <Nux/Nux.h>
-#include <Nux/BaseWindow.h>
-#include <unity-shared/StaticCairoText.h>
-#include <unity-shared/DashStyle.h>
-#include <unity-shared/PreviewStyle.h>
-#include <unity-shared/ThumbnailGenerator.h>
-
-#include <unity-protocol.h>
-#include "dash/previews/ErrorPreview.h"
-#include "test_utils.h"
-
-namespace unity
-{
-
-namespace dash
-{
-
-namespace previews
-{
-
-class ErrorPreviewMock : public ErrorPreview
-{
- public:
- ErrorPreviewMock(dash::Preview::Ptr preview_model)
- : ErrorPreview(preview_model){}
- ~ErrorPreviewMock(){}
-
- using ErrorPreview::intro_;
- using ErrorPreview::title_;
- using ErrorPreview::subtitle_;
- using ErrorPreview::purchase_hint_;
- using ErrorPreview::purchase_prize_;
- using ErrorPreview::purchase_type_;
-};
-
-class TestErrorPreview : public Test
-{
- protected:
- TestErrorPreview() :
- Test(),
- parent_window_(new nux::BaseWindow("TestErrorPayment"))
- {
- title = "Turning Japanese";
- subtitle = "The vapors";
- header = "Hi test, you purchased in the past from Ubuntu One.";
- purchase_prize = "65$";
- purchase_type = "Mp3";
- preview_type = UNITY_PROTOCOL_PREVIEW_PAYMENT_TYPE_ERROR;
-
- glib::Object<UnityProtocolPreview> proto_obj(UNITY_PROTOCOL_PREVIEW(unity_protocol_payment_preview_new()));
-
- unity_protocol_preview_set_title(proto_obj, title.c_str());
- unity_protocol_preview_set_subtitle(proto_obj, subtitle.c_str());
-
- unity_protocol_payment_preview_set_header(UNITY_PROTOCOL_PAYMENT_PREVIEW(proto_obj.RawPtr()), header.c_str());
- unity_protocol_payment_preview_set_purchase_prize(UNITY_PROTOCOL_PAYMENT_PREVIEW(proto_obj.RawPtr()), purchase_prize.c_str());
- unity_protocol_payment_preview_set_purchase_type(UNITY_PROTOCOL_PAYMENT_PREVIEW(proto_obj.RawPtr()), purchase_type.c_str());
- unity_protocol_payment_preview_set_preview_type(UNITY_PROTOCOL_PAYMENT_PREVIEW(proto_obj.RawPtr()), preview_type);
-
- glib::Variant v(dee_serializable_serialize(DEE_SERIALIZABLE(proto_obj.RawPtr())), glib::StealRef());
-
- preview_model = dash::Preview::PreviewForVariant(v);
-
- }
-
- nux::ObjectPtr<nux::BaseWindow> parent_window_;
- dash::Preview::Ptr preview_model;
-
- // testing data
- std::string title;
- std::string subtitle;
- std::string header;
- std::string purchase_prize;
- std::string purchase_type;
- UnityProtocolPreviewPaymentType preview_type;
-
- // needed for styles
- dash::Style dash_style;
-};
-
-} // previews
-
-} // dash
-
-} // unity
diff --git a/tests/test_launcher.cpp b/tests/test_launcher.cpp
index d49f886e1..dddba1040 100644
--- a/tests/test_launcher.cpp
+++ b/tests/test_launcher.cpp
@@ -205,33 +205,6 @@ struct TestWindowCompositor
}
};
-TEST_F(TestLauncher, TestQuirksDuringDnd)
-{
- MockMockLauncherIcon::Ptr first(new MockMockLauncherIcon::Nice);
- model_->AddIcon(first);
-
- MockMockLauncherIcon::Ptr second(new MockMockLauncherIcon::Nice);
- model_->AddIcon(second);
-
- MockMockLauncherIcon::Ptr third(new MockMockLauncherIcon::Nice);
- model_->AddIcon(third);
-
- EXPECT_CALL(*first, ShouldHighlightOnDrag(_))
- .WillRepeatedly(Return(true));
-
- EXPECT_CALL(*second, ShouldHighlightOnDrag(_))
- .WillRepeatedly(Return(true));
-
- EXPECT_CALL(*third, ShouldHighlightOnDrag(_))
- .WillRepeatedly(Return(false));
-
- launcher_->DndStarted("");
-
- EXPECT_FALSE(first->GetQuirk(launcher::AbstractLauncherIcon::Quirk::DESAT, launcher_->monitor()));
- EXPECT_FALSE(second->GetQuirk(launcher::AbstractLauncherIcon::Quirk::DESAT, launcher_->monitor()));
- EXPECT_TRUE(third->GetQuirk(launcher::AbstractLauncherIcon::Quirk::DESAT, launcher_->monitor()));
-}
-
TEST_F(TestLauncher, TestMouseWheelScroll)
{
MockMockLauncherIcon::Ptr icon(new MockMockLauncherIcon::Nice);
@@ -496,17 +469,6 @@ TEST_F(TestLauncher, DragLauncherIconHidesOutsideLauncherEmitsMouseEnter)
EXPECT_FALSE(mouse_entered);
}
-TEST_F(TestLauncher, EdgeReleasesDuringDnd)
-{
- auto barrier = std::make_shared<ui::PointerBarrierWrapper>();
- auto event = std::make_shared<ui::BarrierEvent>(0, 0, 0, 100);
-
- launcher_->DndStarted("");
-
- EXPECT_EQ(launcher_->HandleBarrierEvent(barrier, event),
- ui::EdgeBarrierSubscriber::Result::NEEDS_RELEASE);
-}
-
TEST_F(TestLauncher, EdgeBarriersIgnoreEvents)
{
auto const& launcher_geo = launcher_->GetAbsoluteGeometry();
@@ -618,26 +580,6 @@ TEST_F(TestLauncher, DndIsSpecialRequest)
EXPECT_FALSE(launcher_->DndIsSpecialRequest("file://full/path/to/MyFile.txt"));
}
-TEST_F(TestLauncher, AddRequestSignal)
-{
- auto const& icons = AddMockIcons(1);
- auto const& center = icons[0]->GetCenter(launcher_->monitor());
- launcher_->ProcessDndEnter();
- launcher_->FakeProcessDndMove(center.x, center.y, {"application://MyFile.desktop"});
-
- bool add_request = false;
- launcher_->add_request.connect([&] (std::string const& uri, AbstractLauncherIcon::Ptr const& drop_icon) {
- EXPECT_EQ(drop_icon, icons[0]);
- EXPECT_EQ(uri, "application://MyFile.desktop");
- add_request = true;
- });
-
- launcher_->ProcessDndDrop(center.x, center.y);
- launcher_->ProcessDndLeave();
-
- EXPECT_TRUE(add_request);
-}
-
TEST_F(TestLauncher, IconStartingPulseValue)
{
MockMockLauncherIcon::Ptr icon(new MockMockLauncherIcon::Nice);
diff --git a/tests/test_launcher_controller.cpp b/tests/test_launcher_controller.cpp
index 9495dffff..2f7427138 100644
--- a/tests/test_launcher_controller.cpp
+++ b/tests/test_launcher_controller.cpp
@@ -1758,46 +1758,6 @@ TEST_F(TestLauncherController, DisconnectWMSignalsOnDestruction)
color_property.changed.emit(nux::color::RandomColor());
}
-TEST_F(TestLauncherController, DragAndDrop_MultipleLaunchers)
-{
- lc.multiple_launchers = true;
- uscreen.SetupFakeMultiMonitor();
- lc.options()->hide_mode = LAUNCHER_HIDE_AUTOHIDE;
- unsigned monitor = 0;
- unsigned old_monitor = -1;
-
- auto check_fn = [this](int index) {
- return lc.launchers()[index]->Hidden();
- };
-
- ON_CALL(*xdnd_manager_, Monitor()).WillByDefault(ReturnPointee(&monitor));
- xdnd_manager_->dnd_started.emit("my_awesome_file", monitor);
-
- for (unsigned i = 0; i < monitors::MAX; ++i)
- {
- Utils::WaitUntilMSec(std::bind(check_fn, i), i != monitor);
- ASSERT_EQ(i != monitor, check_fn(i));
- }
-
- old_monitor = monitor;
- monitor = 3;
- xdnd_manager_->monitor_changed.emit("another_file", old_monitor, monitor);
-
- for (unsigned i = 0; i < monitors::MAX; ++i)
- {
- Utils::WaitUntilMSec(std::bind(check_fn, i), i != monitor);
- ASSERT_EQ(i != monitor, check_fn(i));
- }
-
- xdnd_manager_->dnd_finished.emit();
-
- for (unsigned i = 0; i < monitors::MAX; ++i)
- {
- Utils::WaitUntilMSec(std::bind(check_fn, i), true);
- ASSERT_TRUE(check_fn(i));
- }
-}
-
TEST_F(TestLauncherController, DragAndDrop_SingleLauncher)
{
lc.multiple_launchers = false;
@@ -1824,87 +1784,6 @@ TEST_F(TestLauncherController, DragAndDrop_SingleLauncher)
Utils::WaitUntilMSec(check_fn, true);
}
-TEST_F(TestLauncherController, DragAndDrop_MultipleLaunchers_DesaturateIcons)
-{
- lc.multiple_launchers = true;
- uscreen.SetupFakeMultiMonitor();
- unsigned monitor = 0;
- unsigned old_monitor = -1;
- auto const& model = lc.Impl()->model_;
-
- ON_CALL(*xdnd_manager_, Monitor()).WillByDefault(ReturnPointee(&monitor));
- xdnd_manager_->dnd_started.emit("my_awesome_file", monitor);
-
- for (auto const& icon : *model)
- {
- bool is_trash = icon->GetIconType() == AbstractLauncherIcon::IconType::TRASH;
-
- for (unsigned i = 0; i < monitors::MAX; ++i)
- ASSERT_EQ(monitor == i && !is_trash, icon->GetQuirk(AbstractLauncherIcon::Quirk::DESAT, i));
- }
-
- old_monitor = monitor;
- monitor = 3;
- xdnd_manager_->monitor_changed.emit("another_file", old_monitor, monitor);
-
- for (auto const& icon : *model)
- {
- bool is_trash = icon->GetIconType() == AbstractLauncherIcon::IconType::TRASH;
-
- for (unsigned i = 0; i < monitors::MAX; ++i)
- ASSERT_EQ(monitor == i && !is_trash, icon->GetQuirk(AbstractLauncherIcon::Quirk::DESAT, i));
- }
-
- xdnd_manager_->dnd_finished.emit();
-
- for (auto const& icon : *model)
- {
- for (unsigned i = 0; i < monitors::MAX; ++i)
- ASSERT_FALSE(icon->GetQuirk(AbstractLauncherIcon::Quirk::DESAT, i));
- }
-}
-
-TEST_F(TestLauncherController, DragAndDrop_SingleLauncher_DesaturateIcons)
-{
- lc.multiple_launchers = false;
- unsigned monitor = 2;
- unsigned old_monitor = -1;
- uscreen.SetupFakeMultiMonitor(monitor);
- lc.options()->hide_mode = LAUNCHER_HIDE_AUTOHIDE;
- auto const& model = lc.Impl()->model_;
-
- ON_CALL(*xdnd_manager_, Monitor()).WillByDefault(ReturnPointee(&monitor));
- xdnd_manager_->dnd_started.emit("my_awesome_file", monitor);
-
- for (auto const& icon : *model)
- {
- bool is_trash = icon->GetIconType() == AbstractLauncherIcon::IconType::TRASH;
-
- for (unsigned i = 0; i < monitors::MAX; ++i)
- ASSERT_EQ(monitor == i && !is_trash, icon->GetQuirk(AbstractLauncherIcon::Quirk::DESAT, i));
- }
-
- old_monitor = monitor;
- monitor = 0;
- xdnd_manager_->monitor_changed.emit("another_file", old_monitor, monitor);
-
- for (auto const& icon : *model)
- {
- bool is_trash = icon->GetIconType() == AbstractLauncherIcon::IconType::TRASH;
-
- for (unsigned i = 0; i < monitors::MAX; ++i)
- ASSERT_EQ(old_monitor == i && !is_trash, icon->GetQuirk(AbstractLauncherIcon::Quirk::DESAT, i));
- }
-
- xdnd_manager_->dnd_finished.emit();
-
- for (auto const& icon : *model)
- {
- for (unsigned i = 0; i < monitors::MAX; ++i)
- ASSERT_FALSE(icon->GetQuirk(AbstractLauncherIcon::Quirk::DESAT, i));
- }
-}
-
TEST_F(TestLauncherController, SetExistingLauncherIconAsFavorite)
{
const char * desktop_file = "normal-icon.desktop";
diff --git a/tests/test_preview_player.cpp b/tests/test_preview_player.cpp
deleted file mode 100644
index df481e9fc..000000000
--- a/tests/test_preview_player.cpp
+++ /dev/null
@@ -1,230 +0,0 @@
-// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
-/*
- * Copyright (C) 2013 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: Nick Dedekind <nick.dedekinc@canonical.com>
- */
-
-#include <gmock/gmock.h>
-#include <UnityCore/PreviewPlayer.h>
-#include <UnityCore/ConnectionManager.h>
-#include <UnityCore/GLibDBusServer.h>
-#include <UnityCore/Variant.h>
-#include "test_utils.h"
-#include "config.h"
-
-namespace unity
-{
-
-namespace
-{
- const std::string WHITE_NOISE = "file://" BUILDDIR "/tests/data/unity/sounds/whitenoise.mp3";
-
- const std::string PLAYER_NAME = "com.canonical.Unity.Lens.Music.PreviewPlayer";
- const std::string PLAYER_PATH = "/com/canonical/Unity/Lens/Music/PreviewPlayer";
- const std::string PLAYER_INTERFACE =
- R"(<node>
- <interface name="com.canonical.Unity.Lens.Music.PreviewPlayer">
- <method name="Play">
- <arg type="s" name="uri" direction="in"/>
- </method>
- <method name="Pause">
- </method>
- <method name="Resume">
- </method>
- <method name="PauseResume">
- </method>
- <method name="Stop">
- </method>
- <method name="Close">
- </method>
- <method name="VideoProperties">
- <arg type="s" name="uri" direction="in"/>
- <arg type="a{sv}" name="result" direction="out"/>
- </method>
- <signal name="Progress">
- <arg type="s" name="uri"/>
- <arg type="u" name="state"/>
- <arg type="d" name="value"/>
- </signal>
- </interface>
- </node>)";
-
- void PlayAndWait(PreviewPlayer* player, std::string const& uri)
- {
- bool play_returned = false;
- auto play_callback = [&play_returned] (glib::Error const& error) {
- play_returned = true;
- EXPECT_TRUE(!error) << "Error: " << error.Message();
- };
-
- bool updated_called = false;
- auto updated_callback = [uri, &updated_called] (std::string const& _uri, PlayerState state, double) {
- updated_called = true;
- EXPECT_EQ(_uri, uri) << "Uri for PLAY not correct (" << _uri << " != " << _uri << ")";
- EXPECT_EQ((int)state, (int)PlayerState::PLAYING) << "Incorrect state returned on PLAY.";
- };
-
- connection::Wrapper conn(player->updated.connect(updated_callback));
- player->Play(uri, play_callback);
- ::Utils::WaitUntilMSec(play_returned, 3000, "PLAY did not return");
- ::Utils::WaitUntilMSec(updated_called, 5000, "Update not called on PLAY");
- }
-
- void PauseAndWait(PreviewPlayer* player)
- {
- bool pause_returned = false;
- auto callback = [&pause_returned] (glib::Error const& error) {
- pause_returned = true;
- EXPECT_TRUE(!error) << "Error: " << error.Message();
- };
-
- bool updated_called = false;
- auto updated_callback = [&updated_called] (std::string const&, PlayerState state, double) {
- updated_called = true;
- EXPECT_EQ((int)state, (int)PlayerState::PAUSED) << "Incorrect state returned on PAUSE.";
- };
-
- connection::Wrapper conn(player->updated.connect(updated_callback));
- player->Pause(callback);
- ::Utils::WaitUntilMSec(pause_returned, 3000, "PAUSE did not return");
- ::Utils::WaitUntilMSec(updated_called, 5000, "Update not called on PAUSE");
- }
-
- void ResumeAndWait(PreviewPlayer* player)
- {
- bool resume_returned = false;
- auto callback = [&resume_returned] (glib::Error const& error) {
- resume_returned = true;
- EXPECT_TRUE(!error) << "Error: " << error.Message();
- };
-
- bool updated_called = false;
- auto updated_callback = [&updated_called] (std::string const&, PlayerState state, double) {
- updated_called = true;
- EXPECT_EQ((int)state, (int)PlayerState::PLAYING) << "Incorrect state returned on RESUME.";
- };
-
- connection::Wrapper conn(player->updated.connect(updated_callback));
- player->Resume(callback);
- ::Utils::WaitUntilMSec(resume_returned, 3000, "RESUME did not return");
- ::Utils::WaitUntilMSec(updated_called, 5000, "Update not called on RESUME");
- }
-
- void StopAndWait(PreviewPlayer* player)
- {
- bool stop_returned = false;
- auto callback = [&stop_returned] (glib::Error const& error) {
- stop_returned = true;
- EXPECT_TRUE(!error) << "Error: " << error.Message();
- };
-
- bool updated_called = false;
- auto updated_callback = [&updated_called] (std::string const&, PlayerState state, double) {
- updated_called = true;
- EXPECT_EQ((int)state, (int)PlayerState::STOPPED) << "Incorrect state returned on STOP.";
- };
-
- connection::Wrapper conn(player->updated.connect(updated_callback));
- player->Stop(callback);
- ::Utils::WaitUntilMSec(stop_returned, 3000, "STOP did not return");
- ::Utils::WaitUntilMSec(updated_called, 5000, "Update not called on STOP");
- }
-
- struct FakeRemotePlayer
- {
- typedef std::shared_ptr<FakeRemotePlayer> Ptr;
- FakeRemotePlayer()
- : server_(PLAYER_NAME)
- {
- server_.AddObjects(PLAYER_INTERFACE, PLAYER_PATH);
- auto object = server_.GetObjects().front();
-
- object->SetMethodsCallsHandler([this, object] (std::string const& method, GVariant* parameters) {
- if (method == "Play")
- {
- current_uri_ = glib::Variant(parameters).GetString();
- object->EmitSignal("Progress", g_variant_new("(sud)", current_uri_.c_str(), PlayerState::PLAYING, 0));
- }
- else if (method == "Pause")
- {
- object->EmitSignal("Progress", g_variant_new("(sud)", current_uri_.c_str(), PlayerState::PAUSED, 0));
- }
- else if (method == "Resume")
- {
- object->EmitSignal("Progress", g_variant_new("(sud)", current_uri_.c_str(), PlayerState::PLAYING, 0));
- }
- else if (method == "Stop")
- {
- object->EmitSignal("Progress", g_variant_new("(sud)", current_uri_.c_str(), PlayerState::STOPPED, 0));
- current_uri_ = "";
- }
-
- return static_cast<GVariant*>(nullptr);
- });
- }
-
- private:
- glib::DBusServer server_;
- std::string current_uri_;
- };
-}
-
-struct TestPreviewPlayer : testing::Test
-{
- static void SetUpTestCase()
- {
- remote_player_ = std::make_shared<FakeRemotePlayer>();
- }
-
- static void TearDownTestCase()
- {
- remote_player_.reset();
- }
-
- static FakeRemotePlayer::Ptr remote_player_;
- PreviewPlayer player;
-};
-
-FakeRemotePlayer::Ptr TestPreviewPlayer::remote_player_;
-
-TEST_F(TestPreviewPlayer, TestConstruct)
-{
- PreviewPlayer player1;
-}
-
-TEST_F(TestPreviewPlayer, TestPlayerControl)
-{
- PlayAndWait(&player, WHITE_NOISE);
-
- PauseAndWait(&player);
-
- ResumeAndWait(&player);
-
- StopAndWait(&player);
-}
-
-TEST_F(TestPreviewPlayer, TestMultiPlayer)
-{
- {
- PreviewPlayer player2;
- PlayAndWait(&player2, WHITE_NOISE);
- }
-
- StopAndWait(&player);
-}
-
-
-} // namespace unity \ No newline at end of file
diff --git a/tests/test_previews.cpp b/tests/test_previews.cpp
deleted file mode 100644
index 3c99a087e..000000000
--- a/tests/test_previews.cpp
+++ /dev/null
@@ -1,230 +0,0 @@
-// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
-/*
- * Copyright (C) 2011 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 (Treviño) <3v1n0@ubuntu.com>
- */
-
-#include <list>
-#include <algorithm>
-#include <gmock/gmock.h>
-#include <gio/gio.h>
-#include <UnityCore/Variant.h>
-#include <UnityCore/Preview.h>
-#include <UnityCore/ApplicationPreview.h>
-#include <UnityCore/MoviePreview.h>
-#include <UnityCore/MusicPreview.h>
-#include <unity-protocol.h>
-
-using namespace std;
-using namespace testing;
-using namespace unity;
-using namespace unity::glib;
-using namespace unity::dash;
-
-namespace
-{
-
-bool IsVariant(Variant const& variant)
-{
- return g_variant_get_type_string(variant) != NULL;
-}
-
-static void g_variant_unref0(gpointer var)
-{
- if (var) g_variant_unref((GVariant*)var);
-}
-
-TEST(TestPreviews, DeserializeGeneric)
-{
- Object<GIcon> icon(g_icon_new_for_string("accessories", NULL));
- Object<UnityProtocolPreview> proto_obj(UNITY_PROTOCOL_PREVIEW(unity_protocol_generic_preview_new()));
- unity_protocol_preview_set_title(proto_obj, "Title");
- unity_protocol_preview_set_subtitle(proto_obj, "Subtitle");
- unity_protocol_preview_set_description(proto_obj, "Description");
- unity_protocol_preview_set_image(proto_obj, icon);
- unity_protocol_preview_set_image_source_uri(proto_obj, "Source");
-
- Variant v(dee_serializable_serialize(DEE_SERIALIZABLE(proto_obj.RawPtr())),
- glib::StealRef());
- EXPECT_TRUE(IsVariant(v));
-
- Preview::Ptr preview = Preview::PreviewForVariant(v);
- EXPECT_TRUE(preview != nullptr);
-
- EXPECT_EQ(preview->renderer_name, "preview-generic");
- EXPECT_EQ(preview->title, "Title");
- EXPECT_EQ(preview->subtitle, "Subtitle");
- EXPECT_EQ(preview->description, "Description");
- EXPECT_EQ(preview->image_source_uri, "Source");
- EXPECT_TRUE(g_icon_equal(preview->image(), icon) != FALSE);
-}
-
-TEST(TestPreviews, DeserializeGenericWithMeta)
-{
- Object<GIcon> icon(g_icon_new_for_string("accessories", NULL));
- Object<UnityProtocolPreview> proto_obj(UNITY_PROTOCOL_PREVIEW(unity_protocol_generic_preview_new()));
- unity_protocol_preview_set_title(proto_obj, "Title");
- unity_protocol_preview_set_subtitle(proto_obj, "Subtitle");
- unity_protocol_preview_set_description(proto_obj, "Description");
- unity_protocol_preview_set_image(proto_obj, icon);
- unity_protocol_preview_set_image_source_uri(proto_obj, "Source");
-
- GHashTable* hints = g_hash_table_new_full(g_str_hash, g_direct_equal, g_free, g_variant_unref0);
- g_hash_table_insert(hints, g_strdup("extra-text"), g_variant_new_string("Foo"));
- unity_protocol_preview_add_action(proto_obj, "action1", "Action #1", NULL, 0);
- unity_protocol_preview_add_action_with_hints(proto_obj, "action2", "Action #2", NULL, 0, hints);
- unity_protocol_preview_add_info_hint(proto_obj, "hint1", "Hint 1", NULL, g_variant_new("i", 34));
- unity_protocol_preview_add_info_hint(proto_obj, "hint2", "Hint 2", NULL, g_variant_new("s", "string hint"));
-
- Variant v(dee_serializable_serialize(DEE_SERIALIZABLE(proto_obj.RawPtr())),
- glib::StealRef());
- EXPECT_TRUE(IsVariant(v));
-
- Preview::Ptr preview = Preview::PreviewForVariant(v);
- EXPECT_TRUE(preview != nullptr);
-
- EXPECT_EQ(preview->renderer_name, "preview-generic");
- EXPECT_EQ(preview->title, "Title");
- EXPECT_EQ(preview->subtitle, "Subtitle");
- EXPECT_EQ(preview->description, "Description");
- EXPECT_TRUE(g_icon_equal(preview->image(), icon) != FALSE);
- EXPECT_EQ(preview->image_source_uri, "Source");
-
- auto actions = preview->GetActions();
- auto info_hints = preview->GetInfoHints();
-
- EXPECT_EQ(actions.size(), 2u);
-
- auto action1 = actions[0];
- EXPECT_EQ(action1->id, "action1");
- EXPECT_EQ(action1->display_name, "Action #1");
- EXPECT_EQ(action1->icon_hint, "");
- EXPECT_EQ(action1->layout_hint, 0);
- EXPECT_EQ(action1->extra_text, "");
-
- auto action2 = actions[1];
- EXPECT_EQ(action2->id, "action2");
- EXPECT_EQ(action2->display_name, "Action #2");
- EXPECT_EQ(action2->icon_hint, "");
- EXPECT_EQ(action2->extra_text, "Foo");
-
- EXPECT_EQ(info_hints.size(), 2u);
- auto hint1 = info_hints[0];
- EXPECT_EQ(hint1->id, "hint1");
- EXPECT_EQ(hint1->display_name, "Hint 1");
- EXPECT_EQ(hint1->icon_hint, "");
- EXPECT_EQ(hint1->value.GetInt32(), 34);
- auto hint2 = info_hints[1];
- EXPECT_EQ(hint2->id, "hint2");
- EXPECT_EQ(hint2->display_name, "Hint 2");
- EXPECT_EQ(hint2->icon_hint, "");
- EXPECT_EQ(hint2->value.GetString(), "string hint");
-}
-
-TEST(TestPreviews, DeserializeApplication)
-{
- Object<GIcon> icon(g_icon_new_for_string("application", NULL));
- Object<UnityProtocolPreview> proto_obj(UNITY_PROTOCOL_PREVIEW(unity_protocol_application_preview_new()));
- unity_protocol_preview_set_title(proto_obj, "Title");
- unity_protocol_preview_set_subtitle(proto_obj, "Subtitle");
- unity_protocol_preview_set_description(proto_obj, "Description");
- unity_protocol_preview_set_image(proto_obj, icon);
- auto app_proto_obj = glib::object_cast<UnityProtocolApplicationPreview>(proto_obj);
- unity_protocol_application_preview_set_last_update(app_proto_obj, "2012/06/13");
- unity_protocol_application_preview_set_copyright(app_proto_obj, "(c) Canonical");
- unity_protocol_application_preview_set_license(app_proto_obj, "GPLv3");
- unity_protocol_application_preview_set_app_icon(app_proto_obj, icon);
- unity_protocol_application_preview_set_rating(app_proto_obj, 4.0);
- unity_protocol_application_preview_set_num_ratings(app_proto_obj, 12);
-
- Variant v(dee_serializable_serialize(DEE_SERIALIZABLE(proto_obj.RawPtr())),
- glib::StealRef());
- EXPECT_TRUE(IsVariant(v));
-
- Preview::Ptr base_preview = Preview::PreviewForVariant(v);
- ApplicationPreview::Ptr preview = std::dynamic_pointer_cast<ApplicationPreview>(base_preview);
- EXPECT_TRUE(preview != nullptr);
-
- EXPECT_EQ(preview->renderer_name, "preview-application");
- EXPECT_EQ(preview->title, "Title");
- EXPECT_EQ(preview->subtitle, "Subtitle");
- EXPECT_EQ(preview->description, "Description");
- EXPECT_TRUE(g_icon_equal(preview->image(), icon) != FALSE);
- EXPECT_EQ(preview->last_update, "2012/06/13");
- EXPECT_EQ(preview->copyright, "(c) Canonical");
- EXPECT_EQ(preview->license, "GPLv3");
- EXPECT_TRUE(g_icon_equal(preview->app_icon(), icon) != FALSE);
- EXPECT_EQ(preview->rating, 4.0);
- EXPECT_EQ(preview->num_ratings, static_cast<unsigned>(12));
-}
-
-TEST(TestPreviews, DeserializeMovie)
-{
- Object<GIcon> icon(g_icon_new_for_string("movie", NULL));
- Object<UnityProtocolPreview> proto_obj(UNITY_PROTOCOL_PREVIEW(unity_protocol_movie_preview_new()));
- unity_protocol_preview_set_title(proto_obj, "Title");
- unity_protocol_preview_set_subtitle(proto_obj, "Subtitle");
- unity_protocol_preview_set_description(proto_obj, "Description");
- unity_protocol_preview_set_image(proto_obj, icon);
- auto movie_proto_obj = glib::object_cast<UnityProtocolMoviePreview>(proto_obj);
- unity_protocol_movie_preview_set_year(movie_proto_obj, "2012");
- unity_protocol_movie_preview_set_rating(movie_proto_obj, 4.0);
- unity_protocol_movie_preview_set_num_ratings(movie_proto_obj, 12);
-
- Variant v(dee_serializable_serialize(DEE_SERIALIZABLE(proto_obj.RawPtr())),
- glib::StealRef());
- EXPECT_TRUE(IsVariant(v));
-
- Preview::Ptr base_preview = Preview::PreviewForVariant(v);
- MoviePreview::Ptr preview = std::dynamic_pointer_cast<MoviePreview>(base_preview);
- EXPECT_TRUE(preview != nullptr);
-
- EXPECT_EQ(preview->renderer_name, "preview-movie");
- EXPECT_EQ(preview->title, "Title");
- EXPECT_EQ(preview->subtitle, "Subtitle");
- EXPECT_EQ(preview->description, "Description");
- EXPECT_TRUE(g_icon_equal(preview->image(), icon) != FALSE);
- EXPECT_EQ(preview->year, "2012");
- EXPECT_EQ(preview->rating, 4.0);
- EXPECT_EQ(preview->num_ratings, static_cast<unsigned int>(12));
-}
-
-TEST(TestPreviews, DeserializeMusic)
-{
- Object<GIcon> icon(g_icon_new_for_string("music", NULL));
- Object<UnityProtocolPreview> proto_obj(UNITY_PROTOCOL_PREVIEW(unity_protocol_music_preview_new()));
- unity_protocol_preview_set_title(proto_obj, "Title");
- unity_protocol_preview_set_subtitle(proto_obj, "Subtitle");
- unity_protocol_preview_set_description(proto_obj, "Description");
- unity_protocol_preview_set_image(proto_obj, icon);
- auto music_proto_obj = glib::object_cast<UnityProtocolMusicPreview>(proto_obj);
-
- Variant v(dee_serializable_serialize(DEE_SERIALIZABLE(proto_obj.RawPtr())),
- glib::StealRef());
- EXPECT_TRUE(IsVariant(v));
-
- Preview::Ptr base_preview = Preview::PreviewForVariant(v);
- MusicPreview::Ptr preview = std::dynamic_pointer_cast<MusicPreview>(base_preview);
- EXPECT_TRUE(preview != nullptr);
-
- EXPECT_EQ(preview->renderer_name, "preview-music");
- EXPECT_EQ(preview->title, "Title");
- EXPECT_EQ(preview->subtitle, "Subtitle");
- EXPECT_EQ(preview->description, "Description");
- EXPECT_TRUE(g_icon_equal(preview->image(), icon) != FALSE);
-}
-
-} // Namespace
diff --git a/tests/test_previews_application.cpp b/tests/test_previews_application.cpp
deleted file mode 100644
index 82afc2937..000000000
--- a/tests/test_previews_application.cpp
+++ /dev/null
@@ -1,142 +0,0 @@
-// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
-/*
- * Copyright (C) 2012 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: Nick Dedekind <nick.dedekinc@canonical.com>
- */
-
-#include <list>
-#include <gmock/gmock.h>
-using namespace testing;
-
-#include <Nux/Nux.h>
-#include <Nux/BaseWindow.h>
-#include <unity-shared/StaticCairoText.h>
-#include <unity-shared/DashStyle.h>
-#include <unity-shared/PreviewStyle.h>
-#include <unity-shared/ThumbnailGenerator.h>
-
-#include <unity-protocol.h>
-#include "UnityCore/ApplicationPreview.h"
-#include "dash/previews/ApplicationPreview.h"
-#include "dash/previews/PreviewInfoHintWidget.h"
-#include "dash/previews/PreviewRatingsWidget.h"
-#include "dash/previews/ActionButton.h"
-#include "test_utils.h"
-using namespace unity;
-using namespace unity::dash;
-
-namespace
-{
-
-class MockApplicationPreview : public previews::ApplicationPreview
-{
-public:
- typedef nux::ObjectPtr<MockApplicationPreview> Ptr;
-
- MockApplicationPreview(dash::Preview::Ptr preview_model)
- : ApplicationPreview(preview_model)
- {}
-
- using ApplicationPreview::title_;
- using ApplicationPreview::subtitle_;
- using ApplicationPreview::license_;
- using ApplicationPreview::last_update_;
- using ApplicationPreview::copywrite_;
- using ApplicationPreview::description_;
- using ApplicationPreview::action_buttons_;
- using ApplicationPreview::preview_info_hints_;
- using ApplicationPreview::app_rating_;
-};
-
-class TestPreviewApplication : public Test
-{
-public:
- TestPreviewApplication()
- : parent_window_(new nux::BaseWindow("TestPreviewApplication"))
- {
- glib::Object<UnityProtocolPreview> proto_obj(UNITY_PROTOCOL_PREVIEW(unity_protocol_application_preview_new()));
-
- GHashTable* action_hints1(g_hash_table_new(g_direct_hash, g_direct_equal));
- g_hash_table_insert (action_hints1, g_strdup ("extra-text"), g_variant_new_string("£30.99"));
-
- unity_protocol_application_preview_set_app_icon(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), g_icon_new_for_string(TESTDATADIR "/bfb.png", NULL));
- unity_protocol_application_preview_set_license(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), "License & special char");
- unity_protocol_application_preview_set_copyright(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), "Copywrite & special char");
- unity_protocol_application_preview_set_last_update(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), "11th Apr 2012");
- unity_protocol_application_preview_set_rating(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), 0.8);
- unity_protocol_application_preview_set_num_ratings(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), 12);
-
- unity_protocol_preview_set_image_source_uri(proto_obj, "http://ia.media-imdb.com/images/M/MV5BMTM3NDM5MzY5Ml5BMl5BanBnXkFtZTcwNjExMDUwOA@@._V1._SY317_.jpg");
- unity_protocol_preview_set_title(proto_obj, "Application Title & special char");
- unity_protocol_preview_set_subtitle(proto_obj, "Application Subtitle > special char");
- unity_protocol_preview_set_description(proto_obj, "Application Desctiption &lt; special char");
- unity_protocol_preview_add_action(proto_obj, "action1", "Action 1", NULL, 0);
- unity_protocol_preview_add_action_with_hints(proto_obj, "action2", "Action 2", NULL, 0, action_hints1);
- unity_protocol_preview_add_info_hint(proto_obj, "hint1", "Hint 1", NULL, g_variant_new("s", "string hint 1"));
- unity_protocol_preview_add_info_hint(proto_obj, "hint2", "Hint 2", NULL, g_variant_new("s", "string hint 2"));
- unity_protocol_preview_add_info_hint(proto_obj, "hint3", "Hint 3", NULL, g_variant_new("i", 12));
-
- glib::Variant v(dee_serializable_serialize(DEE_SERIALIZABLE(proto_obj.RawPtr())), glib::StealRef());
- preview_model_ = dash::Preview::PreviewForVariant(v);
-
- g_hash_table_unref(action_hints1);
- }
-
- nux::ObjectPtr<nux::BaseWindow> parent_window_;
- dash::Preview::Ptr preview_model_;
-
- previews::Style previews_style;
- dash::Style dash_style;
- ThumbnailGenerator thumbnail_generator;
-};
-
-TEST_F(TestPreviewApplication, TestCreate)
-{
- previews::Preview::Ptr preview_view = previews::Preview::PreviewForModel(preview_model_);
-
- EXPECT_TRUE(dynamic_cast<previews::ApplicationPreview*>(preview_view.GetPointer()) != NULL);
-}
-
-TEST_F(TestPreviewApplication, TestUIValues)
-{
- MockApplicationPreview::Ptr preview_view(new MockApplicationPreview(preview_model_));
-
- EXPECT_EQ(preview_view->title_->GetText(), "Application Title &amp; special char");
- EXPECT_EQ(preview_view->subtitle_->GetText(), "Application Subtitle &gt; special char");
- EXPECT_EQ(preview_view->description_->GetText(), "Application Desctiption &lt; special char");
-
- EXPECT_EQ(preview_view->action_buttons_.size(), 2u);
-
- if (preview_view->action_buttons_.size() >= 2)
- {
- auto iter = preview_view->action_buttons_.begin();
- if ((*iter)->Type().IsDerivedFromType(ActionButton::StaticObjectType))
- {
- ActionButton *action = static_cast<ActionButton*>(*iter);
- EXPECT_EQ(action->GetLabel(), "Action 1");
- EXPECT_EQ(action->GetExtraText(), "");
- }
- iter++;
- if ((*iter)->Type().IsDerivedFromType(ActionButton::StaticObjectType))
- {
- ActionButton *action = static_cast<ActionButton*>(*iter);
- EXPECT_EQ(action->GetLabel(), "Action 2");
- EXPECT_EQ(action->GetExtraText(), "£30.99");
- }
- }
-}
-
-}
diff --git a/tests/test_previews_generic.cpp b/tests/test_previews_generic.cpp
deleted file mode 100644
index c10c99e1a..000000000
--- a/tests/test_previews_generic.cpp
+++ /dev/null
@@ -1,129 +0,0 @@
-// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
-/*
- * Copyright (C) 2012 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: Nick Dedekind <nick.dedekinc@canonical.com>
- */
-
-#include <list>
-#include <gmock/gmock.h>
-using namespace testing;
-
-#include <Nux/Nux.h>
-#include <Nux/BaseWindow.h>
-#include <unity-shared/StaticCairoText.h>
-#include <unity-shared/DashStyle.h>
-#include <unity-shared/PreviewStyle.h>
-#include <unity-shared/ThumbnailGenerator.h>
-
-#include <unity-protocol.h>
-#include "UnityCore/GenericPreview.h"
-#include "dash/previews/GenericPreview.h"
-#include "dash/previews/ActionButton.h"
-#include "test_utils.h"
-using namespace unity;
-using namespace unity::dash;
-
-namespace
-{
-
-class MockGenericPreview : public previews::GenericPreview
-{
-public:
- typedef nux::ObjectPtr<MockGenericPreview> Ptr;
-
- MockGenericPreview(dash::Preview::Ptr preview_model)
- : GenericPreview(preview_model)
- {}
-
- using GenericPreview::title_;
- using GenericPreview::subtitle_;
- using GenericPreview::description_;
- using GenericPreview::action_buttons_;
- using GenericPreview::preview_info_hints_;
-};
-
-class TestPreviewGeneric : public Test
-{
-public:
- TestPreviewGeneric()
- : parent_window_(new nux::BaseWindow("TestPreviewGeneric"))
- {
- glib::Object<UnityProtocolPreview> proto_obj(UNITY_PROTOCOL_PREVIEW(unity_protocol_generic_preview_new()));
-
- GHashTable* action_hints1(g_hash_table_new(g_direct_hash, g_direct_equal));
- g_hash_table_insert (action_hints1, g_strdup ("extra-text"), g_variant_new_string("2.00"));
-
- unity_protocol_preview_set_image_source_uri(proto_obj, "http://ia.media-imdb.com/images/M/MV5BMTM3NDM5MzY5Ml5BMl5BanBnXkFtZTcwNjExMDUwOA@@._V1._SY317_.jpg");
- unity_protocol_preview_set_title(proto_obj, "Generic Title & special char");
- unity_protocol_preview_set_subtitle(proto_obj, "Generic Subtitle > special char");
- unity_protocol_preview_set_description(proto_obj, "Generic Desctiption &lt; special char");
- unity_protocol_preview_add_action(proto_obj, "action1", "Action 1", NULL, 0);
- unity_protocol_preview_add_action_with_hints(proto_obj, "action2", "Action 2", NULL, 0, action_hints1);
- unity_protocol_preview_add_info_hint(proto_obj, "hint1", "Hint 1", NULL, g_variant_new("s", "string hint 1"));
- unity_protocol_preview_add_info_hint(proto_obj, "hint2", "Hint 2", NULL, g_variant_new("s", "string hint 2"));
- unity_protocol_preview_add_info_hint(proto_obj, "hint3", "Hint 3", NULL, g_variant_new("i", 12));
-
- glib::Variant v(dee_serializable_serialize(DEE_SERIALIZABLE(proto_obj.RawPtr())), glib::StealRef());
- preview_model_ = dash::Preview::PreviewForVariant(v);
-
- g_hash_table_unref(action_hints1);
- }
-
- nux::ObjectPtr<nux::BaseWindow> parent_window_;
- dash::Preview::Ptr preview_model_;
-
- previews::Style panel_style;
- dash::Style dash_style;
- ThumbnailGenerator thumbnail_generator;
-};
-
-TEST_F(TestPreviewGeneric, TestCreate)
-{
- previews::Preview::Ptr preview_view = previews::Preview::PreviewForModel(preview_model_);
-
- EXPECT_TRUE(dynamic_cast<previews::GenericPreview*>(preview_view.GetPointer()) != NULL);
-}
-
-TEST_F(TestPreviewGeneric, TestUIValues)
-{
- MockGenericPreview::Ptr preview_view(new MockGenericPreview(preview_model_));
-
- EXPECT_EQ(preview_view->title_->GetText(), "Generic Title &amp; special char");
- EXPECT_EQ(preview_view->subtitle_->GetText(), "Generic Subtitle &gt; special char");
- EXPECT_EQ(preview_view->description_->GetText(), "Generic Desctiption &lt; special char");
-
- EXPECT_EQ(preview_view->action_buttons_.size(), 2u);
-
- if (preview_view->action_buttons_.size() >= 2)
- {
- auto iter = preview_view->action_buttons_.begin();
- if ((*iter)->Type().IsDerivedFromType(ActionButton::StaticObjectType))
- {
- ActionButton *action = static_cast<ActionButton*>(*iter);
- EXPECT_EQ(action->GetLabel(), "Action 1");
- EXPECT_EQ(action->GetExtraText(), "");
- }
- iter++;
- if ((*iter)->Type().IsDerivedFromType(ActionButton::StaticObjectType))
- {
- ActionButton *action = static_cast<ActionButton*>(*iter);
- EXPECT_EQ(action->GetLabel(), "Action 2");
- EXPECT_EQ(action->GetExtraText(), "2.00");
- }
- }
-}
-
-}
diff --git a/tests/test_previews_movie.cpp b/tests/test_previews_movie.cpp
deleted file mode 100644
index ac3b7e1cb..000000000
--- a/tests/test_previews_movie.cpp
+++ /dev/null
@@ -1,149 +0,0 @@
-// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
-/*
- * Copyright (C) 2012 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: Nick Dedekind <nick.dedekinc@canonical.com>
- */
-
-#include <list>
-#include <gmock/gmock.h>
-using namespace testing;
-
-#include <Nux/Nux.h>
-#include <Nux/BaseWindow.h>
-#include <unity-shared/StaticCairoText.h>
-#include <unity-shared/DashStyle.h>
-#include <unity-shared/PreviewStyle.h>
-#include <unity-shared/ThumbnailGenerator.h>
-
-#include <unity-protocol.h>
-#include "UnityCore/MoviePreview.h"
-#include "dash/previews/MoviePreview.h"
-#include "dash/previews/PreviewInfoHintWidget.h"
-#include "dash/previews/PreviewRatingsWidget.h"
-#include "dash/previews/ActionButton.h"
-#include "test_utils.h"
-using namespace unity;
-using namespace unity::dash;
-
-namespace
-{
-
-class MockMoviePreview : public previews::MoviePreview
-{
-public:
- typedef nux::ObjectPtr<MockMoviePreview> Ptr;
-
- MockMoviePreview(dash::Preview::Ptr preview_model)
- : MoviePreview(preview_model)
- {}
-
- using MoviePreview::title_;
- using MoviePreview::subtitle_;
- using MoviePreview::description_;
- using MoviePreview::action_buttons_;
- using MoviePreview::preview_info_hints_;
- using MoviePreview::rating_;
-};
-
-class TestPreviewMovie : public Test
-{
-public:
- TestPreviewMovie()
- : parent_window_(new nux::BaseWindow("TestPreviewMovie")) {}
-
- void create_preview_model(double rating)
- {
- glib::Object<UnityProtocolPreview> proto_obj(UNITY_PROTOCOL_PREVIEW(unity_protocol_movie_preview_new()));
-
- GHashTable* action_hints1(g_hash_table_new(g_direct_hash, g_direct_equal));
- g_hash_table_insert (action_hints1, g_strdup ("extra-text"), g_variant_new_string("£1.00"));
-
- unity_protocol_movie_preview_set_rating(UNITY_PROTOCOL_MOVIE_PREVIEW(proto_obj.RawPtr()), rating);
- unity_protocol_movie_preview_set_num_ratings(UNITY_PROTOCOL_MOVIE_PREVIEW(proto_obj.RawPtr()), 12);
-
- unity_protocol_preview_set_image_source_uri(proto_obj, "http://ia.media-imdb.com/images/M/MV5BMTM3NDM5MzY5Ml5BMl5BanBnXkFtZTcwNjExMDUwOA@@._V1._SY317_.jpg");
- unity_protocol_preview_set_title(proto_obj, "Movie Title & special char");
- unity_protocol_preview_set_subtitle(proto_obj, "Movie Subtitle > special char");
- unity_protocol_preview_set_description(proto_obj, "Movie Desctiption &lt; special char");
- unity_protocol_preview_add_action(proto_obj, "action1", "Action 1", NULL, 0);
- unity_protocol_preview_add_action_with_hints(proto_obj, "action2", "Action 2", NULL, 0, action_hints1);
- unity_protocol_preview_add_info_hint(proto_obj, "hint1", "Hint 1", NULL, g_variant_new("s", "string hint 1"));
- unity_protocol_preview_add_info_hint(proto_obj, "hint2", "Hint 2", NULL, g_variant_new("s", "string hint 2"));
- unity_protocol_preview_add_info_hint(proto_obj, "hint3", "Hint 3", NULL, g_variant_new("i", 12));
-
- glib::Variant v(dee_serializable_serialize(DEE_SERIALIZABLE(proto_obj.RawPtr())), glib::StealRef());
- preview_model_ = dash::Preview::PreviewForVariant(v);
-
- g_hash_table_unref(action_hints1);
- }
-
- nux::ObjectPtr<nux::BaseWindow> parent_window_;
- dash::Preview::Ptr preview_model_;
-
- previews::Style panel_style;
- dash::Style dash_style;
- ThumbnailGenerator thumbnail_generator;
-};
-
-TEST_F(TestPreviewMovie, TestCreate)
-{
- create_preview_model(0.8);
- previews::Preview::Ptr preview_view = previews::Preview::PreviewForModel(preview_model_);
-
- EXPECT_TRUE(dynamic_cast<previews::MoviePreview*>(preview_view.GetPointer()) != NULL);
-}
-
-TEST_F(TestPreviewMovie, TestUIValues)
-{
- create_preview_model(0.8);
- MockMoviePreview::Ptr preview_view(new MockMoviePreview(preview_model_));
-
- EXPECT_EQ(preview_view->title_->GetText(), "Movie Title &amp; special char");
- EXPECT_EQ(preview_view->subtitle_->GetText(), "Movie Subtitle &gt; special char");
- EXPECT_EQ(preview_view->description_->GetText(), "Movie Desctiption &lt; special char");
-
- EXPECT_EQ(preview_view->rating_->GetRating(), 0.8f);
- EXPECT_EQ(preview_view->action_buttons_.size(), 2u);
-
- if (preview_view->action_buttons_.size() >= 2)
- {
- auto iter = preview_view->action_buttons_.begin();
- if ((*iter)->Type().IsDerivedFromType(ActionButton::StaticObjectType))
- {
- ActionButton *action = static_cast<ActionButton*>(*iter);
- EXPECT_EQ(action->GetLabel(), "Action 1");
- EXPECT_EQ(action->GetExtraText(), "");
- }
- iter++;
- if ((*iter)->Type().IsDerivedFromType(ActionButton::StaticObjectType))
- {
- ActionButton *action = static_cast<ActionButton*>(*iter);
- EXPECT_EQ(action->GetLabel(), "Action 2");
- EXPECT_EQ(action->GetExtraText(), "£1.00");
- }
- }
-}
-
-TEST_F(TestPreviewMovie, TestHideRatings)
-{
- create_preview_model(-1);
- MockMoviePreview::Ptr preview_view(new MockMoviePreview(preview_model_));
-
- EXPECT_EQ(preview_view->rating_, NULL);
-}
-
-
-}
diff --git a/tests/test_previews_music.cpp b/tests/test_previews_music.cpp
deleted file mode 100644
index 4398ec292..000000000
--- a/tests/test_previews_music.cpp
+++ /dev/null
@@ -1,131 +0,0 @@
-// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
-/*
- * Copyright (C) 2012 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: Nick Dedekind <nick.dedekinc@canonical.com>
- */
-
-#include <list>
-#include <gmock/gmock.h>
-using namespace testing;
-
-#include <Nux/Nux.h>
-#include <Nux/BaseWindow.h>
-#include <unity-shared/StaticCairoText.h>
-#include <unity-shared/DashStyle.h>
-#include <unity-shared/PreviewStyle.h>
-#include <unity-shared/ThumbnailGenerator.h>
-
-#include <unity-protocol.h>
-#include "UnityCore/MusicPreview.h"
-#include "dash/previews/MusicPreview.h"
-#include "dash/previews/PreviewInfoHintWidget.h"
-#include "dash/previews/PreviewRatingsWidget.h"
-#include "dash/previews/ActionButton.h"
-#include "test_utils.h"
-using namespace unity;
-using namespace unity::dash;
-
-namespace
-{
-
-class MockMusicPreview : public previews::MusicPreview
-{
-public:
- typedef nux::ObjectPtr<MockMusicPreview> Ptr;
-
- MockMusicPreview(dash::Preview::Ptr preview_model)
- : MusicPreview(preview_model)
- {}
-
- using MusicPreview::title_;
- using MusicPreview::subtitle_;
- using MusicPreview::action_buttons_;
- using MusicPreview::preview_info_hints_;
-};
-
-class TestPreviewMusic : public Test
-{
-public:
- TestPreviewMusic()
- : parent_window_(new nux::BaseWindow("TestPreviewMusic"))
- {
- glib::Object<UnityProtocolPreview> proto_obj(UNITY_PROTOCOL_PREVIEW(unity_protocol_music_preview_new()));
-
- GHashTable* action_hints1(g_hash_table_new(g_direct_hash, g_direct_equal));
- g_hash_table_insert (action_hints1, g_strdup ("extra-text"), g_variant_new_string("£3.99"));
-
- unity_protocol_preview_set_image_source_uri(proto_obj, "http://ia.media-imdb.com/images/M/MV5BMTM3NDM5MzY5Ml5BMl5BanBnXkFtZTcwNjExMDUwOA@@._V1._SY317_.jpg");
- unity_protocol_preview_set_title(proto_obj, "Music Title & special char");
- unity_protocol_preview_set_subtitle(proto_obj, "Music Subtitle > special char");
- unity_protocol_preview_set_description(proto_obj, "Music Desctiption &lt; special char");
- unity_protocol_preview_add_action(proto_obj, "action1", "Action 1", NULL, 0);
- unity_protocol_preview_add_action_with_hints(proto_obj, "action2", "Action 2", NULL, 0, action_hints1);
- unity_protocol_preview_add_action(proto_obj, "action3", "Action 3", NULL, 0);
- unity_protocol_preview_add_action(proto_obj, "action4", "Action 4", NULL, 0);
- unity_protocol_preview_add_info_hint(proto_obj, "hint1", "Hint 1", NULL, g_variant_new("s", "string hint 1"));
- unity_protocol_preview_add_info_hint(proto_obj, "hint2", "Hint 2", NULL, g_variant_new("s", "string hint 2"));
- unity_protocol_preview_add_info_hint(proto_obj, "hint3", "Hint 3", NULL, g_variant_new("i", 12));
-
- glib::Variant v(dee_serializable_serialize(DEE_SERIALIZABLE(proto_obj.RawPtr())), glib::StealRef());
- preview_model_ = dash::Preview::PreviewForVariant(v);
-
- g_hash_table_unref(action_hints1);
- }
-
- nux::ObjectPtr<nux::BaseWindow> parent_window_;
- dash::Preview::Ptr preview_model_;
-
- previews::Style panel_style;
- dash::Style dash_style;
- ThumbnailGenerator thumbnail_generator;
-};
-
-TEST_F(TestPreviewMusic, TestCreate)
-{
- previews::Preview::Ptr preview_view = previews::Preview::PreviewForModel(preview_model_);
-
- EXPECT_TRUE(dynamic_cast<previews::MusicPreview*>(preview_view.GetPointer()) != NULL);
-}
-
-TEST_F(TestPreviewMusic, TestUIValues)
-{
- MockMusicPreview::Ptr preview_view(new MockMusicPreview(preview_model_));
-
- EXPECT_EQ(preview_view->title_->GetText(), "Music Title &amp; special char");
- EXPECT_EQ(preview_view->subtitle_->GetText(), "Music Subtitle &gt; special char");
-
- EXPECT_EQ(preview_view->action_buttons_.size(), 4u);
-
- if (preview_view->action_buttons_.size() >= 2)
- {
- auto iter = preview_view->action_buttons_.begin();
- if ((*iter)->Type().IsDerivedFromType(ActionButton::StaticObjectType))
- {
- ActionButton *action = static_cast<ActionButton*>(*iter);
- EXPECT_EQ(action->GetLabel(), "Action 1");
- EXPECT_EQ(action->GetExtraText(), "");
- }
- iter++;
- if ((*iter)->Type().IsDerivedFromType(ActionButton::StaticObjectType))
- {
- ActionButton *action = static_cast<ActionButton*>(*iter);
- EXPECT_EQ(action->GetLabel(), "Action 2");
- EXPECT_EQ(action->GetExtraText(), "£3.99");
- }
- }
-}
-
-}
diff --git a/tests/test_previews_music_payment.cpp b/tests/test_previews_music_payment.cpp
deleted file mode 100644
index daa6a3b47..000000000
--- a/tests/test_previews_music_payment.cpp
+++ /dev/null
@@ -1,150 +0,0 @@
-// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
-/*
- * Copyright (C) 2012-2013 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: Manuel de la Pena <manuel.delapena@canonical.com>
- */
-
-#include <list>
-#include <gmock/gmock.h>
-
-#include <Nux/Nux.h>
-#include <Nux/VLayout.h>
-#include <Nux/BaseWindow.h>
-#include <unity-shared/StaticCairoText.h>
-#include <unity-shared/CoverArt.h>
-#include <unity-shared/DashStyle.h>
-#include <unity-shared/PreviewStyle.h>
-#include <unity-shared/ThumbnailGenerator.h>
-
-#include <unity-protocol.h>
-#include "dash/previews/MusicPaymentPreview.h"
-#include "test_utils.h"
-
-using namespace testing;
-
-namespace unity
-{
-
-namespace dash
-{
-
-namespace previews
-{
-
-class MockedMusicPaymentPreview : public MusicPaymentPreview
-{
-public:
- typedef nux::ObjectPtr<MockedMusicPaymentPreview> Ptr;
-
- MockedMusicPaymentPreview(dash::Preview::Ptr preview_model)
- : MusicPaymentPreview(preview_model)
- {}
-
- using MusicPaymentPreview::image_;
- using MusicPaymentPreview::intro_;
- using MusicPaymentPreview::title_;
- using MusicPaymentPreview::subtitle_;
- using MusicPaymentPreview::email_label_;
- using MusicPaymentPreview::email_;
- using MusicPaymentPreview::payment_label_;
- using MusicPaymentPreview::payment_;
- using MusicPaymentPreview::password_label_;
- using MusicPaymentPreview::password_entry_;
- using MusicPaymentPreview::purchase_hint_;
- using MusicPaymentPreview::purchase_prize_;
- using MusicPaymentPreview::purchase_type_;
- using MusicPaymentPreview::change_payment_;
- using MusicPaymentPreview::forgotten_password_;
- using MusicPaymentPreview::error_label_;
- using MusicPaymentPreview::form_layout_;
- using MusicPaymentPreview::SetupViews;
-};
-
-class TestMusicPaymentPreview : public ::testing::Test
-{
- protected:
- TestMusicPaymentPreview() :
- Test(),
- parent_window_(new nux::BaseWindow("TestPreviewMusicPayment"))
- {
- title = "Turning Japanese";
- subtitle = "The vapors";
- header = "Hi test, you purchased in the past from Ubuntu One.";
- email = "test@canonical.com";
- payment_method = "*** *** ** 12";
- purchase_prize = "65$";
- purchase_type = "Mp3";
- preview_type = UNITY_PROTOCOL_PREVIEW_PAYMENT_TYPE_MUSIC;
-
- glib::Object<UnityProtocolPreview> proto_obj(UNITY_PROTOCOL_PREVIEW(unity_protocol_payment_preview_new()));
-
- unity_protocol_preview_set_title(proto_obj, title.c_str());
- unity_protocol_preview_set_subtitle(proto_obj, subtitle.c_str());
- unity_protocol_preview_add_action(proto_obj, "change_payment_method", "Change payment", NULL, 0);
- unity_protocol_preview_add_action(proto_obj, "forgot_password", "Forgot password", NULL, 0);
- unity_protocol_preview_add_action(proto_obj, "cancel_purchase", "Cancel", NULL, 0);
- unity_protocol_preview_add_action(proto_obj, "purchase_album", "Purchase", NULL, 0);
-
-
- unity_protocol_payment_preview_set_header(UNITY_PROTOCOL_PAYMENT_PREVIEW(proto_obj.RawPtr()), header.c_str());
- unity_protocol_payment_preview_set_email(UNITY_PROTOCOL_PAYMENT_PREVIEW(proto_obj.RawPtr()), email.c_str());
- unity_protocol_payment_preview_set_payment_method(UNITY_PROTOCOL_PAYMENT_PREVIEW(proto_obj.RawPtr()), payment_method.c_str());
- unity_protocol_payment_preview_set_purchase_prize(UNITY_PROTOCOL_PAYMENT_PREVIEW(proto_obj.RawPtr()), purchase_prize.c_str());
- unity_protocol_payment_preview_set_purchase_type(UNITY_PROTOCOL_PAYMENT_PREVIEW(proto_obj.RawPtr()), purchase_type.c_str());
- unity_protocol_payment_preview_set_preview_type(UNITY_PROTOCOL_PAYMENT_PREVIEW(proto_obj.RawPtr()), preview_type);
-
- glib::Variant v(dee_serializable_serialize(DEE_SERIALIZABLE(proto_obj.RawPtr())), glib::StealRef());
-
- preview_model = dash::Preview::PreviewForVariant(v);
- }
-
- nux::ObjectPtr<nux::BaseWindow> parent_window_;
- dash::Preview::Ptr preview_model;
-
- // testing data
- std::string title;
- std::string subtitle;
- std::string header;
- std::string email;
- std::string payment_method;
- std::string purchase_prize;
- std::string purchase_type;
- UnityProtocolPreviewPaymentType preview_type;
-
- // needed for styles
- previews::Style previews_style;
- dash::Style dash_style;
-};
-
-TEST_F(TestMusicPaymentPreview, TestContentLoading)
-{
- MockedMusicPaymentPreview::Ptr preview_view(new MockedMusicPaymentPreview(preview_model));
-
- EXPECT_EQ(preview_view->title_->GetText(), title);
- EXPECT_EQ(preview_view->subtitle_->GetText(), subtitle);
- EXPECT_EQ(preview_view->intro_->GetText(), header);
- EXPECT_EQ(preview_view->email_->GetText(), email);
- EXPECT_EQ(preview_view->payment_->GetText(), payment_method);
- EXPECT_EQ(preview_view->purchase_type_->GetText(), purchase_type);
- EXPECT_EQ(preview_view->purchase_prize_->GetText(), purchase_prize);
-}
-
-
-} // previews
-
-} // dash
-
-} // unity
diff --git a/tests/test_previews_payment.cpp b/tests/test_previews_payment.cpp
deleted file mode 100644
index 53f541743..000000000
--- a/tests/test_previews_payment.cpp
+++ /dev/null
@@ -1,184 +0,0 @@
-// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
-/*
- * Copyright (C) 2012-2013 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: Manuel de la Pena <manuel.delapena@canonical.com>
- */
-#include <list>
-#include <gmock/gmock.h>
-
-#include <Nux/Nux.h>
-#include <Nux/Layout.h>
-#include <Nux/VLayout.h>
-#include <Nux/BaseWindow.h>
-#include <unity-shared/StaticCairoText.h>
-#include <unity-shared/DashStyle.h>
-#include <unity-shared/PreviewStyle.h>
-#include <unity-shared/ThumbnailGenerator.h>
-#include <unity-shared/CoverArt.h>
-
-#include <unity-protocol.h>
-#include "dash/previews/PaymentPreview.h"
-#include "dash/previews/ActionButton.h"
-#include "dash/previews/ActionLink.h"
-#include "test_utils.h"
-
-using namespace testing;
-using ::testing::Return;
-
-namespace unity
-{
-
-namespace dash
-{
-
-namespace previews
-{
-
-class NonAbstractPreview : public PaymentPreview
-{
-public:
- NonAbstractPreview(dash::Preview::Ptr preview_model)
- : PaymentPreview(preview_model)
- {}
-
- virtual nux::Layout* GetTitle()
- {
- return new nux::VLayout();
- }
-
- virtual nux::Layout* GetPrice()
- {
- return new nux::VLayout();
- }
-
- virtual nux::Layout* GetBody()
- {
- return new nux::VLayout();
- }
-
- virtual nux::Layout* GetFooter()
- {
- return new nux::VLayout();
- }
-
- virtual void OnActionActivated(ActionButton* button, std::string const& id)
- {
- // do nothing
- }
-
- virtual void OnActionLinkActivated(ActionLink* link, std::string const& id)
- {
- // do nothing
- }
-
- virtual void PreLayoutManagement()
- {
- // do nothing
- }
-
- virtual void LoadActions()
- {
- // do nothing
- }
-
- using PaymentPreview::GetHeader;
- using PaymentPreview::full_data_layout_;
- using PaymentPreview::content_data_layout_;
- using PaymentPreview::overlay_layout_;
- using PaymentPreview::header_layout_;
- using PaymentPreview::body_layout_;
- using PaymentPreview::footer_layout_;
- using PaymentPreview::SetupViews;
-
-};
-
-class MockedPaymentPreview : public NonAbstractPreview
-{
-public:
- typedef nux::ObjectPtr<MockedPaymentPreview> Ptr;
-
- MockedPaymentPreview(dash::Preview::Ptr preview_model)
- : NonAbstractPreview(preview_model)
- {}
-
- // Mock methods that should be implemented so that we can assert that they are
- // called in the correct moments.
- MOCK_METHOD0(GetTitle, nux::Layout*());
- MOCK_METHOD0(GetPrice, nux::Layout*());
- MOCK_METHOD0(GetBody, nux::Layout*());
- MOCK_METHOD0(GetFooter, nux::Layout*());
- MOCK_METHOD2(OnActionActivated, void(unity::dash::ActionButton*, std::string));
- MOCK_METHOD2(OnActionLinkActivated, void(unity::dash::ActionLink*, std::string));
- MOCK_METHOD0(PreLayoutManagement, void());
- MOCK_METHOD0(LoadActions, void());
-
-};
-
-class TestPaymentPreview : public ::testing::Test
-{
- protected:
- TestPaymentPreview() : Test()
- {
- glib::Object<UnityProtocolPreview> proto_obj(UNITY_PROTOCOL_PREVIEW(unity_protocol_payment_preview_new()));
- // we are not testing how the info is really used is more asserting the method calls, we do not add any data then
- glib::Variant v(dee_serializable_serialize(DEE_SERIALIZABLE(proto_obj.RawPtr())), glib::StealRef());
-
- preview_model = dash::Preview::PreviewForVariant(v);
-
- preview = new MockedPaymentPreview(preview_model);
-
- }
- nux::ObjectPtr<MockedPaymentPreview> preview;
- dash::Preview::Ptr preview_model;
-
- // needed for styles
- previews::Style previews_style;
- dash::Style dash_style;
-};
-
-TEST_F(TestPaymentPreview, GetHeaderCallsCorrectMethods)
-{
- ON_CALL(*preview.GetPointer(), GetTitle()).WillByDefault(Return(new nux::VLayout()));
- EXPECT_CALL(*preview.GetPointer(), GetTitle()).Times(1);
-
- ON_CALL(*preview.GetPointer(), GetPrice()).WillByDefault(Return(new nux::VLayout()));
- EXPECT_CALL(*preview.GetPointer(), GetPrice()).Times(1);
-
- preview->GetHeader()->UnReference();
-}
-
-TEST_F(TestPaymentPreview, SetupViewsCallCorrectMethods)
-{
- ON_CALL(*preview.GetPointer(), GetTitle()).WillByDefault(Return(new nux::VLayout()));
- EXPECT_CALL(*preview.GetPointer(), GetTitle()).Times(1);
-
- ON_CALL(*preview.GetPointer(), GetPrice()).WillByDefault(Return(new nux::VLayout()));
- EXPECT_CALL(*preview.GetPointer(), GetPrice()).Times(1);
-
- ON_CALL(*preview.GetPointer(), GetBody()).WillByDefault(Return(new nux::VLayout()));
- EXPECT_CALL(*preview.GetPointer(), GetBody()).Times(1);
-
- ON_CALL(*preview.GetPointer(), GetFooter()).WillByDefault(Return(new nux::VLayout()));
- EXPECT_CALL(*preview.GetPointer(), GetFooter()).Times(1);
-
- preview->SetupViews();
-}
-
-} // previews
-
-} // dash
-
-} // unity
diff --git a/tests/test_previews_social.cpp b/tests/test_previews_social.cpp
deleted file mode 100644
index 76b42e034..000000000
--- a/tests/test_previews_social.cpp
+++ /dev/null
@@ -1,107 +0,0 @@
-// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
-/*
- * Copyright (C) 2012 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: Ken VanDine <ken.vandine@canonical.com>
- */
-
-#include <list>
-#include <gmock/gmock.h>
-using namespace testing;
-
-#include <Nux/Nux.h>
-#include <Nux/BaseWindow.h>
-#include <unity-shared/StaticCairoText.h>
-#include <unity-shared/DashStyle.h>
-#include <unity-shared/PreviewStyle.h>
-#include <unity-shared/ThumbnailGenerator.h>
-
-#include <unity-protocol.h>
-#include "UnityCore/SocialPreview.h"
-#include "dash/previews/SocialPreview.h"
-#include "dash/previews/SocialPreviewContent.h"
-#include "dash/previews/SocialPreviewComments.h"
-#include "dash/previews/PreviewInfoHintWidget.h"
-#include "dash/previews/PreviewRatingsWidget.h"
-#include "test_utils.h"
-using namespace unity;
-using namespace unity::dash;
-
-namespace
-{
-
-class MockSocialPreview : public previews::SocialPreview
-{
-public:
- typedef nux::ObjectPtr<MockSocialPreview> Ptr;
-
- MockSocialPreview(dash::Preview::Ptr preview_model)
- : SocialPreview(preview_model)
- {}
-
- using SocialPreview::title_;
- using SocialPreview::subtitle_;
- using SocialPreview::content_;
- using SocialPreview::action_buttons_;
- using SocialPreview::preview_info_hints_;
-};
-
-class TestPreviewSocial : public Test
-{
-public:
- TestPreviewSocial()
- : parent_window_(new nux::BaseWindow("TestPreviewSocial"))
- {
- glib::Object<UnityProtocolPreview> proto_obj(UNITY_PROTOCOL_PREVIEW(unity_protocol_social_preview_new()));
-
- unity_protocol_preview_set_image_source_uri(proto_obj, "http://ia.media-imdb.com/images/M/MV5BMTM3NDM5MzY5Ml5BMl5BanBnXkFtZTcwNjExMDUwOA@@._V1._SY317_.jpg");
- unity_protocol_preview_set_title(proto_obj, "Social Title & special char");
- unity_protocol_preview_set_subtitle(proto_obj, "Social Subtitle > special char");
- unity_protocol_preview_set_description(proto_obj, "Social Desctiption &lt; special char");
- unity_protocol_preview_add_action(proto_obj, "action1", "Action 1", NULL, 0);
- unity_protocol_preview_add_action(proto_obj, "action2", "Action 2", NULL, 0);
- unity_protocol_preview_add_info_hint(proto_obj, "hint1", "Hint 1", NULL, g_variant_new("s", "string hint 1"));
- unity_protocol_preview_add_info_hint(proto_obj, "hint2", "Hint 2", NULL, g_variant_new("s", "string hint 2"));
- unity_protocol_preview_add_info_hint(proto_obj, "hint3", "Hint 3", NULL, g_variant_new("i", 12));
-
- glib::Variant v(dee_serializable_serialize(DEE_SERIALIZABLE(proto_obj.RawPtr())), glib::StealRef());
- preview_model_ = dash::Preview::PreviewForVariant(v);
- }
-
- nux::ObjectPtr<nux::BaseWindow> parent_window_;
- dash::Preview::Ptr preview_model_;
-
- previews::Style panel_style;
- dash::Style dash_style;
- ThumbnailGenerator thumbnail_generator;
-};
-
-TEST_F(TestPreviewSocial, TestCreate)
-{
- previews::Preview::Ptr preview_view = previews::Preview::PreviewForModel(preview_model_);
-
- EXPECT_TRUE(dynamic_cast<previews::SocialPreview*>(preview_view.GetPointer()) != NULL);
-}
-
-TEST_F(TestPreviewSocial, TestUIValues)
-{
- MockSocialPreview::Ptr preview_view(new MockSocialPreview(preview_model_));
-
- EXPECT_EQ(preview_view->title_->GetText(), "Social Title &amp; special char");
- EXPECT_EQ(preview_view->subtitle_->GetText(), "Social Subtitle &gt; special char");
- EXPECT_EQ(preview_view->action_buttons_.size(), 2u);
-}
-
-}
diff --git a/unity-shared/BackgroundEffectHelper.cpp b/unity-shared/BackgroundEffectHelper.cpp
index 507c3eacc..274f184c2 100644
--- a/unity-shared/BackgroundEffectHelper.cpp
+++ b/unity-shared/BackgroundEffectHelper.cpp
@@ -27,7 +27,7 @@ namespace
DECLARE_LOGGER(logger, "unity.background_effect_helper");
const int BLUR_RADIUS = 3;
-const float sigma_high = 5.0f;
+const float sigma_high = 10.0f;
const float sigma_med = 3.0f;
const float sigma_low = 1.0f;
}
diff --git a/unity-shared/CMakeLists.txt b/unity-shared/CMakeLists.txt
index eddc80766..673c7ddb3 100644
--- a/unity-shared/CMakeLists.txt
+++ b/unity-shared/CMakeLists.txt
@@ -30,9 +30,9 @@ set (UNITY_SHARED_SOURCES
DesktopApplicationManager.cpp
EMConverter.cpp
ExpanderView.cpp
- FileManager.cpp
GnomeFileManager.cpp
FontSettings.cpp
+ FileManager.cpp
GraphicsUtils.cpp
IMTextEntry.cpp
IconLoader.cpp
diff --git a/unity-shared/DashStyle.cpp b/unity-shared/DashStyle.cpp
index 66ed48c5b..b0c3eac45 100755
--- a/unity-shared/DashStyle.cpp
+++ b/unity-shared/DashStyle.cpp
@@ -374,35 +374,8 @@ Style::Impl::~Impl()
void Style::Impl::Refresh()
{
- const char* const SAMPLE_MAX_TEXT = "Chromium Web Browser";
-
- nux::CairoGraphics util_cg(CAIRO_FORMAT_ARGB32, 1, 1);
- cairo_t* cr = util_cg.GetInternalContext();
-
- auto const& font = theme::Settings::Get()->font();
- PangoFontDescription* desc = ::pango_font_description_from_string(font.c_str());
- ::pango_font_description_set_weight(desc, PANGO_WEIGHT_NORMAL);
- ::pango_font_description_set_size(desc, 9 * PANGO_SCALE);
-
- glib::Object<PangoLayout> layout(::pango_cairo_create_layout(cr));
- ::pango_layout_set_font_description(layout, desc);
- ::pango_layout_set_text(layout, SAMPLE_MAX_TEXT, -1);
-
- PangoContext* cxt = ::pango_layout_get_context(layout);
-
- GdkScreen* screen = ::gdk_screen_get_default();
- ::pango_cairo_context_set_font_options(cxt, ::gdk_screen_get_font_options(screen));
- ::pango_cairo_context_set_resolution(cxt, 96.0 * Settings::Instance().font_scaling());
- ::pango_layout_context_changed(layout);
-
- PangoRectangle log_rect;
- ::pango_layout_get_pixel_extents(layout, NULL, &log_rect);
- text_width_ = log_rect.width;
- text_height_ = log_rect.height;
-
- owner_->changed.emit();
-
- pango_font_description_free(desc);
+ text_width_ = 56;
+ text_height_ = 12;
}
void Style::Impl::UpdateFormFactor(FormFactor form_factor)
@@ -2186,6 +2159,11 @@ BaseTexturePtr Style::GetDashRightCornerMask(double scale) const
return pimpl->LoadScaledTexture("dash_top_right_corner_mask", scale);
}
+BaseTexturePtr Style::GetEmpty(double scale) const
+{
+ return pimpl->LoadScaledTexture("empty", scale);
+}
+
BaseTexturePtr Style::GetSearchMagnifyIcon(double scale) const
{
return pimpl->LoadScaledTexture("search_magnify", scale);
@@ -2236,33 +2214,33 @@ nux::Color const& Style::GetTextColor() const
RawPixel Style::GetTileGIconSize() const
{
- return 64;
+ return 48;
}
RawPixel Style::GetTileImageSize() const
{
- return 96;
+ return 48;
}
RawPixel Style::GetTileWidth() const
{
- return std::max(pimpl->text_width_, 150);
+ return std::max(pimpl->text_width_, 106);
}
RawPixel Style::GetTileHeight() const
{
return std::max(GetTileImageSize() + (pimpl->text_height_ * 2) + 15,
- GetTileImageSize() + 32); // magic design numbers.
+ GetTileImageSize() + 80); // magic design numbers.
}
RawPixel Style::GetTileIconHightlightHeight() const
{
- return 106;
+ return 48;
}
RawPixel Style::GetTileIconHightlightWidth() const
{
- return 106;
+ return 48;
}
RawPixel Style::GetHomeTileIconSize() const
@@ -2363,7 +2341,7 @@ RawPixel Style::GetHSeparatorSize() const
RawPixel Style::GetFilterBarWidth() const
{
- return 300;
+ return 250;
}
RawPixel Style::GetFilterBarLeftPadding() const
@@ -2418,7 +2396,7 @@ RawPixel Style::GetFilterHighlightPadding() const
RawPixel Style::GetSpaceBetweenFilterWidgets() const
{
- return 12;
+ return 6;
}
RawPixel Style::GetAllButtonHeight() const
@@ -2498,12 +2476,12 @@ RawPixel Style::GetPlacesGroupTopSpace() const
RawPixel Style::GetPlacesGroupResultTopPadding() const
{
- return 2;
+ return 19;
}
RawPixel Style::GetPlacesGroupResultLeftPadding() const
{
- return 25;
+ return 19;
}
RawPixel Style::GetCategoryHeaderLeftPadding() const
diff --git a/unity-shared/DashStyle.h b/unity-shared/DashStyle.h
index f080297a9..dd127c421 100755
--- a/unity-shared/DashStyle.h
+++ b/unity-shared/DashStyle.h
@@ -178,6 +178,8 @@ public:
BaseTexturePtr GetDashLeftTile(double scale) const;
BaseTexturePtr GetDashTopTile(double scale) const;
+ BaseTexturePtr GetEmpty(double scale) const;
+
BaseTexturePtr GetDashCorner(double scale) const;
BaseTexturePtr GetDashCornerMask(double scale) const;
BaseTexturePtr GetDashLeftCorner(double scale) const;
diff --git a/unity-shared/FileManager.cpp b/unity-shared/FileManager.cpp
index c48a466bb..6fc574e01 100644
--- a/unity-shared/FileManager.cpp
+++ b/unity-shared/FileManager.cpp
@@ -24,7 +24,7 @@
#include "GnomeFileManager.h"
#include "NemoFileManager.h"
-#include <gio/gdesktopappinfo.h>
+#include <gio/gio.h>
namespace unity
{
diff --git a/unity-shared/FileManager.h b/unity-shared/FileManager.h
index bb636d411..6b802c677 100644
--- a/unity-shared/FileManager.h
+++ b/unity-shared/FileManager.h
@@ -61,4 +61,4 @@ private:
} // namespace unity
-#endif
+#endif \ No newline at end of file
diff --git a/unity-shared/GnomeFileManager.h b/unity-shared/GnomeFileManager.h
index b9c3dd80f..6fa53a69e 100644
--- a/unity-shared/GnomeFileManager.h
+++ b/unity-shared/GnomeFileManager.h
@@ -51,4 +51,4 @@ private:
}
-#endif
+#endif \ No newline at end of file
diff --git a/unity-shared/NemoFileManager.cpp b/unity-shared/NemoFileManager.cpp
index 81432cf42..e8889e6a0 100644
--- a/unity-shared/NemoFileManager.cpp
+++ b/unity-shared/NemoFileManager.cpp
@@ -19,12 +19,12 @@
#include "NemoFileManager.h"
#include <NuxCore/Logger.h>
-
+#include <UnityCore/DesktopUtilities.h>
#include <UnityCore/GLibDBusProxy.h>
#include <UnityCore/GLibWrapper.h>
-#include <gio/gdesktopappinfo.h>
#include <gdk/gdk.h>
#include <gio/gio.h>
+#include <gio/gdesktopappinfo.h>
namespace unity
{
@@ -38,30 +38,48 @@ const std::string FILE_SCHEMA = "file://";
const std::string NEMO_DESKTOP_ID = "nemo.desktop";
const std::string NEMO_NAME = "org.Nemo";
-const std::string NEMO_PATH = "/org/Nemo";
+const std::string NEMO_FILE_OPS_PATH = "/org/Nemo";
}
struct NemoFileManager::Impl
{
Impl(NemoFileManager* parent)
: parent_(parent)
- , app_info_(g_desktop_app_info_new(NEMO_DESKTOP_ID.c_str()))
{
}
glib::DBusProxy::Ptr NemoOperationsProxy() const
{
auto flags = static_cast<GDBusProxyFlags>(G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES|G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS);
- return std::make_shared<glib::DBusProxy>(NEMO_NAME, NEMO_PATH,
+ return std::make_shared<glib::DBusProxy>(NEMO_NAME, NEMO_FILE_OPS_PATH,
"org.Nemo.FileOperations",
G_BUS_TYPE_SESSION, flags);
}
- void Activate(uint64_t timestamp)
- {
- if (!app_info_)
- return;
+ NemoFileManager* parent_;
+};
+
+
+FileManager::Ptr NemoFileManager::Get()
+{
+ static FileManager::Ptr instance(new NemoFileManager());
+ return instance;
+}
+
+NemoFileManager::NemoFileManager()
+ : impl_(new Impl(this))
+{}
+
+NemoFileManager::~NemoFileManager()
+{}
+void Activate(uint64_t timestamp)
+{
+ glib::Cancellable cancellable;
+ glib::Object<GAppInfo> app_info(G_APP_INFO (g_desktop_app_info_new(NEMO_DESKTOP_ID.c_str())));
+
+ if (app_info)
+ {
GdkDisplay* display = gdk_display_get_default();
glib::Object<GdkAppLaunchContext> context(gdk_display_get_app_launch_context(display));
@@ -69,11 +87,10 @@ struct NemoFileManager::Impl
gdk_app_launch_context_set_timestamp(context, timestamp);
auto const& gcontext = glib::object_cast<GAppLaunchContext>(context);
- auto proxy = std::make_shared<glib::DBusProxy>(NEMO_NAME, NEMO_PATH,
- "org.freedesktop.Application");
+ auto proxy = std::make_shared<glib::DBusProxy>(NEMO_NAME, NEMO_FILE_OPS_PATH,
+ "org.freedesktop.Application");
- glib::String context_string(g_app_launch_context_get_startup_notify_id(
- gcontext, glib::object_cast<GAppInfo>(app_info_), nullptr));
+ glib::String context_string(g_app_launch_context_get_startup_notify_id(gcontext, app_info, nullptr));
if (context_string && g_utf8_validate(context_string, -1, nullptr))
{
@@ -86,25 +103,8 @@ struct NemoFileManager::Impl
proxy->CallBegin("Activate", param, [proxy] (GVariant*, glib::Error const&) {});
}
}
-
- glib::Object<GDesktopAppInfo> app_info_;
- NemoFileManager* parent_;
-};
-
-
-FileManager::Ptr NemoFileManager::Get()
-{
- static FileManager::Ptr instance(new NemoFileManager());
- return instance;
}
-NemoFileManager::NemoFileManager()
- : impl_(new Impl(this))
-{}
-
-NemoFileManager::~NemoFileManager()
-{}
-
void NemoFileManager::Open(std::string const& uri, uint64_t timestamp)
{
if (uri.empty())
@@ -152,7 +152,7 @@ void NemoFileManager::EmptyTrash(uint64_t timestamp, Window parent_xid)
auto const& proxy = impl_->NemoOperationsProxy();
// Passing the proxy to the lambda we ensure that it will be destroyed when needed
- impl_->Activate(timestamp);
+ Activate(timestamp);
proxy->CallBegin("EmptyTrash", nullptr, [proxy] (GVariant*, glib::Error const&) {});
}
@@ -184,7 +184,7 @@ void NemoFileManager::CopyFiles(std::set<std::string> const& uris, std::string c
// Passing the proxy to the lambda we ensure that it will be destroyed when needed
auto const& proxy = impl_->NemoOperationsProxy();
proxy->CallBegin("CopyURIs", parameters, [proxy] (GVariant*, glib::Error const&) {});
- impl_->Activate(timestamp);
+ Activate(timestamp);
}
}
@@ -199,4 +199,4 @@ std::string NemoFileManager::LocationForWindow(ApplicationWindowPtr const& win)
return std::string();
}
-} // namespace unity
+} // namespace unity \ No newline at end of file
diff --git a/unity-shared/NemoFileManager.h b/unity-shared/NemoFileManager.h
index aaa4e91d9..94321a93f 100644
--- a/unity-shared/NemoFileManager.h
+++ b/unity-shared/NemoFileManager.h
@@ -47,4 +47,4 @@ private:
std::unique_ptr<Impl> impl_;
};
-} // namespace unity
+}
diff --git a/unity-shared/OverlayRenderer.cpp b/unity-shared/OverlayRenderer.cpp
index 475ad5e9c..e35a3e8e0 100644
--- a/unity-shared/OverlayRenderer.cpp
+++ b/unity-shared/OverlayRenderer.cpp
@@ -99,6 +99,8 @@ public:
nux::ObjectPtr<nux::BaseTexture> right_corner_;
nux::ObjectPtr<nux::BaseTexture> right_corner_mask_;
+ OverlayPosition dash_position = OverlayPosition::LEFT;
+
// temporary variable that stores the number of backgrounds we have rendered
int bgs;
bool visible;
@@ -140,20 +142,37 @@ void OverlayRendererImpl::LoadScaledTextures()
double scale = parent->scale;
auto& style = dash::Style::Instance();
- horizontal_texture_ = style.GetDashHorizontalTile(scale);
- horizontal_texture_mask_ = style.GetDashHorizontalTileMask(scale);
- right_texture_ = style.GetDashRightTile(scale);
- right_texture_mask_ = style.GetDashRightTileMask(scale);
- top_left_texture_ = style.GetDashTopLeftTile(scale);
- left_texture_ = style.GetDashLeftTile(scale);
- top_texture_ = style.GetDashTopTile(scale);
-
- corner_ = style.GetDashCorner(scale);
- corner_mask_ = style.GetDashCornerMask(scale);
- left_corner_ = style.GetDashLeftCorner(scale);
- left_corner_mask_ = style.GetDashLeftCornerMask(scale);
- right_corner_ = style.GetDashRightCorner(scale);
- right_corner_mask_ = style.GetDashRightCornerMask(scale);
+ if (parent->owner_type == OverlayOwner::Hud) {
+ horizontal_texture_ = style.GetDashHorizontalTile(scale);
+ horizontal_texture_mask_ = style.GetDashHorizontalTileMask(scale);
+ right_texture_ = style.GetDashRightTile(scale);
+ right_texture_mask_ = style.GetDashRightTileMask(scale);
+ top_left_texture_ = style.GetDashTopLeftTile(scale);
+ left_texture_ = style.GetDashLeftTile(scale);
+ top_texture_ = style.GetDashTopTile(scale);
+
+ corner_ = style.GetDashCorner(scale);
+ corner_mask_ = style.GetDashCornerMask(scale);
+ left_corner_ = style.GetDashLeftCorner(scale);
+ left_corner_mask_ = style.GetDashLeftCornerMask(scale);
+ right_corner_ = style.GetDashRightCorner(scale);
+ right_corner_mask_ = style.GetDashRightCornerMask(scale);
+ } else {
+ horizontal_texture_ = style.GetEmpty(scale);
+ horizontal_texture_mask_ = style.GetEmpty(scale);
+ right_texture_ = style.GetEmpty(scale);
+ right_texture_mask_ = style.GetEmpty(scale);
+ top_left_texture_ = style.GetEmpty(scale);
+ left_texture_ = style.GetEmpty(scale);
+ top_texture_ = style.GetEmpty(scale);
+
+ corner_ = style.GetEmpty(scale);
+ corner_mask_ = style.GetEmpty(scale);
+ left_corner_ = style.GetEmpty(scale);
+ left_corner_mask_ = style.GetEmpty(scale);
+ right_corner_ = style.GetEmpty(scale);
+ right_corner_mask_ = style.GetEmpty(scale);
+ }
}
void OverlayRendererImpl::OnBgColorChanged(nux::Color const& new_color)
@@ -186,7 +205,7 @@ void OverlayRendererImpl::UpdateTextures()
rop.Blend = true;
rop.SrcBlend = GL_ZERO;
rop.DstBlend = GL_SRC_COLOR;
- nux::Color darken_colour = nux::Color(0.9f, 0.9f, 0.9f, 1.0f);
+ nux::Color darken_colour = nux::Color(1.0f, 1.0f, 1.0f, 1.0f);
//When we are in low gfx mode then our darken layer will act as a background.
if (Settings::Instance().low_gfx())
@@ -198,7 +217,7 @@ void OverlayRendererImpl::UpdateTextures()
}
bg_darken_layer_ = std::make_shared<nux::ColorLayer>(darken_colour, false, rop);
- bg_shine_texture_ = dash::Style::Instance().GetDashShine()->GetDeviceTexture();
+ // bg_shine_texture_ = dash::Style::Instance().GetDashShine()->GetDeviceTexture();
auto const& bg_refine_tex = dash::Style::Instance().GetRefineTextureDash();
@@ -619,7 +638,6 @@ void OverlayRendererImpl::Draw(nux::GraphicsEngine& gfx_context, nux::Geometry c
int launcher_size = Settings::Instance().LauncherSize(monitor);
int panel_height = panel::Style::Instance().PanelHeight(monitor);
- auto dash_position = OverlayPosition::LEFT;
int border_y = content_geo.y;
int border_height = larger_absolute_geo.height;
if (parent->owner_type() == OverlayOwner::Dash && settings.launcher_position() == LauncherPosition::BOTTOM)
diff --git a/unity-shared/OverlayWindowButtons.cpp b/unity-shared/OverlayWindowButtons.cpp
index c373ad191..6b17182ee 100644
--- a/unity-shared/OverlayWindowButtons.cpp
+++ b/unity-shared/OverlayWindowButtons.cpp
@@ -23,7 +23,7 @@
namespace
{
- const int MAIN_LEFT_PADDING = 4;
+ const int MAIN_LEFT_PADDING = 6;
const int MENUBAR_PADDING = 4;
}
diff --git a/unity-shared/PanelStyle.cpp b/unity-shared/PanelStyle.cpp
index e2fb22d2e..92d675164 100644
--- a/unity-shared/PanelStyle.cpp
+++ b/unity-shared/PanelStyle.cpp
@@ -41,8 +41,8 @@ Style* style_instance = nullptr;
DECLARE_LOGGER(logger, "unity.panel.style");
const int BUTTONS_SIZE = 16;
-const int BUTTONS_PADDING = 1;
-const int BASE_PANEL_HEIGHT = 24;
+const int BUTTONS_PADDING = 9;
+const int BASE_PANEL_HEIGHT = 30;
const std::string PANEL_STYLE_CSS_NAME = "UnityPanelWidget";
inline std::string button_id(std::string const& prefix, double scale, WindowButtonType type, WindowState ws)
diff --git a/unity-shared/SearchBar.cpp b/unity-shared/SearchBar.cpp
index 9c3741f86..8e90c58a5 100644
--- a/unity-shared/SearchBar.cpp
+++ b/unity-shared/SearchBar.cpp
@@ -74,11 +74,11 @@ const RawPixel FILTER_HORIZONTAL_MARGIN = 8_em;
// Fonts
const std::string HINT_LABEL_FONT_SIZE = "15"; // == 20px
-const std::string HINT_LABEL_FONT_STYLE = "Italic";
+const std::string HINT_LABEL_FONT_STYLE = "Light";
const std::string HINT_LABEL_DEFAULT_FONT = "Ubuntu " + HINT_LABEL_FONT_STYLE + " " + HINT_LABEL_FONT_SIZE;
-const std::string PANGO_ENTRY_DEFAULT_FONT_FAMILY = "Ubuntu";
-const RawPixel PANGO_ENTRY_FONT_SIZE = 22_em;
+const std::string PANGO_ENTRY_DEFAULT_FONT_FAMILY = "Ubuntu Light";
+const RawPixel PANGO_ENTRY_FONT_SIZE = 15_em;
const std::string SHOW_FILTERS_LABEL_FONT_SIZE = "13";
const std::string SHOW_FILTERS_LABEL_FONT_STYLE = "";
@@ -403,8 +403,6 @@ void SearchBar::Draw(nux::GraphicsEngine& graphics_engine, bool force_draw)
{
nux::Geometry const& base = GetGeometry();
- UpdateBackground(false);
-
graphics_engine.PushClippingRectangle(base);
if (RedirectedAncestor())
@@ -513,64 +511,6 @@ void SearchBar::SetSearchFinished()
spinner_->SetState(is_empty ? STATE_READY : STATE_CLEAR);
}
-void SearchBar::UpdateBackground(bool force)
-{
- nux::Geometry geo(GetGeometry());
- geo.width = layered_layout_->GetAbsoluteX() +
- layered_layout_->GetAbsoluteWidth() -
- GetAbsoluteX() +
- SEARCH_ENTRY_RIGHT_BORDER.CP(scale());
-
- LOG_TRACE(logger) << "height: "
- << geo.height << " - "
- << layered_layout_->GetGeometry().height << " - "
- << pango_entry_->GetGeometry().height;
-
- if (!bg_layer_ &&
- geo.width == last_width_
- && geo.height == last_height_
- && force == false)
- return;
-
- last_width_ = geo.width;
- last_height_ = geo.height;
-
- nux::CairoGraphics cairo_graphics(CAIRO_FORMAT_ARGB32, last_width_, last_height_);
- cairo_t* cr = cairo_graphics.GetInternalContext();
- cairo_surface_set_device_scale(cairo_get_target(cr), scale, scale);
-
- cairo_graphics.DrawRoundedRectangle(cr,
- 1.0f,
- 0.5, 0.5,
- CORNER_RADIUS,
- (last_width_/scale) - 1, (last_height_/scale) - 1,
- false);
-
- cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
- cairo_set_source_rgba(cr, 0.0f, 0.0f, 0.0f, 0.35f);
- cairo_fill_preserve(cr);
- cairo_set_line_width(cr, 1);
- cairo_set_source_rgba(cr, 1.0f, 1.0f, 1.0f, 0.7f);
- cairo_stroke(cr);
-
- auto texture2D = texture_ptr_from_cairo_graphics(cairo_graphics);
-
- nux::TexCoordXForm texxform;
- texxform.SetTexCoordType(nux::TexCoordXForm::OFFSET_COORD);
- texxform.SetWrap(nux::TEXWRAP_REPEAT, nux::TEXWRAP_REPEAT);
-
- nux::ROPConfig rop;
- rop.Blend = true;
- rop.SrcBlend = GL_ONE;
- rop.DstBlend = GL_ONE_MINUS_SRC_ALPHA;
-
- bg_layer_.reset(new nux::TextureLayer(texture2D->GetDeviceTexture(),
- texxform,
- nux::color::White,
- true,
- rop));
-}
-
void SearchBar::OnMouseButtonDown(int x, int y, unsigned long button, unsigned long key)
{
hint_->SetVisible(false);
diff --git a/unity-shared/SearchBar.h b/unity-shared/SearchBar.h
index c9af1db11..fa2833272 100644
--- a/unity-shared/SearchBar.h
+++ b/unity-shared/SearchBar.h
@@ -82,7 +82,6 @@ private:
void OnMouseButtonDown(int x, int y, unsigned long button_flags, unsigned long key_flags);
void OnEndKeyFocus();
- void UpdateBackground(bool force);
void OnSearchChanged(nux::TextEntry* text_entry);
void OnClearClicked(int x, int y, unsigned long button_flags, unsigned long key_flags);
void OnEntryActivated();
diff --git a/unity-standalone/StandaloneUnity.cpp b/unity-standalone/StandaloneUnity.cpp
index 6a0af61b6..29ec25c9a 100644
--- a/unity-standalone/StandaloneUnity.cpp
+++ b/unity-standalone/StandaloneUnity.cpp
@@ -157,6 +157,8 @@ int main(int argc, char **argv)
GError *error = NULL;
GOptionContext *context;
+ unity::Settings settings;
+
nux::NuxInitialize(0);
nux::logging::configure_logging(::getenv("UNITY_LOG_SEVERITY"));
@@ -177,7 +179,6 @@ int main(int argc, char **argv)
FontSettings font_settings;
// The instances for the pseudo-singletons.
- Settings settings;
settings.is_standalone = true;
if (force_tv) Settings::Instance().form_factor(FormFactor::TV);
diff --git a/uwidgets/LICENCE b/uwidgets/LICENCE
new file mode 100644
index 000000000..32b38d425
--- /dev/null
+++ b/uwidgets/LICENCE
@@ -0,0 +1,636 @@
+# GNU GENERAL PUBLIC LICENSE
+Version 3, 29 June 2007
+
+Copyright (C) 2007 [Free Software Foundation, Inc.](http://fsf.org/)
+
+Everyone is permitted to copy and distribute verbatim copies of this license
+document, but changing it is not allowed.
+
+## Preamble
+
+The GNU General Public License is a free, copyleft license for software and
+other kinds of works.
+
+The licenses for most software and other practical works are designed to take
+away your freedom to share and change the works. By contrast, the GNU General
+Public License is intended to guarantee your freedom to share and change all
+versions of a program--to make sure it remains free software for all its users.
+We, the Free Software Foundation, use the GNU General Public License for most
+of our software; it applies also to any other work released this way by its
+authors. You can apply it to your programs, too.
+
+When we speak of free software, we are referring to freedom, not price. Our
+General Public Licenses are designed to make sure that you have the freedom to
+distribute copies of free software (and charge for them if you wish), that you
+receive source code or can get it if you want it, that you can change the
+software or use pieces of it in new free programs, and that you know you can do
+these things.
+
+To protect your rights, we need to prevent others from denying you these rights
+or asking you to surrender the rights. Therefore, you have certain
+responsibilities if you distribute copies of the software, or if you modify it:
+responsibilities to respect the freedom of others.
+
+For example, if you distribute copies of such a program, whether gratis or for
+a fee, you must pass on to the recipients the same freedoms that you received.
+You must make sure that they, too, receive or can get the source code. And you
+must show them these terms so they know their rights.
+
+Developers that use the GNU GPL protect your rights with two steps:
+
+ 1. assert copyright on the software, and
+ 2. offer you this License giving you legal permission to copy, distribute
+ and/or modify it.
+
+For the developers' and authors' protection, the GPL clearly explains that
+there is no warranty for this free software. For both users' and authors' sake,
+the GPL requires that modified versions be marked as changed, so that their
+problems will not be attributed erroneously to authors of previous versions.
+
+Some devices are designed to deny users access to install or run modified
+versions of the software inside them, although the manufacturer can do so. This
+is fundamentally incompatible with the aim of protecting users' freedom to
+change the software. The systematic pattern of such abuse occurs in the area of
+products for individuals to use, which is precisely where it is most
+unacceptable. Therefore, we have designed this version of the GPL to prohibit
+the practice for those products. If such problems arise substantially in other
+domains, we stand ready to extend this provision to those domains in future
+versions of the GPL, as needed to protect the freedom of users.
+
+Finally, every program is threatened constantly by software patents. States
+should not allow patents to restrict development and use of software on
+general-purpose computers, but in those that do, we wish to avoid the special
+danger that patents applied to a free program could make it effectively
+proprietary. To prevent this, the GPL assures that patents cannot be used to
+render the program non-free.
+
+The precise terms and conditions for copying, distribution and modification
+follow.
+
+## TERMS AND CONDITIONS
+
+### 0. Definitions.
+
+*This License* refers to version 3 of the GNU General Public License.
+
+*Copyright* also means copyright-like laws that apply to other kinds of works,
+such as semiconductor masks.
+
+*The Program* refers to any copyrightable work licensed under this License.
+Each licensee is addressed as *you*. *Licensees* and *recipients* may be
+individuals or organizations.
+
+To *modify* a work means to copy from or adapt all or part of the work in a
+fashion requiring copyright permission, other than the making of an exact copy.
+The resulting work is called a *modified version* of the earlier work or a work
+*based on* the earlier work.
+
+A *covered work* means either the unmodified Program or a work based on the
+Program.
+
+To *propagate* a work means to do anything with it that, without permission,
+would make you directly or secondarily liable for infringement under applicable
+copyright law, except executing it on a computer or modifying a private copy.
+Propagation includes copying, distribution (with or without modification),
+making available to the public, and in some countries other activities as well.
+
+To *convey* a work means any kind of propagation that enables other parties to
+make or receive copies. Mere interaction with a user through a computer
+network, with no transfer of a copy, is not conveying.
+
+An interactive user interface displays *Appropriate Legal Notices* to the
+extent that it includes a convenient and prominently visible feature that
+
+ 1. displays an appropriate copyright notice, and
+ 2. tells the user that there is no warranty for the work (except to the
+ extent that warranties are provided), that licensees may convey the work
+ under this License, and how to view a copy of this License.
+
+If the interface presents a list of user commands or options, such as a menu, a
+prominent item in the list meets this criterion.
+
+### 1. Source Code.
+
+The *source code* for a work means the preferred form of the work for making
+modifications to it. *Object code* means any non-source form of a work.
+
+A *Standard Interface* means an interface that either is an official standard
+defined by a recognized standards body, or, in the case of interfaces specified
+for a particular programming language, one that is widely used among developers
+working in that language.
+
+The *System Libraries* of an executable work include anything, other than the
+work as a whole, that (a) is included in the normal form of packaging a Major
+Component, but which is not part of that Major Component, and (b) serves only
+to enable use of the work with that Major Component, or to implement a Standard
+Interface for which an implementation is available to the public in source code
+form. A *Major Component*, in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system (if any) on
+which the executable work runs, or a compiler used to produce the work, or an
+object code interpreter used to run it.
+
+The *Corresponding Source* for a work in object code form means all the source
+code needed to generate, install, and (for an executable work) run the object
+code and to modify the work, including scripts to control those activities.
+However, it does not include the work's System Libraries, or general-purpose
+tools or generally available free programs which are used unmodified in
+performing those activities but which are not part of the work. For example,
+Corresponding Source includes interface definition files associated with source
+files for the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require, such as
+by intimate data communication or control flow between those subprograms and
+other parts of the work.
+
+The Corresponding Source need not include anything that users can regenerate
+automatically from other parts of the Corresponding Source.
+
+The Corresponding Source for a work in source code form is that same work.
+
+### 2. Basic Permissions.
+
+All rights granted under this License are granted for the term of copyright on
+the Program, and are irrevocable provided the stated conditions are met. This
+License explicitly affirms your unlimited permission to run the unmodified
+Program. The output from running a covered work is covered by this License only
+if the output, given its content, constitutes a covered work. This License
+acknowledges your rights of fair use or other equivalent, as provided by
+copyright law.
+
+You may make, run and propagate covered works that you do not convey, without
+conditions so long as your license otherwise remains in force. You may convey
+covered works to others for the sole purpose of having them make modifications
+exclusively for you, or provide you with facilities for running those works,
+provided that you comply with the terms of this License in conveying all
+material for which you do not control copyright. Those thus making or running
+the covered works for you must do so exclusively on your behalf, under your
+direction and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+Conveying under any other circumstances is permitted solely under the
+conditions stated below. Sublicensing is not allowed; section 10 makes it
+unnecessary.
+
+### 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+No covered work shall be deemed part of an effective technological measure
+under any applicable law fulfilling obligations under article 11 of the WIPO
+copyright treaty adopted on 20 December 1996, or similar laws prohibiting or
+restricting circumvention of such measures.
+
+When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention is
+effected by exercising rights under this License with respect to the covered
+work, and you disclaim any intention to limit operation or modification of the
+work as a means of enforcing, against the work's users, your or third parties'
+legal rights to forbid circumvention of technological measures.
+
+### 4. Conveying Verbatim Copies.
+
+You may convey verbatim copies of the Program's source code as you receive it,
+in any medium, provided that you conspicuously and appropriately publish on
+each copy an appropriate copyright notice; keep intact all notices stating that
+this License and any non-permissive terms added in accord with section 7 apply
+to the code; keep intact all notices of the absence of any warranty; and give
+all recipients a copy of this License along with the Program.
+
+You may charge any price or no price for each copy that you convey, and you may
+offer support or warranty protection for a fee.
+
+### 5. Conveying Modified Source Versions.
+
+You may convey a work based on the Program, or the modifications to produce it
+from the Program, in the form of source code under the terms of section 4,
+provided that you also meet all of these conditions:
+
+ - a) The work must carry prominent notices stating that you modified it, and
+ giving a relevant date.
+ - b) The work must carry prominent notices stating that it is released under
+ this License and any conditions added under section 7. This requirement
+ modifies the requirement in section 4 to *keep intact all notices*.
+ - c) You must license the entire work, as a whole, under this License to
+ anyone who comes into possession of a copy. This License will therefore
+ apply, along with any applicable section 7 additional terms, to the whole
+ of the work, and all its parts, regardless of how they are packaged. This
+ License gives no permission to license the work in any other way, but it
+ does not invalidate such permission if you have separately received it.
+ - d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your work need
+ not make them do so.
+
+A compilation of a covered work with other separate and independent works,
+which are not by their nature extensions of the covered work, and which are not
+combined with it such as to form a larger program, in or on a volume of a
+storage or distribution medium, is called an *aggregate* if the compilation and
+its resulting copyright are not used to limit the access or legal rights of the
+compilation's users beyond what the individual works permit. Inclusion of a
+covered work in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+### 6. Conveying Non-Source Forms.
+
+You may convey a covered work in object code form under the terms of sections 4
+and 5, provided that you also convey the machine-readable Corresponding Source
+under the terms of this License, in one of these ways:
+
+ - a) Convey the object code in, or embodied in, a physical product (including
+ a physical distribution medium), accompanied by the Corresponding Source
+ fixed on a durable physical medium customarily used for software
+ interchange.
+ - b) Convey the object code in, or embodied in, a physical product (including
+ a physical distribution medium), accompanied by a written offer, valid for
+ at least three years and valid for as long as you offer spare parts or
+ customer support for that product model, to give anyone who possesses the
+ object code either
+ 1. a copy of the Corresponding Source for all the software in the product
+ that is covered by this License, on a durable physical medium
+ customarily used for software interchange, for a price no more than your
+ reasonable cost of physically performing this conveying of source, or
+ 2. access to copy the Corresponding Source from a network server at no
+ charge.
+ - c) Convey individual copies of the object code with a copy of the written
+ offer to provide the Corresponding Source. This alternative is allowed only
+ occasionally and noncommercially, and only if you received the object code
+ with such an offer, in accord with subsection 6b.
+ - d) Convey the object code by offering access from a designated place
+ (gratis or for a charge), and offer equivalent access to the Corresponding
+ Source in the same way through the same place at no further charge. You
+ need not require recipients to copy the Corresponding Source along with the
+ object code. If the place to copy the object code is a network server, the
+ Corresponding Source may be on a different server operated by you or a
+ third party) that supports equivalent copying facilities, provided you
+ maintain clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the Corresponding
+ Source, you remain obligated to ensure that it is available for as long as
+ needed to satisfy these requirements.
+ - e) Convey the object code using peer-to-peer transmission, provided you
+ inform other peers where the object code and Corresponding Source of the
+ work are being offered to the general public at no charge under subsection
+ 6d.
+
+A separable portion of the object code, whose source code is excluded from the
+Corresponding Source as a System Library, need not be included in conveying the
+object code work.
+
+A *User Product* is either
+
+ 1. a *consumer product*, which means any tangible personal property which is
+ normally used for personal, family, or household purposes, or
+ 2. anything designed or sold for incorporation into a dwelling.
+
+In determining whether a product is a consumer product, doubtful cases shall be
+resolved in favor of coverage. For a particular product received by a
+particular user, *normally used* refers to a typical or common use of that
+class of product, regardless of the status of the particular user or of the way
+in which the particular user actually uses, or expects or is expected to use,
+the product. A product is a consumer product regardless of whether the product
+has substantial commercial, industrial or non-consumer uses, unless such uses
+represent the only significant mode of use of the product.
+
+*Installation Information* for a User Product means any methods, procedures,
+authorization keys, or other information required to install and execute
+modified versions of a covered work in that User Product from a modified
+version of its Corresponding Source. The information must suffice to ensure
+that the continued functioning of the modified object code is in no case
+prevented or interfered with solely because modification has been made.
+
+If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as part of a
+transaction in which the right of possession and use of the User Product is
+transferred to the recipient in perpetuity or for a fixed term (regardless of
+how the transaction is characterized), the Corresponding Source conveyed under
+this section must be accompanied by the Installation Information. But this
+requirement does not apply if neither you nor any third party retains the
+ability to install modified object code on the User Product (for example, the
+work has been installed in ROM).
+
+The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates for a
+work that has been modified or installed by the recipient, or for the User
+Product in which it has been modified or installed. Access to a network may be
+denied when the modification itself materially and adversely affects the
+operation of the network or violates the rules and protocols for communication
+across the network.
+
+Corresponding Source conveyed, and Installation Information provided, in accord
+with this section must be in a format that is publicly documented (and with an
+implementation available to the public in source code form), and must require
+no special password or key for unpacking, reading or copying.
+
+### 7. Additional Terms.
+
+*Additional permissions* are terms that supplement the terms of this License by
+making exceptions from one or more of its conditions. Additional permissions
+that are applicable to the entire Program shall be treated as though they were
+included in this License, to the extent that they are valid under applicable
+law. If additional permissions apply only to part of the Program, that part may
+be used separately under those permissions, but the entire Program remains
+governed by this License without regard to the additional permissions.
+
+When you convey a copy of a covered work, you may at your option remove any
+additional permissions from that copy, or from any part of it. (Additional
+permissions may be written to require their own removal in certain cases when
+you modify the work.) You may place additional permissions on material, added
+by you to a covered work, for which you have or can give appropriate copyright
+permission.
+
+Notwithstanding any other provision of this License, for material you add to a
+covered work, you may (if authorized by the copyright holders of that material)
+supplement the terms of this License with terms:
+
+ - a) Disclaiming warranty or limiting liability differently from the terms of
+ sections 15 and 16 of this License; or
+ - b) Requiring preservation of specified reasonable legal notices or author
+ attributions in that material or in the Appropriate Legal Notices displayed
+ by works containing it; or
+ - c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in reasonable
+ ways as different from the original version; or
+ - d) Limiting the use for publicity purposes of names of licensors or authors
+ of the material; or
+ - e) Declining to grant rights under trademark law for use of some trade
+ names, trademarks, or service marks; or
+ - f) Requiring indemnification of licensors and authors of that material by
+ anyone who conveys the material (or modified versions of it) with
+ contractual assumptions of liability to the recipient, for any liability
+ that these contractual assumptions directly impose on those licensors and
+ authors.
+
+All other non-permissive additional terms are considered *further restrictions*
+within the meaning of section 10. If the Program as you received it, or any
+part of it, contains a notice stating that it is governed by this License along
+with a term that is a further restriction, you may remove that term. If a
+license document contains a further restriction but permits relicensing or
+conveying under this License, you may add to a covered work material governed
+by the terms of that license document, provided that the further restriction
+does not survive such relicensing or conveying.
+
+If you add terms to a covered work in accord with this section, you must place,
+in the relevant source files, a statement of the additional terms that apply to
+those files, or a notice indicating where to find the applicable terms.
+
+Additional terms, permissive or non-permissive, may be stated in the form of a
+separately written license, or stated as exceptions; the above requirements
+apply either way.
+
+### 8. Termination.
+
+You may not propagate or modify a covered work except as expressly provided
+under this License. Any attempt otherwise to propagate or modify it is void,
+and will automatically terminate your rights under this License (including any
+patent licenses granted under the third paragraph of section 11).
+
+However, if you cease all violation of this License, then your license from a
+particular copyright holder is reinstated
+
+ - a) provisionally, unless and until the copyright holder explicitly and
+ finally terminates your license, and
+ - b) permanently, if the copyright holder fails to notify you of the
+ violation by some reasonable means prior to 60 days after the cessation.
+
+Moreover, your license from a particular copyright holder is reinstated
+permanently if the copyright holder notifies you of the violation by some
+reasonable means, this is the first time you have received notice of violation
+of this License (for any work) from that copyright holder, and you cure the
+violation prior to 30 days after your receipt of the notice.
+
+Termination of your rights under this section does not terminate the licenses
+of parties who have received copies or rights from you under this License. If
+your rights have been terminated and not permanently reinstated, you do not
+qualify to receive new licenses for the same material under section 10.
+
+### 9. Acceptance Not Required for Having Copies.
+
+You are not required to accept this License in order to receive or run a copy
+of the Program. Ancillary propagation of a covered work occurring solely as a
+consequence of using peer-to-peer transmission to receive a copy likewise does
+not require acceptance. However, nothing other than this License grants you
+permission to propagate or modify any covered work. These actions infringe
+copyright if you do not accept this License. Therefore, by modifying or
+propagating a covered work, you indicate your acceptance of this License to do
+so.
+
+### 10. Automatic Licensing of Downstream Recipients.
+
+Each time you convey a covered work, the recipient automatically receives a
+license from the original licensors, to run, modify and propagate that work,
+subject to this License. You are not responsible for enforcing compliance by
+third parties with this License.
+
+An *entity transaction* is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered work
+results from an entity transaction, each party to that transaction who receives
+a copy of the work also receives whatever licenses to the work the party's
+predecessor in interest had or could give under the previous paragraph, plus a
+right to possession of the Corresponding Source of the work from the
+predecessor in interest, if the predecessor has it or can get it with
+reasonable efforts.
+
+You may not impose any further restrictions on the exercise of the rights
+granted or affirmed under this License. For example, you may not impose a
+license fee, royalty, or other charge for exercise of rights granted under this
+License, and you may not initiate litigation (including a cross-claim or
+counterclaim in a lawsuit) alleging that any patent claim is infringed by
+making, using, selling, offering for sale, or importing the Program or any
+portion of it.
+
+### 11. Patents.
+
+A *contributor* is a copyright holder who authorizes use under this License of
+the Program or a work on which the Program is based. The work thus licensed is
+called the contributor's *contributor version*.
+
+A contributor's *essential patent claims* are all patent claims owned or
+controlled by the contributor, whether already acquired or hereafter acquired,
+that would be infringed by some manner, permitted by this License, of making,
+using, or selling its contributor version, but do not include claims that would
+be infringed only as a consequence of further modification of the contributor
+version. For purposes of this definition, *control* includes the right to grant
+patent sublicenses in a manner consistent with the requirements of this
+License.
+
+Each contributor grants you a non-exclusive, worldwide, royalty-free patent
+license under the contributor's essential patent claims, to make, use, sell,
+offer for sale, import and otherwise run, modify and propagate the contents of
+its contributor version.
+
+In the following three paragraphs, a *patent license* is any express agreement
+or commitment, however denominated, not to enforce a patent (such as an express
+permission to practice a patent or covenant not to sue for patent
+infringement). To *grant* such a patent license to a party means to make such
+an agreement or commitment not to enforce a patent against the party.
+
+If you convey a covered work, knowingly relying on a patent license, and the
+Corresponding Source of the work is not available for anyone to copy, free of
+charge and under the terms of this License, through a publicly available
+network server or other readily accessible means, then you must either
+
+ 1. cause the Corresponding Source to be so available, or
+ 2. arrange to deprive yourself of the benefit of the patent license for this
+ particular work, or
+ 3. arrange, in a manner consistent with the requirements of this License, to
+ extend the patent license to downstream recipients.
+
+*Knowingly relying* means you have actual knowledge that, but for the patent
+license, your conveying the covered work in a country, or your recipient's use
+of the covered work in a country, would infringe one or more identifiable
+patents in that country that you have reason to believe are valid.
+
+If, pursuant to or in connection with a single transaction or arrangement, you
+convey, or propagate by procuring conveyance of, a covered work, and grant a
+patent license to some of the parties receiving the covered work authorizing
+them to use, propagate, modify or convey a specific copy of the covered work,
+then the patent license you grant is automatically extended to all recipients
+of the covered work and works based on it.
+
+A patent license is *discriminatory* if it does not include within the scope of
+its coverage, prohibits the exercise of, or is conditioned on the non-exercise
+of one or more of the rights that are specifically granted under this License.
+You may not convey a covered work if you are a party to an arrangement with a
+third party that is in the business of distributing software, under which you
+make payment to the third party based on the extent of your activity of
+conveying the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory patent
+license
+
+ - a) in connection with copies of the covered work conveyed by you (or copies
+ made from those copies), or
+ - b) primarily for and in connection with specific products or compilations
+ that contain the covered work, unless you entered into that arrangement, or
+ that patent license was granted, prior to 28 March 2007.
+
+Nothing in this License shall be construed as excluding or limiting any implied
+license or other defenses to infringement that may otherwise be available to
+you under applicable patent law.
+
+### 12. No Surrender of Others' Freedom.
+
+If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not excuse
+you from the conditions of this License. If you cannot convey a covered work so
+as to satisfy simultaneously your obligations under this License and any other
+pertinent obligations, then as a consequence you may not convey it at all. For
+example, if you agree to terms that obligate you to collect a royalty for
+further conveying from those to whom you convey the Program, the only way you
+could satisfy both those terms and this License would be to refrain entirely
+from conveying the Program.
+
+### 13. Use with the GNU Affero General Public License.
+
+Notwithstanding any other provision of this License, you have permission to
+link or combine any covered work with a work licensed under version 3 of the
+GNU Affero General Public License into a single combined work, and to convey
+the resulting work. The terms of this License will continue to apply to the
+part which is the covered work, but the special requirements of the GNU Affero
+General Public License, section 13, concerning interaction through a network
+will apply to the combination as such.
+
+### 14. Revised Versions of this License.
+
+The Free Software Foundation may publish revised and/or new versions of the GNU
+General Public License from time to time. Such new versions will be similar in
+spirit to the present version, but may differ in detail to address new problems
+or concerns.
+
+Each version is given a distinguishing version number. If the Program specifies
+that a certain numbered version of the GNU General Public License *or any later
+version* applies to it, you have the option of following the terms and
+conditions either of that numbered version or of any later version published by
+the Free Software Foundation. If the Program does not specify a version number
+of the GNU General Public License, you may choose any version ever published by
+the Free Software Foundation.
+
+If the Program specifies that a proxy can decide which future versions of the
+GNU General Public License can be used, that proxy's public statement of
+acceptance of a version permanently authorizes you to choose that version for
+the Program.
+
+Later license versions may give you additional or different permissions.
+However, no additional obligations are imposed on any author or copyright
+holder as a result of your choosing to follow a later version.
+
+### 15. Disclaimer of Warranty.
+
+THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE
+LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER
+PARTIES PROVIDE THE PROGRAM *AS IS* WITHOUT WARRANTY OF ANY KIND, EITHER
+EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE
+QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE
+DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
+CORRECTION.
+
+### 16. Limitation of Liability.
+
+IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY
+COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS
+PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL,
+INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
+THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED
+INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE
+PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY
+HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+### 17. Interpretation of Sections 15 and 16.
+
+If the disclaimer of warranty and limitation of liability provided above cannot
+be given local legal effect according to their terms, reviewing courts shall
+apply local law that most closely approximates an absolute waiver of all civil
+liability in connection with the Program, unless a warranty or assumption of
+liability accompanies a copy of the Program in return for a fee.
+
+## END OF TERMS AND CONDITIONS ###
+
+### How to Apply These Terms to Your New Programs
+
+If you develop a new program, and you want it to be of the greatest possible
+use to the public, the best way to achieve this is to make it free software
+which everyone can redistribute and change under these terms.
+
+To do so, attach the following notices to the program. It is safest to attach
+them to the start of each source file to most effectively state the exclusion
+of warranty; and each file should have at least the *copyright* line and a
+pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program does terminal interaction, make it output a short notice like
+this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w` and `show c` should show the appropriate
+parts of the General Public License. Of course, your program's commands might
+be different; for a GUI interface, you would use an *about box*.
+
+You should also get your employer (if you work as a programmer) or school, if
+any, to sign a *copyright disclaimer* for the program, if necessary. For more
+information on this, and how to apply and follow the GNU GPL, see
+[http://www.gnu.org/licenses/](http://www.gnu.org/licenses/).
+
+The GNU General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may consider
+it more useful to permit linking proprietary applications with the library. If
+this is what you want to do, use the GNU Lesser General Public License instead
+of this License. But first, please read
+[http://www.gnu.org/philosophy/why-not-lgpl.html](http://www.gnu.org/philosophy/why-not-lgpl.html).
diff --git a/uwidgets/MANIFEST.in b/uwidgets/MANIFEST.in
new file mode 100644
index 000000000..a47d446b4
--- /dev/null
+++ b/uwidgets/MANIFEST.in
@@ -0,0 +1,3 @@
+include LICENSE
+include README.md
+include uwidgets/x11/*.h
diff --git a/uwidgets/official-widgets/clock/clock.py b/uwidgets/official-widgets/clock/clock.py
new file mode 100755
index 000000000..121a1065e
--- /dev/null
+++ b/uwidgets/official-widgets/clock/clock.py
@@ -0,0 +1,104 @@
+#!/usr/bin/env python3
+
+"""
+This file is part of "blighty" and "uwidgets" which is released under GPL.
+
+See file LICENCE or go to http://www.gnu.org/licenses/ for full license
+details.
+
+uwidgets is a desktop widget creation and management library for Python 3.
+
+Copyright (c) 2022 Rudra Saraswat <rs2009@ubuntu.com>.
+Copyright (c) 2018 Gabriele N. Tornetta <phoenix1987@gmail.com>.
+All rights reserved.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+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/>.
+"""
+
+from uwidgets import CanvasGravity, brush
+from uwidgets.x11 import Canvas, start_event_loop
+
+import datetime
+import subprocess
+import configparser
+
+from math import pi as PI
+
+
+class Clock(Canvas):
+ def on_button_pressed(self, button, state, x, y):
+ if button == 3: # Right button
+ subprocess.run(['unity-control-center', 'datetime'])
+
+ def draw_circle_background(ctx):
+ ctx.arc(2, 1, 90, 0, 2*PI)
+ ctx.set_source_rgba(0, 0, 0, 0.6)
+ ctx.fill()
+
+ def draw_rect_background(ctx):
+ ctx.rectangle(-180, -180, 360, 360)
+ ctx.set_source_rgba(0, 0, 0, 0.6)
+ ctx.fill()
+
+ ctx.rectangle(-180, -100, 360, 3)
+ ctx.set_source_rgba(1, 1, 1, 1)
+ ctx.fill()
+
+ @brush
+ def hand(ctx, angle, length, thickness):
+ ctx.save()
+ ctx.set_source_rgba(1, 1, 1, 1)
+ ctx.set_line_width(thickness)
+ ctx.rotate(angle)
+ ctx.move_to(0, length * .2)
+ ctx.line_to(0, -length)
+ ctx.stroke()
+ ctx.restore()
+
+ def on_draw(self, ctx):
+ now = datetime.datetime.now()
+
+ ctx.translate(self.width >> 1, self.height >> 1)
+
+ getattr(ctx, f"draw_{config.get('settings', 'clock_style')}_background")()
+
+ ctx.hand(
+ angle = now.second / 30 * PI,
+ length = ((self.height >> 1) * .9) - 20,
+ thickness = 1
+ )
+
+ mins = now.minute + now.second / 60
+ ctx.hand(
+ angle = mins / 30 * PI,
+ length = ((self.height >> 1) * .8) - 20,
+ thickness = 3
+ )
+
+ hours = (now.hour % 12) + mins / 60
+ ctx.hand(
+ angle = hours / 6 * PI,
+ length = ((self.height >> 1) * .5) - 20,
+ thickness = 4.5
+ )
+
+if __name__ == "__main__":
+ config = configparser.ConfigParser()
+ config.read('settings.ini')
+ clock = Clock(int(config.get('settings', 'margin_x')),
+ int(config.get('settings', 'margin_y')),
+ 200,
+ 200,
+ gravity = getattr(CanvasGravity, str(config.get('settings', 'gravity'))))
+ clock.show()
+ start_event_loop()
diff --git a/uwidgets/official-widgets/clock/settings.ini b/uwidgets/official-widgets/clock/settings.ini
new file mode 100644
index 000000000..cae5b6b53
--- /dev/null
+++ b/uwidgets/official-widgets/clock/settings.ini
@@ -0,0 +1,7 @@
+[settings]
+# supported options for gravity: NORTH_WEST, NORTH, NORTH_EAST, WEST, CENTER, EAST, SOUTH_WEST, SOUTH, SOUTH_EAST (default)
+gravity=SOUTH_EAST
+margin_x=360
+margin_y=150
+# supported options for gravity: rect (default), circle
+clock_style=rect \ No newline at end of file
diff --git a/uwidgets/official-widgets/clock/widget.ini b/uwidgets/official-widgets/clock/widget.ini
new file mode 100644
index 000000000..b7d474ec1
--- /dev/null
+++ b/uwidgets/official-widgets/clock/widget.ini
@@ -0,0 +1,5 @@
+[widget]
+name=Clock
+summary=A clock widget for the Unity desktop.
+exec=python3 clock.py
+enabled=true \ No newline at end of file
diff --git a/uwidgets/official-widgets/cpu/cpu.py b/uwidgets/official-widgets/cpu/cpu.py
new file mode 100755
index 000000000..acca57f2b
--- /dev/null
+++ b/uwidgets/official-widgets/cpu/cpu.py
@@ -0,0 +1,169 @@
+#!/usr/bin/env python3
+
+from math import pi as PI
+
+import configparser
+import psutil
+import cairo
+import os
+from uwidgets import CanvasGravity, TextAlign
+from uwidgets.legacy import Graph
+from uwidgets.x11 import Canvas, start_event_loop
+
+
+class AttrDict(dict):
+ def __init__(self, *args, **kwargs):
+ super(AttrDict, self).__init__(*args, **kwargs)
+ self.__dict__ = self
+
+class Fonts:
+ UBUNTU_NORMAL = "Ubuntu", cairo.FontSlant.NORMAL, cairo.FontWeight.NORMAL
+
+
+class Cpu(Canvas):
+ SIZE = (256, 256)
+ CORE_POLYGON = AttrDict({"height": 30, "length": 20})
+
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+
+ with open('/proc/cpuinfo', 'r') as fin:
+ raw_cpuinfo = fin.read().strip()
+
+ self.coreinfo = [
+ {
+ k.strip(): v
+ for k, v in [p.split(":") for p in core.split('\n')]
+ }
+ for core in raw_cpuinfo.split('\n\n')
+ ]
+
+ self.graph = Graph(0, 110, self.width, 40)
+
+ @staticmethod
+ def build(x = 0, y = 0, gravity = CanvasGravity.CENTER):
+ return Cpu(x, y, *Cpu.SIZE, gravity = gravity, interval = 2000)
+
+ def on_button_pressed(self, button, *args):
+ os.system('stacer')
+
+ def draw_polygon(c, n, x, y, size):
+ a = 2 * PI / n
+
+ c.save()
+
+ c.translate(x, y)
+ c.move_to(size, 0)
+ for i in range(n):
+ c.rotate(a)
+ c.line_to(size, 0)
+ c.stroke()
+
+ c.restore()
+
+ def draw_core_polygon(c, x, y):
+ size = Cpu.CORE_POLYGON.height
+ length = Cpu.CORE_POLYGON.length
+
+ c.save()
+
+ c.translate(x, y)
+
+ c.set_source_rgb(.8, .8, .8)
+
+ cpus = psutil.cpu_percent(0.1, percpu = True)
+ n = len(cpus)
+ a = 2 * PI / n
+
+ c.set_line_width(1)
+ c.draw_polygon(n, 0, 0, size)
+
+ c.set_line_width(2)
+ c.set_source_rgb(1, 1, 1)
+ c.move_to(size + length * cpus[-1] / 100, 0)
+ for i in range(n):
+ c.rotate(a)
+ c.line_to(size + length * cpus[i] / 100, 0)
+ c.stroke()
+
+ value = int(sum(cpus) / n)
+ c.canvas.graph.push_value(value)
+
+ c.set_font_size(18)
+ c.write_text(0, 0, '{}%'.format(value), TextAlign.CENTER_MIDDLE)
+
+ c.restore()
+
+ return value
+
+ def draw_processes(c):
+ ps = [
+ p.info
+ for p in psutil.process_iter(attrs=['pid', 'name', 'cpu_percent'])
+ ]
+
+ ps = sorted(ps, key=lambda p: p["cpu_percent"], reverse=True)[:5]
+
+ y = 170
+ c.save()
+ c.select_font_face(*Fonts.UBUNTU_NORMAL)
+ c.set_font_size(12)
+ for p in ps:
+ c.write_text(48, y, str(p["pid"]), align = TextAlign.TOP_RIGHT)
+ c.write_text(52, y, p["name"][:24])
+ c.write_text(
+ c.canvas.width - 15, y, "{}%".format(p["cpu_percent"]),
+ align=TextAlign.TOP_RIGHT
+ )
+ y += 18
+
+ c.restore()
+
+ def draw_cpu_name(c):
+ c.save()
+ c.set_font_size(12)
+ c.write_text(
+ 15, 110,
+ c.canvas.coreinfo[0]["model name"].strip()
+ .replace("(TM)", "™")
+ .replace("(R)", "©")
+ )
+ c.restore()
+
+ def draw_background(c):
+ size = c.canvas.get_size()
+ c.rectangle(0, 0, *size)
+ c.set_source_rgba(0, 0, 0, 0.6)
+ c.fill()
+
+ c.rectangle(0, 0, c.canvas.width, 3)
+ c.set_source_rgba(1, 1, 1, 1)
+ c.fill()
+
+ def on_draw(self, c):
+ c.draw_background()
+
+ c.select_font_face(*Fonts.UBUNTU_NORMAL)
+ c.set_font_size(36)
+ c.set_source_rgb(1, 1, 1)
+
+ w, h = Cpu.SIZE
+
+ y_poly = (Cpu.CORE_POLYGON.height + Cpu.CORE_POLYGON.length)
+
+ c.write_text(15, y_poly, "CPU", align = TextAlign.TOP_LEFT)
+ c.draw_core_polygon(w - y_poly, y_poly)
+ c.draw_processes()
+ c.draw_cpu_name()
+
+ c.set_source_rgb(1, 1, 1)
+ self.graph.draw(c)
+
+
+if __name__ == "__main__":
+ config = configparser.ConfigParser()
+ config.read('settings.ini')
+ Cpu.build(int(config.get('settings', 'margin_x')),
+ int(config.get('settings', 'margin_y')),
+ gravity = getattr(CanvasGravity, config.get('settings', 'gravity'))).show()
+ start_event_loop()
diff --git a/uwidgets/official-widgets/cpu/settings.ini b/uwidgets/official-widgets/cpu/settings.ini
new file mode 100644
index 000000000..f3f809114
--- /dev/null
+++ b/uwidgets/official-widgets/cpu/settings.ini
@@ -0,0 +1,5 @@
+[settings]
+# supported options for gravity: NORTH_WEST, NORTH, NORTH_EAST, WEST, CENTER, EAST, SOUTH_WEST, SOUTH, SOUTH_EAST (default)
+gravity=SOUTH_EAST
+margin_x=20
+margin_y=150 \ No newline at end of file
diff --git a/uwidgets/official-widgets/cpu/widget.ini b/uwidgets/official-widgets/cpu/widget.ini
new file mode 100644
index 000000000..49532fdc1
--- /dev/null
+++ b/uwidgets/official-widgets/cpu/widget.ini
@@ -0,0 +1,5 @@
+[widget]
+name=CPU
+summary=A system monitor widget for the Unity desktop (that links to Stacer).
+exec=python3 cpu.py
+enabled=true \ No newline at end of file
diff --git a/uwidgets/official-widgets/spotify/settings.ini b/uwidgets/official-widgets/spotify/settings.ini
new file mode 100644
index 000000000..4784595b6
--- /dev/null
+++ b/uwidgets/official-widgets/spotify/settings.ini
@@ -0,0 +1,5 @@
+[settings]
+# supported options for gravity: NORTH_WEST, NORTH, NORTH_EAST, WEST, CENTER, EAST, SOUTH_WEST, SOUTH, SOUTH_EAST (default)
+gravity=SOUTH_EAST
+margin_x=20
+margin_y=20 \ No newline at end of file
diff --git a/uwidgets/official-widgets/spotify/spotify.py b/uwidgets/official-widgets/spotify/spotify.py
new file mode 100755
index 000000000..a8e4c8625
--- /dev/null
+++ b/uwidgets/official-widgets/spotify/spotify.py
@@ -0,0 +1,176 @@
+#!/usr/bin/env python3
+
+"""
+This file is part of "blighty" and "uwidgets" which is released under GPL.
+
+See file LICENCE or go to http://www.gnu.org/licenses/ for full license
+details.
+
+uwidgets is a desktop widget creation and management library for Python 3.
+
+Copyright (c) 2022 Rudra Saraswat <rs2009@ubuntu.com>.
+Copyright (c) 2018 Gabriele N. Tornetta <phoenix1987@gmail.com>.
+All rights reserved.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+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/>.
+"""
+
+from uwidgets import CanvasGravity
+from uwidgets.x11 import Canvas, start_event_loop
+from uwidgets import CanvasType
+
+import cairo
+import shutil
+import requests
+import subprocess
+import configparser
+
+from gi.repository import GLib
+
+from PIL import Image
+from pydbus import SessionBus
+
+
+class Fonts:
+ UBUNTU_NORMAL = "Ubuntu", cairo.FontSlant.NORMAL, cairo.FontWeight.NORMAL
+
+
+class SpotifyDBus:
+ def __init__(self):
+ self.proxy = SessionBus().get(
+ 'org.mpris.MediaPlayer2.spotify',
+ '/org/mpris/MediaPlayer2'
+ )
+
+ def get_metadata(self):
+ return {k.split(':')[1]: v for k, v in self.proxy.Metadata.items()}
+
+ def toggle_play(self):
+ self.proxy.PlayPause()
+
+ def is_paused(self):
+ return self.proxy.PlaybackStatus == "Paused"
+
+
+class Spotify(Canvas):
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+
+ self.init_dbus()
+
+ def init_dbus(self):
+ try:
+ self.spotify = SpotifyDBus()
+ except GLib.Error:
+ self.spotify = None
+
+ self.last_art_url = ""
+
+ def on_button_pressed(self, button, state, x, y):
+ if button == 1: # Left button
+ self.spotify.toggle_play()
+ elif button == 3: # Right button
+ subprocess.run(['spotify'])
+
+ def draw_background(ctx):
+ size = ctx.canvas.get_size()
+ ctx.rectangle(0, 0, *size)
+ ctx.set_source_rgba(0, 0, 0, 0.6)
+ ctx.fill()
+
+ def draw_decoration(ctx):
+ ctx.rectangle(0, 0, ctx.canvas.width, 3)
+ ctx.set_source_rgba(1, 1, 1, 1)
+ ctx.fill()
+
+ def draw_art(ctx, url, pause):
+ temp_file = "/tmp/spotify_art"
+ temp_img = temp_file + ".png"
+
+ if ctx.canvas.last_art_url != url:
+ response = requests.get(url, stream=True)
+ with open(temp_file, 'wb') as out_file:
+ shutil.copyfileobj(response.raw, out_file)
+ del response
+ ctx.canvas.last_art_url = url
+
+ # Ensure it is a PNG image
+ size = min(ctx.canvas.width, ctx.canvas.height)
+ image = Image.open(temp_file)
+ image.thumbnail((size, size), Image.ANTIALIAS)
+ image.save(temp_img)
+
+ surface = cairo.ImageSurface.create_from_png(temp_img)
+ ctx.set_source_surface(surface, 0, 0)
+ ctx.paint()
+
+ if pause:
+ ctx.set_source_rgba(0, 0, 0, 0.75)
+ ctx.rectangle(0, 0, size, size)
+ ctx.fill()
+ ctx.set_source_rgba(.8, 0.8, 0.8, 0.5)
+ size2 = size >> 1
+ size4 = size2 >> 1
+ size5 = size // 5
+ ctx.rectangle(size4, size4, size5, size2)
+ ctx.rectangle(size - size4 - size5, size4, size5, size2)
+ ctx.fill()
+
+ def draw_metadata(ctx, metadata):
+ ctx.set_source_rgb(0.9, 0.9, 0.9)
+
+ ctx.select_font_face(*Fonts.UBUNTU_NORMAL)
+ ctx.set_font_size(24)
+ ctx.move_to(112, 42)
+ ctx.show_text(metadata["title"])
+
+ ctx.set_source_rgb(0.5, 0.5, 0.5)
+ ctx.set_font_size(15)
+ ctx.move_to(112, 72)
+ ctx.show_text("{artists} ({album})".format(
+ artists = ", ".join(metadata["artist"]),
+ album = metadata["album"]
+ ))
+
+ def on_draw(self, ctx):
+ if self.spotify is None:
+ self.init_dbus()
+ return
+
+ try:
+ metadata = self.spotify.get_metadata()
+ except GLib.Error:
+ self.spotify = None
+ return
+
+ _ctx = ctx
+ ctx.draw_background()
+ ctx.draw_art(metadata["artUrl"], self.spotify.is_paused())
+ ctx.draw_metadata(metadata)
+ ctx.draw_decoration()
+
+
+if __name__ == "__main__":
+ config = configparser.ConfigParser()
+ config.read('settings.ini')
+ spotify = Spotify(
+ x = int(config.get('settings', 'margin_x')),
+ y = int(config.get('settings', 'margin_y')),
+ width = 540,
+ height = 96,
+ gravity = getattr(CanvasGravity, config.get('settings', 'gravity')),
+ interval = 1000
+ )
+
+ spotify.show()
+ start_event_loop()
diff --git a/uwidgets/official-widgets/spotify/widget.ini b/uwidgets/official-widgets/spotify/widget.ini
new file mode 100644
index 000000000..3103638b5
--- /dev/null
+++ b/uwidgets/official-widgets/spotify/widget.ini
@@ -0,0 +1,5 @@
+[widget]
+name=Spotify
+summary=A Spotify (music) widget for the Unity desktop.
+exec=python3 spotify.py
+enabled=true \ No newline at end of file
diff --git a/uwidgets/official-widgets/unsplash-background/settings.ini b/uwidgets/official-widgets/unsplash-background/settings.ini
new file mode 100644
index 000000000..3ba5536b3
--- /dev/null
+++ b/uwidgets/official-widgets/unsplash-background/settings.ini
@@ -0,0 +1,5 @@
+[settings]
+# supported options for gravity: NORTH_WEST, NORTH, NORTH_EAST, WEST, CENTER, EAST, SOUTH_WEST, SOUTH, SOUTH_EAST (default)
+gravity=SOUTH_EAST
+margin_x=20
+margin_y=440 \ No newline at end of file
diff --git a/uwidgets/official-widgets/unsplash-background/unsplash-background.py b/uwidgets/official-widgets/unsplash-background/unsplash-background.py
new file mode 100755
index 000000000..80363cbcc
--- /dev/null
+++ b/uwidgets/official-widgets/unsplash-background/unsplash-background.py
@@ -0,0 +1,96 @@
+#!/usr/bin/env python3
+
+"""
+This file is part of "blighty" and "uwidgets" which is released under GPL.
+
+See file LICENCE or go to http://www.gnu.org/licenses/ for full license
+details.
+
+uwidgets is a desktop widget creation and management library for Python 3.
+
+Copyright (c) 2022 Rudra Saraswat <rs2009@ubuntu.com>.
+Copyright (c) 2018 Gabriele N. Tornetta <phoenix1987@gmail.com>.
+All rights reserved.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+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/>.
+"""
+
+from uwidgets import CanvasGravity
+from uwidgets.x11 import Canvas, start_event_loop
+from uwidgets.settings import UnityWallpaper
+
+import cairo
+import subprocess
+import configparser
+
+from gi.repository import GLib
+
+
+class Fonts:
+ UBUNTU_NORMAL = "Ubuntu", cairo.FontSlant.NORMAL, cairo.FontWeight.NORMAL
+
+
+class UnBackground(Canvas):
+ def on_button_pressed(self, button, state, x, y):
+ if button == 1: # Left button
+ self.change_wallpaper()
+ elif button == 3: # Right button
+ subprocess.run(['unity-control-center', 'appearance'])
+
+ def change_wallpaper(ctx):
+ UnityWallpaper().set_wallpaper_from_url("https://source.unsplash.com/random/3840x2160")
+
+ def draw_background(ctx):
+ size = ctx.canvas.get_size()
+ ctx.rectangle(0, 0, *size)
+ ctx.set_source_rgba(0, 0, 0, 0.6)
+ ctx.fill()
+
+ def draw_decoration(ctx):
+ ctx.rectangle(0, 0, ctx.canvas.width, 3)
+ ctx.set_source_rgba(1, 1, 1, 1)
+ ctx.fill()
+
+ def draw_info(ctx):
+ ctx.set_source_rgb(0.9, 0.9, 0.9)
+
+ ctx.select_font_face(*Fonts.UBUNTU_NORMAL)
+ ctx.set_font_size(24)
+ ctx.move_to(20, 42)
+ ctx.show_text('Unsplash | Random Background')
+
+ ctx.set_source_rgb(0.5, 0.5, 0.5)
+ ctx.set_font_size(15)
+ ctx.move_to(20, 64)
+ ctx.show_text('Click this to set a random Unsplash background (requires internet).')
+
+ def on_draw(self, ctx):
+ ctx.draw_background()
+ ctx.draw_decoration()
+ ctx.draw_info()
+
+
+if __name__ == "__main__":
+ config = configparser.ConfigParser()
+ config.read('settings.ini')
+ unbg = UnBackground(
+ x = int(config.get('settings', 'margin_x')),
+ y = int(config.get('settings', 'margin_y')),
+ width = 540,
+ height = 80,
+ gravity = getattr(CanvasGravity, config.get('settings', 'gravity')),
+ interval = 1000
+ )
+
+ unbg.show()
+ start_event_loop()
diff --git a/uwidgets/official-widgets/unsplash-background/widget.ini b/uwidgets/official-widgets/unsplash-background/widget.ini
new file mode 100644
index 000000000..d997844a0
--- /dev/null
+++ b/uwidgets/official-widgets/unsplash-background/widget.ini
@@ -0,0 +1,5 @@
+[widget]
+name=Unsplash Background
+summary=A widget to set a random Unsplash wallpaper for the Unity desktop.
+exec=python3 unsplash-background.py
+enabled=true \ No newline at end of file
diff --git a/uwidgets/setup.py b/uwidgets/setup.py
new file mode 100755
index 000000000..49bef351e
--- /dev/null
+++ b/uwidgets/setup.py
@@ -0,0 +1,64 @@
+#!/usr/bin/env python3
+
+"""
+This file is part of "uwidgets" which is released under GPL.
+
+See file LICENCE or go to http://www.gnu.org/licenses/ for full license
+details.
+
+uwidgets is a desktop widget creation and management library for Python 3.
+
+Copyright (c) 2022 Rudra Saraswat <rs2009@ubuntu.com>.
+Copyright (c) 2018 Gabriele N. Tornetta <phoenix1987@gmail.com>.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+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/>.
+"""
+
+from setuptools import Extension, find_packages, setup
+
+x11 = Extension('uwidgets._x11',
+ include_dirs = ['/usr/include/cairo/'],
+ libraries = ['cairo', 'X11', 'Xinerama'],
+ extra_compile_args = ['-std=c99'],
+ sources = [
+ 'uwidgets/x11/_x11module.c',
+ 'uwidgets/x11/atelier.c',
+ 'uwidgets/x11/base_canvas.c',
+ ]
+)
+
+
+setup(
+ name = 'uwidgets',
+ version = '1.0.0',
+ description = 'Desktop Widget Manager for Unity, based on Blighty.',
+ author = 'Rudra Saraswat',
+ author_email = 'rs2009@ubuntu.com',
+ url = 'https://unityd.org',
+ classifiers=[
+ 'Development Status :: 5 - Production/Stable',
+
+ 'Intended Audience :: Developers',
+ 'Topic :: Software Development :: Build Tools',
+
+ 'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',
+
+ 'Programming Language :: Python :: 3',
+ 'Programming Language :: Python :: 3.11',
+ ],
+ keywords = 'desklet widget infotainment',
+ packages = find_packages(exclude=['contrib', 'docs']),
+ ext_modules = [x11],
+ install_requires = ['pycairo'],
+ scripts = ['uwidgets-runner'],
+)
diff --git a/uwidgets/uwidgets-runner b/uwidgets/uwidgets-runner
new file mode 100755
index 000000000..3efeac56e
--- /dev/null
+++ b/uwidgets/uwidgets-runner
@@ -0,0 +1,24 @@
+#!/usr/bin/env python3
+
+import os
+import configparser
+
+widgets=[]
+widgets_dir=os.path.expanduser('~/.local/share/unity/widgets')
+
+if os.path.exists(widgets_dir):
+ for widget in [f.path for f in os.scandir(widgets_dir) if f.is_dir() and os.path.exists(os.path.join(f, 'widget.ini'))]:
+ try:
+ os.chdir(widget)
+ config = configparser.ConfigParser()
+ config.read(os.path.join(widget, 'widget.ini'))
+ if config.get('widget', 'enabled') == 'true':
+ os.popen(config.get('widget', 'exec'))
+ widgets.append(os.path.basename(widget))
+ except (KeyError, configparser.NoSectionError, configparser.NoOptionError) as e:
+ print(f'uwidget-runner: error occurred when attempting to run {widget}:\n {e}')
+
+if len(widgets) == 0:
+ print("No widgets found.")
+else:
+ print("Loaded:", ' '.join(widgets))
diff --git a/uwidgets/uwidgets-runner.desktop b/uwidgets/uwidgets-runner.desktop
new file mode 100644
index 000000000..2616869c3
--- /dev/null
+++ b/uwidgets/uwidgets-runner.desktop
@@ -0,0 +1,9 @@
+[Desktop Entry]
+Type=Application
+Name=UWidgets Runner
+Comment=Start UWidgets at login
+Exec=uwidgets-runner
+OnlyShowIn=Unity
+X-GNOME-AutoRestart=true
+X-GNOME-Autostart-Delay=2
+NoDisplay=false \ No newline at end of file
diff --git a/uwidgets/uwidgets/__init__.py b/uwidgets/uwidgets/__init__.py
new file mode 100644
index 000000000..ae9dc085a
--- /dev/null
+++ b/uwidgets/uwidgets/__init__.py
@@ -0,0 +1,77 @@
+# This file is part of "blighty" and "uwidgets" which is released under GPL.
+#
+# See file LICENCE or go to http://www.gnu.org/licenses/ for full license
+# details.
+#
+# uwidgets is a desktop widget creation and management library for Python 3.
+#
+# Copyright (c) 2018 Gabriele N. Tornetta <phoenix1987@gmail.com>.
+# All rights reserved.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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/>.
+
+"""
+This module contains the common objects and types for the different kind of
+canvases provided by ``uwidgets``.
+"""
+
+# XWayland fix
+import os
+os.environ["GDK_BACKEND"] = "x11"
+
+from . _extended_context import ExtendedContext
+
+from . _brush import brush, TextAlign
+
+
+class CanvasType:
+ """The Canvas type.
+
+ The canvas types enumerated in this Python type reflect the same window
+ types that one can request to the window manager via the `Extended
+ Window Manager Hints <https://standards.freedesktop.org/wm-spec/wm-spec-1.3.html>`_.
+
+ - ``NORMAL`` is a normal top-level window.
+ - ``DESKTOP`` is a window drawn directly on the desktop.
+ - ``DOCK`` indicates a dock or panel window that will usually stay on top
+ of other windows.
+ - ``UNDECORATED`` is a type of window that behaves as a toolbar. As such,
+ it is undecorated.
+ """
+
+ NORMAL = 0 # _NET_WM_WINDOW_TYPE_NORMAL
+ DESKTOP = 1 # _NET_WM_WINDOW_TYPE_DESKTOP
+ DOCK = 2 # _NET_WM_WINDOW_TYPE_DOCK
+ UNDECORATED = 3 # _NET_WM_WINDOW_TYPE_TOOLBAR
+
+
+class CanvasGravity:
+ """Window gravity control type.
+
+ The positioning of a canvas on the screen is controlled by its gravity.
+ By default, a window is positioned in a coordinate system where the origin
+ is located in the top-left corner of the screen, with the *x* axis running
+ horizontally from left to right, and the *y* from top to bottom. To change
+ the location of the origin, use one of the following values.
+ """
+
+ NORTH_WEST = 1
+ NORTH = 2
+ NORTH_EAST = 3
+ WEST = 4
+ CENTER = 5
+ EAST = 6
+ SOUTH_WEST = 7
+ SOUTH = 8
+ SOUTH_EAST = 9
+ STATIC = 10
diff --git a/uwidgets/uwidgets/_brush.py b/uwidgets/uwidgets/_brush.py
new file mode 100644
index 000000000..763690aaf
--- /dev/null
+++ b/uwidgets/uwidgets/_brush.py
@@ -0,0 +1,163 @@
+"""
+This file is part of "blighty" "uwidgets" which is released under GPL.
+
+See file LICENCE or go to http://www.gnu.org/licenses/ for full license
+details.
+
+uwidgets is a desktop widget creation and management library for Python 3.
+
+Copyright (c) 2018 Gabriele N. Tornetta <phoenix1987@gmail.com>.
+All rights reserved.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+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/>.
+"""
+
+from functools import wraps
+
+
+def not_callable_from_instance(*args, **kwargs):
+ raise RuntimeError(
+ "Method not callable on instances of type {}".format(
+ type(args[0]).__name__
+ )
+ )
+
+
+class BrushSets:
+ brush_sets = {}
+ inherited = {}
+
+ @staticmethod
+ def add_brush(brush_set, method_name, method):
+ if brush_set not in BrushSets.brush_sets:
+ BrushSets.brush_sets[brush_set] = {}
+
+ BrushSets.brush_sets[brush_set][method_name] = method
+
+ @staticmethod
+ def get_brush_set(brush_set):
+ return BrushSets.brush_sets.get(brush_set, {})
+
+ @staticmethod
+ def inherit(klass):
+ if klass.__qualname__ in BrushSets.inherited:
+ return
+
+ for e in klass.__bases__:
+ try:
+ BrushSets.inherit(e)
+ if klass.__qualname__ not in BrushSets.brush_sets:
+ BrushSets.brush_sets[klass.__qualname__] = {}
+ BrushSets.brush_sets[klass.__qualname__].update(BrushSets.brush_sets[e.__qualname__])
+ except KeyError:
+ # No brushes registered for the superclass so we can skip it
+ pass
+
+ BrushSets.inherited[klass.__qualname__] = True
+
+
+def brush(f):
+ """Brush decorator.
+
+ Used to mark a bound method of a subclass of the `Canvas` class as a
+ _brush_. The method is then rebound to to the extended Cairo context that
+ is passed to the `on_draw` callback. The first argument should then be
+ called `ctx` or `cr` instead of `self`, but this is not enforced so that
+ any keyword can be chosen.
+
+ Example:
+ class BrushExample(uwidgets.x11.Canvas):
+ @brush
+ def brush_method(ctx, data):
+ ctx.save()
+ # Draw something on the Cairo context
+ ctx.restore()
+
+ def on_draw(self, ctx):
+ ctx.brush_method(42)
+
+ In the above example, the `brush_method` has been decorated with the
+ `brush` decorator. Therefore it will be callable as a method of `ctx`
+ rather than `self`. An attempt to call it from `self` will cause a
+ `RuntimeError` since the method is now bound to `ctx`.
+
+ The use of the `brush` decorator is not restricted to X11 canvases.
+ """
+ BrushSets.add_brush(*f.__qualname__.rsplit('.', 1), method = f)
+
+ @wraps(f)
+ def wrapper(*args, **kwargs):
+ return not_callable_from_instance(*args, **kwargs)
+
+ return wrapper
+
+
+## Basic brushes ##############################################################
+
+def draw_grid(ctx, x = 50, y = 50):
+ w, h = ctx.canvas.get_size()
+
+ ctx.save()
+
+ ctx.set_source_rgba(.8, .8, .8, .8)
+ ctx.set_line_width(1)
+ ctx.set_font_size(9)
+ for i in range(x, w, x):
+ ctx.write_text(i, 0, str(i), align = TextAlign.BOTTOM_MIDDLE)
+ ctx.move_to(i, 8)
+ ctx.line_to(i, h)
+ ctx.stroke()
+
+ for i in range(y, h, y):
+ ctx.write_text(0, i, str(i), align = TextAlign.CENTER_LEFT)
+ ctx.move_to(8, i)
+ ctx.line_to(w, i)
+ ctx.stroke()
+
+ ctx.restore()
+
+
+class TextAlign:
+ TOP_RIGHT = 1
+ TOP_MIDDLE = 2
+ TOP_LEFT = 3
+ CENTER_RIGHT = 4
+ CENTER_MIDDLE = 5
+ CENTER_LEFT = 6
+ BOTTOM_RIGHT = 7
+ BOTTOM_MIDDLE = 8
+ BOTTOM_LEFT = 9
+
+
+def write_text(cr, x, y, text, align = TextAlign.TOP_LEFT):
+ ex = cr.text_extents(text)
+
+ if align <= TextAlign.TOP_LEFT:
+ dy = 0
+ elif align <= TextAlign.CENTER_LEFT:
+ dy = ex.height // 2
+ else:
+ dy = ex.height
+
+ if align % 3 == 1:
+ dx = ex.width
+ elif align % 3 == 2:
+ dx = ex.width // 2
+ else:
+ dx = 0
+
+ cr.move_to(x - dx, y + dy)
+ cr.show_text(text)
+ cr.stroke()
+
+ return ex
diff --git a/uwidgets/uwidgets/_extended_context.py b/uwidgets/uwidgets/_extended_context.py
new file mode 100644
index 000000000..c5517b9fd
--- /dev/null
+++ b/uwidgets/uwidgets/_extended_context.py
@@ -0,0 +1,72 @@
+"""
+This file is part of "blighty" and "uwidgets" which is released under GPL.
+
+See file LICENCE or go to http://www.gnu.org/licenses/ for full license
+details.
+
+uwidgets is a desktop widget creation and management library for Python 3.
+
+Copyright (c) 2018 Gabriele N. Tornetta <phoenix1987@gmail.com>.
+All rights reserved.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+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/>.
+"""
+
+from . _brush import BrushSets, not_callable_from_instance
+
+
+class ExtendedContext:
+ """Extension of the standard `cairo.Context` class.
+
+ This class is used to extend the vanilla `cairo.Context` with _brushes_.
+ These are either methods of a subclass of `Canvas` that are prefixed with
+ `draw_`, or those that are explicitly decorated with the `@brush`
+ decorator.
+
+ There shouldn't be any reasons why you'd want to use instantiate this class
+ directly. The `ctx` argument that is passed to the `Canvas` `on_draw`
+ callback is an instance of this class. This can be passed as an argument
+ to any callable object that expects a `cairo.Context` instance. The
+ underlying `Canvas` object can be accessed via the `canvas` attribute. This
+ can be useful if one needs to refer to the parent canvas geometry (e.g.
+ its size).
+ """
+ def __init__(self, ctx, canvas):
+ self._ctx = ctx
+ self.canvas = canvas
+
+ collected_methods = []
+
+ for dm in dir(canvas):
+ try:
+ if callable(getattr(canvas, dm)) and dm[:5] == "draw_":
+ collected_methods.append(dm)
+ except RuntimeError:
+ # In the GTK case, introspection breaks getattr so we ignore
+ # the attributes we cannot retrieve.
+ pass
+
+ # for m in [dm for dm in dir(canvas) if callable(getattr(canvas, dm)) and dm[:5] == "draw_"]:
+ for m in collected_methods:
+ # Re-bind brush method and mark the original as non-callable
+ setattr(self, m, getattr(type(canvas), m).__get__(self, ExtendedContext))
+ setattr(canvas, m, not_callable_from_instance.__get__(canvas, type(canvas)))
+
+ for n, m in BrushSets.get_brush_set(type(canvas).__qualname__).items():
+ if n in dir(ctx):
+ raise RuntimeError("Brush name '{}' clashes with attribute or method in {}".format(n, type(ctx).__qualname__))
+ setattr(self, n, m.__get__(self, ExtendedContext))
+
+ def __getattr__(self, name):
+ """Access the underling context methods."""
+ return getattr(self._ctx, name)
diff --git a/uwidgets/uwidgets/legacy.py b/uwidgets/uwidgets/legacy.py
new file mode 100644
index 000000000..25b4109b6
--- /dev/null
+++ b/uwidgets/uwidgets/legacy.py
@@ -0,0 +1,73 @@
+# This file is part of "blighty" and "uwidgets" which is released under GPL.
+#
+# See file LICENCE or go to http://www.gnu.org/licenses/ for full license
+# details.
+#
+# uwidgets is a desktop widget creation and management library for Python 3.
+#
+# Copyright (c) 2018 Gabriele N. Tornetta <phoenix1987@gmail.com>.
+# All rights reserved.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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/>.
+
+"""Legacy visual tools.
+
+Most of the classes in this module are inspired from Conky.
+"""
+
+from collections import deque
+
+
+class Graph:
+ """A uwidgets take on Conky graphsself.
+
+ The constructor allows you to specify where the graph should be located
+ as well as its size. You push values to it by calling the ``push_value``
+ method. By default, the values are assumed to be in the range from 0 to
+ 100. If this is not the case, you can change the Y scale by specifying a
+ value for the ``scale`` keyword argument.
+ """
+ def __init__(self, x, y, width, height, scale=100):
+ self.x = x
+ self.y = y
+ self.width = width
+ self.height = height
+ self.scale = scale if scale else 0
+ self.auto = not scale
+ self._values = deque(maxlen=width)
+
+ def push_value(self, v):
+ self._values.append(v)
+ if self.auto:
+ self.scale = max(self._values)
+
+ def draw(self, cr):
+ if not self.scale:
+ return
+
+ offset = self.x + self.width - len(self._values)
+ for i in range(len(self._values)):
+ cr.set_line_width(1)
+ if self.height > 0:
+ cr.move_to(offset + i + .5, self.y + self.height)
+ cr.line_to(
+ offset + i + .5,
+ self.y + int(self.height * (1-self._values[i]/self.scale))
+ )
+ else:
+ cr.move_to(offset + i + .5, self.y)
+ cr.line_to(
+ offset + i + .5,
+ self.y + int(-self.height * self._values[i] / self.scale)
+ )
+ cr.stroke()
diff --git a/uwidgets/uwidgets/settings/__init__.py b/uwidgets/uwidgets/settings/__init__.py
new file mode 100644
index 000000000..b8410bcab
--- /dev/null
+++ b/uwidgets/uwidgets/settings/__init__.py
@@ -0,0 +1,4 @@
+from uwidgets.settings import *
+
+from . launcher import UnityLauncher
+from . wallpaper import UnityWallpaper \ No newline at end of file
diff --git a/uwidgets/uwidgets/settings/launcher.py b/uwidgets/uwidgets/settings/launcher.py
new file mode 100644
index 000000000..c5d7151d0
--- /dev/null
+++ b/uwidgets/uwidgets/settings/launcher.py
@@ -0,0 +1,18 @@
+import os
+from gi.repository import Gio, GLib
+
+
+class UnityLauncher:
+ launcher_settings = Gio.Settings.new('com.canonical.Unity.Launcher')
+ launcher_compiz_settings = Gio.Settings.new_with_path('org.compiz.unityshell', '/org/compiz/profiles/unity/plugins/unityshell/')
+
+ def set_launcher_position(self, position: str):
+ if position == 'Bottom' or position == 'bottom':
+ self.launcher_settings['launcher-position'] = 'Bottom'
+ elif position == 'Left' or position == 'left':
+ self.launcher_settings['launcher-position'] = 'Left'
+
+ def set_launcher_autohide(self, hidemode: bool):
+ self.launcher_compiz_settings['launcher-hide-mode'] = hidemode
+
+# XXX: Add more settings
diff --git a/uwidgets/uwidgets/settings/wallpaper.py b/uwidgets/uwidgets/settings/wallpaper.py
new file mode 100644
index 000000000..f5f8c95b9
--- /dev/null
+++ b/uwidgets/uwidgets/settings/wallpaper.py
@@ -0,0 +1,27 @@
+import os
+from gi.repository import Gio, GLib
+
+import requests
+
+
+class UnityWallpaper:
+ cache_dir = GLib.get_user_cache_dir()
+ pictures_dir = GLib.get_user_special_dir(GLib.USER_DIRECTORY_PICTURES)
+ splash_wallpaper_file_path = os.path.join(
+ cache_dir,
+ "org.unityd.wallpapers"
+ )
+ background_settings = Gio.Settings.new("org.gnome.desktop.background")
+
+ def set_wallpaper_from_file_uri(self, file_uri: str):
+ self.background_settings['picture-uri'] = f"file:///{file_uri}"
+
+ def write_image_url_to_wallpaper_file(self, image_url: str):
+ response = requests.get(image_url, stream=True)
+ if response.ok:
+ with open(self.splash_wallpaper_file_path, "wb") as wallpaper_path:
+ wallpaper_path.write(response.raw.read())
+
+ def set_wallpaper_from_url(self, image_url: str):
+ self.write_image_url_to_wallpaper_file(image_url)
+ self.set_wallpaper_from_file_uri(self.splash_wallpaper_file_path)
diff --git a/uwidgets/uwidgets/x11/__init__.py b/uwidgets/uwidgets/x11/__init__.py
new file mode 100644
index 000000000..e2a032d80
--- /dev/null
+++ b/uwidgets/uwidgets/x11/__init__.py
@@ -0,0 +1,31 @@
+# This file is part of "blighty" and "uwidgets" which is released under GPL.
+#
+# See file LICENCE or go to http://www.gnu.org/licenses/ for full license
+# details.
+#
+# uwidgets is a desktop widget creation and management library for Python 3.
+#
+# Copyright (c) 2018 Gabriele N. Tornetta <phoenix1987@gmail.com>.
+# All rights reserved.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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/>.
+
+"""
+This module provides support for creating X11 canvases. If you are trying to
+replicate conky's behaviour, the API offered by this module is the closest to
+it.
+"""
+
+from uwidgets._x11 import *
+
+from . canvas import Canvas
diff --git a/uwidgets/uwidgets/x11/_x11module.c b/uwidgets/uwidgets/x11/_x11module.c
new file mode 100644
index 000000000..31cb4132d
--- /dev/null
+++ b/uwidgets/uwidgets/x11/_x11module.c
@@ -0,0 +1,71 @@
+// This file is part of "blighty" and "uwidgets" which is released under GPL.
+//
+// See file LICENCE or go to http://www.gnu.org/licenses/ for full license
+// details.
+//
+// uwidgets is a desktop widget creation and management library for Python 3.
+//
+// Copyright (c) 2018 Gabriele N. Tornetta <phoenix1987@gmail.com>.
+// All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// 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/>.
+
+#include <Python.h>
+#include "pycairo.h"
+
+#include "atelier.h"
+
+extern PyTypeObject BaseCanvasType;
+
+
+static PyMethodDef x11methods[] = {
+ {
+ "start_event_loop",
+ Atelier_start_event_loop,
+ METH_NOARGS,
+ "Starts the main event loop for all the BaseCanvas objects."
+ },
+ {NULL, NULL, 0, NULL}
+};
+
+static PyModuleDef x11module = {
+ PyModuleDef_HEAD_INIT,
+ "_x11",
+ "C X11 support module for uwidgets.",
+ -1,
+ x11methods, // m_methods
+ NULL, NULL, NULL, NULL
+};
+
+PyMODINIT_FUNC
+PyInit__x11(void)
+{
+ PyObject* m;
+
+ if (PyType_Ready(&BaseCanvasType) < 0)
+ return NULL;
+
+ m = PyModule_Create(&x11module);
+ if (m == NULL)
+ return NULL;
+
+ if (import_cairo() < 0)
+ return NULL;
+
+ Py_INCREF(&BaseCanvasType);
+ PyModule_AddObject(m, "BaseCanvas", (PyObject *)&BaseCanvasType);
+
+ // Initialise Atelier
+ Atelier_init();
+ return m;
+}
diff --git a/uwidgets/uwidgets/x11/atelier.c b/uwidgets/uwidgets/x11/atelier.c
new file mode 100644
index 000000000..0f229e226
--- /dev/null
+++ b/uwidgets/uwidgets/x11/atelier.c
@@ -0,0 +1,265 @@
+// This file is part of "blighty" and "uwidgets" which is released under GPL.
+//
+// See file LICENCE or go to http://www.gnu.org/licenses/ for full license
+// details.
+//
+// uwidgets is a desktop widget creation and management library for Python 3.
+//
+// Copyright (c) 2018 Gabriele N. Tornetta <phoenix1987@gmail.com>.
+// All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// 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/>.
+
+
+#include "atelier.h"
+#include <stdio.h>
+
+#define LOOP_INTERVAL 2000
+
+static PyObject * atelier = NULL;
+
+static Display * display = NULL;
+static XineramaScreenInfo * info = NULL;
+static int n_scr = 0;
+
+
+// ----------------------------------------------------------------------------
+static PyObject *
+get_callback(PyObject * object, char * method) {
+ PyObject * py_method = PyUnicode_FromString(method);
+
+ return PyObject_HasAttr(object, py_method) > 0
+ ? PyObject_GetAttr(object, py_method)
+ : NULL;
+}
+
+
+// ----------------------------------------------------------------------------
+Display *
+Atelier_get_display(void) {
+ if (display == NULL)
+ Atelier_set_display(XOpenDisplay(NULL));
+
+ return display;
+}
+
+
+// ----------------------------------------------------------------------------
+void
+Atelier_set_display(Display * d) {
+ if (d == NULL) {
+ if (display != NULL) {
+ if (info != NULL) {
+ XFree(info);
+ info = NULL;
+ n_scr = 0;
+ }
+
+ XCloseDisplay(display);
+ display = NULL;
+ }
+ return;
+ }
+
+ display = d;
+
+ // Xinerama support
+ int event, error;
+
+ if (!XineramaQueryExtension(d, &event, &error))
+ return;
+
+ if (!XineramaIsActive(d))
+ return;
+
+ info = XineramaQueryScreens(d, &n_scr);
+}
+
+
+// ----------------------------------------------------------------------------
+XineramaScreenInfo *
+Atelier_get_screen_info(int screen) {
+ if (screen < n_scr) {
+ for (register int i = 0; i < n_scr; i++)
+ if (screen == info[i].screen_number)
+ return &(info[i]);
+ }
+
+ return NULL;
+}
+
+
+// ----------------------------------------------------------------------------
+void
+Atelier_init(void) {
+ // Initialise Xlib and CPython for concurrent threads.
+ XInitThreads();
+ PyEval_InitThreads();
+
+ // Initialise atelier to an empty list
+ if (atelier != NULL) {
+ Py_DECREF(atelier);
+ }
+ atelier = PyList_New(0);
+}
+
+
+// ----------------------------------------------------------------------------
+void
+Atelier_add_canvas(BaseCanvas * canvas) {
+ // TODO: Check that the canvas is not registered already.
+ PyList_Append(atelier, (PyObject*) canvas);
+}
+
+
+// ----------------------------------------------------------------------------
+int
+Atelier_remove_canvas(BaseCanvas * canvas) {
+ BaseCanvas * c;
+ for (int i = 0; i < PyList_Size(atelier); i++) {
+ c = (BaseCanvas *) PyList_GetItem(atelier, i);
+ if (c == canvas) {
+ PyList_SetSlice(atelier, i, i + 1, NULL);
+ int n_canvas = PyList_Size(atelier);
+ if (!n_canvas)
+ Atelier_set_display(NULL);
+ return n_canvas;
+ }
+ }
+ return -1;
+}
+
+
+/******************************************************************************
+ ** EVENT LOOP
+ ******************************************************************************/
+
+static int main_loop_running = 0;
+
+
+// ----------------------------------------------------------------------------
+static void
+dispatch_event(BaseCanvas * canvas, XEvent * e) {
+ char keybuf[8];
+ KeySym key;
+ PyObject * cb;
+
+ switch (e->type) {
+ case ClientMessage:
+ // TODO: Extend
+ if ((Atom) e->xclient.data.l[0] == canvas->wm_delete_window) {
+ PyObject_CallMethod((PyObject *) canvas, "destroy", NULL);
+ }
+ return;
+
+ case ButtonPress:
+ cb = get_callback((PyObject *) canvas, "on_button_pressed");
+ if (cb != NULL) {
+ PyObject_CallObject(cb, Py_BuildValue("(iiii)",
+ e->xbutton.button,
+ e->xbutton.state,
+ e->xbutton.x,
+ e->xbutton.y
+ ));
+ }
+ return;
+
+ case KeyPress:
+ cb = get_callback((PyObject *) canvas, "on_key_pressed");
+ if (cb != NULL) {
+ XLookupString(&(e->xkey), keybuf, sizeof(keybuf), &key, NULL);
+ PyObject_CallObject(cb, Py_BuildValue("(ii)",
+ key,
+ e->xkey.state
+ ));
+ }
+ return;
+
+ case Expose:
+ if (e->xexpose.count == 0) {
+ if (canvas->_needs_redraw != 0) {
+ BaseCanvas__on_draw(canvas, canvas->context_arg);
+ canvas->_needs_redraw = 0;
+ }
+
+ // Only clear the window when we are sure we are ready to paint.
+ BaseCanvas__redraw(canvas);
+
+ if (PyErr_Occurred() != NULL) {
+ PyErr_Print();
+ PyObject_CallMethod((PyObject *) canvas, "dispose", NULL);
+ break;
+ }
+ }
+ return;
+
+ default:
+ fprintf(stderr, "Dropping unhandled XEevent.type = %d.\n", e->type);
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+PyObject *
+Atelier_start_event_loop(PyObject * args, PyObject * kwargs) {
+ if (main_loop_running > 0 || atelier == NULL) {
+ Py_INCREF(Py_None); return Py_None;
+ }
+
+ main_loop_running = 1;
+
+ XEvent e;
+ BaseCanvas * canvas;
+ while (main_loop_running != 0 && PyList_Size(atelier) > 0 && display != NULL) {
+ Py_BEGIN_ALLOW_THREADS
+ XNextEvent(display, &e);
+ Py_END_ALLOW_THREADS
+
+ if (e.type >= LASTEvent) continue;
+ // Find the canvas based on window ID
+ int found = 0;
+ for (int i = 0; i < PyList_Size(atelier); i++) {
+ canvas = (BaseCanvas *) PyList_GetItem(atelier, i);
+ if (canvas->win_id == e.xany.window) {
+ found = 1;
+ break;
+ }
+ }
+
+ // TODO: Raise RuntimeError!
+ if (!found) {
+ fprintf(stderr, "Canvas not found!\n");
+ return NULL;
+ }
+
+ dispatch_event(canvas, &e);
+ }
+
+ main_loop_running = 0;
+
+ Py_INCREF(Py_None); return Py_None;
+}
+
+
+// ----------------------------------------------------------------------------
+void
+Atelier_stop_event_loop(void) {
+ main_loop_running = 0;
+}
+
+
+// ----------------------------------------------------------------------------
+int
+Atelier_is_running(void) {
+ return main_loop_running;
+}
diff --git a/uwidgets/uwidgets/x11/atelier.h b/uwidgets/uwidgets/x11/atelier.h
new file mode 100644
index 000000000..61bf704c2
--- /dev/null
+++ b/uwidgets/uwidgets/x11/atelier.h
@@ -0,0 +1,63 @@
+// This file is part of "uwidgets" which is released under GPL.
+//
+// See file LICENCE or go to http://www.gnu.org/licenses/ for full license
+// details.
+//
+// uwidgets is a desktop widget creation and management library for Python 3.
+//
+// Copyright (c) 2018 Gabriele N. Tornetta <phoenix1987@gmail.com>.
+// All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// 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/>.
+
+
+#ifndef ATELIER_H
+#define ATELIER_H
+
+#include "base_canvas.h"
+
+#include <X11/extensions/Xinerama.h> // Must be included AFTER base_canvas!
+
+Display *
+Atelier_get_display(void);
+
+void
+Atelier_set_display(Display *);
+
+XineramaScreenInfo *
+Atelier_get_screen_info(int);
+
+void
+Atelier_init(void);
+
+void
+Atelier_add_canvas(BaseCanvas * canvas);
+
+int
+Atelier_remove_canvas(BaseCanvas * canvas);
+
+
+/******************************************************************************
+ ** EVENT LOOP
+ ******************************************************************************/
+
+PyObject *
+Atelier_start_event_loop(PyObject *, PyObject *);
+
+void
+Atelier_stop_event_loop(void);
+
+int
+Atelier_is_running(void);
+
+#endif
diff --git a/uwidgets/uwidgets/x11/base_canvas.c b/uwidgets/uwidgets/x11/base_canvas.c
new file mode 100644
index 000000000..20b9ae54e
--- /dev/null
+++ b/uwidgets/uwidgets/x11/base_canvas.c
@@ -0,0 +1,445 @@
+// This file is part of "uwidgets" which is released under GPL.
+//
+// See file LICENCE or go to http://www.gnu.org/licenses/ for full license
+// details.
+//
+// uwidgets is a desktop widget creation and management library for Python 3.
+//
+// Copyright (c) 2018 Gabriele N. Tornetta <phoenix1987@gmail.com>.
+// All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// 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/>.
+
+#define BASE_CANVAS_C
+
+
+#include "atelier.h"
+#include "base_canvas.h"
+
+#include <X11/extensions/Xinerama.h>
+
+#define PYCAIRO_NO_IMPORT
+#include "pycairo.h"
+#include "pythread.h"
+
+
+//
+// CONSTANTS
+//
+#define UI_INTERVAL 1000 // 1 ms
+
+static const char * WINDOW_TYPE_MAP[] = {
+ "_NET_WM_WINDOW_TYPE_NORMAL",
+ "_NET_WM_WINDOW_TYPE_DESKTOP",
+ "_NET_WM_WINDOW_TYPE_DOCK",
+ "_NET_WM_WINDOW_TYPE_TOOLBAR"
+};
+
+
+//
+// PRIVATE GLOBAL STATE
+//
+static XVisualInfo visualinfo;
+static XSetWindowAttributes attr;
+
+
+//
+// LOCAL HELPERS
+//
+
+// ----------------------------------------------------------------------------
+static time_t
+gettime(void) {
+ struct timespec ts;
+ clock_gettime(CLOCK_BOOTTIME, &ts);
+ return ts.tv_sec * 1000 + ts.tv_nsec / 1e6;
+}
+
+
+// ----------------------------------------------------------------------------
+static void
+BaseCanvas__change_property(BaseCanvas * self, const char * property_name, const char * property_value, int mode) {
+ Display * display = Atelier_get_display();
+
+ Atom value = XInternAtom(display, property_value, False);
+ XChangeProperty(
+ display,
+ self->win_id,
+ XInternAtom(display, property_name, False),
+ XA_ATOM,
+ 32,
+ mode,
+ (unsigned char *) &value,
+ 1
+ );
+}
+
+
+// ----------------------------------------------------------------------------
+void
+BaseCanvas__redraw(BaseCanvas * self) {
+ cairo_save(self->context);
+ cairo_set_operator(self->context, CAIRO_OPERATOR_SOURCE);
+ cairo_paint(self->context);
+ cairo_restore(self->context);
+ XFlush(Atelier_get_display());
+}
+
+
+// ----------------------------------------------------------------------------
+void
+BaseCanvas__on_draw(BaseCanvas * self, PyObject * args) {
+ PyObject * cb = PyObject_GetAttr((PyObject *) self, PyUnicode_FromString("_on_draw"));
+
+ if (cb == NULL) {
+ PyErr_SetString(
+ PyExc_TypeError,
+ "Subclasses of BaseCanvas must implement the 'on_draw(self, context)' method."
+ );
+ return;
+ }
+ else {
+ if (!PyCallable_Check(cb)) {
+ PyErr_SetString(PyExc_TypeError, "on_draw callback must be callable.");
+ return;
+ }
+
+ // Required for animations in order to avoid flickers.
+ // The X server queues up draw requests. This way we group
+ // them together and we send a single draw request
+ cairo_push_group(self->context);
+
+ // Call user declaration of the 'on_draw' method
+ PyObject * cb_result = PyObject_CallObject(cb, args);
+
+ cairo_pattern_t * group = cairo_pop_group(self->context);
+ if (cb_result == Py_None)
+ cairo_set_source(self->context, group);
+ cairo_pattern_destroy(group);
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+static void
+BaseCanvas__ui_thread(BaseCanvas * self) {
+ PyGILState_STATE gstate;
+ gstate = PyGILState_Ensure();
+
+ self->context_arg = Py_BuildValue("(O)", PycairoContext_FromContext(
+ self->context, &PycairoContext_Type, (PyObject*) NULL
+ ));
+
+ self->_expiry = gettime();
+
+ while (self->_running) {
+ Py_BEGIN_ALLOW_THREADS
+ usleep(self->interval > 100 ? 100 * UI_INTERVAL : UI_INTERVAL);
+ Py_END_ALLOW_THREADS
+
+ if (Atelier_is_running() > 0 && self->_expiry <= gettime()) {
+ self->_needs_redraw = 1;
+
+ // Request redraw
+ XEvent event;
+ event.type = Expose;
+ event.xany.window = self->win_id;
+ event.xexpose.count = 0;
+
+ Display * display = Atelier_get_display();
+ XLockDisplay(display);
+ XSendEvent(display, self->win_id, False, ExposureMask, &event);
+ // Send the event immediately
+ XFlush(display);
+ XUnlockDisplay(display);
+
+ self->_expiry += self->interval ? self->interval : UI_INTERVAL;
+ }
+ }
+
+ Py_DECREF(self->context_arg);
+
+ PyGILState_Release(gstate);
+}
+
+
+// ----------------------------------------------------------------------------
+static void
+BaseCanvas__transform_coordinates(BaseCanvas * self, int * x, int * y) {
+ Display * display = Atelier_get_display();
+ int screen = DefaultScreen(display);
+ XineramaScreenInfo * si = Atelier_get_screen_info(self->xine_screen);
+
+ int width = si ? si->width : XDisplayWidth(display, screen);
+ int height = si ? si->height : XDisplayHeight(display, screen);
+ int x_org = si ? si->x_org : 0;
+ int y_org = si ? si->y_org : 0;
+
+ if ((self->gravity - 1) % 3 == 0) *x = self->x;
+ else if ((self->gravity - 2) % 3 == 0) *x = ((width - self->width) >> 1) + self->x;
+ else *x = width - self->width - self->x;
+ *x += x_org;
+
+ if (self->gravity <= 3) *y = self->y;
+ else if (self->gravity <= 6) *y = ((height - self->height) >> 1) + self->y;
+ else *y = height - self->height - self->y;
+ *y += y_org;
+}
+
+
+//
+// class BaseCanvas:
+//
+
+//
+// def __del__(self):
+//
+static void
+BaseCanvas_dealloc(BaseCanvas* self) {
+ Py_TYPE(self)->tp_free((PyObject*)self);
+}
+
+
+//
+// def __new__(self, *args, **kwargs):
+//
+static PyObject *
+BaseCanvas_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) {
+ BaseCanvas * self;
+
+ self = (BaseCanvas *)type->tp_alloc(type, 0);
+ if (self != NULL) {
+ char * keywords[] = {"x", "y", "width", "height",
+ "interval", // 1000
+ "screen", // 0
+ "window_type", // CanvasType.DOCK
+ "gravity", // CanvasGravity.NORTH_WEST
+ "sticky", // True
+ "keep_below" // True
+ "skip_taskbar", // True
+ "skip_pager", // True
+ NULL
+ };
+
+ // Default keyword arguments
+ self->interval = 1000;
+ self->xine_screen = 0;
+ int window_type = 2; // BaseCanvasType.DOCK
+ self->gravity = 1; // BaseCanvasGravity.NORTH_WEST
+ int sticky = 1;
+ int keep_below = 1;
+ int skip_taskbar = 1;
+ int skip_pager = 1;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "IIII|IIIIpppp:BaseCanvas.__new__",
+ keywords,
+ &self->x, &self->y, &self->width, &self->height,
+ &self->interval,
+ &self->xine_screen,
+ &window_type,
+ &self->gravity,
+ &sticky,
+ &keep_below,
+ &skip_taskbar,
+ &skip_pager
+ )
+ ) return NULL;
+
+ Display * display = Atelier_get_display();
+ if (display == NULL)
+ return NULL;
+
+ int screen = DefaultScreen(display);
+
+ // Query Visual for "TrueColor" and 32 bits depth (RGBA)
+ XMatchVisualInfo(display, screen, 32, TrueColor, &visualinfo);
+ attr.colormap = XCreateColormap(display, DefaultRootWindow(display), visualinfo.visual, AllocNone);
+ attr.border_pixel = 0;
+ attr.background_pixel = 0;
+
+ int x, y;
+ BaseCanvas__transform_coordinates(self, &x, &y);
+
+ self->win_id = XCreateWindow(
+ display,
+ DefaultRootWindow(display),
+ x,
+ y,
+ self->width,
+ self->height,
+ 0,
+ visualinfo.depth,
+ InputOutput,
+ visualinfo.visual,
+ CWColormap | CWBorderPixel | CWBackPixel | CWWinGravity,
+ &attr
+ );
+
+ BaseCanvas__change_property(self, "_NET_WM_WINDOW_TYPE", WINDOW_TYPE_MAP[window_type], PropModeReplace);
+
+ if (keep_below != 0) BaseCanvas__change_property(self, "_NET_WM_STATE", "_NET_WM_STATE_BELOW" , PropModeAppend);
+ if (sticky != 0) BaseCanvas__change_property(self, "_NET_WM_STATE", "_NET_WM_STATE_STICKY" , PropModeAppend);
+ if (skip_taskbar != 0) BaseCanvas__change_property(self, "_NET_WM_STATE", "_NET_WM_STATE_SKIP_TASKBAR" , PropModeAppend);
+ if (skip_pager != 0) BaseCanvas__change_property(self, "_NET_WM_STATE", "_NET_WM_STATE_SKIP_PAGER" , PropModeAppend);
+
+ XCreateGC(display, self->win_id, 0, 0);
+
+ // Handle Delete Event
+ self->wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", False);
+ XSetWMProtocols(display, self->win_id, (Atom *) &(self->wm_delete_window), 1);
+
+ // Create the Cairo Context
+ self->surface = cairo_xlib_surface_create(
+ display,
+ self->win_id,
+ visualinfo.visual,
+ self->width,
+ self->height
+ );
+ cairo_xlib_surface_set_size(self->surface, self->width, self->height);
+ self->context = cairo_create(self->surface);
+
+ self->_running = 0;
+ self->_drawing = 0;
+ self->_needs_redraw = 0;
+
+ // Register the BaseCanvas with the Atelier
+ Atelier_add_canvas(self);
+ }
+
+ return (PyObject *)self;
+}
+
+
+//
+// def __init__(self, *args, **kwargs):
+//
+static int
+BaseCanvas_init(BaseCanvas *self, PyObject *args, PyObject *kwds)
+{
+ return 0;
+}
+
+
+//
+// def move(self, x, y):
+// """Move the canvas to new coordinates relative to the current gravity.
+// """
+//
+static PyObject *
+BaseCanvas_move(BaseCanvas * self, PyObject * args, PyObject * kwargs) {
+ int new_x, new_y;
+ char * keywords[] = {"x", "y", NULL};
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "II:BaseCanvas.move",
+ keywords, &new_x, &new_y)
+ ) return NULL;
+
+ int x, y;
+ self->x = new_x;
+ self->y = new_y;
+ BaseCanvas__transform_coordinates(self, &x, &y);
+
+ XMoveWindow(Atelier_get_display(), self->win_id, x, y);
+
+ Py_INCREF(Py_None); return Py_None;
+}
+
+
+//
+// def show(self):
+// """Show the canvas.
+// """
+//
+static PyObject *
+BaseCanvas_show(BaseCanvas* self) {
+ Display * display = Atelier_get_display();
+
+ // Input events
+ XSelectInput(display, self->win_id,
+ ButtonPressMask
+ | KeyPressMask
+ | ExposureMask
+ );
+ XMapWindow(display, self->win_id);
+
+ self->_running = 1;
+
+ // Use the allocated BaseCanvas object to pass arguments to the UI thread.
+ PyThread_start_new_thread((void (*)(void *)) BaseCanvas__ui_thread, self);
+
+ Py_INCREF(Py_None); return Py_None;
+}
+
+
+//
+// def get_size(self):
+// """Get the size of the BaseCanvas.
+//
+// Return:
+// (tuple) The `(width, height)` tuple.
+// """
+//
+static PyObject *
+BaseCanvas_get_size(BaseCanvas * self) {
+ return Py_BuildValue("(ii)", self->width, self->height);
+}
+
+
+//
+// def dispose(self):
+// """Dispose of the canvas when no longer needed.
+// This method marks the canvas it is called on as ready to be destroyed.
+// The actual destruction is performed by the event loop, which calls the
+// `destroy` method. This is the thread-safe way of destrying an X11
+// BaseCanvas object.
+// """
+//
+static PyObject *
+BaseCanvas_dispose(BaseCanvas * self) {
+ Display * display = Atelier_get_display();
+
+ XUnmapWindow(display, self->win_id);
+
+ XEvent event;
+ event.type = ClientMessage;
+ event.xany.window = self->win_id;
+ event.xclient.format = 32;
+ event.xclient.data.l[0] = self->wm_delete_window;
+
+ XLockDisplay(display);
+ XSendEvent(display, self->win_id, True, 0, &event);
+ // Send the event immediately
+ XFlush(display);
+ XUnlockDisplay(display);
+
+ Py_INCREF(Py_None); return Py_None;
+}
+
+
+//
+// def destroy(self):
+// """Destroy the canvas.
+// WARNING: Not thread-safe. Use `dispose` instead.
+// """
+//
+static PyObject *
+BaseCanvas_destroy(BaseCanvas * self) {
+ self->_running = 0;
+ cairo_destroy(self->context);
+ cairo_surface_destroy(self->surface);
+
+ // De-register BaseCanvas from Atelier;
+ Atelier_remove_canvas(self);
+
+ Py_INCREF(Py_None); return Py_None;
+}
diff --git a/uwidgets/uwidgets/x11/base_canvas.h b/uwidgets/uwidgets/x11/base_canvas.h
new file mode 100644
index 000000000..14398bca1
--- /dev/null
+++ b/uwidgets/uwidgets/x11/base_canvas.h
@@ -0,0 +1,163 @@
+// This file is part of "uwidgets" which is released under GPL.
+//
+// See file LICENCE or go to http://www.gnu.org/licenses/ for full license
+// details.
+//
+// uwidgets is a desktop widget creation and management library for Python 3.
+//
+// Copyright (c) 2018 Gabriele N. Tornetta <phoenix1987@gmail.com>.
+// All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// 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/>.
+
+#ifndef BASE_CANVAS_H
+#define BASE_CANVAS_H
+
+#include <Python.h>
+#include "structmember.h"
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <X11/Xutil.h>
+#include <cairo.h>
+#include <cairo-xlib.h>
+
+
+typedef struct {
+ PyObject_HEAD
+ // Geometry
+ int x;
+ int y;
+ int width;
+ int height;
+
+ // X/Cairo data structures
+ cairo_t * context;
+ PyObject * context_arg;
+ cairo_surface_t * surface;
+ Display * display;
+ int screen;
+ Drawable win_id;
+
+ // Signals
+ Atom wm_delete_window;
+
+ // Attributes
+ unsigned int interval;
+ unsigned int xine_screen;
+ int gravity;
+
+ // Internal attributes
+ int _running;
+ long _expiry;
+ int _drawing;
+ int _needs_redraw;
+} BaseCanvas;
+
+void BaseCanvas__redraw(BaseCanvas * self);
+
+#ifdef BASE_CANVAS_C
+// ---- METHODS ----
+static void BaseCanvas_dealloc (BaseCanvas *);
+static PyObject * BaseCanvas_new (PyTypeObject *, PyObject *, PyObject *);
+static int BaseCanvas_init (BaseCanvas *, PyObject *, PyObject *);
+
+static PyObject * BaseCanvas_move (BaseCanvas *, PyObject *, PyObject *);
+static PyObject * BaseCanvas_show (BaseCanvas *);
+static PyObject * BaseCanvas_get_size (BaseCanvas *);
+static PyObject * BaseCanvas_dispose (BaseCanvas *);
+static PyObject * BaseCanvas_destroy (BaseCanvas *);
+
+
+static PyMethodDef BaseCanvas_methods[] = {
+ {"move" , (PyCFunction) BaseCanvas_move , METH_VARARGS | METH_KEYWORDS,
+ "Move the canvas to new coordinates.\n\n"
+
+ "The *x* and *y* coordinates are relative to the canvas gravity."
+ },
+ {"show" , (PyCFunction) BaseCanvas_show , METH_NOARGS,
+ "Map the canvas to screen and set it ready for drawing."
+ },
+ {"get_size" , (PyCFunction) BaseCanvas_get_size , METH_NOARGS,
+ "Get the canvas size.\n\n"
+
+ "Returns:\n"
+ " tuple: the 2-tuple of width and height in pixels."
+ },
+ {"dispose" , (PyCFunction) BaseCanvas_dispose , METH_NOARGS,
+ "Mark the canvas as ready to be destroyed to free up resources."
+ },
+ {"destroy" , (PyCFunction) BaseCanvas_destroy , METH_NOARGS,
+ "Destroy the canvas.\n\n"
+
+ "This method is not thread-safe. Use the :func:`dispose` method instead."
+ },
+ {NULL} /* Sentinel */
+};
+
+
+// ---- ATTRIBUTES ----
+static PyMemberDef BaseCanvas_members[] = {
+ {"interval" , T_INT , offsetof(BaseCanvas, interval) , 0 , "The refresh interval, in milliseconds."},
+ {"x" , T_INT , offsetof(BaseCanvas, x) , READONLY , "The canvas *x* coordinate. *Read-only*."},
+ {"y" , T_INT , offsetof(BaseCanvas, y) , READONLY , "The canvas *y* coordinate. *Read-only*."},
+ {"width" , T_INT , offsetof(BaseCanvas, width) , READONLY , "The canvas width. *Read-only*."},
+ {"height" , T_INT , offsetof(BaseCanvas, height) , READONLY , "The canvas height. *Read-only*."},
+ {NULL} /* Sentinel */
+};
+
+// ---- OBJECT TYPE DECLARATION ----
+PyTypeObject BaseCanvasType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "x11.BaseCanvas", /* tp_name */
+ sizeof(BaseCanvas), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)BaseCanvas_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT |
+ Py_TPFLAGS_BASETYPE, /* tp_flags */
+ "BaseCanvas objects", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BaseCanvas_methods, /* tp_methods */
+ BaseCanvas_members, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)BaseCanvas_init, /* tp_init */
+ 0, /* tp_alloc */
+ BaseCanvas_new, /* tp_new */
+};
+#endif
+
+#endif
diff --git a/uwidgets/uwidgets/x11/canvas.py b/uwidgets/uwidgets/x11/canvas.py
new file mode 100644
index 000000000..17e2d5e9e
--- /dev/null
+++ b/uwidgets/uwidgets/x11/canvas.py
@@ -0,0 +1,407 @@
+# This file is part of "uwidgets" which is released under GPL.
+#
+# See file LICENCE or go to http://www.gnu.org/licenses/ for full license
+# details.
+#
+# uwidgets is a desktop widget creation and management library for Python 3.
+#
+# Copyright (c) 2018 Gabriele N. Tornetta <phoenix1987@gmail.com>.
+# All rights reserved.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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/>.
+
+"""
+Description
+===========
+
+This module provides the :class:`Canvas` class for the creation of X11
+canvases.
+
+The :class:`Canvas` class is, in Java terminoly, *abstract* and should not be
+instantiated directly. Instead, applications should define their own subclasses
+of the :class:`Canvas` and implement the :func:`on_draw` method, which gets
+called periodically to perform the required draw operations using pycairo.
+
+Once created, an instance of a subclass of :class:`Canvas` can be shown on
+screen by calling the :func:`show` method. This starts drawing the canvas on
+screen by calling the `on_draw` callback at regular intervals in time. Events
+can be handled by starting the event loop with
+:func:`uwidgets.x11.start_event_loop`, as described in more details in the
+`Event handling`_ section.
+
+
+Creating a canvas
+-----------------
+
+Canvases are created by simply subclassing the `Canvas` class and implementing
+the :func:`on_draw` callback.
+
+The :class:`Canvas` constructor (i.e. the :func:`__new__` magic method) takes
+the following arguments:
+
++----------------+------------------------------------------------------------+
+| Argument | Description |
++================+========================+===================================+
+| *x* | These arguments describe the basic geometry of the canvas. |
++----------------+ The *x* and *y* coordinates are relative to the ``gravity``|
+| *y* | argument (see below). The *width* and *height* arguments |
++----------------+ give the canvas size in pixels. |
+| *width* | |
++----------------+ |
+| *height* | |
++----------------+------------------------------------------------------------+
+| *interval* | The time interval between calls to the :func:`on_draw` |
+| | callback, in `milliseconds`. |
+| | |
+| | **Default value**: 1000 (i.e. 1 second) |
++----------------+------------------------------------------------------------+
+| *screen* | In multi-screen setups, specifies on which screen the |
+| | canvas is to be drawn. The value 0 identifies the first |
+| | screen. To treat the physical screens as a single virtual |
+| | screen, use the value -1. |
+| | |
+| | **Default value**: 0 (i.e. the first screen) |
++----------------+------------------------------------------------------------+
+| *window_type* | The type of window to create. The possible choices are |
+| | enumerated in the ``uwidgets.CanvasType`` type and are |
+| | named after the equivalent _NET_WM_WINDOW_TYPE hints for |
+| | the window manager. This is analogous to conky's |
+| | ``own_window_type`` configuration setting. |
+| | |
+| | **Default value**: ``CanvasType.DOCK`` |
++----------------+------------------------------------------------------------+
+| *gravity* | Defines the coordinate system for the canvas relative to |
+| | the screen. The allowed values are enumerated in the |
+| | ``uwidgets.CanvasGravity`` type. This is the equivalent of |
+| | the conky ``alignment`` configuration setting. For example,|
+| | the value ``CanvasGravity.SOUTH_EAST`` indicates that the |
+| | canvas should be positioned relative to the bottom-right |
+| | corner of the screen. |
+| | |
+| | **Default value**: ``CanvasGravity.NORTH_WEST`` |
++----------------+------------------------------------------------------------+
+| *sticky* | Whether the window should *stick* to the desktop and hence |
+| | be visible in all workspaces. |
+| | |
+| | **Default value**: ``True`` |
++----------------+------------------------------------------------------------+
+| *keep_below* | Whether the window should stay below any other window on |
+| | the screen. |
+| | |
+| | **Default value**: ``True`` |
++----------------+------------------------------------------------------------+
+| *skip_taskbar* | Whether the window should not have an entry in the taskbar.|
+| | |
+| | **Default value**: ``True`` |
++----------------+------------------------------------------------------------+
+| *skip_pager* | Whether the window should not appear in the pager. |
+| | |
+| | **Default value**: ``True`` |
++----------------+------------------------------------------------------------+
+
+Note that the interval can be changed dynamically by setting the ``interval``
+attribute on the canvas object directly after it has been created.
+
+If you want to distribute your subclasses of :class:`Canvas`, we recommend that
+you create a static method ``build`` that returns an instance of the subclass,
+with some of the argumets set to a predefined values. This is useful if you
+want to distribute widgets with, e.g., a predefined size, as a Python module.
+
+Showing the canvas
+------------------
+
+When a canvas is created, it is not immediately shown to screen. To map it to
+screen and start the draw cycle one has to call the :func:`show` method
+explicitly.
+
+If you need to pass data to the canvas, you might want to do that before
+calling this method, since presumably the :func:`on_draw` callback, which will
+start to be called, makes use of it.
+
+Finally, you must start the main event loop with
+:func:`uwidgets.x11.start_event_loop` to start drawing on the canvases, and in
+case that they should handle input events, like mouse button clicks or key
+presses. Note however that execution in the current thread will halt at this
+call, until it returns after a call to :func:`uwidgets.x11.stop_event_loop`.
+
+For more details on how to handle events with your X11 canvases, see the
+section `Event handling`_ below.
+
+
+Disposing of a canvas
+---------------------
+
+If you want to programmatically dispose of a canvas, you can call the
+:func:`dispose` method. This doesn't destroy the canvas immediately, but sends
+a delete request to the main event loop instead. This is the preffered way of
+getting rid of a canvas when you are running the event loop. You can also use
+the :func:`destroy` method directly, which destroys the canvas immediately.
+However this is not thread safe and should not be called in the :func:`on_draw`
+callback when running the event loop.
+
+
+Event handling
+--------------
+
+A feature that distinguishes uwidgets from conky is that it allows you to handle
+simple user input on the canvases. Currently, X11 canvases support two events:
+mouse button and key press events.
+
+Mouse button events can be handled by implementing the
+:func:`on_button_pressed` callback in the subclass of :class:`Canvas`. The
+signature is the following::
+
+ def on_button_pressed(self, button, state, x, y):
+
+and the semantics of the arguments is the same as the ``XButtonEvent`` [1]_.
+
+To handle key presses, implement the ``on_key_pressed`` callback with the
+following signature::
+
+ def on_key_pressed(self, keysym, state):
+
+The ``state`` argument has the same semantics as in the
+:func:`on_button_pressed` case, while the ``keysym`` is described, e,g, in the
+`Keyboard Econding
+<https://tronche.com/gui/x/xlib/input/keyboard-encoding.html>`_ section of the
+Xlib guide.
+
+A simple example
+----------------
+
+Here is a simple example that shows all the above concepts in action::
+
+ from uwidgets import CanvasGravity
+ from uwidgets.x11 import Canvas, start_event_loop
+
+ class MyCanvas(Canvas):
+ @staticmethod
+ def build(x, y):
+ return MyCanvas(x, y, 200, 200, gravity = CanvasGravity.NORTH)
+
+ def on_button_pressed(self, button, state, x, y):
+ if button == 1: # Left mouse button pressed
+ self.dispose()
+
+ def on_draw(self, ctx):
+ ctx.set_source_rgb(1, 0, 0)
+ ctx.rectangle(0, 0, ctx.canvas.width >> 1, ctx.canvas.height >> 1)
+ ctx.fill()
+
+ if __name__ == "__main__":
+ # Instantiate the canvas
+ canvas = MyCanvas.build()
+
+ # Map it on screen
+ canvas.show()
+
+ # Start the event loop
+ start_event_loop()
+
+
+Extra features
+==============
+
+The :class:`Canvas` class comes with some handy extra features that can help
+with common patterns, thus sparing you to have to type boilerplate code.
+
+Brushes
+-------
+
+Brushes are a way to rebind methods from your subclass of :class:`Canvas` to
+the Cairo context. Consider the following example::
+
+ from random import random as r
+
+ class RectCanvas(uwidgets.x11.Canvas):
+ def rect(self, ctx, width, height):
+ ctx.set_source_rgb(*[r() for _ in range(3)])
+ ctx.rectangle(0, 0, width, height)
+ ctx.fill()
+
+ def on_draw(self, ctx):
+ for i in range(4):
+ self.rect(ctx, self.width >> i, self.height >> i)
+
+The method ``rect`` is defined under the class ``RectCanvas`` for convenience.
+However, from a logical point of view, it would make more sense for this method
+to belong to ``ctx``, since the general pattern of these helper methods
+requires that we pass ``ctx`` as one of the arguments.
+
+If one prefixes the ``rect`` method with ``draw_`` then it turns into an
+*implicit brush*. The :func:`on_draw` callback is called with the ``ctx``
+argument being an instance of ``ExtendedContext``. The ``draw_rect`` brush is
+then available from ``ctx`` as a bound method. The sample code above can then
+be refactored as::
+
+ from random import random as r
+
+ class RectCanvas(uwidgets.x11.Canvas):
+ def draw_rect(ctx, width, height):
+ ctx.set_source_rgb(*[r() for _ in range(3)])
+ ctx.rectangle(0, 0, width, height)
+ ctx.fill()
+
+ def on_draw(self, ctx):
+ for i in range(4):
+ ctx.rect(self.width >> i, self.height >> i)
+
+Notice how ``draw_rect`` now takes less arguments, and how the first one is
+``ctx``, the (extended) Cairo context.
+
+If you do not wish to prefix your methods with ``draw_``, you can use the
+:func:`uwidgets.brush` decorator instead to create an *explicit brush*. The code
+would then look like this::
+
+ from uwidgets import brush
+ from random import random as r
+
+ class RectCanvas(uwidgets.x11.Canvas):
+ @brush
+ def rect(ctx, width, height):
+ ctx.set_source_rgb(*[r() for _ in range(3)])
+ ctx.rectangle(0, 0, width, height)
+ ctx.fill()
+
+ def on_draw(self, ctx):
+ for i in range(4):
+ ctx.rect(self.width >> i, self.height >> i)
+
+
+Text alignment
+--------------
+
+A common task is writing text on a canvas. With Cairo, text alignment usually
+requires the same pattern: get the text extents and compute the new position.
+To help with that, :class:`Canvas` objects come with a pre-defined
+:func:`write_text` brush. Please refer to the API documentation below for usage
+details.
+
+
+Grid
+----
+
+When designing a canvas from scrach, it is hard to guess at positions without
+any guiding lines. To help with precise placement, every :class:`Canvas` object
+comes with a ``draw_grid`` brush that creates a rectangular grid on the canvas.
+The spacing between the lines is set to 50 pixels by default (assuming that
+the scale hasn't been changed before). This can be adjusted by passing the new
+spacing along the two directions as arguments. Please refer to the API
+documentation below for more details.
+
+
+References
+==========
+
+.. [1] https://tronche.com/gui/x/xlib/events/keyboard-pointer/keyboard-pointer.html
+
+
+Module API
+==========
+"""
+
+from uwidgets import ExtendedContext, TextAlign, brush
+from uwidgets._brush import BrushSets, draw_grid, write_text
+from uwidgets._x11 import BaseCanvas
+
+
+class Canvas(BaseCanvas):
+ """X11 Canvas object.
+
+ This class is meant to be used as a superclass and should not be
+ instantiated directly. Subclasses should implement the :func:`on_draw`
+ callback, which is invoked every time the canvas needs to be redrawn.
+ Redraws happen at regular intervals in time, as specified by the
+ ``interval`` attribute (also passed as an argument via the constructor).
+ """
+
+ def __init__(self, *args, **kwargs):
+ """Initialise the Canvas object.
+
+ If this method is overriden, keep in mind that the initialisation looks
+ up for brushes inherited from all the superclasses. It is therefore
+ important that the method from ``super()`` is called to ensure the
+ correct functioning of the brushes.
+ """
+ BrushSets.inherit(type(self))
+ self._extended_context = None
+
+ def _on_draw(self, ctx):
+ """Draw callback (internal).
+
+ This is the callback that actually gets called from the BaseCanvas
+ class. It ensures that an instance of ``ExtendedContext`` is created
+ before going on to delegate the draw procedures to the user-defined
+ :func:`on_draw` callback.
+
+ If you want to skip some of the iterations and retain the current
+ content of the canvas, you can return ``True``. This is useful to avoid
+ performing the same drawing operations when not required because no
+ data to display has changed.
+ """
+ if self._extended_context is None:
+ self._extended_context = ExtendedContext(ctx, self)
+
+ return self.on_draw(self._extended_context)
+
+ def on_draw(self, ctx):
+ """Draw callback.
+
+ Once the :func:`show` method is called on a :class:`Canvas` object,
+ this method gets called at regular intervals of time to perform the
+ draw operation. Every subclass of :class:`Canvas` must implement this
+ method.
+ """
+ raise NotImplementedError("on_draw method not implemented in subclass.")
+
+ def draw_grid(ctx, x = 50, y = 50):
+ """Draw a grid on the canvas [**implicit brush**].
+
+ This implicit brush method is intended to help with determining the
+ location of points on the canvas during development.
+
+ Args:
+ x (int): The horizontal spacing between lines.
+ y (int): The vertical spacing between lines.
+ """
+ draw_grid(ctx, x, y)
+
+ @brush
+ def write_text(cr, x, y, text, align = TextAlign.TOP_LEFT):
+ """Write aligned text [**explicit brush**].
+
+ This explicit brush method helps write aligned text on the canvas. The
+ *x* and *y* coordinates are relative to the specified *alignment*. By
+ default, this is ``uwidgets.TextAlign.TOP_LEFT``, meaning that the text
+ will be left-aligned and on top of the horizontal line that passes
+ through *y* on the vertical axis. In terms of the point *(x,y)* on the
+ Canvas, the text will develop in the NE direction.
+
+ The return value is the text extents, in case that some further draw
+ operations depend on the space required by the text to be drawn on the
+ canvas.
+
+ Note that font face and size need to be set on the Cairo context prior
+ to a call to this method.
+
+ Args:
+ x (int): The horizontal coordinate.
+ y (int): The vertical coordinate.
+ text (str): The text to write.
+ align (int): The text alignment. Detaulf is ``TextAlign.TOP_LEFT``.
+
+ Returns:
+ tuple: The same return value as ``cairo.text_extents``.
+
+ """
+ return write_text(cr, x, y, text, align)
diff --git a/uwidgets/uwidgets/x11/pycairo.h b/uwidgets/uwidgets/x11/pycairo.h
new file mode 100755
index 000000000..c96526806
--- /dev/null
+++ b/uwidgets/uwidgets/x11/pycairo.h
@@ -0,0 +1,280 @@
+/* -*- mode: C; c-basic-offset: 2 -*-
+ *
+ * Pycairo - Python bindings for cairo
+ *
+ * Copyright © 2003 James Henstridge
+ * Copyright © 2004-2011 Steven Chaplin
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ */
+
+#ifndef _PYCAIRO_H_
+#define _PYCAIRO_H_
+
+#include <Python.h>
+
+#include <cairo.h>
+
+
+typedef struct {
+ PyObject_HEAD
+ cairo_t *ctx;
+ PyObject *base; /* base object used to create context, or NULL */
+} PycairoContext;
+
+typedef struct {
+ PyObject_HEAD
+ cairo_font_face_t *font_face;
+} PycairoFontFace;
+
+#define PycairoToyFontFace PycairoFontFace
+
+typedef struct {
+ PyObject_HEAD
+ cairo_font_options_t *font_options;
+} PycairoFontOptions;
+
+typedef struct {
+ PyObject_HEAD
+ cairo_matrix_t matrix;
+} PycairoMatrix;
+
+typedef struct {
+ PyObject_HEAD
+ cairo_path_t *path;
+} PycairoPath;
+
+typedef struct {
+ PyObject_HEAD
+ cairo_pattern_t *pattern;
+ PyObject *base; /* base object used to create pattern, or NULL */
+} PycairoPattern;
+
+typedef struct {
+ PyObject_HEAD
+ cairo_rectangle_int_t rectangle_int;
+} PycairoRectangleInt;
+
+typedef struct {
+ PyObject_HEAD
+ cairo_region_t *region;
+} PycairoRegion;
+
+#define PycairoSolidPattern PycairoPattern
+#define PycairoSurfacePattern PycairoPattern
+#define PycairoGradient PycairoPattern
+#define PycairoLinearGradient PycairoPattern
+#define PycairoRadialGradient PycairoPattern
+
+typedef struct {
+ PyObject_HEAD
+ cairo_scaled_font_t *scaled_font;
+} PycairoScaledFont;
+
+typedef struct {
+ PyObject_HEAD
+ cairo_surface_t *surface;
+ PyObject *base; /* base object used to create surface, or NULL */
+} PycairoSurface;
+
+#define PycairoImageSurface PycairoSurface
+#define PycairoPDFSurface PycairoSurface
+#define PycairoPSSurface PycairoSurface
+#define PycairoRecordingSurface PycairoSurface
+#define PycairoSVGSurface PycairoSurface
+#define PycairoWin32Surface PycairoSurface
+#define PycairoWin32PrintingSurface PycairoSurface
+#define PycairoXCBSurface PycairoSurface
+#define PycairoXlibSurface PycairoSurface
+
+/* get C object out of the Python wrapper */
+#define PycairoContext_GET(obj) (((PycairoContext *)(obj))->ctx)
+
+/* Define structure for C API. */
+typedef struct {
+ /* (type object, constructor) pairs */
+ PyTypeObject *Context_Type;
+ PyObject *(*Context_FromContext)(cairo_t *ctx, PyTypeObject *type,
+ PyObject *base);
+ PyTypeObject *FontFace_Type;
+ PyTypeObject *ToyFontFace_Type;
+ PyObject *(*FontFace_FromFontFace)(cairo_font_face_t *font_face);
+ PyTypeObject *FontOptions_Type;
+ PyObject *(*FontOptions_FromFontOptions)(
+ cairo_font_options_t *font_options);
+ PyTypeObject *Matrix_Type;
+ PyObject *(*Matrix_FromMatrix)(const cairo_matrix_t *matrix);
+ PyTypeObject *Path_Type;
+ PyObject *(*Path_FromPath)(cairo_path_t *path);
+
+ PyTypeObject *Pattern_Type;
+ PyTypeObject *SolidPattern_Type;
+ PyTypeObject *SurfacePattern_Type;
+ PyTypeObject *Gradient_Type;
+ PyTypeObject *LinearGradient_Type;
+ PyTypeObject *RadialGradient_Type;
+ PyObject *(*Pattern_FromPattern)(cairo_pattern_t *pattern, PyObject *base);
+
+ PyTypeObject *ScaledFont_Type;
+ PyObject *(*ScaledFont_FromScaledFont)(cairo_scaled_font_t *scaled_font);
+
+ PyTypeObject *Surface_Type;
+ PyTypeObject *ImageSurface_Type;
+ PyTypeObject *PDFSurface_Type;
+ PyTypeObject *PSSurface_Type;
+ PyTypeObject *SVGSurface_Type;
+ PyTypeObject *Win32Surface_Type;
+ PyTypeObject *Win32PrintingSurface_Type;
+ PyTypeObject *XCBSurface_Type;
+ PyTypeObject *XlibSurface_Type;
+ PyObject *(*Surface_FromSurface)(cairo_surface_t *surface, PyObject *base);
+
+ /* misc functions */
+ int (*Check_Status)(cairo_status_t status);
+
+ PyTypeObject *RectangleInt_Type;
+ PyObject *(*RectangleInt_FromRectangleInt)(
+ const cairo_rectangle_int_t *rectangle_int);
+
+ PyTypeObject *Region_Type;
+ PyObject *(*Region_FromRegion)(cairo_region_t *region);
+
+ PyTypeObject *RecordingSurface_Type;
+} Pycairo_CAPI_t;
+
+
+#ifndef _INSIDE_PYCAIRO_
+
+/* Macros for accessing the C API */
+#define PycairoContext_Type *(Pycairo_CAPI->Context_Type)
+#define PycairoContext_FromContext (Pycairo_CAPI->Context_FromContext)
+#define PycairoFontFace_Type *(Pycairo_CAPI->FontFace_Type)
+#define PycairoToyFontFace_Type *(Pycairo_CAPI->ToyFontFace_Type)
+#define PycairoFontFace_FromFontFace (Pycairo_CAPI->FontFace_FromFontFace)
+#define PycairoFontOptions_Type *(Pycairo_CAPI->FontOptions_Type)
+#define PycairoFontOptions_FromFontOptions \
+ (Pycairo_CAPI->FontOptions_FromFontOptions)
+#define PycairoMatrix_Type *(Pycairo_CAPI->Matrix_Type)
+#define PycairoMatrix_FromMatrix (Pycairo_CAPI->Matrix_FromMatrix)
+#define PycairoPath_Type *(Pycairo_CAPI->Path_Type)
+#define PycairoPath_FromPath (Pycairo_CAPI->Path_FromPath)
+
+#define PycairoPattern_Type *(Pycairo_CAPI->Pattern_Type)
+#define PycairoSolidPattern_Type *(Pycairo_CAPI->SolidPattern_Type)
+#define PycairoSurfacePattern_Type *(Pycairo_CAPI->SurfacePattern_Type)
+#define PycairoGradient_Type *(Pycairo_CAPI->Gradient_Type)
+#define PycairoLinearGradient_Type *(Pycairo_CAPI->LinearGradient_Type)
+#define PycairoRadialGradient_Type *(Pycairo_CAPI->RadialGradient_Type)
+#define PycairoPattern_FromPattern (Pycairo_CAPI->Pattern_FromPattern)
+
+#define PycairoRectangleInt_Type *(Pycairo_CAPI->RectangleInt_Type)
+#define PycairoRectangleInt_FromRectangleInt \
+ (Pycairo_CAPI->RectangleInt_FromRectangleInt)
+
+#define PycairoRegion_Type *(Pycairo_CAPI->Region_Type)
+#define PycairoRegion_FromRegion (Pycairo_CAPI->Region_FromRegion)
+
+#define PycairoScaledFont_Type *(Pycairo_CAPI->ScaledFont_Type)
+#define PycairoScaledFont_FromScaledFont \
+ (Pycairo_CAPI->ScaledFont_FromScaledFont)
+
+#define PycairoSurface_Type *(Pycairo_CAPI->Surface_Type)
+#define PycairoImageSurface_Type *(Pycairo_CAPI->ImageSurface_Type)
+
+#ifdef CAIRO_HAS_PDF_SURFACE
+#define PycairoPDFSurface_Type *(Pycairo_CAPI->PDFSurface_Type)
+#endif
+
+#ifdef CAIRO_HAS_PS_SURFACE
+#define PycairoPSSurface_Type *(Pycairo_CAPI->PSSurface_Type)
+#endif
+
+#ifdef CAIRO_HAS_RECORDING_SURFACE
+#define PycairoRecordingSurface_Type \
+ *(Pycairo_CAPI->RecordingSurface_Type)
+#endif
+
+#ifdef CAIRO_HAS_SVG_SURFACE
+#define PycairoSVGSurface_Type *(Pycairo_CAPI->SVGSurface_Type)
+#endif
+
+#ifdef CAIRO_HAS_WIN32_SURFACE
+#define PycairoWin32Surface_Type *(Pycairo_CAPI->Win32Surface_Type)
+#define PycairoWin32PrintingSurface_Type \
+ *(Pycairo_CAPI->Win32PrintingSurface_Type)
+#endif
+
+#ifdef CAIRO_HAS_XCB_SURFACE
+#define PycairoXCBSurface_Type *(Pycairo_CAPI->XCBSurface_Type)
+#endif
+
+#ifdef CAIRO_HAS_XLIB_SURFACE
+#define PycairoXlibSurface_Type *(Pycairo_CAPI->XlibSurface_Type)
+#endif
+
+#define PycairoSurface_FromSurface (Pycairo_CAPI->Surface_FromSurface)
+
+#define Pycairo_Check_Status (Pycairo_CAPI->Check_Status)
+
+#if PY_MAJOR_VERSION < 3
+
+/* To access the Pycairo C API, edit the client module file to:
+ * 1) Add the following line to define a global variable for the C API
+ * static Pycairo_CAPI_t *Pycairo_CAPI;
+ * 2) Add 'Pycairo_IMPORT;' to the init<module> function
+ */
+#define Pycairo_IMPORT \
+ Pycairo_CAPI = (Pycairo_CAPI_t*) PyCObject_Import("cairo", "CAPI")
+
+#else
+
+#ifdef PYCAIRO_NO_IMPORT
+
+extern Pycairo_CAPI_t *Pycairo_CAPI;
+
+#else
+
+/* To access the Pycairo C API, the client module should call 'import_cairo()'
+ * from the init<module> function, and check the return value, < 0 means the
+ * import failed.
+ */
+Pycairo_CAPI_t *Pycairo_CAPI;
+
+/* Return -1 on error, 0 on success.
+ * PyCapsule_Import will set an exception if there's an error.
+ */
+static int
+import_cairo(void)
+{
+ Pycairo_CAPI = (Pycairo_CAPI_t*) PyCapsule_Import("cairo.CAPI", 0);
+ return (Pycairo_CAPI != 0) ? 0 : -1;
+}
+
+#endif
+
+#endif
+
+#endif /* ifndef _INSIDE_PYCAIRO_ */
+
+#endif /* ifndef _PYCAIRO_H_ */
diff --git a/uwidgets/widget.ini b/uwidgets/widget.ini
new file mode 100644
index 000000000..8c0d94f78
--- /dev/null
+++ b/uwidgets/widget.ini
@@ -0,0 +1,4 @@
+[widget]
+name=Unsplash Background
+summary=A widget to set a random Unsplash wallpaper for the Unity desktop.
+exec=python3 unsplash-background.py \ No newline at end of file