diff options
68 files changed, 1770 insertions, 581 deletions
diff --git a/com.canonical.Unity.gschema.xml b/com.canonical.Unity.gschema.xml index 62061a117..517ce1ac6 100644 --- a/com.canonical.Unity.gschema.xml +++ b/com.canonical.Unity.gschema.xml @@ -9,6 +9,10 @@ <value nick="Not Expanded" value="0" /> <value nick="Expanded" value="1" /> </enum> + <enum id="launcher-position-enum"> + <value nick="Left" value="0"/> + <value nick="Bottom" value="1"/> + </enum> <enum id="desktop-type-enum"> <value nick="Ubuntu" value="0" /> <value nick="UbuntuKylin" value="1" /> @@ -145,6 +149,11 @@ <summary>Version of last migration done</summary> <description>This is a detection key for the favorite migration script to know whether the needed migration is done or not.</description> </key> + <key enum="launcher-position-enum" name="launcher-position"> + <default>"Left"</default> + <summary>The position of launcher.</summary> + <description>The position of launcher.</description> + </key> </schema> <schema path="/com/canonical/unity/devices/" id="com.canonical.Unity.Devices" gettext-domain="unity"> <key type="as" name="blacklist"> diff --git a/dash/DashController.cpp b/dash/DashController.cpp index 55519d28b..b55cf3ecc 100644 --- a/dash/DashController.cpp +++ b/dash/DashController.cpp @@ -89,7 +89,7 @@ Controller::Controller(Controller::WindowCreator const& create_window) } SetupWindow(); - UScreen::GetDefault()->changed.connect([this] (int, std::vector<nux::Geometry> const&) { Relayout(true); }); + UScreen::GetDefault()->changed.connect(sigc::mem_fun(this, &Controller::OnMonitorChanged)); form_factor_changed_ = Settings::Instance().form_factor.changed.connect([this] (FormFactor) { @@ -177,7 +177,6 @@ void Controller::RegisterUBusInterests() HideDash(); } }); - } void Controller::EnsureDash() @@ -231,30 +230,62 @@ int Controller::GetIdealMonitor() nux::Geometry Controller::GetIdealWindowGeometry() { UScreen *uscreen = UScreen::GetDefault(); - auto monitor_geo = uscreen->GetMonitorGeometry(GetIdealMonitor()); - int launcher_width = unity::Settings::Instance().LauncherWidth(monitor_); + auto ideal_geo = uscreen->GetMonitorGeometry(GetIdealMonitor()); + int launcher_size = unity::Settings::Instance().LauncherSize(monitor_); // We want to cover as much of the screen as possible to grab any mouse events outside // of our window - return nux::Geometry (monitor_geo.x + launcher_width, - monitor_geo.y, - monitor_geo.width - launcher_width, - monitor_geo.height); + if (Settings::Instance().launcher_position() == LauncherPosition::LEFT) + { + ideal_geo.x += launcher_size; + ideal_geo.width -= launcher_size; + } + else + { + ideal_geo.height -= launcher_size; + } + + return ideal_geo; } -void Controller::Relayout(bool check_monitor) +void Controller::OnMonitorChanged(int primary, std::vector<nux::Geometry> const& monitors) { - EnsureDash(); + if (!visible_ || !window_ || !view_) + return; - if (check_monitor) - monitor_ = CLAMP(GetIdealMonitor(), 0, static_cast<int>(UScreen::GetDefault()->GetMonitors().size()-1)); + monitor_ = std::min<int>(GetIdealMonitor(), monitors.size()-1); + view_->SetMonitor(monitor_); + Relayout(); +} - int launcher_width = unity::Settings::Instance().LauncherWidth(monitor_); - nux::Geometry geo = GetIdealWindowGeometry(); +void Controller::Relayout() +{ + EnsureDash(); view_->Relayout(); - window_->SetGeometry(geo); - view_->SetMonitorOffset(launcher_width, panel::Style::Instance().PanelHeight(monitor_)); + window_->SetGeometry(GetIdealWindowGeometry()); + UpdateDashPosition(); +} + +void Controller::UpdateDashPosition() +{ + auto launcher_position = Settings::Instance().launcher_position(); + int left_offset = 0; + int top_offset = panel::Style::Instance().PanelHeight(monitor_); + int launcher_size = unity::Settings::Instance().LauncherSize(monitor_); + + if (launcher_position == LauncherPosition::LEFT) + { + left_offset = launcher_size; + } + else if (launcher_position == LauncherPosition::BOTTOM && + Settings::Instance().form_factor() == FormFactor::DESKTOP) + { + auto const& monitor_geo = UScreen::GetDefault()->GetMonitorGeometry(monitor_); + top_offset = monitor_geo.height - view_->GetContentGeometry().height - launcher_size; + } + + view_->SetMonitorOffset(left_offset, top_offset); } void Controller::OnMouseDownOutsideWindow(int x, int y, @@ -308,14 +339,14 @@ bool Controller::ShowDash() return false; } + screen_ungrabbed_slot_->disconnect(); wm.SaveInputFocus(); EnsureDash(); monitor_ = GetIdealMonitor(); - screen_ungrabbed_slot_->disconnect(); - int launcher_width = unity::Settings::Instance().LauncherWidth(monitor_); - view_->SetMonitorOffset(launcher_width, panel::Style::Instance().PanelHeight(monitor_)); - view_->AboutToShow(monitor_); + view_->SetMonitor(monitor_); + view_->AboutToShow(); + UpdateDashPosition(); FocusWindow(); visible_ = true; @@ -465,13 +496,29 @@ bool Controller::IsCommandLensOpen() const nux::Geometry Controller::GetInputWindowGeometry() { EnsureDash(); + int launcher_size = Settings::Instance().LauncherSize(monitor_); + auto const& monitor_geo = UScreen::GetDefault()->GetMonitorGeometry(monitor_); dash::Style& style = dash::Style::Instance(); nux::Geometry const& window_geo(window_->GetGeometry()); nux::Geometry const& view_content_geo(view_->GetContentGeometry()); nux::Geometry geo(window_geo.x, window_geo.y, view_content_geo.width, view_content_geo.height); - geo.width += style.GetDashRightTileWidth().CP(view_->scale()); - geo.height += style.GetDashBottomTileHeight().CP(view_->scale()); + + if (Settings::Instance().form_factor() == FormFactor::DESKTOP) + { + geo.width += style.GetDashVerticalBorderWidth().CP(view_->scale()); + geo.height += style.GetDashHorizontalBorderHeight().CP(view_->scale()); + + if (Settings::Instance().launcher_position() == LauncherPosition::BOTTOM) + geo.y = monitor_geo.height - view_content_geo.height - launcher_size - style.GetDashHorizontalBorderHeight().CP(view_->scale()); + } + else if (Settings::Instance().form_factor() == FormFactor::NETBOOK) + { + geo.height = monitor_geo.height; + if (Settings::Instance().launcher_position() == LauncherPosition::BOTTOM) + geo.height -= launcher_size; + } + return geo; } diff --git a/dash/DashController.h b/dash/DashController.h index 6228a458e..686871d50 100644 --- a/dash/DashController.h +++ b/dash/DashController.h @@ -82,7 +82,9 @@ private: nux::Geometry GetIdealWindowGeometry(); int GetIdealMonitor(); - void Relayout(bool check_monitor =false); + void OnMonitorChanged(int primary, std::vector<nux::Geometry> const&); + void UpdateDashPosition(); + void Relayout(); void OnMouseDownOutsideWindow(int x, int y, unsigned long bflags, unsigned long kflags); void OnExternalShowDash(GVariant* variant); diff --git a/dash/DashView.cpp b/dash/DashView.cpp index 391ffe625..763779a08 100644 --- a/dash/DashView.cpp +++ b/dash/DashView.cpp @@ -133,16 +133,15 @@ DashView::DashView(Scopes::Ptr const& scopes, ApplicationStarter::Ptr const& app , monitor_(0) { renderer_.SetOwner(this); + renderer_.owner = OverlayOwner::Dash; renderer_.need_redraw.connect([this] () { QueueDraw(); }); SetupViews(); SetupUBusConnections(); - AddChild(overlay_window_buttons_.GetPointer()); - mouse_down.connect(sigc::mem_fun(this, &DashView::OnMouseButtonDown)); preview_state_machine_.PreviewActivated.connect(sigc::mem_fun(this, &DashView::BuildPreview)); if (scopes_) @@ -169,6 +168,15 @@ DashView::~DashView() RemoveLayout(); } +void DashView::SetMonitor(int monitor) +{ + if (monitor_== monitor) + return; + + monitor_ = monitor; + scale = Settings::Instance().em(monitor_)->DPIScale(); +} + void DashView::SetMonitorOffset(int x, int y) { renderer_.x_offset = x; @@ -460,17 +468,11 @@ void DashView::OnPreviewAnimationFinished() content_view_->SetPresentRedirectedView(true); } -void DashView::AboutToShow(int monitor) +void DashView::AboutToShow() { visible_ = true; search_bar_->text_entry()->SelectAll(); - if (monitor_ != monitor) - { - monitor_ = monitor; - scale = Settings::Instance().em(monitor_)->DPIScale(); - } - /* Give the scopes a chance to prep data before we map them */ if (active_scope_view_) { @@ -614,7 +616,7 @@ void DashView::SetupUBusConnections() sigc::mem_fun(this, &DashView::OnActivateRequest)); } -long DashView::PostLayoutManagement (long LayoutResult) +long DashView::PostLayoutManagement(long LayoutResult) { Relayout(); return LayoutResult; @@ -649,7 +651,20 @@ void DashView::Relayout() ubus_manager_.SendMessage(UBUS_DASH_SIZE_CHANGED, g_variant_new("(ii)", content_geo_.width, content_geo_.height)); if (preview_displaying_) - preview_container_->SetGeometry(layout_->GetGeometry()); + { + if (Settings::Instance().launcher_position() == LauncherPosition::BOTTOM) + { + auto preview_geo = content_geo_; + int padding = style.GetDashHorizontalBorderHeight().CP(scale()); + preview_geo.y += padding; + preview_geo.height -= padding; + preview_container_->SetGeometry(preview_geo); + } + else + { + preview_container_->SetGeometry(layout_->GetGeometry()); + } + } renderer_.UpdateBlurBackgroundSize(content_geo_, GetRenderAbsoluteGeometry(), false); @@ -662,7 +677,12 @@ void DashView::Relayout() nux::Geometry DashView::GetBestFitGeometry(nux::Geometry const& for_geo) { dash::Style& style = dash::Style::Instance(); - int panel_height = renderer_.y_offset; + int vertical_offset = renderer_.y_offset; + + if (style.always_maximised) + { + return nux::Geometry(0, vertical_offset, for_geo.width, for_geo.height - vertical_offset); + } int width = 0, height = 0; int tile_width = style.GetTileWidth().CP(scale); @@ -689,14 +709,9 @@ nux::Geometry DashView::GetBestFitGeometry(nux::Geometry const& for_geo) // width/height 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 - panel_height); // panel height is not 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. - if (style.always_maximised) - { - width = std::max(0, for_geo.width); - height = std::max(0, for_geo.height - panel_height); - } - return nux::Geometry(0, panel_height, width, height); + return nux::Geometry(0, vertical_offset, width, height); } void DashView::Draw(nux::GraphicsEngine& graphics_engine, bool force_draw) @@ -728,6 +743,8 @@ void DashView::DrawContent(nux::GraphicsEngine& graphics_engine, bool force_draw // See lp bug: 1125346 (The sharp white line between dash and launcher is missing) nux::Geometry clip_geo = geo_layout; clip_geo.x += 1; + if (Settings::Instance().launcher_position() == LauncherPosition::BOTTOM) + clip_geo.y += renderer_y_offset; graphics_engine.PushClippingRectangle(clip_geo); if (IsFullRedraw()) @@ -1119,18 +1136,6 @@ void DashView::DrawPreview(nux::GraphicsEngine& graphics_engine, bool force_draw } } -void DashView::OnMouseButtonDown(int x, int y, unsigned long button, unsigned long key) -{ - nux::Geometry geo(content_geo_); - - if (Settings::Instance().form_factor() == FormFactor::DESKTOP) - { - dash::Style& style = dash::Style::Instance(); - geo.width += style.GetDashRightTileWidth().CP(scale); - geo.height += style.GetDashBottomTileHeight().CP(scale); - } -} - void DashView::OnActivateRequest(GVariant* args) { glib::String uri; @@ -1508,8 +1513,8 @@ void DashView::AddProperties(debug::IntrospectionData& introspection) introspection.add(nux::Geometry(GetAbsoluteX(), GetAbsoluteY(), content_geo_.width, content_geo_.height)) .add("num_rows", num_rows) .add("form_factor", form_factor) - .add("right-border-width", style.GetDashRightTileWidth().CP(scale)) - .add("bottom-border-height", style.GetDashBottomTileHeight().CP(scale)) + .add("vertical-border-width", style.GetDashVerticalBorderWidth().CP(scale)) + .add("horizontal-border-height", style.GetDashHorizontalBorderHeight().CP(scale)) .add("preview_displaying", preview_displaying_) .add("preview_animation", animate_split_value_ * animate_preview_container_value_ * animate_preview_value_) .add("dash_maximized", style.always_maximised()) diff --git a/dash/DashView.h b/dash/DashView.h index cdcf70767..95f485157 100644 --- a/dash/DashView.h +++ b/dash/DashView.h @@ -64,11 +64,12 @@ public: nux::Property<double> scale; - void AboutToShow(int monitor); + void AboutToShow(); void AboutToHide(); void Relayout(); void DisableBlur(); void OnActivateRequest(GVariant* args); + void SetMonitor(int monitor); void SetMonitorOffset(int x, int y); bool IsCommandLensOpen() const; @@ -108,7 +109,6 @@ private: void BuildPreview(Preview::Ptr model); void ClosePreview(); void OnPreviewAnimationFinished(); - void OnMouseButtonDown(int x, int y, unsigned long button, unsigned long key); void OnBackgroundColorChanged(GVariant* args); void OnSearchChanged(std::string const& search_string); void OnLiveSearchReached(std::string const& search_string); diff --git a/dash/StandaloneDash.cpp b/dash/StandaloneDash.cpp index 81b0a6aa1..4f0a03d76 100644 --- a/dash/StandaloneDash.cpp +++ b/dash/StandaloneDash.cpp @@ -74,7 +74,7 @@ void TestRunner::Init () layout->AddView (view, 1, nux::MINOR_POSITION_CENTER); layout->SetMinMaxSize(WIDTH.CP(scale_), HEIGHT.CP(scale_)); - view->AboutToShow(0); + view->AboutToShow(); nux::GetWindowThread()->SetLayout (layout); nux::GetWindowCompositor().SetKeyFocusArea(view->default_focus()); diff --git a/hud/HudController.cpp b/hud/HudController.cpp index 4f39477bf..b09726be4 100644 --- a/hud/HudController.cpp +++ b/hud/HudController.cpp @@ -174,7 +174,7 @@ int Controller::GetIdealMonitor() bool Controller::IsLockedToLauncher(int monitor) { - if (launcher_locked_out) + if (launcher_locked_out && Settings::Instance().launcher_position() == LauncherPosition::LEFT) { int primary_monitor = UScreen::GetDefault()->GetPrimaryMonitor(); @@ -206,13 +206,13 @@ void Controller::EnsureHud() void Controller::SetIcon(std::string const& icon_name) { LOG_DEBUG(logger) << "setting icon to - " << icon_name; - int launcher_width = unity::Settings::Instance().LauncherWidth(monitor_index_); + int launcher_size = unity::Settings::Instance().LauncherSize(monitor_index_); if (view_) { double scale = view_->scale(); int tsize = tile_size().CP(scale); - view_->SetIcon(icon_name, tsize, icon_size().CP(scale), launcher_width - tsize); + view_->SetIcon(icon_name, tsize, icon_size().CP(scale), launcher_size - tsize); } ubus.SendMessage(UBUS_HUD_ICON_CHANGED, g_variant_new_string(icon_name.c_str())); @@ -253,7 +253,7 @@ nux::Geometry Controller::GetIdealWindowGeometry() if (IsLockedToLauncher(ideal_monitor)) { - int launcher_width = unity::Settings::Instance().LauncherWidth(ideal_monitor); + int launcher_width = unity::Settings::Instance().LauncherSize(ideal_monitor); geo.x += launcher_width; geo.width -= launcher_width; } @@ -269,12 +269,17 @@ void Controller::Relayout(bool check_monitor) monitor_index_ = CLAMP(GetIdealMonitor(), 0, static_cast<int>(UScreen::GetDefault()->GetMonitors().size()-1)); nux::Geometry const& geo = GetIdealWindowGeometry(); - int launcher_width = unity::Settings::Instance().LauncherWidth(monitor_index_); view_->QueueDraw(); window_->SetGeometry(geo); panel::Style &panel_style = panel::Style::Instance(); - view_->SetMonitorOffset(launcher_width, panel_style.PanelHeight(monitor_index_)); + + int horizontal_offset = 0; + + if (Settings::Instance().launcher_position() == LauncherPosition::LEFT) + horizontal_offset = unity::Settings::Instance().LauncherSize(monitor_index_); + + view_->SetMonitorOffset(horizontal_offset, panel_style.PanelHeight(monitor_index_)); } void Controller::OnMouseDownOutsideWindow(int x, int y, diff --git a/hud/HudView.cpp b/hud/HudView.cpp index f021ad4ec..8d0aa7364 100644 --- a/hud/HudView.cpp +++ b/hud/HudView.cpp @@ -73,6 +73,7 @@ View::View() scale = Settings::Instance().em()->DPIScale(); renderer_.scale = scale(); renderer_.SetOwner(this); + renderer_.owner = OverlayOwner::Hud; renderer_.need_redraw.connect([this] () { QueueDraw(); }); diff --git a/launcher/BFBLauncherIcon.cpp b/launcher/BFBLauncherIcon.cpp index 12c8a80bc..dfa621ec1 100644 --- a/launcher/BFBLauncherIcon.cpp +++ b/launcher/BFBLauncherIcon.cpp @@ -30,10 +30,10 @@ namespace unity namespace launcher { -BFBLauncherIcon::BFBLauncherIcon(LauncherHideMode hide_mode) +BFBLauncherIcon::BFBLauncherIcon() : SimpleLauncherIcon(IconType::HOME) , reader_(dash::GSettingsScopesReader::GetDefault()) - , launcher_hide_mode_(hide_mode) + , launcher_hide_mode_(LAUNCHER_HIDE_NEVER) { icon_name = PKGDATADIR"/launcher_bfb.png"; position = Position::BEGIN; @@ -73,7 +73,8 @@ void BFBLauncherIcon::OnOverlayShown(GVariant *data, bool visible) // If the hud is open, we hide the BFB if we have a locked launcher else if (overlay_identity.Str() == "hud") { - if (launcher_hide_mode_ == LAUNCHER_HIDE_NEVER) + if (launcher_hide_mode_ == LAUNCHER_HIDE_NEVER && + Settings::Instance().launcher_position() == LauncherPosition::LEFT) { SetVisibleOnMonitor(overlay_monitor, !visible); SkipQuirkAnimation(Quirk::VISIBLE, overlay_monitor); diff --git a/launcher/BFBLauncherIcon.h b/launcher/BFBLauncherIcon.h index 0c03ddb81..75bf0b64a 100644 --- a/launcher/BFBLauncherIcon.h +++ b/launcher/BFBLauncherIcon.h @@ -37,7 +37,7 @@ class BFBLauncherIcon : public SimpleLauncherIcon { public: - BFBLauncherIcon(LauncherHideMode hide_mode); + BFBLauncherIcon(); virtual nux::Color BackgroundColor() const; virtual nux::Color GlowColor(); diff --git a/launcher/EdgeBarrierController.cpp b/launcher/EdgeBarrierController.cpp index 8d7fb9fc4..a0354f585 100644 --- a/launcher/EdgeBarrierController.cpp +++ b/launcher/EdgeBarrierController.cpp @@ -23,6 +23,7 @@ #include "EdgeBarrierControllerPrivate.h" #include "Decaymulator.h" #include <NuxCore/Logger.h> +#include "unity-shared/UnitySettings.h" #include "unity-shared/UScreen.h" #include "UnityCore/GLibSource.h" @@ -93,6 +94,7 @@ EdgeBarrierController::Impl::Impl(EdgeBarrierController *parent) }));*/ uscreen->changed.connect(sigc::mem_fun(this, &EdgeBarrierController::Impl::OnUScreenChanged)); + Settings::Instance().launcher_position.changed.connect(sigc::hide(sigc::mem_fun(this, &EdgeBarrierController::Impl::OnOptionsChanged))); parent_->force_disable.changed.connect(sigc::mem_fun(this, &EdgeBarrierController::Impl::OnForceDisableChanged)); @@ -218,6 +220,7 @@ void EdgeBarrierController::Impl::SetupBarriers(std::vector<nux::Geometry> const return; bool edge_resist = parent_->sticky_edges(); + auto launcher_position = Settings::Instance().launcher_position(); for (unsigned i = 0; i < layout.size(); i++) { @@ -246,10 +249,22 @@ void EdgeBarrierController::Impl::SetupBarriers(std::vector<nux::Geometry> const if (!edge_resist && parent_->options()->hide_mode() == launcher::LauncherHideMode::LAUNCHER_HIDE_NEVER) continue; - vertical_barrier->x1 = monitor.x; - vertical_barrier->x2 = monitor.x; - vertical_barrier->y1 = monitor.y; - vertical_barrier->y2 = monitor.y + monitor.height; + if (launcher_position == LauncherPosition::LEFT) + { + vertical_barrier->x1 = monitor.x; + vertical_barrier->x2 = monitor.x; + vertical_barrier->y1 = monitor.y; + vertical_barrier->y2 = monitor.y + monitor.height; + } + else + { + vertical_barrier->x1 = monitor.x; + vertical_barrier->x2 = monitor.x + monitor.width; + vertical_barrier->y1 = monitor.y + monitor.height; + vertical_barrier->y2 = monitor.y + monitor.height; + vertical_barrier->direction = DOWN; + } + vertical_barrier->index = i; vertical_barrier->threshold = parent_->options()->edge_stop_velocity(); diff --git a/launcher/HudLauncherIcon.cpp b/launcher/HudLauncherIcon.cpp index b97c326f1..41d833af7 100644 --- a/launcher/HudLauncherIcon.cpp +++ b/launcher/HudLauncherIcon.cpp @@ -22,6 +22,7 @@ #include <NuxCore/Logger.h> #include "unity-shared/UBusMessages.h" +#include "unity-shared/UnitySettings.h" #include "config.h" #include <glib/gi18n-lib.h> @@ -32,9 +33,9 @@ namespace launcher { DECLARE_LOGGER(logger, "unity.launcher.icon.hud"); -HudLauncherIcon::HudLauncherIcon(LauncherHideMode hide_mode) +HudLauncherIcon::HudLauncherIcon() : SingleMonitorLauncherIcon(IconType::HUD) - , launcher_hide_mode_(hide_mode) + , launcher_hide_mode_(LAUNCHER_HIDE_NEVER) , overlay_monitor_(0) , single_launcher_(false) , launcher_monitor_(0) @@ -90,7 +91,7 @@ void HudLauncherIcon::SetSingleLauncher(bool single_launcher, int launcher_monit { if (single_launcher_ == single_launcher && launcher_monitor_ == launcher_monitor) return; - + single_launcher_ = single_launcher; launcher_monitor_ = launcher_monitor; @@ -112,6 +113,7 @@ void HudLauncherIcon::OnOverlayShown(GVariant* data, bool visible) // If the hud is open, we show the HUD button if we have a locked launcher if (overlay_identity.Str() == "hud" && launcher_hide_mode_ == LAUNCHER_HIDE_NEVER && + Settings::Instance().launcher_position() == LauncherPosition::LEFT && (!single_launcher_ || (single_launcher_ && launcher_monitor_ == overlay_monitor_))) { SetMonitor(visible ? overlay_monitor_ : -1); diff --git a/launcher/HudLauncherIcon.h b/launcher/HudLauncherIcon.h index d7c7cade4..9eb7f59a2 100644 --- a/launcher/HudLauncherIcon.h +++ b/launcher/HudLauncherIcon.h @@ -32,9 +32,8 @@ namespace launcher class HudLauncherIcon : public SingleMonitorLauncherIcon { - public: - HudLauncherIcon(LauncherHideMode hide_mode); + HudLauncherIcon(); virtual nux::Color BackgroundColor() const; virtual nux::Color GlowColor(); @@ -53,7 +52,7 @@ private: nux::Color background_color_; LauncherHideMode launcher_hide_mode_; UBusManager ubus_manager_; - gint32 overlay_monitor_; + gint32 overlay_monitor_; bool single_launcher_; int launcher_monitor_; }; diff --git a/launcher/Launcher.cpp b/launcher/Launcher.cpp index 62fa5fb1b..fa4e13834 100644 --- a/launcher/Launcher.cpp +++ b/launcher/Launcher.cpp @@ -66,7 +66,7 @@ const int PULSE_BLINK_LAMBDA = 2; const float BACKLIGHT_STRENGTH = 0.9f; const RawPixel ICON_PADDING = 6_em; -const RawPixel RIGHT_LINE_WIDTH = 1_em; +const RawPixel SIDE_LINE_WIDTH = 1_em; const int ANIM_DURATION_SHORT = 125; const int ANIM_DURATION_SHORT_SHORT = 100; @@ -126,6 +126,7 @@ Launcher::Launcher(MockableBaseWindow* parent, , launcher_drag_delta_(0) , launcher_drag_delta_max_(0) , launcher_drag_delta_min_(0) + , enter_x_(0) , enter_y_(0) , last_button_press_(0) , urgent_animation_period_(0) @@ -135,6 +136,7 @@ Launcher::Launcher(MockableBaseWindow* parent, , last_reveal_progress_(0.0f) , drag_action_(nux::DNDACTION_NONE) , bg_effect_helper_(this) + , launcher_position_(unity::Settings::Instance().launcher_position()) , auto_hide_animation_(ANIM_DURATION_SHORT) , hover_animation_(ANIM_DURATION) , drag_over_animation_(ANIM_DURATION_LONG) @@ -184,11 +186,16 @@ Launcher::Launcher(MockableBaseWindow* parent, TextureCache& cache = TextureCache::GetDefault(); launcher_sheen_ = cache.FindTexture("dash_sheen.png"); - launcher_pressure_effect_ = cache.FindTexture("launcher_pressure_effect.png"); options.changed.connect(sigc::mem_fun(this, &Launcher::OnOptionsChanged)); monitor.changed.connect(sigc::mem_fun(this, &Launcher::OnMonitorChanged)); + launcher_position_changed_ = unity::Settings::Instance().launcher_position.changed.connect([this] (LauncherPosition const& position) { + launcher_position_ = position; + OnMonitorChanged(monitor); + QueueDraw(); + }); + unity::Settings::Instance().dpi_changed.connect(sigc::mem_fun(this, &Launcher::OnDPIChanged)); auto_hide_animation_.updated.connect(redraw_cb); @@ -303,7 +310,12 @@ void Launcher::SetIconUnderMouse(AbstractLauncherIcon::Ptr const& icon) bool Launcher::MouseBeyondDragThreshold() const { if (GetActionState() == ACTION_DRAG_ICON) - return mouse_position_.x > GetGeometry().width + icon_size_.CP(cv_) / 2; + { + if (launcher_position_ == LauncherPosition::LEFT) + return mouse_position_.x > GetGeometry().width + icon_size_.CP(cv_) / 2; + else + return mouse_position_.y < GetGeometry().y - icon_size_.CP(cv_) / 2; + } return false; } @@ -339,27 +351,37 @@ float Launcher::GetAutohidePositionMax() const void Launcher::OnDPIChanged() { monitor.changed.emit(monitor()); + if (launcher_position_ == LauncherPosition::BOTTOM) + options.changed.emit(options()); } void Launcher::SetDndDelta(float x, float y, nux::Geometry const& geo) { - auto const& anchor = MouseIconIntersection(x, enter_y_); - + auto const& anchor = (launcher_position_ == LauncherPosition::LEFT) ? MouseIconIntersection(x, enter_y_) : MouseIconIntersection(enter_x_, y); int c_icon_size = icon_size_.CP(cv_); if (anchor) { - float position = y; + float position =(launcher_position_ == LauncherPosition::LEFT) ? y: x; + for (AbstractLauncherIcon::Ptr const& model_icon : *model_) { if (model_icon == anchor) { position += c_icon_size / 2; - launcher_drag_delta_ = enter_y_ - position; - - if (position + c_icon_size / 2 + launcher_drag_delta_ > geo.height) - launcher_drag_delta_ -= (position + c_icon_size / 2 + launcher_drag_delta_) - geo.height; + if (launcher_position_ == LauncherPosition::LEFT) + { + launcher_drag_delta_ = enter_y_ - position; + if (position + c_icon_size / 2 + launcher_drag_delta_ > geo.height) + launcher_drag_delta_ -= (position + c_icon_size / 2 + launcher_drag_delta_) - geo.height; + } + else + { + launcher_drag_delta_ = enter_x_ - position; + if (position + c_icon_size / 2 + launcher_drag_delta_ > geo.width) + launcher_drag_delta_ -= (position + c_icon_size / 2 + launcher_drag_delta_) - geo.width; + } break; } float visibility = model_icon->GetQuirkProgress(AbstractLauncherIcon::Quirk::VISIBLE, monitor()); @@ -667,8 +689,9 @@ void Launcher::FillRenderArg(AbstractLauncherIcon::Ptr const& icon, arg.skip = true; int c_icon_size = icon_size_.CP(cv_); + auto moving_center = (launcher_position_ == LauncherPosition::LEFT) ? center.y : center.x; // goes for 0.0f when fully unfolded, to 1.0f folded - float folding_progress = CLAMP((center.y + c_icon_size - folding_threshold) / (float) c_icon_size, 0.0f, 1.0f); + float folding_progress = CLAMP((moving_center + c_icon_size - folding_threshold) / (float) c_icon_size, 0.0f, 1.0f); float unfold_progress = icon->GetQuirkProgress(AbstractLauncherIcon::Quirk::UNFOLDED, monitor()); float active_progress = icon->GetQuirkProgress(AbstractLauncherIcon::Quirk::ACTIVE, monitor()); @@ -688,23 +711,41 @@ void Launcher::FillRenderArg(AbstractLauncherIcon::Ptr const& icon, // icon is crossing threshold, start folding center.z += folded_z_distance * folding_progress; - arg.rotation.x = animation_neg_rads * folding_progress; + if (launcher_position_ == LauncherPosition::LEFT) + arg.rotation.x = animation_neg_rads * folding_progress; + else + arg.rotation.y = animation_neg_rads * folding_progress; - float spacing_overlap = CLAMP((float)(center.y + (2.0f * half_size * size_modifier) + (SPACE_BETWEEN_ICONS.CP(cv_) * size_modifier) - folding_threshold) / (float) c_icon_size, 0.0f, 1.0f); + float spacing_overlap = CLAMP((float)(moving_center + (2.0f * half_size * size_modifier) + (SPACE_BETWEEN_ICONS.CP(cv_) * size_modifier) - folding_threshold) / (float) c_icon_size, 0.0f, 1.0f); float spacing = (SPACE_BETWEEN_ICONS.CP(cv_) * (1.0f - spacing_overlap) + folded_spacing * spacing_overlap) * size_modifier; nux::Point3 centerOffset; float center_transit_progress = icon->GetQuirkProgress(AbstractLauncherIcon::Quirk::CENTER_SAVED, monitor()); if (center_transit_progress <= 1.0f) { - int saved_center = icon->GetSavedCenter(monitor).y - parent_abs_geo.y; - centerOffset.y = (saved_center - (center.y + (half_size * size_modifier))) * (1.0f - center_transit_progress); + if (launcher_position_ == LauncherPosition::LEFT) + { + int saved_center = icon->GetSavedCenter(monitor).y - parent_abs_geo.y; + centerOffset.y = (saved_center - (center.y + (half_size * size_modifier))) * (1.0f - center_transit_progress); + } + else + { + int saved_center = icon->GetSavedCenter(monitor).x - parent_abs_geo.x; + centerOffset.x = (saved_center - (center.x + (half_size * size_modifier))) * (1.0f - center_transit_progress); + } + } + if (launcher_position_ == LauncherPosition::LEFT) + { + center.y += half_size * size_modifier; // move to center + arg.render_center = nux::Point3(roundf(center.x + icon_hide_offset), roundf(center.y + centerOffset.y), roundf(center.z)); + arg.logical_center = nux::Point3(roundf(center.x + icon_hide_offset), roundf(center.y), roundf(center.z)); + } + else + { + center.x += half_size * size_modifier; + arg.render_center = nux::Point3(roundf(center.x + centerOffset.x), roundf(center.y + icon_hide_offset), roundf(center.z)); + arg.logical_center = nux::Point3(roundf(center.x), roundf(center.y + icon_hide_offset), roundf(center.z)); } - - center.y += half_size * size_modifier; // move to center - - arg.render_center = nux::Point3(roundf(center.x + icon_hide_offset), roundf(center.y + centerOffset.y), roundf(center.z)); - arg.logical_center = nux::Point3(roundf(center.x + icon_hide_offset), roundf(center.y), roundf(center.z)); nux::Point3 icon_center(parent_abs_geo.x + roundf(center.x), parent_abs_geo.y + roundf(center.y), roundf(center.z)); icon->SetCenter(icon_center, monitor); @@ -715,7 +756,10 @@ void Launcher::FillRenderArg(AbstractLauncherIcon::Ptr const& icon, drag_window_->SetAnimationTarget(icon_center.x, icon_center.y); } - center.y += (half_size * size_modifier) + spacing; // move to end + if (launcher_position_ == LauncherPosition::LEFT) + center.y += (half_size * size_modifier) + spacing; // move to end + else + center.x += (half_size * size_modifier) + spacing; } float Launcher::DragLimiter(float x) @@ -757,21 +801,30 @@ void Launcher::RenderArgs(std::list<RenderArg> &launcher_args, float folded_size = c_icon_size * folding_not_constant; float folded_spacing = SPACE_BETWEEN_ICONS.CP(cv_) * folding_not_constant; - center.x = geo.width / 2; - center.y = SPACE_BETWEEN_ICONS.CP(cv_); + if (launcher_position_ == LauncherPosition::LEFT) + { + center.x = geo.width / 2; + center.y = SPACE_BETWEEN_ICONS.CP(cv_); + } + else + { + center.x = SPACE_BETWEEN_ICONS.CP(cv_); + center.y = geo.height / 2; + } center.z = 0; - int launcher_height = geo.height; + int launcher_size = (launcher_position_ == LauncherPosition::LEFT) ? geo.height : geo.width; folded_ = true; - // compute required height of launcher AND folding threshold - float sum = 0.0f + center.y; - float folding_threshold = launcher_height - c_icon_size / 2.5f; + // compute required height/width of launcher AND folding threshold + float sum = (launcher_position_ == LauncherPosition::LEFT) ? (0.0f + center.y) : (0.0f + center.x); + float folding_threshold = launcher_size - c_icon_size / 2.5f; + for (it = model_->begin(); it != model_->end(); ++it) { float visibility = (*it)->GetQuirkProgress(AbstractLauncherIcon::Quirk::VISIBLE, monitor()); - float height = (c_icon_size + SPACE_BETWEEN_ICONS.CP(cv_)) * visibility; - sum += height; + float size = (c_icon_size + SPACE_BETWEEN_ICONS.CP(cv_)) * visibility; + sum += size; // magic constant must some day be explained, for now suffice to say this constant prevents the bottom from "marching"; const float magic_constant = 1.3f; @@ -780,12 +833,12 @@ void Launcher::RenderArgs(std::list<RenderArg> &launcher_args, float active_progress = (*it)->GetQuirkProgress(AbstractLauncherIcon::Quirk::ACTIVE, monitor()); unfold_progress = CLAMP(unfold_progress + active_progress, 0.0f, 1.0f); - folding_threshold -= CLAMP(sum - launcher_height, 0.0f, height * magic_constant) * (folding_constant + (1.0f - folding_constant) * unfold_progress); + folding_threshold -= CLAMP(sum - launcher_size, 0.0f, size * magic_constant) * (folding_constant + (1.0f - folding_constant) * unfold_progress); } - if (sum - SPACE_BETWEEN_ICONS.CP(cv_) <= launcher_height) + if (sum - SPACE_BETWEEN_ICONS.CP(cv_) <= launcher_size) { - folding_threshold = launcher_height; + folding_threshold = launcher_size; folded_ = false; } @@ -806,7 +859,10 @@ void Launcher::RenderArgs(std::list<RenderArg> &launcher_args, { if (autohide_progress > 0.0f) { - autohide_offset -= geo.width * autohide_progress; + if (launcher_position_ == LauncherPosition::LEFT) + autohide_offset -= geo.width * autohide_progress; + else + autohide_offset += geo.height * autohide_progress; if (options()->auto_hide_animation() == FADE_AND_SLIDE) *launcher_alpha = 1.0f - 0.5f * autohide_progress; } @@ -816,7 +872,10 @@ void Launcher::RenderArgs(std::list<RenderArg> &launcher_args, if (options()->hide_mode != LAUNCHER_HIDE_NEVER) { float drag_hide_progress = dnd_hide_animation_.GetCurrentValue(); - autohide_offset -= geo.width * 0.25f * drag_hide_progress; + if (launcher_position_ == LauncherPosition::LEFT) + autohide_offset -= geo.width * 0.25f * drag_hide_progress; + else + autohide_offset += geo.height * 0.25f * drag_hide_progress; hide_machine_.SetQuirk(LauncherHideMachine::DND_PUSHED_OFF, (drag_hide_progress >= 1.0f)); } @@ -824,7 +883,12 @@ void Launcher::RenderArgs(std::list<RenderArg> &launcher_args, box_geo = geo; if (options()->hide_mode != LAUNCHER_HIDE_NEVER || hide_machine_.GetQuirk(LauncherHideMachine::LOCK_HIDE)) - box_geo.x += autohide_offset; + { + if (launcher_position_ == LauncherPosition::LEFT) + box_geo.x += autohide_offset; + else + box_geo.y += autohide_offset; + } /* Why we need last_geo? It stores the last box_geo (note: as it is a static variable, * it is initialized only first time). Infact we call SetDndDelta that calls MouseIconIntersection @@ -835,26 +899,35 @@ void Launcher::RenderArgs(std::list<RenderArg> &launcher_args, static nux::Geometry last_geo = box_geo; // this happens on hover, basically its a flag and a value in one, we translate this into a dnd offset - if (enter_y_ != 0 && enter_y_ + c_icon_size / 2 > folding_threshold) - SetDndDelta(last_geo.x + last_geo.width / 2, center.y, geo); + if (launcher_position_ == LauncherPosition::LEFT) + { + if (enter_y_ != 0 && enter_y_ + c_icon_size / 2 > folding_threshold) + SetDndDelta(last_geo.x + last_geo.width / 2, center.y, geo); + } + else + { + if (enter_x_ != 0 && enter_x_ + c_icon_size / 2 > folding_threshold) + SetDndDelta(center.x, last_geo.y + last_geo.height / 2, geo); + } // Update the last_geo value. last_geo = box_geo; enter_y_ = 0; + enter_x_ = 0; // logically dnd exit only restores to the clamped ranges // hover_progress restores to 0 launcher_drag_delta_max_ = 0.0f; - launcher_drag_delta_min_ = MIN(0.0f, launcher_height - sum); + launcher_drag_delta_min_ = MIN(0.0f, launcher_size - sum); if (hover_progress > 0.0f && launcher_drag_delta_ != 0) { - float delta_y = launcher_drag_delta_; + float delta = launcher_drag_delta_; if (launcher_drag_delta_ > launcher_drag_delta_max_) - delta_y = launcher_drag_delta_max_ + DragLimiter(delta_y - launcher_drag_delta_max_); + delta = launcher_drag_delta_max_ + DragLimiter(delta - launcher_drag_delta_max_); else if (launcher_drag_delta_ < launcher_drag_delta_min_) - delta_y = launcher_drag_delta_min_ + DragLimiter(delta_y - launcher_drag_delta_min_); + delta = launcher_drag_delta_min_ + DragLimiter(delta - launcher_drag_delta_min_); if (GetActionState() != ACTION_DRAG_LAUNCHER) { @@ -862,17 +935,21 @@ void Launcher::RenderArgs(std::list<RenderArg> &launcher_args, float dnd_progress = std::pow(drag_over_animation_.GetCurrentValue(), 2); if (launcher_drag_delta_ > launcher_drag_delta_max_) - delta_y = launcher_drag_delta_max_ + (delta_y - launcher_drag_delta_max_) * dnd_progress; + delta = launcher_drag_delta_max_ + (delta - launcher_drag_delta_max_) * dnd_progress; else if (launcher_drag_delta_ < launcher_drag_delta_min_) - delta_y = launcher_drag_delta_min_ + (delta_y - launcher_drag_delta_min_) * dnd_progress; + delta = launcher_drag_delta_min_ + (delta - launcher_drag_delta_min_) * dnd_progress; if (dnd_progress == 0.0f) - launcher_drag_delta_ = (int) delta_y; + launcher_drag_delta_ = (int) delta; } - delta_y *= hover_progress; - center.y += delta_y; - folding_threshold += delta_y; + delta *= hover_progress; + folding_threshold += delta; + + if (launcher_position_ == LauncherPosition::LEFT) + center.y += delta; + else + center.x += delta; } else { @@ -903,17 +980,26 @@ void Launcher::RenderArgs(std::list<RenderArg> &launcher_args, for (it = model_->shelf_begin(); it != model_->shelf_end(); ++it) { float visibility = (*it)->GetQuirkProgress(AbstractLauncherIcon::Quirk::VISIBLE, monitor()); - float height = (c_icon_size + SPACE_BETWEEN_ICONS.CP(cv_)) * visibility; - shelf_sum += height; + float size = (c_icon_size + SPACE_BETWEEN_ICONS.CP(cv_)) * visibility; + shelf_sum += size; } // add bottom padding if (shelf_sum > 0.0f) shelf_sum += SPACE_BETWEEN_ICONS.CP(cv_); - float shelf_delta = MAX(((launcher_height - shelf_sum) + SPACE_BETWEEN_ICONS.CP(cv_)) - center.y, 0.0f); + float shelf_delta = 0; + if (launcher_position_ == LauncherPosition::LEFT) + { + shelf_delta = MAX(((launcher_size - shelf_sum) + SPACE_BETWEEN_ICONS.CP(cv_)) - center.y, 0.0f); + center.y += shelf_delta; + } + else + { + shelf_delta = MAX(((launcher_size - shelf_sum) + SPACE_BETWEEN_ICONS.CP(cv_)) - center.x, 0.0f); + center.x += shelf_delta; + } folding_threshold += shelf_delta; - center.y += shelf_delta; force_show_window = false; @@ -1225,9 +1311,13 @@ void Launcher::OnMonitorChanged(int new_monitor) auto monitor_geo = uscreen->GetMonitorGeometry(new_monitor); unity::panel::Style &panel_style = panel::Style::Instance(); int panel_height = panel_style.PanelHeight(new_monitor); + int launcher_height = unity::Settings::Instance().LauncherSize(new_monitor); cv_ = unity::Settings::Instance().em(monitor); - Resize(nux::Point(monitor_geo.x, monitor_geo.y + panel_height), monitor_geo.height - panel_height); + if (launcher_position_ == LauncherPosition::LEFT) + Resize(nux::Point(monitor_geo.x, monitor_geo.y + panel_height), monitor_geo.height - panel_height); + else + Resize(nux::Point(monitor_geo.x, monitor_geo.y + monitor_geo.height - launcher_height), monitor_geo.width); icon_renderer_->monitor = new_monitor; icon_renderer_->scale = cv_->DPIScale(); @@ -1240,6 +1330,7 @@ void Launcher::UpdateOptions(Options::Ptr options) SetHideMode(options->hide_mode); SetScrollInactiveIcons(options->scroll_inactive_icons); SetLauncherMinimizeWindow(options->minimize_window_on_click); + OnMonitorChanged(monitor); if (model_) { @@ -1318,7 +1409,10 @@ void Launcher::SetHover(bool hovered) hovered_ = hovered; if (!IsInKeyNavMode() && hovered_) + { enter_y_ = mouse_position_.y; + enter_x_ = mouse_position_.x; + } if (folded_) animation::StartOrReverseIf(hover_animation_, hovered_); @@ -1334,12 +1428,18 @@ void Launcher::SetHover(bool hovered) bool Launcher::MouseOverTopScrollArea() { - return mouse_position_.y < SCROLL_AREA_HEIGHT.CP(cv_); + if (launcher_position_ == LauncherPosition::LEFT) + return mouse_position_.y < SCROLL_AREA_HEIGHT.CP(cv_); + else + return mouse_position_.x < SCROLL_AREA_HEIGHT.CP(cv_); } bool Launcher::MouseOverBottomScrollArea() { - return mouse_position_.y >= GetGeometry().height - SCROLL_AREA_HEIGHT.CP(cv_); + if (launcher_position_ == LauncherPosition::LEFT) + return mouse_position_.y >= GetGeometry().height - SCROLL_AREA_HEIGHT.CP(cv_); + else + return mouse_position_.x >= GetGeometry().width - SCROLL_AREA_HEIGHT.CP(cv_); } bool Launcher::OnScrollTimeout() @@ -1358,7 +1458,11 @@ bool Launcher::OnScrollTimeout() } else { - int mouse_distance = (SCROLL_AREA_HEIGHT.CP(cv_) - mouse_position_.y); + int mouse_distance = 0; + if (launcher_position_ == LauncherPosition::LEFT) + mouse_distance = (SCROLL_AREA_HEIGHT.CP(cv_) - mouse_position_.y); + else + mouse_distance = (SCROLL_AREA_HEIGHT.CP(cv_) - mouse_position_.x); int speed = static_cast<float>(mouse_distance) / SCROLL_AREA_HEIGHT.CP(cv_) * SCROLL_FPS; launcher_drag_delta_ += speed; } @@ -1371,7 +1475,11 @@ bool Launcher::OnScrollTimeout() } else { - int mouse_distance = (mouse_position_.y + 1) - (GetGeometry().height - SCROLL_AREA_HEIGHT.CP(cv_)); + int mouse_distance = 0; + if (launcher_position_ == LauncherPosition::LEFT) + mouse_distance = (mouse_position_.y + 1) - (GetGeometry().height - SCROLL_AREA_HEIGHT.CP(cv_)); + else + mouse_distance = (mouse_position_.x + 1) - (GetGeometry().width - SCROLL_AREA_HEIGHT.CP(cv_)); int speed = static_cast<float>(mouse_distance) / SCROLL_AREA_HEIGHT.CP(cv_) * SCROLL_FPS; launcher_drag_delta_ -= speed; } @@ -1533,7 +1641,10 @@ void Launcher::SetIconSize(int tile_size, int icon_size) AbstractLauncherIcon::icon_size = icon_size_; nux::Geometry const& parent_geo = parent_->GetGeometry(); - Resize(nux::Point(parent_geo.x, parent_geo.y), parent_geo.height); + if (launcher_position_ == LauncherPosition::LEFT) + Resize(nux::Point(parent_geo.x, parent_geo.y), parent_geo.height); + else + Resize(nux::Point(parent_geo.x, parent_geo.y), parent_geo.width); } int Launcher::GetIconSize() const @@ -1541,13 +1652,24 @@ int Launcher::GetIconSize() const return icon_size_.CP(cv_); } -void Launcher::Resize(nux::Point const& offset, int height) +void Launcher::Resize(nux::Point const& offset, int size) { - RawPixel width = icon_size_ + ICON_PADDING * 2 + RIGHT_LINE_WIDTH - 2; - - width = width.CP(cv_); + RawPixel width = 0, height = 0; + if (launcher_position_ == LauncherPosition::LEFT) + { + width = icon_size_ + ICON_PADDING * 2 + SIDE_LINE_WIDTH - 2; + width = width.CP(cv_); + height = size; + SetMaximumHeight(height); + } + else + { + height = icon_size_ + ICON_PADDING * 2 + SIDE_LINE_WIDTH - 2; + height = height.CP(cv_); + width = size; + SetMaximumWidth(width); + } - SetMaximumHeight(height); SetGeometry(nux::Geometry(0, 0, width, height)); parent_->SetGeometry(nux::Geometry(offset.x, offset.y, width, height)); @@ -1692,7 +1814,11 @@ void Launcher::DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw) bool force_show_window; nux::Geometry const& geo_absolute = GetAbsoluteGeometry(); RenderArgs(args, bkg_box, &launcher_alpha, geo_absolute, force_show_window); - bkg_box.width -= RIGHT_LINE_WIDTH.CP(cv_); + + if (launcher_position_ == LauncherPosition::LEFT) + bkg_box.width -= SIDE_LINE_WIDTH.CP(cv_); + else + bkg_box.height -= SIDE_LINE_WIDTH.CP(cv_); if (options()->hide_mode != LAUNCHER_HIDE_NEVER && bkg_box.x + bkg_box.width <= 0 && @@ -1717,10 +1843,19 @@ void Launcher::DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw) int push_count = 1; - // clip vertically but not horizontally - GfxContext.PushClippingRectangle(nux::Geometry(base.x, bkg_box.y, base.width, bkg_box.height)); + if (launcher_position_ == LauncherPosition::LEFT) + GfxContext.PushClippingRectangle(nux::Geometry(base.x, bkg_box.y, base.width, bkg_box.height)); + else + GfxContext.PushClippingRectangle(nux::Geometry(bkg_box.x, base.y, bkg_box.width, base.height)); float reveal_progress = hide_machine_.reveal_progress; + TextureCache& cache = TextureCache::GetDefault(); + + std::string launcher_pressure_icon = "launcher_pressure_effect.png"; + if (launcher_position_ == LauncherPosition::BOTTOM) + launcher_pressure_icon = "launcher_pressure_effect_rotated.png"; + + launcher_pressure_effect_ = cache.FindTexture(launcher_pressure_icon); if ((reveal_progress > 0 || last_reveal_progress_ > 0) && launcher_pressure_effect_.IsValid()) { @@ -1737,7 +1872,22 @@ void Launcher::DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw) } nux::Color pressure_color = nux::color::White * last_reveal_progress_; nux::TexCoordXForm texxform_pressure; - GfxContext.QRP_1Tex(base.x, base.y, launcher_pressure_effect_->GetWidth(), base.height, + + int pressure_y = 0, pressure_width = 0, pressure_height = 0; + if (launcher_position_ == LauncherPosition::LEFT) + { + pressure_y = base.y; + pressure_width = launcher_pressure_effect_->GetWidth(); + pressure_height = base.height; + } + else + { + pressure_y = base.y + base.height - SIDE_LINE_WIDTH.CP(cv_) - launcher_pressure_effect_->GetHeight(); + pressure_width = base.width; + pressure_height = launcher_pressure_effect_->GetHeight(); + } + + GfxContext.QRP_1Tex(base.x, pressure_y, pressure_width, pressure_height, launcher_pressure_effect_->GetDeviceTexture(), texxform_pressure, pressure_color); @@ -1749,7 +1899,12 @@ void Launcher::DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw) { nux::ObjectPtr<nux::IOpenGLBaseTexture> blur_texture; - if (BackgroundEffectHelper::blur_type != unity::BLUR_NONE && (bkg_box.x + bkg_box.width > 0)) + bool visible = false; + if ((launcher_position_ == LauncherPosition::LEFT && (bkg_box.x + bkg_box.width > 0)) || + (launcher_position_ == LauncherPosition::BOTTOM && (bkg_box.y < bkg_box.height))) + visible = true; + + if (BackgroundEffectHelper::blur_type != unity::BLUR_NONE && visible) { blur_texture = bg_effect_helper_.GetBlurRegion(); } @@ -1849,13 +2004,42 @@ void Launcher::DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw) icon_renderer_->PreprocessIcons(args, base); EventLogic(); + if (!IsOverlayOpen() && launcher_position_ == LauncherPosition::BOTTOM) + { + const double top_line_opacity = 0.15f * launcher_alpha; + + gPainter.Paint2DQuadColor(GfxContext, + nux::Geometry(bkg_box.x, + bkg_box.y, + bkg_box.width, + SIDE_LINE_WIDTH.CP(cv_)), + nux::color::White * top_line_opacity); + + gPainter.Paint2DQuadColor(GfxContext, + nux::Geometry(bkg_box.x, + bkg_box.y, + bkg_box.width, + 8), + nux::Color(0x70000000), + nux::Color(0x00000000), + nux::Color(0x00000000), + nux::Color(0x70000000)); + } + /* draw launcher */ for (rev_it = args.rbegin(); rev_it != args.rend(); ++rev_it) { if ((*rev_it).stick_thingy) - gPainter.Paint2DQuadColor(GfxContext, - nux::Geometry(bkg_box.x, (*rev_it).render_center.y - 3, bkg_box.width, 2), - nux::Color(0xAAAAAAAA)); + { + if (launcher_position_ == LauncherPosition::LEFT) + gPainter.Paint2DQuadColor(GfxContext, + nux::Geometry(bkg_box.x, (*rev_it).render_center.y - 3, bkg_box.width, 2), + nux::Color(0xAAAAAAAA)); + else + gPainter.Paint2DQuadColor(GfxContext, + nux::Geometry((*rev_it).render_center.x - 3, bkg_box.y, 2, bkg_box.height), + nux::Color(0xAAAAAAAA)); + } if ((*rev_it).skip) continue; @@ -1863,14 +2047,14 @@ void Launcher::DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw) icon_renderer_->RenderIcon(GfxContext, *rev_it, bkg_box, base); } - if (!IsOverlayOpen()) + if (!IsOverlayOpen() && launcher_position_ == LauncherPosition::LEFT) { const double right_line_opacity = 0.15f * launcher_alpha; gPainter.Paint2DQuadColor(GfxContext, nux::Geometry(bkg_box.x + bkg_box.width, bkg_box.y, - RIGHT_LINE_WIDTH.CP(cv_), + SIDE_LINE_WIDTH.CP(cv_), bkg_box.height), nux::color::White * right_line_opacity); @@ -1929,7 +2113,18 @@ bool Launcher::StartIconDragTimeout(int x, int y) void Launcher::StartIconDragRequest(int x, int y) { auto const& abs_geo = GetAbsoluteGeometry(); - auto const& drag_icon = MouseIconIntersection(abs_geo.width / 2.0f, y); + int mouse_x = 0, mouse_y = 0; + if (launcher_position_ == LauncherPosition::LEFT) + { + mouse_x = abs_geo.width / 2.0f; + mouse_y = y; + } + else + { + mouse_x = x; + mouse_y = abs_geo.height / 2.0f; + } + auto const& drag_icon = MouseIconIntersection(mouse_x, mouse_y); // FIXME: nux doesn't give nux::GetEventButton (button_flags) there, relying // on an internal Launcher property then @@ -2064,7 +2259,18 @@ void Launcher::UpdateDragWindowPosition(int x, int y) return; auto const& launcher_geo = GetGeometry(); - auto const& hovered_icon = MouseIconIntersection((launcher_geo.x + launcher_geo.width) / 2.0, y - GetAbsoluteY()); + int mouse_x = 0, mouse_y = 0; + if (launcher_position_ == LauncherPosition::LEFT) + { + mouse_x = (launcher_geo.x + launcher_geo.width) / 2.0; + mouse_y = y - GetAbsoluteY(); + } + else + { + mouse_x = x - GetAbsoluteX(); + mouse_y = (launcher_geo.y + launcher_geo.height) / 2.0; + } + auto const& hovered_icon = MouseIconIntersection(mouse_x, mouse_y); bool mouse_beyond_drag_threshold = MouseBeyondDragThreshold(); if (hovered_icon && drag_icon_ != hovered_icon) @@ -2088,7 +2294,8 @@ void Launcher::UpdateDragWindowPosition(int x, int y) if (!icon->IsVisibleOnMonitor(monitor)) continue; - if (y >= icon->GetCenter(monitor).y) + if ((launcher_position_ == LauncherPosition::LEFT && y >= icon->GetCenter(monitor).y) || + (launcher_position_ == LauncherPosition::BOTTOM && x >= icon->GetCenter(monitor).x)) { model_->ReorderAfter(drag_icon_, icon); break; @@ -2154,12 +2361,18 @@ void Launcher::RecvMouseDrag(int x, int y, int dx, int dy, unsigned long button_ if (GetActionState() == ACTION_NONE) { #ifdef USE_X11 - if (nux::Abs(dnd_delta_y_) >= nux::Abs(dnd_delta_x_)) + if (nux::Abs(dnd_delta_y_) >= nux::Abs(dnd_delta_x_) && launcher_position_ == LauncherPosition::LEFT) { launcher_drag_delta_ += dnd_delta_y_; SetActionState(ACTION_DRAG_LAUNCHER); hide_machine_.SetQuirk(LauncherHideMachine::VERTICAL_SLIDE_ACTIVE, true); } + else if (nux::Abs(dnd_delta_x_) >= nux::Abs(dnd_delta_y_) && launcher_position_ == LauncherPosition::BOTTOM) + { + launcher_drag_delta_ += dnd_delta_x_; + SetActionState(ACTION_DRAG_LAUNCHER); + hide_machine_.SetQuirk(LauncherHideMachine::VERTICAL_SLIDE_ACTIVE, true); + } else { // We we can safely start the icon drag, from the original mouse-down position @@ -2170,7 +2383,10 @@ void Launcher::RecvMouseDrag(int x, int y, int dx, int dy, unsigned long button_ } else if (GetActionState() == ACTION_DRAG_LAUNCHER) { - launcher_drag_delta_ += dy; + if (launcher_position_ == LauncherPosition::LEFT) + launcher_drag_delta_ += dy; + else + launcher_drag_delta_ += dx; } else if (GetActionState() == ACTION_DRAG_ICON) { @@ -2256,20 +2472,42 @@ ui::EdgeBarrierSubscriber::Result Launcher::HandleBarrierEvent(ui::PointerBarrie nux::Geometry const& abs_geo = GetAbsoluteGeometry(); bool apply_to_reveal = false; - if (event->x >= abs_geo.x && event->x <= abs_geo.x + abs_geo.width) + if (launcher_position_ == LauncherPosition::LEFT) { - if (!hidden_) - return ui::EdgeBarrierSubscriber::Result::ALREADY_HANDLED; - - if (options()->reveal_trigger == RevealTrigger::EDGE) + if (event->x >= abs_geo.x && event->x <= abs_geo.x + abs_geo.width) { - if (event->y >= abs_geo.y) - apply_to_reveal = true; + if (!hidden_) + return ui::EdgeBarrierSubscriber::Result::ALREADY_HANDLED; + + if (options()->reveal_trigger == RevealTrigger::EDGE) + { + if (event->y >= abs_geo.y) + apply_to_reveal = true; + } + else if (options()->reveal_trigger == RevealTrigger::CORNER) + { + if (event->y < abs_geo.y) + apply_to_reveal = true; + } } - else if (options()->reveal_trigger == RevealTrigger::CORNER) + } + else + { + if (event->y >= abs_geo.y && event->y <= abs_geo.y + abs_geo.height) { - if (event->y < abs_geo.y) - apply_to_reveal = true; + if (!hidden_) + return ui::EdgeBarrierSubscriber::Result::ALREADY_HANDLED; + + if (options()->reveal_trigger == RevealTrigger::EDGE) + { + if (event->x >= abs_geo.x + panel::Style::Instance().PanelHeight(monitor())) + apply_to_reveal = true; + } + else if (options()->reveal_trigger == RevealTrigger::CORNER) + { + if (event->x < abs_geo.x + panel::Style::Instance().PanelHeight(monitor())) + apply_to_reveal = true; + } } } @@ -2455,6 +2693,7 @@ void Launcher::RenderIconToTexture(nux::GraphicsEngine& GfxContext, nux::ObjectP arg.render_center = nux::Point3(roundf(texture->GetWidth() / 2.0f), roundf(texture->GetHeight() / 2.0f), 0.0f); arg.logical_center = arg.render_center; arg.rotation.x = 0.0f; + arg.rotation.y = 0.0f; arg.running_arrow = false; arg.active_arrow = false; arg.skip = false; @@ -2616,8 +2855,11 @@ void Launcher::ProcessDndMove(int x, int y, std::list<char*> mimes) if (options()->hide_mode != LAUNCHER_HIDE_NEVER) { - if (monitor() == 0 && !IsOverlayOpen() && mouse_position_.x == 0 && !drag_edge_touching_ && - mouse_position_.y <= (parent_->GetGeometry().height - icon_size_.CP(cv_) - 2 * SPACE_BETWEEN_ICONS.CP(cv_))) + 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_) { @@ -2628,7 +2870,9 @@ void Launcher::ProcessDndMove(int x, int y, std::list<char*> mimes) animation::StartOrReverse(dnd_hide_animation_, animation::Direction::FORWARD); drag_edge_touching_ = true; } - else if (mouse_position_.x != 0 && drag_edge_touching_) + 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; diff --git a/launcher/Launcher.h b/launcher/Launcher.h index 1b124abff..1cd434e07 100644 --- a/launcher/Launcher.h +++ b/launcher/Launcher.h @@ -43,6 +43,7 @@ #include "LauncherHoverMachine.h" #include "unity-shared/MockableBaseWindow.h" #include "unity-shared/UBusWrapper.h" +#include "unity-shared/UnitySettings.h" #include "SoftwareCenterLauncherIcon.h" #include "TooltipManager.h" @@ -345,6 +346,7 @@ private: int launcher_drag_delta_; int launcher_drag_delta_max_; int launcher_drag_delta_min_; + int enter_x_; int enter_y_; int last_button_press_; int drag_icon_position_; @@ -367,6 +369,9 @@ private: BaseTexturePtr launcher_pressure_effect_; BackgroundEffectHelper bg_effect_helper_; + LauncherPosition launcher_position_; + connection::Wrapper launcher_position_changed_; + nux::animation::AnimateValue<float> auto_hide_animation_; nux::animation::AnimateValue<float> hover_animation_; nux::animation::AnimateValue<float> drag_over_animation_; diff --git a/launcher/LauncherController.cpp b/launcher/LauncherController.cpp index 4cd56b745..3c13310c3 100644 --- a/launcher/LauncherController.cpp +++ b/launcher/LauncherController.cpp @@ -34,13 +34,11 @@ #include "VolumeLauncherIcon.h" #include "FavoriteStore.h" #include "FileManagerLauncherIcon.h" -#include "HudLauncherIcon.h" #include "LauncherController.h" #include "LauncherControllerPrivate.h" #include "SoftwareCenterLauncherIcon.h" #include "ExpoLauncherIcon.h" #include "TrashLauncherIcon.h" -#include "BFBLauncherIcon.h" #include "unity-shared/AppStreamApplication.h" #include "unity-shared/IconRenderer.h" #include "unity-shared/UScreen.h" @@ -107,6 +105,8 @@ Controller::Impl::Impl(Controller* parent, XdndManager::Ptr const& xdnd_manager, , model_(std::make_shared<LauncherModel>()) , xdnd_manager_(xdnd_manager) , device_section_(std::make_shared<DeviceLauncherSection>()) + , bfb_icon_(new BFBLauncherIcon()) + , hud_icon_(new HudLauncherIcon()) , expo_icon_(new ExpoLauncherIcon()) , desktop_icon_(new DesktopLauncherIcon()) , edge_barriers_(edge_barriers) @@ -130,20 +130,28 @@ Controller::Impl::Impl(Controller* parent, XdndManager::Ptr const& xdnd_manager, remote_model_.entry_added.connect(sigc::mem_fun(this, &Impl::OnLauncherEntryRemoteAdded)); remote_model_.entry_removed.connect(sigc::mem_fun(this, &Impl::OnLauncherEntryRemoteRemoved)); - LauncherHideMode hide_mode = parent_->options()->hide_mode; - BFBLauncherIcon* bfb = new BFBLauncherIcon(hide_mode); - RegisterIcon(AbstractLauncherIcon::Ptr(bfb)); + auto hide_mode = parent_->options()->hide_mode(); + bfb_icon_->SetHideMode(hide_mode); + RegisterIcon(AbstractLauncherIcon::Ptr(bfb_icon_)); - HudLauncherIcon* hud = new HudLauncherIcon(hide_mode); - RegisterIcon(AbstractLauncherIcon::Ptr(hud)); - hud_icon_ = hud; + hud_icon_->SetHideMode(hide_mode); + RegisterIcon(AbstractLauncherIcon::Ptr(hud_icon_)); TrashLauncherIcon* trash = new TrashLauncherIcon(); RegisterIcon(AbstractLauncherIcon::Ptr(trash)); - parent_->options()->hide_mode.changed.connect([bfb, hud](LauncherHideMode mode) { - bfb->SetHideMode(mode); - hud->SetHideMode(mode); + parent_->options()->hide_mode.changed.connect([this] (LauncherHideMode mode) { + bfb_icon_->SetHideMode(mode); + hud_icon_->SetHideMode(mode); + }); + + parent_->multiple_launchers.changed.connect([this] (bool value) { + UScreen* uscreen = UScreen::GetDefault(); + auto monitors = uscreen->GetMonitors(); + int primary = uscreen->GetPrimaryMonitor(); + EnsureLaunchers(primary, monitors); + parent_->options()->show_for_all = !value; + hud_icon_->SetSingleLauncher(!value, primary); }); WindowManager& wm = WindowManager::Default(); @@ -1049,16 +1057,7 @@ Controller::Controller(XdndManager::Ptr const& xdnd_manager, ui::EdgeBarrierCont : options(std::make_shared<Options>()) , multiple_launchers(true) , pimpl(new Impl(this, xdnd_manager, edge_barriers)) -{ - multiple_launchers.changed.connect([this] (bool value) { - UScreen* uscreen = UScreen::GetDefault(); - auto monitors = uscreen->GetMonitors(); - int primary = uscreen->GetPrimaryMonitor(); - pimpl->EnsureLaunchers(primary, monitors); - options()->show_for_all = !value; - pimpl->hud_icon_->SetSingleLauncher(!value, primary); - }); -} +{} Controller::~Controller() {} @@ -1446,35 +1445,60 @@ void Controller::Impl::ReceiveLauncherKeyPress(unsigned long eventType, switch (keysym) { - // up (move selection up or go to global-menu if at top-most icon) + // up case NUX_VK_UP: case NUX_KP_UP: - parent_->KeyNavPrevious(); + if (Settings::Instance().launcher_position() == LauncherPosition::LEFT) + // move selection up or go to global-menu if at top-most icon + parent_->KeyNavPrevious(); + else + OpenQuicklist(); break; - // down (move selection down and unfold launcher if needed) + // down case NUX_VK_DOWN: case NUX_KP_DOWN: - parent_->KeyNavNext(); + if (Settings::Instance().launcher_position() == LauncherPosition::LEFT) + // move selection down and unfold launcher if needed + parent_->KeyNavNext(); + else + // exit launcher key-focus + parent_->KeyNavTerminate(false); break; - // super/control/esc/left (close quicklist or exit laucher key-focus) + // left + case NUX_VK_LEFT: + case NUX_KP_LEFT: + if (Settings::Instance().launcher_position() == LauncherPosition::LEFT) + parent_->KeyNavTerminate(false); + else + // move selection left or go to global-menu if at top-most icon or close quicklist + parent_->KeyNavPrevious(); + break; + + // right + case NUX_VK_RIGHT: + case NUX_KP_RIGHT: + if (Settings::Instance().launcher_position() == LauncherPosition::LEFT) + OpenQuicklist(); + else + // move selection right and unfold launcher if needed + parent_->KeyNavNext(); + break; + + // super/control/esc (close quicklist or exit laucher key-focus) case NUX_VK_LWIN: case NUX_VK_RWIN: case NUX_VK_CONTROL: - case NUX_VK_LEFT: - case NUX_KP_LEFT: case NUX_VK_ESCAPE: // hide again parent_->KeyNavTerminate(false); break; - // right/shift-f10 (open quicklist of currently selected icon) + // shift-f10 (open quicklist of currently selected icon) case XK_F10: if (!(state & nux::NUX_STATE_SHIFT)) break; - case NUX_VK_RIGHT: - case NUX_KP_RIGHT: case XK_Menu: OpenQuicklist(); break; diff --git a/launcher/LauncherControllerPrivate.h b/launcher/LauncherControllerPrivate.h index 268c1fb58..2596d212e 100644 --- a/launcher/LauncherControllerPrivate.h +++ b/launcher/LauncherControllerPrivate.h @@ -36,10 +36,11 @@ #include "LauncherEntryRemote.h" #include "LauncherEntryRemoteModel.h" #include "LauncherModel.h" +#include "BFBLauncherIcon.h" +#include "HudLauncherIcon.h" #include "SoftwareCenterLauncherIcon.h" #include "unity-shared/UBusWrapper.h" #include "XdndManager.h" -#include "HudLauncherIcon.h" namespace unity { @@ -124,9 +125,10 @@ public: XdndManager::Ptr xdnd_manager_; DeviceLauncherSection::Ptr device_section_; LauncherEntryRemoteModel remote_model_; + BFBLauncherIcon* bfb_icon_; + HudLauncherIcon* hud_icon_; AbstractLauncherIcon::Ptr expo_icon_; AbstractLauncherIcon::Ptr desktop_icon_; - HudLauncherIcon* hud_icon_; #ifdef USE_X11 ui::EdgeBarrierController::Ptr edge_barriers_; @@ -148,7 +150,7 @@ public: connection::Wrapper launcher_key_press_connection_; connection::Wrapper launcher_event_outside_connection_; - connection::Wrapper launcher_key_nav_terminate_; + connection::Wrapper launcher_key_nav_terminate_; connection::Wrapper average_color_connection_; }; diff --git a/launcher/LauncherIcon.cpp b/launcher/LauncherIcon.cpp index f67dd0020..d121f56a5 100644 --- a/launcher/LauncherIcon.cpp +++ b/launcher/LauncherIcon.cpp @@ -509,7 +509,14 @@ guint64 LauncherIcon::GetShortcut() nux::Point LauncherIcon::GetTipPosition(int monitor) const { auto const& converter = Settings::Instance().em(monitor); - return nux::Point(_center[monitor].x + converter->CP(icon_size()) / 2 + 1, _center[monitor].y); + if (Settings::Instance().launcher_position() == LauncherPosition::LEFT) + { + return nux::Point(_center[monitor].x + converter->CP(icon_size()) / 2 + 1, _center[monitor].y); + } + else + { + return nux::Point(_center[monitor].x, _center[monitor].y - converter->CP(icon_size()) / 2 - 1); + } } void LauncherIcon::ShowTooltip() diff --git a/launcher/QuicklistView.cpp b/launcher/QuicklistView.cpp index 95a9da557..7d5c95164 100644 --- a/launcher/QuicklistView.cpp +++ b/launcher/QuicklistView.cpp @@ -81,8 +81,16 @@ QuicklistView::QuicklistView(int monitor) { SetGeometry(nux::Geometry(0, 0, 1, 1)); - _left_space = new nux::SpaceLayout(RawPixel(_padding + ANCHOR_WIDTH + CORNER_RADIUS + LEFT_PADDING_CORRECTION).CP(cv_), - RawPixel(_padding + ANCHOR_WIDTH + CORNER_RADIUS + LEFT_PADDING_CORRECTION).CP(cv_), + int width = 0; + int height = 0; + // when launcher is on the left, the anchor is on the left of the menuitem, and + // when launcher is on the bottom, the anchor is on the bottom of the menuitem. + if (Settings::Instance().launcher_position == LauncherPosition::LEFT) + width = ANCHOR_WIDTH; + else + height = ANCHOR_WIDTH; + _left_space = new nux::SpaceLayout(RawPixel(_padding + width + CORNER_RADIUS + LEFT_PADDING_CORRECTION).CP(cv_), + RawPixel(_padding + width + CORNER_RADIUS + LEFT_PADDING_CORRECTION).CP(cv_), 1, MAX_HEIGHT.CP(cv_)); _right_space = new nux::SpaceLayout(_padding.CP(cv_) + CORNER_RADIUS.CP(cv_), @@ -94,8 +102,8 @@ QuicklistView::QuicklistView(int monitor) _padding.CP(cv_) + CORNER_RADIUS.CP(cv_)); _bottom_space = new nux::SpaceLayout(1, MAX_WIDTH.CP(cv_), - _padding.CP(cv_) + CORNER_RADIUS.CP(cv_), - _padding.CP(cv_) + CORNER_RADIUS.CP(cv_)); + _padding.CP(cv_) + height + CORNER_RADIUS.CP(cv_), + _padding.CP(cv_) + height + CORNER_RADIUS.CP(cv_)); _vlayout = new nux::VLayout(TEXT(""), NUX_TRACKER_LOCATION); _vlayout->AddLayout(_top_space, 0); @@ -129,12 +137,35 @@ QuicklistView::QuicklistView(int monitor) int QuicklistView::CalculateX() const { - return _anchorX - _padding.CP(cv_); + int x = 0; + if (Settings::Instance().launcher_position() == LauncherPosition::LEFT) + x = _anchorX - _padding.CP(cv_); + else + { + int size = 0; + int max = GetBaseWidth() - ANCHOR_HEIGHT.CP(cv_) - 2 * CORNER_RADIUS.CP(cv_) - 2 * _padding.CP(cv_); + if (_top_size.CP(cv_) > max) + { + size = max; + } + else if (_top_size.CP(cv_) > 0) + { + size = _top_size.CP(cv_); + } + x = _anchorX - (ANCHOR_HEIGHT.CP(cv_) / 2) - size - CORNER_RADIUS.CP(cv_) - _padding.CP(cv_); + } + + return x; } int QuicklistView::CalculateY() const { - return _anchorY - (ANCHOR_HEIGHT.CP(cv_) / 2) - _top_size.CP(cv_) - CORNER_RADIUS.CP(cv_) - _padding.CP(cv_); + int y = 0; + if (Settings::Instance().launcher_position() == LauncherPosition::LEFT) + y = _anchorY - (ANCHOR_HEIGHT.CP(cv_) / 2) - _top_size.CP(cv_) - CORNER_RADIUS.CP(cv_) - _padding.CP(cv_); + else + y = _anchorY - GetBaseHeight() + _padding.CP(cv_); + return y; } void @@ -338,12 +369,29 @@ void QuicklistView::SetQuicklistPosition(int tip_x, int tip_y) auto* us = UScreen::GetDefault(); int ql_monitor = us->GetMonitorAtPosition(_anchorX, _anchorY); auto const& ql_monitor_geo = us->GetMonitorGeometry(ql_monitor); - int offscreen_size = GetBaseY() + GetBaseHeight() - (ql_monitor_geo.y + ql_monitor_geo.height); + auto launcher_position = Settings::Instance().launcher_position(); - if (offscreen_size > 0) - _top_size = offscreen_size + TOP_SIZE; + if (launcher_position == LauncherPosition::LEFT) + { + int offscreen_size = GetBaseY() + GetBaseHeight() - (ql_monitor_geo.y + ql_monitor_geo.height); + if (offscreen_size > 0) + _top_size = offscreen_size + TOP_SIZE; + else + _top_size = TOP_SIZE; + } else - _top_size = TOP_SIZE; + { + int offscreen_size_left = ql_monitor_geo.x - (_anchorX - GetBaseWidth() / 2); + int offscreen_size_right = _anchorX + GetBaseWidth()/2 - (ql_monitor_geo.x + ql_monitor_geo.width); + int half_size = (GetBaseWidth() / 2) - _padding.CP(cv_) - CORNER_RADIUS.CP(cv_) - (ANCHOR_HEIGHT.CP(cv_) / 2); + + if (offscreen_size_left > 0) + _top_size = half_size - offscreen_size_left; + else if (offscreen_size_right > 0) + _top_size = half_size + offscreen_size_right; + else + _top_size = half_size; + } SetXY(CalculateX(), CalculateY()); } @@ -442,10 +490,14 @@ void QuicklistView::PreLayoutManagement() TotalItemHeight += text_extents.height; } + int rotated_anchor_height = 0; + if (Settings::Instance().launcher_position() == LauncherPosition::BOTTOM) + rotated_anchor_height = ANCHOR_WIDTH; + if (TotalItemHeight < ANCHOR_HEIGHT.CP(cv_)) { - int b = (ANCHOR_HEIGHT.CP(cv_) - TotalItemHeight) / 2 + _padding.CP(cv_) + CORNER_RADIUS.CP(cv_); - int t = b + OFFSET_CORRECTION.CP(cv_); + int b = (ANCHOR_HEIGHT.CP(cv_) - TotalItemHeight) / 2 + _padding.CP(cv_) + CORNER_RADIUS.CP(cv_) + rotated_anchor_height; + int t = b + OFFSET_CORRECTION.CP(cv_) - rotated_anchor_height; _top_space->SetMinimumHeight(t); _top_space->SetMaximumHeight(t); @@ -455,8 +507,8 @@ void QuicklistView::PreLayoutManagement() } else { - int b = _padding.CP(cv_) + CORNER_RADIUS.CP(cv_); - int t = b + OFFSET_CORRECTION.CP(cv_); + int b = _padding.CP(cv_) + CORNER_RADIUS.CP(cv_) + rotated_anchor_height; + int t = b + OFFSET_CORRECTION.CP(cv_) - rotated_anchor_height; _top_space->SetMinimumHeight(t); _top_space->SetMaximumHeight(t); @@ -476,7 +528,10 @@ long QuicklistView::PostLayoutManagement(long LayoutResult) UpdateTexture(); - int x = RawPixel(_padding + ANCHOR_WIDTH + CORNER_RADIUS + OFFSET_CORRECTION).CP(cv_); + int width = 0; + if (Settings::Instance().launcher_position() == LauncherPosition::LEFT) + width = ANCHOR_WIDTH; + int x = RawPixel(_padding + width + CORNER_RADIUS + OFFSET_CORRECTION).CP(cv_); int y = _top_space->GetMinimumHeight(); for (auto const& item : _item_list) @@ -655,7 +710,9 @@ void QuicklistView::RecvMouseDownOutsideOfQuicklist(int x, int y, unsigned long nux::Area* QuicklistView::FindAreaUnderMouse(const nux::Point& mouse_position, nux::NuxEventType event_type) { - if (mouse_position.x > _anchorX) + auto launcher_position = Settings::Instance().launcher_position(); + if ((launcher_position == LauncherPosition::LEFT && (mouse_position.x > _anchorX)) || + (launcher_position == LauncherPosition::BOTTOM && (mouse_position.y < _anchorY))) { return (CairoBaseWindow::FindAreaUnderMouse(mouse_position, event_type)); } @@ -864,109 +921,164 @@ void ql_compute_full_mask_path(cairo_t* cr, gfloat radius, guint pad) { - // 0 1 2 3 - // +--+--------+--+ - // | | - // + 14 + 4 - // | | - // | | - // | | - // + 13 | - // / | - // / | - // + 12 | - // \ | - // \ | - // 11 + | - // | | - // | | - // | | - // 10 + + 5 - // | | - // +--+--------+--+ 6 - // 9 8 7 + // On the right of the icon: On the top of the icon: + // 0 1 2 3 0 1 2 3 + // +--+--------+--+ +--+-----------+--+ + // | | | | + // + 14 + 4 14 + + 4 + // | | | | + // | | | | + // | | | | + // + 13 | | | + // / | | | + // / | | | + // + 12 | | | + // \ | | | + // \ | | | + // 11 + | | | + // | | 13 + + 5 + // | | | 10 8 | + // | | 12 +--+--+ +--+--+ 6 + // 10 + + 5 11 \ / 7 + // | | \ / + // +--+--------+--+ 6 + + // 9 8 7 9 gfloat padding = pad; int ZEROPOINT5 = 0.0f; + auto launcher_position = Settings::Instance().launcher_position(); + + //gint dynamic_size = height - 2*radius - 2*padding - anchor_height; + //gint upper_dynamic_size = upper_size; + //gint lower_dynamic_size = dynamic_size - upper_dynamic_size; + + int size = 0; + if (launcher_position == LauncherPosition::LEFT) + size = height; + else + size = width; - gfloat HeightToAnchor = ((gfloat) height - 2.0f * radius - anchor_height - 2 * padding) / 2.0f; + gfloat HeightToAnchor = ((gfloat) size - 2.0f * radius - anchor_height - 2 * padding) / 2.0f; if (HeightToAnchor < 0.0f) { g_warning("Anchor-height and corner-radius a higher than whole texture!"); return; } - //gint dynamic_size = height - 2*radius - 2*padding - anchor_height; - //gint upper_dynamic_size = upper_size; - //gint lower_dynamic_size = dynamic_size - upper_dynamic_size; - if (upper_size >= 0) { - if (upper_size > height - 2.0f * radius - anchor_height - 2 * padding) + if (upper_size > size - 2.0f * radius - anchor_height - 2 * padding) { //g_warning ("[_compute_full_mask_path] incorrect upper_size value"); HeightToAnchor = 0; } else { - HeightToAnchor = height - 2.0f * radius - anchor_height - 2 * padding - upper_size; + HeightToAnchor = size - 2.0f * radius - anchor_height - 2 * padding - upper_size; } } else { - HeightToAnchor = (height - 2.0f * radius - anchor_height - 2 * padding) / 2.0f; + if (launcher_position == LauncherPosition::LEFT) + HeightToAnchor = (size - 2.0f * radius - anchor_height - 2 * padding) / 2.0f; + else + HeightToAnchor = size - 2.0f * radius - anchor_height - 2 * padding; } cairo_translate(cr, -0.5f, -0.5f); // create path - cairo_move_to(cr, padding + anchor_width + radius + ZEROPOINT5, padding + ZEROPOINT5); // Point 1 - cairo_line_to(cr, width - padding - radius, padding + ZEROPOINT5); // Point 2 - cairo_arc(cr, - width - padding - radius + ZEROPOINT5, - padding + radius + ZEROPOINT5, - radius, - -90.0f * G_PI / 180.0f, - 0.0f * G_PI / 180.0f); // Point 4 - cairo_line_to(cr, - (gdouble) width - padding + ZEROPOINT5, - (gdouble) height - radius - padding + ZEROPOINT5); // Point 5 - cairo_arc(cr, - (gdouble) width - padding - radius + ZEROPOINT5, - (gdouble) height - padding - radius + ZEROPOINT5, - radius, - 0.0f * G_PI / 180.0f, - 90.0f * G_PI / 180.0f); // Point 7 - cairo_line_to(cr, - anchor_width + padding + radius + ZEROPOINT5, - (gdouble) height - padding + ZEROPOINT5); // Point 8 - - cairo_arc(cr, - anchor_width + padding + radius + ZEROPOINT5, - (gdouble) height - padding - radius, - radius, - 90.0f * G_PI / 180.0f, - 180.0f * G_PI / 180.0f); // Point 10 - - cairo_line_to(cr, - padding + anchor_width + ZEROPOINT5, - (gdouble) height - padding - radius - HeightToAnchor + ZEROPOINT5); // Point 11 - cairo_line_to(cr, - padding + ZEROPOINT5, - (gdouble) height - padding - radius - HeightToAnchor - anchor_height / 2.0f + ZEROPOINT5); // Point 12 - cairo_line_to(cr, - padding + anchor_width + ZEROPOINT5, - (gdouble) height - padding - radius - HeightToAnchor - anchor_height + ZEROPOINT5); // Point 13 - - cairo_line_to(cr, padding + anchor_width + ZEROPOINT5, padding + radius + ZEROPOINT5); // Point 14 - cairo_arc(cr, - padding + anchor_width + radius + ZEROPOINT5, - padding + radius + ZEROPOINT5, - radius, - 180.0f * G_PI / 180.0f, - 270.0f * G_PI / 180.0f); - + if (launcher_position == LauncherPosition::LEFT) + { + cairo_move_to(cr, padding + anchor_width + radius + ZEROPOINT5, padding + ZEROPOINT5); // Point 1 + cairo_line_to(cr, width - padding - radius, padding + ZEROPOINT5); // Point 2 + cairo_arc(cr, + width - padding - radius + ZEROPOINT5, + padding + radius + ZEROPOINT5, + radius, + -90.0f * G_PI / 180.0f, + 0.0f * G_PI / 180.0f); // Point 4 + cairo_line_to(cr, + (gdouble) width - padding + ZEROPOINT5, + (gdouble) height - radius - padding + ZEROPOINT5); // Point 5 + cairo_arc(cr, + (gdouble) width - padding - radius + ZEROPOINT5, + (gdouble) height - padding - radius + ZEROPOINT5, + radius, + 0.0f * G_PI / 180.0f, + 90.0f * G_PI / 180.0f); // Point 7 + cairo_line_to(cr, + anchor_width + padding + radius + ZEROPOINT5, + (gdouble) height - padding + ZEROPOINT5); // Point 8 + cairo_arc(cr, + anchor_width + padding + radius + ZEROPOINT5, + (gdouble) height - padding - radius, + radius, + 90.0f * G_PI / 180.0f, + 180.0f * G_PI / 180.0f); // Point 10 + cairo_line_to(cr, + padding + anchor_width + ZEROPOINT5, + (gdouble) height - padding - radius - HeightToAnchor + ZEROPOINT5); // Point 11 + cairo_line_to(cr, + padding + ZEROPOINT5, + (gdouble) height - padding - radius - HeightToAnchor - anchor_height / 2.0f + ZEROPOINT5); // Point 12 + cairo_line_to(cr, + padding + anchor_width + ZEROPOINT5, + (gdouble) height - padding - radius - HeightToAnchor - anchor_height + ZEROPOINT5); // Point 13 + cairo_line_to(cr, padding + anchor_width + ZEROPOINT5, padding + radius + ZEROPOINT5); // Point 14 + cairo_arc(cr, + padding + anchor_width + radius + ZEROPOINT5, + padding + radius + ZEROPOINT5, + radius, + 180.0f * G_PI / 180.0f, + 270.0f * G_PI / 180.0f); + } + else + { + cairo_move_to(cr, padding + radius + ZEROPOINT5, padding + ZEROPOINT5); // Point 1 + cairo_line_to(cr, width - padding - radius, padding + ZEROPOINT5); // Point 2 + cairo_arc(cr, + width - padding - radius + ZEROPOINT5, + padding + radius + ZEROPOINT5, + radius, + -90.0f * G_PI / 180.0f, + 0.0f * G_PI / 180.0f); // Point 4 + cairo_line_to(cr, + (gdouble) width - padding + ZEROPOINT5, + (gdouble) height - radius - anchor_width - padding + ZEROPOINT5); // Point 5 + cairo_arc(cr, + (gdouble) width - padding - radius + ZEROPOINT5, + (gdouble) height - padding - anchor_width - radius + ZEROPOINT5, + radius, + 0.0f * G_PI / 180.0f, + 90.0f * G_PI / 180.0f); // Point 7 + cairo_line_to(cr, + (gdouble) width - padding - radius - HeightToAnchor + ZEROPOINT5, + height - padding - anchor_width + ZEROPOINT5); // Point 8 + cairo_line_to(cr, + (gdouble) width - padding - radius - HeightToAnchor - anchor_height / 2.0f + ZEROPOINT5, + height - padding + ZEROPOINT5); // Point 9 + cairo_line_to(cr, + (gdouble) width - padding - radius - HeightToAnchor - anchor_height + ZEROPOINT5, + height - padding - anchor_width + ZEROPOINT5); // Point 10 + cairo_arc(cr, + padding + radius + ZEROPOINT5, + (gdouble) height - padding - anchor_width - radius, + radius, + 90.0f * G_PI / 180.0f, + 180.0f * G_PI / 180.0f); // Point 11 + cairo_line_to(cr, + padding + ZEROPOINT5, + (gdouble) height - padding -anchor_width - radius + ZEROPOINT5); // Point 13 + cairo_line_to(cr, padding + ZEROPOINT5, padding + radius + ZEROPOINT5); // Point 14 + cairo_arc(cr, + padding + radius + ZEROPOINT5, + padding + radius + ZEROPOINT5, + radius, + 180.0f * G_PI / 180.0f, + 270.0f * G_PI / 180.0f); + } cairo_close_path(cr); } diff --git a/launcher/SoftwareCenterLauncherIcon.cpp b/launcher/SoftwareCenterLauncherIcon.cpp index ef345a670..8c25549d2 100644 --- a/launcher/SoftwareCenterLauncherIcon.cpp +++ b/launcher/SoftwareCenterLauncherIcon.cpp @@ -31,6 +31,7 @@ #include "LauncherDragWindow.h" #include "LauncherModel.h" #include "DesktopUtilities.h" +#include "unity-shared/UnitySettings.h" namespace unity { diff --git a/launcher/Tooltip.cpp b/launcher/Tooltip.cpp index 42570f5a3..e7a0f8341 100644 --- a/launcher/Tooltip.cpp +++ b/launcher/Tooltip.cpp @@ -25,6 +25,7 @@ #include <unity-shared/CairoTexture.h> #include <unity-shared/RawPixel.h> #include <unity-shared/UnitySettings.h> +#include <unity-shared/UScreen.h> #include "unity-shared/DecorationStyle.h" #include "Tooltip.h" @@ -33,11 +34,14 @@ namespace unity { namespace { - const RawPixel ANCHOR_WIDTH = 14_em; - const RawPixel ANCHOR_HEIGHT = 18_em; - const RawPixel CORNER_RADIUS = 4_em; - const RawPixel TEXT_PADDING = 8_em; - const RawPixel MINIMUM_TEXT_WIDTH = 100_em; + const RawPixel ANCHOR_WIDTH = 14_em; + const RawPixel ANCHOR_HEIGHT = 18_em; + const RawPixel ROTATED_ANCHOR_WIDTH = 18_em; + const RawPixel ROTATED_ANCHOR_HEIGHT = 10_em; + const RawPixel CORNER_RADIUS = 4_em; + const RawPixel LEFT_SIZE = 4_em; + const RawPixel TEXT_PADDING = 8_em; + const RawPixel MINIMUM_TEXT_WIDTH = 100_em; } NUX_IMPLEMENT_OBJECT_TYPE(Tooltip); @@ -45,17 +49,30 @@ Tooltip::Tooltip(int monitor) : CairoBaseWindow(monitor), _anchorX(0), _anchorY(0), + _left_size(LEFT_SIZE), _padding(decoration::Style::Get()->ActiveShadowRadius()), _cairo_text_has_changed(true) { _hlayout = new nux::HLayout(TEXT(""), NUX_TRACKER_LOCATION); _vlayout = new nux::VLayout(TEXT(""), NUX_TRACKER_LOCATION); - _left_space = new nux::SpaceLayout(_padding.CP(cv_) + ANCHOR_WIDTH.CP(cv_), _padding.CP(cv_) + ANCHOR_WIDTH.CP(cv_), 1, 1000); + int left_space_width = 0; + int bottom_space_height = 0; + if (Settings::Instance().launcher_position() == LauncherPosition::LEFT) + { + left_space_width = _padding.CP(cv_) + ANCHOR_WIDTH.CP(cv_); + bottom_space_height = _padding.CP(cv_); + } + else + { + left_space_width = _padding.CP(cv_); + bottom_space_height = _padding.CP(cv_) + ROTATED_ANCHOR_HEIGHT.CP(cv_); + } + _left_space = new nux::SpaceLayout(left_space_width, left_space_width, 1, 1000); _right_space = new nux::SpaceLayout(_padding.CP(cv_) + CORNER_RADIUS.CP(cv_), _padding.CP(cv_) + CORNER_RADIUS.CP(cv_), 1, 1000); _top_space = new nux::SpaceLayout(1, 1000, _padding.CP(cv_), _padding.CP(cv_)); - _bottom_space = new nux::SpaceLayout(1, 1000, _padding.CP(cv_), _padding.CP(cv_)); + _bottom_space = new nux::SpaceLayout(1, 1000, bottom_space_height, bottom_space_height); _vlayout->AddLayout(_top_space, 0); @@ -96,6 +113,44 @@ Tooltip::Tooltip(int monitor) : SetLayout(_hlayout); } +int Tooltip::CalculateX() const +{ + int x = 0; + if (Settings::Instance().launcher_position() == LauncherPosition::LEFT) + { + x = _anchorX - _padding.CP(cv_); + } + else + { + int size = 0; + int max = GetBaseWidth() - ROTATED_ANCHOR_WIDTH.CP(cv_) - 2 * CORNER_RADIUS.CP(cv_) - 2 * _padding.CP(cv_); + if (_left_size.CP(cv_) > max) + { + size = max; + } + else if (_left_size.CP(cv_) > 0) + { + size = _left_size.CP(cv_); + } + x = _anchorX - (ROTATED_ANCHOR_WIDTH.CP(cv_) / 2) - size - CORNER_RADIUS.CP(cv_) - _padding.CP(cv_); + } + return x; +} + +int Tooltip::CalculateY() const +{ + int y = 0; + if (Settings::Instance().launcher_position() == LauncherPosition::LEFT) + { + y = _anchorY - ANCHOR_HEIGHT.CP(cv_) / 2 - CORNER_RADIUS.CP(cv_) - _padding.CP(cv_); + } + else + { + y = _anchorY - GetBaseHeight() + _padding.CP(cv_); + } + return y; +} + nux::Area* Tooltip::FindAreaUnderMouse(const nux::Point& mouse_position, nux::NuxEventType event_type) { // No area under mouse to allow click through to entities below @@ -107,10 +162,25 @@ void Tooltip::SetTooltipPosition(int tip_x, int tip_y) _anchorX = tip_x; _anchorY = tip_y; - int x = _anchorX - _padding.CP(cv_); - int y = _anchorY - ANCHOR_HEIGHT.CP(cv_) / 2 - CORNER_RADIUS.CP(cv_) - _padding.CP(cv_); + if (Settings::Instance().launcher_position() == LauncherPosition::BOTTOM) + { + auto* us = UScreen::GetDefault(); + int monitor = us->GetMonitorAtPosition(_anchorX, _anchorY); + auto const& monitor_geo = us->GetMonitorGeometry(monitor); + int offscreen_size_right = _anchorX + GetBaseWidth()/2 - (monitor_geo.x + monitor_geo.width); + int offscreen_size_left = monitor_geo.x - (_anchorX - GetBaseWidth()/2); + int half_size = (GetBaseWidth() / 2) - _padding.CP(cv_) - CORNER_RADIUS.CP(cv_) - (ROTATED_ANCHOR_WIDTH.CP(cv_) / 2); + + if (offscreen_size_left > 0) + _left_size = half_size - offscreen_size_left; + else if (offscreen_size_right > 0) + _left_size = half_size + offscreen_size_right; + else + _left_size = half_size; + _cairo_text_has_changed = true; + } - SetBaseXY(x, y); + SetBaseXY(CalculateX(), CalculateY()); } void Tooltip::ShowTooltipWithTipAt(int x, int y) @@ -149,7 +219,10 @@ void Tooltip::PreLayoutManagement() space_height += (ANCHOR_HEIGHT.CP(cv_) - text_height) / 2; _top_space->SetMinMaxSize(1, space_height); - _bottom_space->SetMinMaxSize(1, space_height + 1); + if (Settings::Instance().launcher_position() == LauncherPosition::LEFT) + _bottom_space->SetMinMaxSize(1, space_height + 1); + else + _bottom_space->SetMinMaxSize(1, space_height + ROTATED_ANCHOR_HEIGHT + 1); CairoBaseWindow::PreLayoutManagement(); } @@ -250,51 +323,120 @@ void _compute_full_mask_path(cairo_t* cr, gfloat anchor_height, gfloat width, gfloat height, - gint upper_size, + gint left_size, gfloat radius, guint pad) { - // 0 1 2 - // +------------+-+ - // / + 3 - // / | - // + 8 | - // \ | - // \ + 4 - // +------------+-+ - // 7 6 5 + // On the right of the icon: On the top of the icon: + // 0 1 2 0 1 2 3 + // +------------------+-+ +-+----------------+-+ + // / + 3 14 + + 4 + // / | | | + // + 8 | | | + // \ | | | + // \ + 4 13 + 10 8 + 5 + // +------------------+-+ +-+---+ +--------+-+ + // 7 6 5 12 11 \ / 7 6 + // + 9 gfloat padding = pad; cairo_translate(cr, -0.5f, -0.5f); // create path - cairo_move_to(cr, padding + anchor_width, padding); // Point 0 - cairo_line_to(cr, width - padding - radius, padding); // Point 1 - cairo_arc(cr, - width - padding - radius, - padding + radius, - radius, - -90.0f * G_PI / 180.0f, - 0.0f * G_PI / 180.0f); // Point 3 - cairo_line_to(cr, - (gdouble) width - padding, - (gdouble) height - radius - padding); // Point 4 - cairo_arc(cr, - (gdouble) width - padding - radius, - (gdouble) height - padding - radius, - radius, - 0.0f * G_PI / 180.0f, - 90.0f * G_PI / 180.0f); // Point 6 - cairo_line_to(cr, - anchor_width + padding, - (gdouble) height - padding); // Point 7 - - cairo_line_to(cr, - padding, - (gdouble) height / 2.0f); // Point 8 + if (Settings::Instance().launcher_position() == LauncherPosition::LEFT) + { + cairo_move_to(cr, padding + anchor_width, padding); // Point 0 + cairo_line_to(cr, width - padding - radius, padding); // Point 1 + cairo_arc(cr, + width - padding - radius, + padding + radius, + radius, + -90.0f * G_PI / 180.0f, + 0.0f * G_PI / 180.0f); // Point 3 + cairo_line_to(cr, + (gdouble) width - padding, + (gdouble) height - radius - padding); // Point 4 + cairo_arc(cr, + (gdouble) width - padding - radius, + (gdouble) height - padding - radius, + radius, + 0.0f * G_PI / 180.0f, + 90.0f * G_PI / 180.0f); // Point 6 + cairo_line_to(cr, + anchor_width + padding, + (gdouble) height - padding); // Point 7 + + cairo_line_to(cr, + padding, + (gdouble) height / 2.0f); // Point 8 + } + else + { + gfloat WidthToAnchor = ((gfloat) width - 2.0f * radius - anchor_width - 2 * padding) / 2.0f; + if (WidthToAnchor < 0.0f) + { + g_warning("Anchor-width and corner-radius a wider than whole texture!"); + return; + } + if (left_size > width - 2.0f * radius - anchor_width - 2 * padding) + { + WidthToAnchor = 0; + } + else if (left_size < 0) + { + WidthToAnchor = width - 2.0f * radius - anchor_width - 2 * padding; + } + else + { + WidthToAnchor = width - 2.0f * radius - anchor_width - 2 * padding - left_size; + } + + cairo_move_to(cr, padding + radius, padding); // Point 1 + cairo_line_to(cr, width - padding - radius, padding); // Point 2 + cairo_arc(cr, + width - padding - radius, + padding + radius, + radius, + -90.0f * G_PI / 180.0f, + 0.0f * G_PI / 180.0f); // Point 4 + cairo_line_to(cr, + (gdouble) width - padding, + (gdouble) height - radius - anchor_height - padding); // Point 5 + cairo_arc(cr, + (gdouble) width - padding - radius, + (gdouble) height - padding - anchor_height - radius, + radius, + 0.0f * G_PI / 180.0f, + 90.0f * G_PI / 180.0f); // Point 7 + cairo_line_to(cr, + (gdouble) width - padding - radius - WidthToAnchor, + height - padding - anchor_height); // Point 8 + cairo_line_to(cr, + (gdouble) width - padding - radius - WidthToAnchor - anchor_width / 2.0f, + height - padding); // Point 9 + cairo_line_to(cr, + (gdouble) width - padding - radius - WidthToAnchor - anchor_width, + height - padding - anchor_height); // Point 10 + cairo_arc(cr, + padding + radius, + (gdouble) height - padding - anchor_height - radius, + radius, + 90.0f * G_PI / 180.0f, + 180.0f * G_PI / 180.0f); // Point 11 + cairo_line_to(cr, + padding, + (gdouble) height - padding -anchor_height - radius); // Point 13 + cairo_line_to(cr, padding, padding + radius); // Point 14 + cairo_arc(cr, + padding + radius, + padding + radius, + radius, + 180.0f * G_PI / 180.0f, + 270.0f * G_PI / 180.0f); + } cairo_close_path(cr); } @@ -388,7 +530,7 @@ compute_full_outline_shadow( gfloat height, gfloat anchor_width, gfloat anchor_height, - gint upper_size, + gint left_size, gfloat corner_radius, guint blur_coeff, nux::Color const& shadow_color, @@ -402,7 +544,7 @@ compute_full_outline_shadow( anchor_height, width, height, - upper_size, + left_size, corner_radius, padding_size); @@ -421,7 +563,7 @@ void compute_full_mask( gfloat radius, gfloat anchor_width, gfloat anchor_height, - gint upper_size, + gint left_size, gboolean negative, gboolean outline, gfloat line_width, @@ -434,7 +576,7 @@ void compute_full_mask( anchor_height, width, height, - upper_size, + left_size, radius, padding_size); _finalize(&cr, outline, line_width, color, negative, outline); @@ -445,12 +587,22 @@ void Tooltip::UpdateTexture() if (_cairo_text_has_changed == false) return; + SetTooltipPosition(_anchorX, _anchorY); + int width = GetBaseWidth(); int height = GetBaseHeight(); - - int x = _anchorX - _padding.CP(cv_); - int y = _anchorY - height / 2; - SetXY(x, y); + int anchor_width = 0; + int anchor_height = 0; + if (Settings::Instance().launcher_position == LauncherPosition::LEFT) + { + anchor_width = ANCHOR_WIDTH; + anchor_height = ANCHOR_HEIGHT; + } + else + { + anchor_width = ROTATED_ANCHOR_WIDTH; + anchor_height = ROTATED_ANCHOR_HEIGHT; + } auto const& deco_style = decoration::Style::Get(); float dpi_scale = cv_->DPIScale(); @@ -499,9 +651,9 @@ void Tooltip::UpdateTexture() cairo_outline.GetSurface(), width / dpi_scale, height / dpi_scale, - ANCHOR_WIDTH, - ANCHOR_HEIGHT, - -1, + anchor_width, + anchor_height, + _left_size, CORNER_RADIUS, blur_coef, shadow_color, @@ -515,9 +667,9 @@ void Tooltip::UpdateTexture() width / dpi_scale, height / dpi_scale, CORNER_RADIUS, // radius, - ANCHOR_WIDTH, // anchor_width, - ANCHOR_HEIGHT, // anchor_height, - -1, // upper_size, + anchor_width, // anchor_width, + anchor_height, // anchor_height, + _left_size, // left_size, true, // negative, false, // outline, 1.0, // line_width, diff --git a/launcher/Tooltip.h b/launcher/Tooltip.h index aab4696f1..431180d6f 100644 --- a/launcher/Tooltip.h +++ b/launcher/Tooltip.h @@ -73,8 +73,12 @@ private: void NotifyConfigurationChange(int width, int height); + int CalculateX() const; + int CalculateY() const; + int _anchorX; int _anchorY; + RawPixel _left_size; // size of the segment from point 10 to 11, used when launcher at bottom. RawPixel _padding; nux::HLayout* _hlayout; diff --git a/panel/PanelView.cpp b/panel/PanelView.cpp index 4a5982843..e80ebca74 100644 --- a/panel/PanelView.cpp +++ b/panel/PanelView.cpp @@ -367,7 +367,8 @@ PanelView::Draw(nux::GraphicsEngine& GfxContext, bool force_draw) int refine_x_pos = geo.x + (stored_dash_width_ - refine_gradient_midpoint); - refine_x_pos += unity::Settings::Instance().LauncherWidth(monitor_); + if (Settings::Instance().launcher_position() == LauncherPosition::LEFT) + refine_x_pos += unity::Settings::Instance().LauncherSize(monitor_); GfxContext.QRP_1Tex(refine_x_pos, geo.y, bg_refine_tex_->GetWidth(), bg_refine_tex_->GetHeight(), @@ -464,7 +465,8 @@ PanelView::DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw) nux::Geometry refine_geo = geo; int refine_x_pos = geo.x + (stored_dash_width_ - refine_gradient_midpoint); - refine_x_pos += unity::Settings::Instance().LauncherWidth(monitor_); + if (Settings::Instance().launcher_position() == LauncherPosition::LEFT) + refine_x_pos += unity::Settings::Instance().LauncherSize(monitor_); refine_geo.x = refine_x_pos; refine_geo.width = bg_refine_tex_->GetWidth(); diff --git a/plugins/unityshell/src/unityshell.cpp b/plugins/unityshell/src/unityshell.cpp index 514eb2c83..2ddf8c6c9 100644 --- a/plugins/unityshell/src/unityshell.cpp +++ b/plugins/unityshell/src/unityshell.cpp @@ -77,6 +77,7 @@ #include "UScreen.h" #include "config.h" +#include "unity-shared/UnitySettings.h" /* FIXME: once we get a better method to add the toplevel windows to the accessible root object, this include would not be required */ @@ -3813,9 +3814,9 @@ bool UnityScreen::layoutSlotsAndAssignWindows() } auto max_bounds = NuxGeometryFromCompRect(output.workArea()); - if (launcher_controller_->options()->hide_mode != LAUNCHER_HIDE_NEVER) + if (launcher_controller_->options()->hide_mode != LAUNCHER_HIDE_NEVER && Settings::Instance().launcher_position() == LauncherPosition::LEFT) { - int monitor_width = unity_settings_.LauncherWidth(monitor); + int monitor_width = unity_settings_.LauncherSize(monitor); max_bounds.x += monitor_width; max_bounds.width -= monitor_width; } @@ -4058,22 +4059,35 @@ void UnityScreen::InitUnityComponents() manager->PromptLockScreen(); auto on_launcher_size_changed = [this] (nux::Area* area, int w, int h) { - /* The launcher geometry includes 1px used to draw the right margin + /* The launcher geometry includes 1px used to draw the right/top margin * that must not be considered when drawing an overlay */ auto* launcher = static_cast<Launcher*>(area); - int launcher_width = w - (1_em).CP(unity_settings_.em(launcher->monitor)->DPIScale()); + auto launcher_position = Settings::Instance().launcher_position(); - unity::Settings::Instance().SetLauncherWidth(launcher_width, launcher->monitor); - shortcut_controller_->SetAdjustment(launcher_width, panel_style_.PanelHeight(launcher->monitor)); + int size = 0; + if (launcher_position == LauncherPosition::LEFT) + size = w; + else + size = h; + int launcher_size = size - (1_em).CP(unity_settings_.em(launcher->monitor)->DPIScale()); + + unity::Settings::Instance().SetLauncherSize(launcher_size, launcher->monitor); + int adjustment_x = 0; + if (launcher_position == LauncherPosition::LEFT) + adjustment_x = launcher_size; + shortcut_controller_->SetAdjustment(adjustment_x, panel_style_.PanelHeight(launcher->monitor)); - CompOption::Value v(launcher_width); - screen->setOptionForPlugin("expo", "x_offset", v); + if (launcher_position == LauncherPosition::LEFT) + { + CompOption::Value v(launcher_size); + screen->setOptionForPlugin("expo", "x_offset", v); - if (launcher_controller_->options()->hide_mode == LAUNCHER_HIDE_NEVER) - v.set(0); + if (launcher_controller_->options()->hide_mode == LAUNCHER_HIDE_NEVER) + v.set(0); - screen->setOptionForPlugin("scale", "x_offset", v); + screen->setOptionForPlugin("scale", "x_offset", v); + } }; auto check_launchers_size = [this, on_launcher_size_changed] { diff --git a/resources/dash_bottom_right_corner_rotated.png b/resources/dash_bottom_right_corner_rotated.png Binary files differnew file mode 100644 index 000000000..ec458a101 --- /dev/null +++ b/resources/dash_bottom_right_corner_rotated.png diff --git a/resources/dash_bottom_right_corner_rotated_mask.png b/resources/dash_bottom_right_corner_rotated_mask.png Binary files differnew file mode 100644 index 000000000..a0b8fe006 --- /dev/null +++ b/resources/dash_bottom_right_corner_rotated_mask.png diff --git a/resources/dash_bottom_tile.png b/resources/dash_bottom_tile.png Binary files differnew file mode 100644 index 000000000..963a034df --- /dev/null +++ b/resources/dash_bottom_tile.png diff --git a/resources/dash_top_border_tile.png b/resources/dash_top_border_tile.png Binary files differnew file mode 100644 index 000000000..a90e10432 --- /dev/null +++ b/resources/dash_top_border_tile.png diff --git a/resources/dash_top_border_tile_mask.png b/resources/dash_top_border_tile_mask.png Binary files differnew file mode 100644 index 000000000..bc030c827 --- /dev/null +++ b/resources/dash_top_border_tile_mask.png diff --git a/resources/dash_top_left_corner.png b/resources/dash_top_left_corner.png Binary files differnew file mode 100644 index 000000000..c3b8de33d --- /dev/null +++ b/resources/dash_top_left_corner.png diff --git a/resources/dash_top_left_corner_mask.png b/resources/dash_top_left_corner_mask.png Binary files differnew file mode 100644 index 000000000..7f9e7e0c3 --- /dev/null +++ b/resources/dash_top_left_corner_mask.png diff --git a/resources/dash_top_right_corner_rotated.png b/resources/dash_top_right_corner_rotated.png Binary files differnew file mode 100644 index 000000000..7d2a1337e --- /dev/null +++ b/resources/dash_top_right_corner_rotated.png diff --git a/resources/dash_top_right_corner_rotated_mask.png b/resources/dash_top_right_corner_rotated_mask.png Binary files differnew file mode 100644 index 000000000..b17cf351e --- /dev/null +++ b/resources/dash_top_right_corner_rotated_mask.png diff --git a/resources/launcher_arrow_btt_19.svg b/resources/launcher_arrow_btt_19.svg new file mode 100644 index 000000000..19381e620 --- /dev/null +++ b/resources/launcher_arrow_btt_19.svg @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg version="1.1" + id="svg2" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" inkscape:version="0.48+devel r" sodipodi:docname="launcher_arrow_ltr.svg" inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="test.png" + xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="18.992px" + height="10.006px" viewBox="0 0 18.992 10.006" enable-background="new 0 0 18.992 10.006" xml:space="preserve"> +<sodipodi:namedview id="base" inkscape:cx="6.1247407" showgrid="true" borderopacity="1.0" bordercolor="#666666" inkscape:cy="9.1968087" pagecolor="#5c48bb" inkscape:bbox-nodes="true" inkscape:bbox-paths="true" inkscape:snap-bbox="true" inkscape:snap-text-baseline="false" inkscape:snap-object-midpoints="true" inkscape:snap-smooth-nodes="true" inkscape:snap-intersection-paths="true" inkscape:snap-bbox-midpoints="true" inkscape:snap-bbox-edge-midpoints="true" inkscape:window-maximized="1" inkscape:zoom="59.292307" inkscape:window-y="24" inkscape:window-x="65" inkscape:window-height="1056" inkscape:window-width="1855" inkscape:current-layer="layer1" inkscape:document-units="px" inkscape:pageshadow="2" inkscape:pageopacity="0" inkscape:snap-page="true" inkscape:snap-center="true" inkscape:snap-midpoints="true" inkscape:object-nodes="true" inkscape:object-paths="true"> + <inkscape:grid type="xygrid" enabled="true" visible="true" id="grid4740" snapvisiblegridlinesonly="true" empspacing="8"> + </inkscape:grid> +</sodipodi:namedview> +<g id="layer1" transform="translate(0,-1033.3622)" inkscape:label="Layer 1" inkscape:groupmode="layer"> + <path id="path5726" inkscape:connector-curvature="0" sodipodi:nodetypes="cccc" opacity="0.14" enable-background="new " d=" + M4.696,1043.368l4.8-6.316l4.8,6.316H4.696z"/> + <path id="path4097" inkscape:connector-curvature="0" sodipodi:nodetypes="cccc" fill="#FFFFFF" d="M5.696,1043.368l3.8-5.001 + l3.802,5.001H5.696z"/> +</g> +</svg> diff --git a/resources/launcher_arrow_btt_37.svg b/resources/launcher_arrow_btt_37.svg new file mode 100644 index 000000000..4cbc36e8a --- /dev/null +++ b/resources/launcher_arrow_btt_37.svg @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg version="1.1" + id="svg2" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" inkscape:version="0.48+devel r" sodipodi:docname="launcher_arrow_large_ltr.svg" inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="test.png" + xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="36.992px" + height="20.012px" viewBox="0 0 36.992 20.012" enable-background="new 0 0 36.992 20.012" xml:space="preserve"> +<sodipodi:namedview id="base" inkscape:cx="-5.367523" showgrid="true" borderopacity="1.0" bordercolor="#666666" inkscape:cy="31.963893" pagecolor="#5c48bb" inkscape:bbox-nodes="true" inkscape:bbox-paths="true" inkscape:snap-bbox="true" inkscape:snap-object-midpoints="true" inkscape:snap-smooth-nodes="true" inkscape:snap-intersection-paths="true" inkscape:snap-bbox-midpoints="true" inkscape:snap-bbox-edge-midpoints="true" inkscape:window-maximized="1" showguides="false" inkscape:zoom="9.3132256" inkscape:snap-grids="false" inkscape:guide-bbox="true" inkscape:window-y="24" inkscape:window-x="65" inkscape:window-height="1056" inkscape:window-width="1855" inkscape:current-layer="layer1" inkscape:document-units="px" inkscape:pageshadow="2" inkscape:pageopacity="0" inkscape:snap-page="true" inkscape:snap-center="true" inkscape:snap-midpoints="true" inkscape:object-nodes="true" inkscape:object-paths="true"> + <inkscape:grid type="xygrid" enabled="true" visible="true" id="grid4740" snapvisiblegridlinesonly="true" empspacing="8"> + </inkscape:grid> + <sodipodi:guide id="guide3004" position="8,19" orientation="0,1"></sodipodi:guide> +</sodipodi:namedview> +<g id="layer1" transform="translate(0,-1015.3622)" inkscape:label="Layer 1" inkscape:groupmode="layer"> + + <path id="path5730" inkscape:connector-curvature="0" inkscape:transform-center-x="16.337474" sodipodi:nodetypes="cccc" opacity="0.14" enable-background="new " d=" + M8.014,1035.374l9.944-12.785l9.945,12.785H8.014z"/> + + <path id="path4079" inkscape:connector-curvature="0" inkscape:transform-center-x="14.694444" sodipodi:nodetypes="cccc" fill="#FFFFFF" d=" + M9.014,1035.374l8.944-11.5l8.944,11.5H9.014z"/> +</g> +</svg> diff --git a/resources/launcher_arrow_outline_btt_19.svg b/resources/launcher_arrow_outline_btt_19.svg new file mode 100644 index 000000000..d662d9120 --- /dev/null +++ b/resources/launcher_arrow_outline_btt_19.svg @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg version="1.1" + id="svg2" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" inkscape:version="0.48+devel r" sodipodi:docname="launcher_arrow_outline_ltr.svg" inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="test.png" + xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="18.992px" + height="10.006px" viewBox="0 0 18.992 10.006" enable-background="new 0 0 18.992 10.006" xml:space="preserve"> +<sodipodi:namedview id="base" inkscape:cx="2.8593254" showgrid="true" borderopacity="1.0" bordercolor="#666666" inkscape:cy="8.2525377" pagecolor="#5c48bb" inkscape:bbox-nodes="true" inkscape:bbox-paths="true" inkscape:snap-bbox="true" inkscape:snap-text-baseline="false" inkscape:snap-object-midpoints="true" inkscape:snap-smooth-nodes="true" inkscape:snap-intersection-paths="true" inkscape:snap-bbox-midpoints="true" inkscape:snap-bbox-edge-midpoints="true" inkscape:window-maximized="1" inkscape:zoom="92.64423" inkscape:window-y="24" inkscape:window-x="65" inkscape:window-height="1056" inkscape:window-width="1855" inkscape:current-layer="layer1" inkscape:document-units="px" inkscape:pageshadow="2" inkscape:pageopacity="0" inkscape:snap-page="true" inkscape:snap-center="true" inkscape:snap-midpoints="true" inkscape:object-nodes="true" inkscape:object-paths="true"> + <inkscape:grid type="xygrid" enabled="true" visible="true" id="grid4740" snapvisiblegridlinesonly="true" empspacing="8"> + </inkscape:grid> +</sodipodi:namedview> +<path id="path5726" opacity="0.14" enable-background="new " d="M5.008,10.006h3.496L9.809,8.29l1.305,1.716h3.496L9.809,3.689 + L5.008,10.006z"/> +<path id="path4097" fill="#FFFFFF" d="M6.008,10.006h1.52l2.281-3l2.281,3h1.52l-3.801-5L6.008,10.006z"/> +</svg> diff --git a/resources/launcher_arrow_outline_btt_37.svg b/resources/launcher_arrow_outline_btt_37.svg new file mode 100644 index 000000000..f7d64072c --- /dev/null +++ b/resources/launcher_arrow_outline_btt_37.svg @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg version="1.1" + id="svg2" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" inkscape:version="0.48+devel r" sodipodi:docname="launcher_arrow_large_outline_ltr.svg" inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="test.png" + xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="36.992px" + height="20.012px" viewBox="0 0 36.992 20.012" enable-background="new 0 0 36.992 20.012" xml:space="preserve"> +<sodipodi:namedview id="base" inkscape:cx="-2.301892" showgrid="true" borderopacity="1.0" bordercolor="#666666" inkscape:cy="19.020977" pagecolor="#5c48bb" inkscape:bbox-nodes="true" inkscape:bbox-paths="true" inkscape:snap-bbox="true" inkscape:snap-object-midpoints="true" inkscape:snap-smooth-nodes="true" inkscape:snap-intersection-paths="true" inkscape:snap-bbox-midpoints="true" inkscape:snap-bbox-edge-midpoints="true" inkscape:window-maximized="1" showguides="false" inkscape:zoom="22.737367" inkscape:snap-grids="false" inkscape:guide-bbox="true" inkscape:window-y="24" inkscape:window-x="65" inkscape:window-height="1056" inkscape:window-width="1855" inkscape:current-layer="layer1" inkscape:document-units="px" inkscape:pageshadow="2" inkscape:pageopacity="0" inkscape:snap-page="true" inkscape:snap-center="true" inkscape:snap-midpoints="true" inkscape:object-nodes="true" inkscape:object-paths="true"> + <inkscape:grid type="xygrid" enabled="true" visible="true" id="grid4740" snapvisiblegridlinesonly="true" empspacing="8"> + </inkscape:grid> + <sodipodi:guide id="guide3004" position="8,19" orientation="0,1"></sodipodi:guide> +</sodipodi:namedview> +<g id="layer1" transform="translate(0,-1015.3622)" inkscape:label="Layer 1" inkscape:groupmode="layer"> + <path id="path5730" inkscape:connector-curvature="0" opacity="0.14" enable-background="new " d="M8.551,1035.374l9.945-12.785 + l9.946,12.785h-4.899l-5.045-6.486l-5.045,6.486H8.551z"/> + <path id="path4079" inkscape:connector-curvature="0" fill="#FFFFFF" d="M9.551,1035.374h2.957l5.988-7.699l5.989,7.699h2.957 + l-8.946-11.5L9.551,1035.374z"/> +</g> +</svg> diff --git a/resources/launcher_arrow_ttb_19.svg b/resources/launcher_arrow_ttb_19.svg new file mode 100644 index 000000000..8600850ce --- /dev/null +++ b/resources/launcher_arrow_ttb_19.svg @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg version="1.1" + id="svg2" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" inkscape:version="0.48+devel r" sodipodi:docname="launcher_arrow_ltr.svg" inkscape:export-xdpi="90" inkscape:export-ydpi="90" inkscape:export-filename="test.png" + xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="18.992px" + height="10.006px" viewBox="0 0 18.992 10.006" enable-background="new 0 0 18.992 10.006" xml:space="preserve"> +<sodipodi:namedview id="base" inkscape:cx="6.1247407" inkscape:window-maximized="1" inkscape:snap-bbox-edge-midpoints="true" inkscape:snap-bbox-midpoints="true" inkscape:snap-intersection-paths="true" inkscape:snap-smooth-nodes="true" inkscape:snap-object-midpoints="true" inkscape:snap-text-baseline="false" pagecolor="#5c48bb" inkscape:cy="9.1968087" bordercolor="#666666" borderopacity="1.0" showgrid="true" inkscape:zoom="59.292307" inkscape:snap-bbox="true" inkscape:bbox-paths="true" inkscape:bbox-nodes="true" inkscape:object-paths="true" inkscape:object-nodes="true" inkscape:snap-midpoints="true" inkscape:snap-center="true" inkscape:snap-page="true" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:document-units="px" inkscape:current-layer="layer1" inkscape:window-width="1855" inkscape:window-height="1056" inkscape:window-x="65" inkscape:window-y="24"> + <inkscape:grid type="xygrid" visible="true" enabled="true" id="grid4740" snapvisiblegridlinesonly="true" empspacing="8"> + </inkscape:grid> +</sodipodi:namedview> +<path id="path5726" inkscape:connector-curvature="0" sodipodi:nodetypes="cccc" opacity="0.14" enable-background="new " d=" + M14.296,0l-4.8,6.316L4.696,0H14.296z"/> +<path id="path4097" inkscape:connector-curvature="0" sodipodi:nodetypes="cccc" fill="#FFFFFF" d="M13.296,0l-3.8,5L5.695,0H13.296 + z"/> +</svg> diff --git a/resources/launcher_arrow_ttb_37.svg b/resources/launcher_arrow_ttb_37.svg new file mode 100644 index 000000000..dcc3f9ba4 --- /dev/null +++ b/resources/launcher_arrow_ttb_37.svg @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg version="1.1" + id="svg2" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" inkscape:version="0.48+devel r" sodipodi:docname="launcher_arrow_large_ltr.svg" inkscape:export-xdpi="90" inkscape:export-ydpi="90" inkscape:export-filename="test.png" + xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="36.992px" + height="20.012px" viewBox="0 0 36.992 20.012" enable-background="new 0 0 36.992 20.012" xml:space="preserve"> +<sodipodi:namedview id="base" inkscape:cx="-5.367523" inkscape:window-maximized="1" inkscape:snap-bbox-edge-midpoints="true" inkscape:snap-bbox-midpoints="true" inkscape:snap-intersection-paths="true" inkscape:snap-smooth-nodes="true" inkscape:snap-object-midpoints="true" showguides="false" pagecolor="#5c48bb" inkscape:cy="31.963893" bordercolor="#666666" borderopacity="1.0" showgrid="true" inkscape:zoom="9.3132256" inkscape:snap-bbox="true" inkscape:bbox-paths="true" inkscape:bbox-nodes="true" inkscape:object-paths="true" inkscape:object-nodes="true" inkscape:snap-midpoints="true" inkscape:snap-center="true" inkscape:snap-page="true" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:document-units="px" inkscape:current-layer="layer1" inkscape:window-width="1855" inkscape:window-height="1056" inkscape:window-x="65" inkscape:window-y="24" inkscape:guide-bbox="true" inkscape:snap-grids="false"> + <inkscape:grid type="xygrid" visible="true" enabled="true" id="grid4740" snapvisiblegridlinesonly="true" empspacing="8"> + </inkscape:grid> + <sodipodi:guide id="guide3004" orientation="0,1" position="8,19"></sodipodi:guide> +</sodipodi:namedview> +<g id="layer1" transform="translate(0,-1015.3622)" inkscape:label="Layer 1" inkscape:groupmode="layer"> + + <path id="path5730" inkscape:connector-curvature="0" sodipodi:nodetypes="cccc" inkscape:transform-center-x="16.337474" opacity="0.14" enable-background="new " d=" + M28.646,1015.362l-9.943,12.785l-9.945-12.785H28.646z"/> + + <path id="path4079" inkscape:connector-curvature="0" sodipodi:nodetypes="cccc" inkscape:transform-center-x="14.694444" fill="#FFFFFF" d=" + M27.647,1015.362l-8.944,11.5l-8.945-11.5H27.647z"/> +</g> +</svg> diff --git a/resources/launcher_pip_btt_19.svg b/resources/launcher_pip_btt_19.svg new file mode 100644 index 000000000..1bb4cbe1e --- /dev/null +++ b/resources/launcher_pip_btt_19.svg @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg version="1.1" + id="svg2" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" inkscape:version="0.48+devel r" sodipodi:docname="launcher_pip_ltr.svg" inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="test.png" + xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="18.992px" + height="10.006px" viewBox="0 0 18.992 10.006" enable-background="new 0 0 18.992 10.006" xml:space="preserve"> +<sodipodi:namedview id="base" inkscape:cx="6.9043528" showgrid="true" borderopacity="1.0" bordercolor="#666666" inkscape:cy="9.653247" pagecolor="#5c48bb" inkscape:bbox-nodes="true" inkscape:bbox-paths="true" inkscape:snap-bbox="true" inkscape:snap-text-baseline="false" inkscape:snap-object-midpoints="true" inkscape:snap-smooth-nodes="true" inkscape:snap-intersection-paths="true" inkscape:snap-bbox-midpoints="true" inkscape:snap-bbox-edge-midpoints="true" inkscape:window-maximized="1" inkscape:zoom="30.357661" inkscape:window-y="24" inkscape:window-x="65" inkscape:window-height="1056" inkscape:window-width="1855" inkscape:current-layer="layer1" inkscape:document-units="px" inkscape:pageshadow="2" inkscape:pageopacity="0" inkscape:snap-page="true" inkscape:snap-center="true" inkscape:snap-midpoints="true" inkscape:object-nodes="true" inkscape:object-paths="true"> + <inkscape:grid type="xygrid" enabled="true" visible="true" id="grid4740" snapvisiblegridlinesonly="true" empspacing="8"> + </inkscape:grid> +</sodipodi:namedview> +<g id="layer1" transform="translate(0,-1033.3622)" inkscape:label="Layer 1" inkscape:groupmode="layer"> + <path id="path5728" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccc" opacity="0.14" enable-background="new " d=" + M6.996,1043.368v-3.5l2.5-3l2.5,3v3.5H6.996z"/> + <path id="path4742" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccc" fill="#FFFFFF" d="M7.996,1043.368v-3l1.5-2 + l1.5,2v3H7.996z"/> +</g> +</svg> diff --git a/resources/launcher_pip_btt_37.svg b/resources/launcher_pip_btt_37.svg new file mode 100644 index 000000000..bfe405cef --- /dev/null +++ b/resources/launcher_pip_btt_37.svg @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg version="1.1" + id="svg2" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" inkscape:export-xdpi="90" inkscape:export-ydpi="90" sodipodi:docname="launcher_pip_large_ltr.svg" inkscape:version="0.48+devel r" inkscape:export-filename="test.png" + xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 37 20" + enable-background="new 0 0 37 20" xml:space="preserve"> +<sodipodi:namedview id="base" pagecolor="#5c48bb" inkscape:zoom="28.42171" showguides="false" inkscape:cy="12.499554" bordercolor="#666666" borderopacity="1.0" showgrid="true" inkscape:cx="3.9411358" inkscape:snap-global="true" inkscape:object-paths="true" inkscape:object-nodes="true" inkscape:snap-midpoints="true" inkscape:snap-center="true" inkscape:snap-page="true" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:document-units="px" inkscape:current-layer="layer1" inkscape:window-width="1855" inkscape:window-height="1056" inkscape:window-x="65" inkscape:window-y="24" inkscape:guide-bbox="true" inkscape:snap-bbox="true" inkscape:bbox-paths="true" inkscape:bbox-nodes="true" inkscape:window-maximized="1" inkscape:snap-bbox-edge-midpoints="true" inkscape:snap-bbox-midpoints="true" inkscape:snap-intersection-paths="true" inkscape:snap-smooth-nodes="true" inkscape:snap-object-midpoints="true"> + <inkscape:grid type="xygrid" enabled="true" id="grid4740" visible="true" empspacing="8" snapvisiblegridlinesonly="true"> + </inkscape:grid> + <sodipodi:guide id="guide3004" orientation="0,1" position="8,19"></sodipodi:guide> +</sodipodi:namedview> +<g id="layer1" transform="translate(0,-1015.3622)" inkscape:label="Layer 1" inkscape:groupmode="layer"> + <path id="path5745" sodipodi:nodetypes="cccccc" inkscape:connector-curvature="0" opacity="0.14" enable-background="new " d=" + M14,1035.4v-7.5l4.5-5.5l4.5,5.5v7.5H14z"/> + <path id="path4742" sodipodi:nodetypes="cccccc" inkscape:connector-curvature="0" fill="#FFFFFF" d="M15,1035.4v-7l3.5-4.5 + l3.5,4.5v7H15z"/> +</g> +</svg> diff --git a/resources/launcher_pressure_effect_rotated.png b/resources/launcher_pressure_effect_rotated.png Binary files differnew file mode 100644 index 000000000..de5dfbac5 --- /dev/null +++ b/resources/launcher_pressure_effect_rotated.png diff --git a/tests/autopilot/unity/emulators/__init__.py b/tests/autopilot/unity/emulators/__init__.py index f10173c37..fd6c6aee1 100644 --- a/tests/autopilot/unity/emulators/__init__.py +++ b/tests/autopilot/unity/emulators/__init__.py @@ -20,7 +20,14 @@ from autopilot.introspection.backends import DBusAddress from dbus import DBusException - +keys = { + "Left/launcher/keynav/prev": "launcher/keynav/prev", + "Left/launcher/keynav/next": "launcher/keynav/next", + "Left/launcher/keynav/open-quicklist": "launcher/keynav/open-quicklist", + "Bottom/launcher/keynav/prev": "launcher/keynav/close-quicklist", + "Bottom/launcher/keynav/next": "launcher/keynav/open-quicklist", + "Bottom/launcher/keynav/open-quicklist": "launcher/keynav/prev", +} class UnityIntrospectionObject(CustomEmulatorBase): DBUS_SERVICE = "com.canonical.Unity" diff --git a/tests/autopilot/unity/emulators/launcher.py b/tests/autopilot/unity/emulators/launcher.py index 5786079f8..f846f3c75 100644 --- a/tests/autopilot/unity/emulators/launcher.py +++ b/tests/autopilot/unity/emulators/launcher.py @@ -17,6 +17,7 @@ from testtools.matchers import NotEquals from time import sleep from unity.emulators import UnityIntrospectionObject +from unity.emulators import keys from unity.emulators.icons import ( ApplicationLauncherIcon, BFBLauncherIcon, @@ -37,6 +38,10 @@ class IconDragType: BEFORE = 3 AFTER = 4 +class LauncherPosition: + """Define launcher possible positions""" + LEFT = "Left" + BOTTOM = "Bottom" class LauncherController(UnityIntrospectionObject): """The LauncherController class.""" @@ -104,12 +109,16 @@ class Launcher(UnityIntrospectionObject, KeybindingsHelper): """Places the mouse on the screen of this launcher.""" move_mouse_to_screen(self.monitor) - def move_mouse_to_right_of_launcher(self): + def move_mouse_beside_launcher(self): """Places the mouse to the right of this launcher.""" move_mouse_to_screen(self.monitor) (x, y, w, h) = self.geometry - target_x = x + w + 10 - target_y = y + h / 2 + if h > w: + target_x = x + w + 10 + target_y = y + h / 2 + else: + target_x = x + w / 2 + target_y = y - 10 logger.debug("Moving mouse away from launcher.") self._mouse.move(target_x, target_y, False) @@ -153,8 +162,13 @@ class Launcher(UnityIntrospectionObject, KeybindingsHelper): move_mouse_to_screen(self.monitor) (x, y, w, h) = self.geometry - target_x = x - 300 # this is the pressure we need to reveal the launcher. - target_y = y + h / 2 + if h > w: + target_x = x - 300 # this is the pressure we need to reveal the launcher. + target_y = y + h / 2 + else: + target_x = x + w / 2 + target_y = y + h + 300 + logger.debug("Revealing launcher on monitor %d with mouse.", self.monitor) self._mouse.move(target_x, target_y, True, 5, .002) @@ -177,7 +191,7 @@ class Launcher(UnityIntrospectionObject, KeybindingsHelper): if self.hidemode == 1: self.is_showing.wait_for(False) - def keyboard_select_icon(self, **kwargs): + def keyboard_select_icon(self, launcher_position = LauncherPosition.LEFT, **kwargs): """Using either keynav mode or the switcher, select an icon in the launcher. The desired mode (keynav or switcher) must be started already before @@ -218,7 +232,7 @@ class Launcher(UnityIntrospectionObject, KeybindingsHelper): if matches: return if self.in_keynav_mode: - self.key_nav_next() + self.key_nav_next(launcher_position) elif self.in_switcher_mode: self.switcher_next() raise ValueError("No icon found that matches: %r", kwargs) @@ -244,23 +258,23 @@ class Launcher(UnityIntrospectionObject, KeybindingsHelper): self._perform_key_nav_exit_binding("launcher/keynav/activate") self._get_controller().key_nav_is_active.wait_for(False) - def key_nav_next(self): + def key_nav_next(self, launcher_position = LauncherPosition.LEFT): """Moves the launcher keynav focus to the next launcher icon""" logger.debug("Selecting next item in keyboard navigation mode.") old_selection = self._get_controller().key_nav_selection - self._perform_key_nav_binding("launcher/keynav/next") + self._perform_key_nav_binding(keys[launcher_position + "/launcher/keynav/next"]) self._get_controller().key_nav_selection.wait_for(NotEquals(old_selection)) - def key_nav_prev(self): + def key_nav_prev(self, launcher_position = LauncherPosition.LEFT): """Moves the launcher keynav focus to the previous launcher icon""" logger.debug("Selecting previous item in keyboard navigation mode.") old_selection = self._get_controller().key_nav_selection - self._perform_key_nav_binding("launcher/keynav/prev") + self._perform_key_nav_binding(keys[launcher_position + "/launcher/keynav/prev"]) self._get_controller().key_nav_selection.wait_for(NotEquals(old_selection)) - def key_nav_enter_quicklist(self): + def key_nav_enter_quicklist(self, launcher_position = LauncherPosition.LEFT): logger.debug("Opening quicklist for currently selected icon.") - self._perform_key_nav_binding("launcher/keynav/open-quicklist") + self._perform_key_nav_binding(keys[launcher_position + "/launcher/keynav/open-quicklist"]) self.quicklist_open.wait_for(True) def key_nav_exit_quicklist(self): @@ -329,9 +343,9 @@ class Launcher(UnityIntrospectionObject, KeybindingsHelper): self._mouse.click(button) if (move_mouse_after): - self.move_mouse_to_right_of_launcher() + self.move_mouse_beside_launcher() - def drag_icon_to_position(self, icon, pos, target, drag_type=IconDragType.INSIDE): + def drag_icon_to_position(self, icon, pos, target, drag_type=IconDragType.INSIDE, launcher_position=LauncherPosition.LEFT): """Drag a launcher icon to a new position. 'icon' is the icon to move. It must be either a ApplicationLauncherIcon or an @@ -345,9 +359,14 @@ class Launcher(UnityIntrospectionObject, KeybindingsHelper): 'drag_type' must be one of IconDragType.INSIDE or IconDragType.OUTSIDE. This specifies whether the icon is gragged inside the launcher, or to the - right of it. The default is to drag inside the launcher. If it is + right/top of it. The default is to drag inside the launcher. If it is specified, and not one of the allowed values, a ValueError will be raised. + 'launcher_position' must be one of LauncherPosition.LEFT or LauncherPosition.BOTTOM. + This specifies the launcher position when dragging the icon. The default launcher + position is at left. If it is specified, and not one of the allowed values, a + ValueError will be raised. + For example: >>> drag_icon_to_position(calc_icon, IconDragType.BEFORE, switcher_icon) @@ -374,29 +393,41 @@ class Launcher(UnityIntrospectionObject, KeybindingsHelper): if drag_type not in (IconDragType.INSIDE, IconDragType.OUTSIDE): raise ValueError("'drag_type' parameter must be one of IconDragType.INSIDE, IconDragType.OUTSIDE") - icon_height = get_compiz_option("unityshell", "icon_size") + icon_size = get_compiz_option("unityshell", "icon_size") self.move_mouse_to_icon(icon) self._mouse.press() sleep(1) if drag_type == IconDragType.OUTSIDE: - shift_over = self._mouse.x + (icon_height * 2) - self._mouse.move(shift_over, self._mouse.y, rate=20, time_between_events=0.005) + if launcher_position == LauncherPosition.LEFT: + shift_over = self._mouse.x + (icon_size * 3) + self._mouse.move(shift_over, self._mouse.y, rate=20, time_between_events=0.005) + else: + shift_over = self._mouse.y - (icon_size * 3) + self._mouse.move(self._mouse.x, shift_over, rate=20, time_between_events=0.005) sleep(0.5) self.move_mouse_to_icon(target) - target_y = target.center.y - if target_y < icon.center.y: - target_y += icon_height - if pos == IconDragType.BEFORE: - target_y -= icon_height + (icon_height / 2) + if launcher_position == LauncherPosition.LEFT: + target_y = target.center.y + if target_y < icon.center.y: + target_y += icon_size + if pos == IconDragType.BEFORE: + target_y -= icon_size + (icon_size / 2) + self._mouse.move(self._mouse.x, target_y, rate=20, time_between_events=0.005) + else: + target_x = target.center.x + if target_x < icon.center.x: + target_x += icon_size + if pos == IconDragType.BEFORE: + target_x -= icon_size + (icon_size / 2) + self._mouse.move(target_x, self._mouse.y, rate=20, time_between_events=0.005) - self._mouse.move(self._mouse.x, target_y, rate=20, time_between_events=0.005) sleep(1) self._mouse.release() - self.move_mouse_to_right_of_launcher() + self.move_mouse_beside_launcher() def lock_to_launcher(self, icon): """lock 'icon' to the launcher, if it's not already. diff --git a/tests/autopilot/unity/tests/launcher/__init__.py b/tests/autopilot/unity/tests/launcher/__init__.py index ef0852bf1..6371cb339 100644 --- a/tests/autopilot/unity/tests/launcher/__init__.py +++ b/tests/autopilot/unity/tests/launcher/__init__.py @@ -13,6 +13,7 @@ from autopilot.testcase import multiply_scenarios from unity.tests import UnityTestCase from unity.emulators.X11 import set_primary_monitor +from unity.emulators.launcher import LauncherPosition def _make_scenarios(): @@ -35,7 +36,11 @@ class LauncherTestCase(UnityTestCase): """A base class for all launcher tests that uses scenarios to run on each launcher (for multi-monitor setups). """ - scenarios = _make_scenarios() + scenarios = multiply_scenarios(_make_scenarios(), + [ + ('left', {'launcher_position': LauncherPosition.LEFT}), + ('bottom', {'launcher_position': LauncherPosition.BOTTOM}), + ]) def setUp(self): super(LauncherTestCase, self).setUp() @@ -45,6 +50,10 @@ class LauncherTestCase(UnityTestCase): self.set_unity_option('num_launchers', int(self.only_primary)) self.launcher_instance = self.get_launcher() + old_pos = self.call_gsettings_cmd('get', 'com.canonical.Unity.Launcher', 'launcher-position') + self.call_gsettings_cmd('set', 'com.canonical.Unity.Launcher', 'launcher-position', '"%s"' % self.launcher_position) + self.addCleanup(self.call_gsettings_cmd, 'set', 'com.canonical.Unity.Launcher', 'launcher-position', old_pos) + if not self.launcher_instance: self.skipTest("Cannot run test with no Launcher on monitor %d." % self.launcher_monitor) diff --git a/tests/autopilot/unity/tests/launcher/test_icon_behavior.py b/tests/autopilot/unity/tests/launcher/test_icon_behavior.py index cec00f6da..b51267dee 100644 --- a/tests/autopilot/unity/tests/launcher/test_icon_behavior.py +++ b/tests/autopilot/unity/tests/launcher/test_icon_behavior.py @@ -17,6 +17,7 @@ from time import sleep from unity.emulators.icons import ApplicationLauncherIcon, ExpoLauncherIcon from unity.emulators.launcher import IconDragType +from unity.emulators.launcher import LauncherPosition from unity.tests.launcher import LauncherTestCase, _make_scenarios from Xlib import Xutil @@ -196,7 +197,8 @@ class LauncherIconsTests(LauncherTestCase): self.launcher_instance.drag_icon_to_position( calc_icon, IconDragType.AFTER, - bfb_icon) + bfb_icon, + launcher_position = self.launcher_position) self.launcher_instance.keyboard_reveal_launcher() self.addCleanup(self.launcher_instance.keyboard_unreveal_launcher) @@ -354,6 +356,10 @@ class LauncherDragIconsBehavior(LauncherTestCase): [ ('inside', {'drag_type': IconDragType.INSIDE}), ('outside', {'drag_type': IconDragType.OUTSIDE}), + ], + [ + ('left', {'launcher_position': LauncherPosition.LEFT}), + ('bottom', {'launcher_position': LauncherPosition.BOTTOM}), ]) def setUp(self): @@ -386,7 +392,8 @@ class LauncherDragIconsBehavior(LauncherTestCase): calc_icon, IconDragType.AFTER, bfb_icon, - self.drag_type) + self.drag_type, + self.launcher_position) moved_icon = self.unity.launcher.model.\ get_launcher_icons_for_monitor(self.launcher_monitor)[1] self.assertThat(moved_icon, Equals(calc_icon)) @@ -406,14 +413,16 @@ class LauncherDragIconsBehavior(LauncherTestCase): calc_icon, IconDragType.AFTER, bfb_icon, - self.drag_type) + self.drag_type, + self.launcher_position) sleep(1) self.launcher_instance.drag_icon_to_position( calc_icon, IconDragType.BEFORE, trash_icon, - self.drag_type) + self.drag_type, + self.launcher_position) # Must be the last bamf icon - not necessarily the third-from-end icon. expected_pos = -2 if self.workspace.num_workspaces < 2 else -1 diff --git a/tests/autopilot/unity/tests/launcher/test_keynav.py b/tests/autopilot/unity/tests/launcher/test_keynav.py index dda2b88ec..f8e787d2c 100644 --- a/tests/autopilot/unity/tests/launcher/test_keynav.py +++ b/tests/autopilot/unity/tests/launcher/test_keynav.py @@ -68,7 +68,7 @@ class LauncherKeyNavTests(LauncherTestCase): def test_launcher_keynav_forward(self): """Must be able to move forwards while in keynav mode.""" self.start_keynav_with_cleanup_cancel() - self.launcher_instance.key_nav_next() + self.launcher_instance.key_nav_next(self.launcher_position) # The launcher model has hidden items, so the keynav indexes do not # increase by 1 each time. This test was failing because the 2nd icon # had an index of 2, not 1 as expected. The best we can do here is to @@ -80,9 +80,9 @@ class LauncherKeyNavTests(LauncherTestCase): def test_launcher_keynav_prev_works(self): """Must be able to move backwards while in keynav mode.""" self.start_keynav_with_cleanup_cancel() - self.launcher_instance.key_nav_next() + self.launcher_instance.key_nav_next(self.launcher_position) self.assertThat(self.unity.launcher.key_nav_selection, Eventually(GreaterThan(0))) - self.launcher_instance.key_nav_prev() + self.launcher_instance.key_nav_prev(self.launcher_position) self.assertThat(self.unity.launcher.key_nav_selection, Eventually(Equals(0))) def test_launcher_keynav_cycling_forward(self): @@ -90,29 +90,29 @@ class LauncherKeyNavTests(LauncherTestCase): self.start_keynav_with_cleanup_cancel() prev_icon = 0 for icon in range(1, self.unity.launcher.model.num_launcher_icons()): - self.launcher_instance.key_nav_next() + self.launcher_instance.key_nav_next(self.launcher_position) # FIXME We can't directly check for selection/icon number equalty # since the launcher model also contains "hidden" icons that aren't # shown, so the selection index can increment by more than 1. self.assertThat(self.unity.launcher.key_nav_selection, Eventually(GreaterThan(prev_icon))) prev_icon = self.unity.launcher.key_nav_selection - self.launcher_instance.key_nav_next() + self.launcher_instance.key_nav_next(self.launcher_position) self.assertThat(self.unity.launcher.key_nav_selection, Eventually(Equals(0))) def test_launcher_keynav_cycling_backward(self): """Launcher keynav must loop through icons when cycling backwards""" self.start_keynav_with_cleanup_cancel() - self.launcher_instance.key_nav_prev() + self.launcher_instance.key_nav_prev(self.launcher_position) # FIXME We can't directly check for self.unity.launcher.num_launcher_icons - 1 self.assertThat(self.unity.launcher.key_nav_selection, Eventually(GreaterThan(1))) def test_launcher_keynav_can_open_and_close_quicklist(self): """Tests that we can open and close a quicklist from keynav mode.""" self.start_keynav_with_cleanup_cancel() - self.launcher_instance.key_nav_next() + self.launcher_instance.key_nav_next(self.launcher_position) self.addCleanup(self.keyboard.press_and_release, "Escape") - self.launcher_instance.key_nav_enter_quicklist() + self.launcher_instance.key_nav_enter_quicklist(self.launcher_position) self.assertThat(self.launcher_instance.quicklist_open, Eventually(Equals(True))) self.launcher_instance.key_nav_exit_quicklist() self.assertThat(self.launcher_instance.quicklist_open, Eventually(Equals(False))) @@ -135,7 +135,7 @@ class LauncherKeyNavTests(LauncherTestCase): self.start_keynav_with_cleanup_cancel() - self.launcher_instance.keyboard_select_icon(tooltip_text=calc.name) + self.launcher_instance.keyboard_select_icon(self.launcher_position, tooltip_text=calc.name) self.launcher_instance.key_nav_activate() self.assertTrue(calc.is_active) @@ -148,7 +148,7 @@ class LauncherKeyNavTests(LauncherTestCase): self.start_keynav_with_cleanup_cancel() - self.launcher_instance.keyboard_select_icon(tooltip_text="Workspace Switcher") + self.launcher_instance.keyboard_select_icon(self.launcher_position, tooltip_text="Workspace Switcher") self.launcher_instance.key_nav_activate() self.addCleanup(self.keybinding, "expo/cancel") @@ -160,7 +160,7 @@ class LauncherKeyNavTests(LauncherTestCase): self.skipTest("This test requires enabled more than one workspace.") self.start_keynav_with_cleanup_cancel() - self.launcher_instance.keyboard_select_icon(tooltip_text="Workspace Switcher") + self.launcher_instance.keyboard_select_icon(self.launcher_position, tooltip_text="Workspace Switcher") self.launcher_instance.key_nav_activate() self.keyboard.press_and_release("Escape") @@ -209,7 +209,7 @@ class LauncherKeyNavTests(LauncherTestCase): """A single click outside of launcher must cancel keynav.""" self.start_keynav_with_cleanup_cancel() - self.launcher_instance.move_mouse_to_right_of_launcher() + self.launcher_instance.move_mouse_beside_launcher() self.mouse.click() self.assertThat(self.unity.launcher.key_nav_is_active, Eventually(Equals(False))) @@ -229,7 +229,7 @@ class LauncherKeyNavTests(LauncherTestCase): def test_launcher_keynav_cancel_on_quicklist_activate(self): """A single click on a quicklist item must cancel keynav.""" self.start_keynav_with_cleanup_cancel() - self.launcher_instance.key_nav_enter_quicklist() + self.launcher_instance.key_nav_enter_quicklist(self.launcher_position) bfb_icon = self.unity.launcher.model.get_bfb_icon() bfb_ql = bfb_icon.get_quicklist() diff --git a/tests/autopilot/unity/tests/launcher/test_reveal.py b/tests/autopilot/unity/tests/launcher/test_reveal.py index 922cc1efd..7d57f12b2 100644 --- a/tests/autopilot/unity/tests/launcher/test_reveal.py +++ b/tests/autopilot/unity/tests/launcher/test_reveal.py @@ -39,7 +39,7 @@ class LauncherRevealTests(LauncherTestCase): def test_reveal_on_mouse_to_edge(self): """Tests reveal of launchers by mouse pressure.""" - self.launcher_instance.move_mouse_to_right_of_launcher() + self.launcher_instance.move_mouse_beside_launcher() self.launcher_instance.mouse_reveal_launcher() self.assertThat(self.launcher_instance.is_showing, Eventually(Equals(True))) @@ -58,7 +58,7 @@ class LauncherRevealTests(LauncherTestCase): """Tests reveal of launchers by mouse pressure to ensure it doesn't automatically hide again. """ - self.launcher_instance.move_mouse_to_right_of_launcher() + self.launcher_instance.move_mouse_beside_launcher() self.launcher_instance.mouse_reveal_launcher() self.assertThat(self.launcher_instance.is_showing, Eventually(Equals(True))) diff --git a/tests/autopilot/unity/tests/launcher/test_scroll.py b/tests/autopilot/unity/tests/launcher/test_scroll.py index 59814d0f6..5e500c765 100644 --- a/tests/autopilot/unity/tests/launcher/test_scroll.py +++ b/tests/autopilot/unity/tests/launcher/test_scroll.py @@ -88,8 +88,9 @@ class LauncherScrollTests(LauncherTestCase): launcher_instance.move_mouse_to_icon(last_icon) # Make sure the first icon is off the screen or else there is no - # scrolling. - self.assertThat(first_icon.center.y, LessThan(y)) + # scrolling when launcher at left + if w < h: + self.assertThat(first_icon.center.y, LessThan(y)) # Autoscroll to the first icon launcher_instance.move_mouse_to_icon(first_icon, autoscroll_offset) diff --git a/tests/autopilot/unity/tests/launcher/test_switcher.py b/tests/autopilot/unity/tests/launcher/test_switcher.py index 06f82792b..657cc2357 100644 --- a/tests/autopilot/unity/tests/launcher/test_switcher.py +++ b/tests/autopilot/unity/tests/launcher/test_switcher.py @@ -152,7 +152,7 @@ class LauncherSwitcherTests(LauncherTestCase): self.start_switcher_with_cleanup_cancel() - self.launcher_instance.keyboard_select_icon(tooltip_text=calc.name) + self.launcher_instance.keyboard_select_icon(self.launcher_position, tooltip_text=calc.name) self.launcher_instance.switcher_activate() self.assertThat(lambda: calc.is_active, Eventually(Equals(True))) diff --git a/tests/autopilot/unity/tests/launcher/test_tooltips.py b/tests/autopilot/unity/tests/launcher/test_tooltips.py index f403a8a80..c2eaaf9a0 100644 --- a/tests/autopilot/unity/tests/launcher/test_tooltips.py +++ b/tests/autopilot/unity/tests/launcher/test_tooltips.py @@ -18,7 +18,7 @@ class LauncherTooltipTests(LauncherTestCase): def setUp(self): super(LauncherTooltipTests, self).setUp() self.set_unity_option('launcher_hide_mode', 0) - self.launcher_instance.move_mouse_to_right_of_launcher() + self.launcher_instance.move_mouse_beside_launcher() self.icons = self.unity.launcher.model.get_launcher_icons(visible_only=True) def test_launcher_tooltip_show(self): @@ -49,7 +49,7 @@ class LauncherTooltipTests(LauncherTestCase): b -= 1 # leaving launcher clears tooltips, and instant reveal - self.launcher_instance.move_mouse_to_right_of_launcher() + self.launcher_instance.move_mouse_beside_launcher() self.assertEqual(self.get_reveal_behavior(self.icons[b]), self.DELAYED) def test_launcher_tooltip_disabling(self): diff --git a/tests/autopilot/unity/tests/test_dash.py b/tests/autopilot/unity/tests/test_dash.py index 606144b8e..8e488750e 100644 --- a/tests/autopilot/unity/tests/test_dash.py +++ b/tests/autopilot/unity/tests/test_dash.py @@ -689,8 +689,10 @@ class DashVisualTests(DashTestCase): self.unity.dash.ensure_visible() - self.assertThat(self.unity.dash.view.x, Eventually(Equals(launcher.geometry.x + launcher.geometry.width - 1))) - + if launcher.geometry.width < launcher.geometry.height: + self.assertThat(self.unity.dash.view.x, Eventually(Equals(launcher.geometry.x + launcher.geometry.width - 1))) + else: + self.assertThat(self.unity.dash.view.x, Eventually(Equals(0))) def test_see_more_result_alignment(self): """The see more results label should be baseline aligned @@ -740,7 +742,7 @@ class DashBorderTests(DashTestCase): if (self.unity.dash.view.form_factor != "desktop"): self.skip("Not in desktop form-factor.") - x = self.unity.dash.view.x + self.unity.dash.view.width + self.unity.dash.view.right_border_width / 2 + x = self.unity.dash.view.x + self.unity.dash.view.width + self.unity.dash.view.vertical_border_width / 2 y = self.unity.dash.view.y + self.unity.dash.view.height / 2 self.mouse.move(x, y) @@ -756,7 +758,7 @@ class DashBorderTests(DashTestCase): self.skip("Not in desktop form-factor.") x = self.unity.dash.view.x + self.unity.dash.view.width / 2 - y = self.unity.dash.view.y + self.unity.dash.view.height + self.unity.dash.view.bottom_border_height / 2 + y = self.unity.dash.view.y + self.unity.dash.view.height + self.unity.dash.view.horizontal_border_height / 2 self.mouse.move(x, y) self.mouse.click() diff --git a/tests/autopilot/unity/tests/test_hud.py b/tests/autopilot/unity/tests/test_hud.py index de0929338..8467caa53 100644 --- a/tests/autopilot/unity/tests/test_hud.py +++ b/tests/autopilot/unity/tests/test_hud.py @@ -471,10 +471,10 @@ class HudBehaviorTests(HudTestsBase): self.unity.hud.ensure_visible() - # Click bottom right of the screen, but take into account the non-maximized window - + # Click right of the screen, but take into account the non-maximized window - # we do not want to click on it as it focuses the wrong window w = self.display.get_screen_width() - 1 - h = self.display.get_screen_height() - 1 + h = (self.display.get_screen_height() - 1) / 2 # If the mouse is over the non-maximized window, move it away from it. (calc_x, calc_y, calc_w, calc_h) = calc_win.get_windows()[0].geometry @@ -671,10 +671,11 @@ class HudVisualTests(HudTestsBase): monitor_geo = self.display.get_screen_geometry(self.hud_monitor) monitor_x = monitor_geo[0] monitor_w = monitor_geo[2] + launcher = self.unity.launcher.get_launcher_for_monitor(self.hud_monitor) hud_x = self.unity.hud.geometry[0] hud_w = self.unity.hud.geometry[2] - if self.hud_locked: + if self.hud_locked and launcher.geometry.w < launcher.geometry.h: self.assertThat(hud_x, GreaterThan(monitor_x)) self.assertThat(hud_x, LessThan(monitor_x + monitor_w)) self.assertThat(hud_w, Equals(monitor_x + monitor_w - hud_x)) diff --git a/tests/autopilot/unity/tests/test_quicklist.py b/tests/autopilot/unity/tests/test_quicklist.py index c54ccc3b8..a6a197196 100644 --- a/tests/autopilot/unity/tests/test_quicklist.py +++ b/tests/autopilot/unity/tests/test_quicklist.py @@ -17,7 +17,9 @@ from testtools.matchers import Contains, Equals, NotEquals, Not, Raises from time import sleep from xdg.DesktopEntry import DesktopEntry +from unity.emulators import keys from unity.emulators.quicklist import QuicklistMenuItemLabel +from unity.emulators.launcher import LauncherPosition from unity.tests import UnityTestCase @@ -193,12 +195,12 @@ class QuicklistActionTests(UnityTestCase): icons = self.unity.launcher.model.get_launcher_icons() - icon0_ql = self.open_quicklist_for_icon(icons[0]) - self.assertThat(icon0_ql.active, Eventually(Equals(True))) - icon1_ql = self.open_quicklist_for_icon(icons[1]) self.assertThat(icon1_ql.active, Eventually(Equals(True))) - self.assertThat(icon0_ql.wait_until_destroyed, Not(Raises())) + + icon0_ql = self.open_quicklist_for_icon(icons[0]) + self.assertThat(icon0_ql.active, Eventually(Equals(True))) + self.assertThat(icon1_ql.wait_until_destroyed, Not(Raises())) def test_right_clicking_same_icon_doesnt_reopen_ql(self): """A right click to the same icon in the launcher must @@ -224,6 +226,10 @@ class QuicklistActionTests(UnityTestCase): class QuicklistKeyNavigationTests(UnityTestCase): """Tests for the quicklist key navigation.""" + scenarios = [ + ('left', {'launcher_position': LauncherPosition.LEFT}), + ('bottom', {'launcher_position': LauncherPosition.BOTTOM}), + ] def setUp(self): super(QuicklistKeyNavigationTests, self).setUp() @@ -239,6 +245,10 @@ class QuicklistKeyNavigationTests(UnityTestCase): self.ql_launcher = self.unity.launcher.get_launcher_for_monitor(0) + old_pos = self.call_gsettings_cmd('get', 'com.canonical.Unity.Launcher', 'launcher-position') + self.call_gsettings_cmd('set', 'com.canonical.Unity.Launcher', 'launcher-position', '"%s"' % self.launcher_position) + self.addCleanup(self.call_gsettings_cmd, 'set', 'com.canonical.Unity.Launcher', 'launcher-position', old_pos) + def open_quicklist_with_mouse(self): """Opens a quicklist with the mouse.""" self.ql_launcher.click_launcher_icon(self.ql_launcher_icon, button=3) @@ -256,8 +266,8 @@ class QuicklistKeyNavigationTests(UnityTestCase): self.ql_launcher.key_nav_start() self.addCleanup(self.ql_launcher.key_nav_cancel) - self.ql_launcher.keyboard_select_icon(tooltip_text=self.ql_app.name) - self.keybinding("launcher/keynav/open-quicklist") + self.ql_launcher.keyboard_select_icon(self.launcher_position, tooltip_text=self.ql_app.name) + self.keybinding(keys[self.launcher_position + "/launcher/keynav/open-quicklist"]) self.addCleanup(self.keybinding, "launcher/keynav/close-quicklist") self.assertThat(self.ql_launcher_icon.get_quicklist, diff --git a/tests/autopilot/unity/tests/test_spread.py b/tests/autopilot/unity/tests/test_spread.py index c3c5b769d..0cc91a10e 100644 --- a/tests/autopilot/unity/tests/test_spread.py +++ b/tests/autopilot/unity/tests/test_spread.py @@ -150,7 +150,7 @@ class SpreadTests(UnityTestCase): """Test that the screen spread desaturates the launcher icons""" self.start_test_application_windows("Calculator", 1) self.initiate_spread_for_screen() - self.launcher.move_mouse_to_right_of_launcher() + self.launcher.move_mouse_beside_launcher() self.assertLauncherIconsDesaturated() def test_spread_saturate_launcher_icons_on_mouse_over(self): diff --git a/tests/autopilot/unity/tests/test_wm_keybindings.py b/tests/autopilot/unity/tests/test_wm_keybindings.py index f6dec986a..fe5418d6a 100644 --- a/tests/autopilot/unity/tests/test_wm_keybindings.py +++ b/tests/autopilot/unity/tests/test_wm_keybindings.py @@ -99,10 +99,16 @@ class WindowManagerKeybindingsForWindowHandling(UnityTestCase): monitor = self.bamf_win.monitor monitor_geo = self.display.get_screen_geometry(monitor) launcher = self.unity.launcher.get_launcher_for_monitor(monitor) - launcher_w = 0 if launcher.hidemode else launcher.geometry[2] + # When launcher at left, do not use launcher_h, otherwise, do not use launcher_w + if launcher.geometry[2] < launcher.geometry[3]: + launcher_h = 0 + launcher_w = 0 if launcher.hidemode else launcher.geometry[2] + else: + launcher_h = 0 if launcher.hidemode else launcher.geometry[3] + launcher_w = 0 panel_h = self.unity.panels.get_panel_for_monitor(monitor).geometry[3] return (monitor_geo[0] + launcher_w, monitor_geo[1] + panel_h, - monitor_geo[2] - launcher_w, monitor_geo[3] - panel_h) + monitor_geo[2] - launcher_w, monitor_geo[3] - panel_h - launcher_h) def test_maximize_window(self): if self.start_restored: diff --git a/tests/test_bfb_launcher_icon.cpp b/tests/test_bfb_launcher_icon.cpp index e4e0cb3f7..cd9519b9f 100644 --- a/tests/test_bfb_launcher_icon.cpp +++ b/tests/test_bfb_launcher_icon.cpp @@ -31,7 +31,7 @@ class MockBFBLauncherIcon : public BFBLauncherIcon { public: MockBFBLauncherIcon() - : BFBLauncherIcon(LauncherHideMode::LAUNCHER_HIDE_NEVER) + : BFBLauncherIcon() {} }; diff --git a/tests/test_hud_launcher_icon.cpp b/tests/test_hud_launcher_icon.cpp index 26b8aa978..a9b88936e 100644 --- a/tests/test_hud_launcher_icon.cpp +++ b/tests/test_hud_launcher_icon.cpp @@ -32,7 +32,7 @@ class MockHudLauncherIcon : public HudLauncherIcon { public: MockHudLauncherIcon() - : HudLauncherIcon(LauncherHideMode::LAUNCHER_HIDE_NEVER) + : HudLauncherIcon() {} }; diff --git a/tests/test_launcher.cpp b/tests/test_launcher.cpp index 33893151a..0a2b8a9a5 100644 --- a/tests/test_launcher.cpp +++ b/tests/test_launcher.cpp @@ -31,6 +31,7 @@ using namespace testing; #include "unity-shared/PanelStyle.h" #include "unity-shared/IconRenderer.h" #include "unity-shared/UBusMessages.h" +#include "unity-shared/UnitySettings.h" #include "test_standalone_wm.h" #include "test_utils.h" @@ -537,11 +538,13 @@ TEST_F(TestLauncher, EdgeBarriersIgnoreEvents) TEST_F(TestLauncher, EdgeBarriersHandlesEvent) { - auto const& launcher_geo = launcher_->GetAbsoluteGeometry(); + glib::Object<GSettings> gsettings(g_settings_new("com.canonical.Unity.Launcher")); + auto launcher_geo = launcher_->GetAbsoluteGeometry(); auto barrier = std::make_shared<ui::PointerBarrierWrapper>(); auto event = std::make_shared<ui::BarrierEvent>(0, 0, 0, 100); launcher_->SetHidden(true); + g_settings_set_enum(gsettings, "launcher-position", static_cast<int>(LauncherPosition::LEFT)); options_->reveal_trigger = RevealTrigger::EDGE; for (int x = launcher_geo.x; x < launcher_geo.x+launcher_geo.width; ++x) @@ -567,6 +570,37 @@ TEST_F(TestLauncher, EdgeBarriersHandlesEvent) ui::EdgeBarrierSubscriber::Result::HANDLED); } } + + g_settings_set_enum(gsettings, "launcher-position", static_cast<int>(LauncherPosition::BOTTOM)); + launcher_geo = launcher_->GetAbsoluteGeometry(); + options_->reveal_trigger = RevealTrigger::EDGE; + int panel_height = panel::Style::Instance().PanelHeight(launcher_->monitor()); + + for (int y = launcher_geo.y; y < launcher_geo.y+launcher_geo.height; ++y) + { + for (int x = launcher_geo.x + panel_height; x < launcher_geo.x+launcher_geo.width; ++x) + { + event->x = x; + event->y = y; + ASSERT_EQ(launcher_->HandleBarrierEvent(barrier, event), + ui::EdgeBarrierSubscriber::Result::HANDLED); + } + } + + options_->reveal_trigger = RevealTrigger::CORNER; + + for (int y = launcher_geo.y; y < launcher_geo.y+launcher_geo.height; ++y) + { + for (int x = launcher_geo.x; x < launcher_geo.x + panel_height; ++x) + { + event->x = x; + event->y = y; + ASSERT_EQ(launcher_->HandleBarrierEvent(barrier, event), + ui::EdgeBarrierSubscriber::Result::HANDLED); + } + } + + g_settings_reset(gsettings, "launcher-position"); } TEST_F(TestLauncher, DndIsSpecialRequest) diff --git a/tests/test_launcher_controller.cpp b/tests/test_launcher_controller.cpp index eee05c0bf..7cf9455b0 100644 --- a/tests/test_launcher_controller.cpp +++ b/tests/test_launcher_controller.cpp @@ -42,6 +42,7 @@ #include "mock-application.h" #include "BamfApplicationManager.h" #include "bamf-mock-application.h" +#include "unity-shared/UnitySettings.h" using namespace testmocks; using namespace unity::launcher; @@ -490,6 +491,25 @@ TEST_F(TestLauncherController, MonitorResizesLauncher) ASSERT_EQ(launcher_geo.height, monitor_geo.height - panel_style.PanelHeight()); } +TEST_F(TestLauncherController, LauncherPositionResetsOnGsettingsUpdated) +{ + glib::Object<GSettings> gsettings(g_settings_new("com.canonical.Unity.Launcher")); + g_settings_set_enum(gsettings, "launcher-position", static_cast<int>(LauncherPosition::LEFT)); + nux::Geometry const& monitor_geo = uscreen.GetMonitorGeometry(0); + nux::Geometry launcher_geo = lc.launcher().GetAbsoluteGeometry(); + ASSERT_EQ(launcher_geo.x, monitor_geo.x); + ASSERT_EQ(launcher_geo.y, monitor_geo.y + panel_style.PanelHeight(0)); + ASSERT_EQ(launcher_geo.height, monitor_geo.height - panel_style.PanelHeight(0)); + + g_settings_set_enum(gsettings, "launcher-position", static_cast<int>(LauncherPosition::BOTTOM)); + launcher_geo = lc.launcher().GetAbsoluteGeometry(); + ASSERT_EQ(launcher_geo.x, monitor_geo.x); + ASSERT_EQ(launcher_geo.y, monitor_geo.y + monitor_geo.height - launcher_geo.height + 1); + ASSERT_EQ(launcher_geo.width, monitor_geo.width); + + g_settings_reset(gsettings, "launcher-position"); +} + TEST_F(TestLauncherController, IconCentersResetsOnMonitorsUpdated) { uscreen.SetupFakeMultiMonitor(); diff --git a/unity-shared/DashStyle.cpp b/unity-shared/DashStyle.cpp index 987fefcdb..d9e7a825c 100755 --- a/unity-shared/DashStyle.cpp +++ b/unity-shared/DashStyle.cpp @@ -2090,14 +2090,24 @@ bool Style::SeparatorHoriz(cairo_t* cr) return true; } -BaseTexturePtr Style::GetDashBottomTile(double scale) const +BaseTexturePtr Style::GetDashHorizontalTile(double scale, bool at_bottom) const { - return pimpl->LoadScaledTexture("dash_bottom_border_tile.png", scale); + std::string horizontal_tile; + if (at_bottom) + horizontal_tile = "dash_top_border_tile.png"; + else + horizontal_tile = "dash_bottom_border_tile.png"; + return pimpl->LoadScaledTexture(horizontal_tile, scale); } -BaseTexturePtr Style::GetDashBottomTileMask(double scale) const +BaseTexturePtr Style::GetDashHorizontalTileMask(double scale, bool at_bottom) const { - return pimpl->LoadScaledTexture("dash_bottom_border_tile_mask.png", scale); + std::string horizontal_tile_mask; + if (at_bottom) + horizontal_tile_mask = "dash_top_border_tile_mask.png"; + else + horizontal_tile_mask = "dash_bottom_border_tile_mask.png"; + return pimpl->LoadScaledTexture(horizontal_tile_mask, scale); } BaseTexturePtr Style::GetDashRightTile(double scale) const @@ -2115,39 +2125,74 @@ BaseTexturePtr Style::GetDashLeftTile(double scale) const return pimpl->LoadScaledTexture("dash_left_tile.png", scale); } -BaseTexturePtr Style::GetDashTopTile(double scale) const +BaseTexturePtr Style::GetDashTopOrBottomTile(double scale, bool at_bottom) const { - return pimpl->LoadScaledTexture("dash_top_tile.png", scale); + std::string top_bottom_tile; + if (at_bottom) + top_bottom_tile = "dash_bottom_tile.png"; + else + top_bottom_tile = "dash_top_tile.png"; + return pimpl->LoadScaledTexture(top_bottom_tile, scale); } -BaseTexturePtr Style::GetDashCorner(double scale) const +BaseTexturePtr Style::GetDashCorner(double scale, bool at_bottom) const { - return pimpl->LoadScaledTexture("dash_bottom_right_corner.png", scale); + std::string corner; + if (at_bottom) + corner = "dash_top_right_corner_rotated.png"; + else + corner = "dash_bottom_right_corner.png"; + return pimpl->LoadScaledTexture(corner, scale); } -BaseTexturePtr Style::GetDashCornerMask(double scale) const +BaseTexturePtr Style::GetDashCornerMask(double scale, bool at_bottom) const { - return pimpl->LoadScaledTexture("dash_bottom_right_corner_mask.png", scale); + std::string corner_mask; + if (at_bottom) + corner_mask = "dash_top_right_corner_rotated_mask.png"; + else + corner_mask = "dash_bottom_right_corner_mask.png"; + return pimpl->LoadScaledTexture(corner_mask, scale); } -BaseTexturePtr Style::GetDashLeftCorner(double scale) const +BaseTexturePtr Style::GetDashLeftCorner(double scale, bool at_bottom) const { - return pimpl->LoadScaledTexture("dash_bottom_left_corner.png", scale); + std::string left_corner; + if (at_bottom) + left_corner = "dash_top_left_corner.png"; + else + left_corner = "dash_bottom_left_corner.png"; + return pimpl->LoadScaledTexture(left_corner, scale); } -BaseTexturePtr Style::GetDashLeftCornerMask(double scale) const +BaseTexturePtr Style::GetDashLeftCornerMask(double scale, bool at_bottom) const { - return pimpl->LoadScaledTexture("dash_bottom_left_corner_mask.png", scale); + std::string left_corner_mask; + if (at_bottom) + left_corner_mask = "dash_top_left_corner_mask.png"; + else + left_corner_mask = "dash_bottom_left_corner_mask.png"; + return pimpl->LoadScaledTexture(left_corner_mask, scale); } -BaseTexturePtr Style::GetDashTopCorner(double scale) const +BaseTexturePtr Style::GetDashRightCorner(double scale, bool at_bottom) const { - return pimpl->LoadScaledTexture("dash_top_right_corner.png", scale); + std::string right_corner; + if (at_bottom) + right_corner = "dash_bottom_right_corner_rotated.png"; + else + right_corner = "dash_top_right_corner.png"; + return pimpl->LoadScaledTexture(right_corner, scale); } -BaseTexturePtr Style::GetDashTopCornerMask(double scale) const +BaseTexturePtr Style::GetDashRightCornerMask(double scale, bool at_bottom) const { - return pimpl->LoadScaledTexture("dash_top_right_corner_mask.png", scale); + std::string right_corner_mask; + if (at_bottom) + right_corner_mask = "dash_bottom_right_corner_rotated_mask.png"; + else + right_corner_mask = "dash_top_right_corner_mask.png"; + return pimpl->LoadScaledTexture(right_corner_mask, scale); } BaseTexturePtr Style::GetSearchMagnifyIcon(double scale) const @@ -2306,12 +2351,12 @@ BaseTexturePtr const& Style::GetDashShine() const return pimpl->dash_shine_.texture(); } -RawPixel Style::GetDashBottomTileHeight() const +RawPixel Style::GetDashHorizontalBorderHeight() const { return 30; } -RawPixel Style::GetDashRightTileWidth() const +RawPixel Style::GetDashVerticalBorderWidth() const { return 30; } diff --git a/unity-shared/DashStyle.h b/unity-shared/DashStyle.h index dd73a3048..e8d9783a6 100755 --- a/unity-shared/DashStyle.h +++ b/unity-shared/DashStyle.h @@ -170,22 +170,22 @@ public: BaseTexturePtr const& GetCategoryBackground() const; BaseTexturePtr const& GetCategoryBackgroundNoFilters() const; - BaseTexturePtr GetDashBottomTile(double scale) const; - BaseTexturePtr GetDashBottomTileMask(double scale) const; + BaseTexturePtr GetDashHorizontalTile(double scale, bool at_bottom) const; + BaseTexturePtr GetDashHorizontalTileMask(double scale, bool at_bottom) const; BaseTexturePtr GetDashRightTile(double scale) const; BaseTexturePtr GetDashRightTileMask(double scale) const; BaseTexturePtr GetDashLeftTile(double scale) const; - BaseTexturePtr GetDashTopTile(double scale) const; + BaseTexturePtr GetDashTopOrBottomTile(double scale, bool at_bottom) const; - BaseTexturePtr GetDashCorner(double scale) const; - BaseTexturePtr GetDashCornerMask(double scale) const; - BaseTexturePtr GetDashLeftCorner(double scale) const; - BaseTexturePtr GetDashLeftCornerMask(double scale) const; - BaseTexturePtr GetDashTopCorner(double scale) const; - BaseTexturePtr GetDashTopCornerMask(double scale) const; + BaseTexturePtr GetDashCorner(double scale, bool at_bottom) const; + BaseTexturePtr GetDashCornerMask(double scale, bool at_bottom) const; + BaseTexturePtr GetDashLeftCorner(double scale, bool at_bottom) const; + BaseTexturePtr GetDashLeftCornerMask(double scale, bool at_bottom) const; + BaseTexturePtr GetDashRightCorner(double scale, bool at_bottom) const; + BaseTexturePtr GetDashRightCornerMask(double scale, bool at_bottom) const; - RawPixel GetDashBottomTileHeight() const; - RawPixel GetDashRightTileWidth() const; + RawPixel GetDashHorizontalBorderHeight() const; + RawPixel GetDashVerticalBorderWidth() const; BaseTexturePtr const& GetDashShine() const; diff --git a/unity-shared/IconRenderer.cpp b/unity-shared/IconRenderer.cpp index 844ffe88a..78374dd99 100644 --- a/unity-shared/IconRenderer.cpp +++ b/unity-shared/IconRenderer.cpp @@ -285,8 +285,12 @@ struct IconRenderer::LocalTextures {&icon_shine, "launcher_icon_shine_"+tile_sufix, icon_size}, {&arrow_ltr, "launcher_arrow_ltr_"+marker_sufix, marker_size}, {&arrow_rtl, "launcher_arrow_rtl_"+marker_sufix, marker_size}, + {&arrow_btt, "launcher_arrow_btt_"+marker_sufix, marker_size}, + {&arrow_ttb, "launcher_arrow_ttb_"+marker_sufix, marker_size}, {&arrow_empty_ltr, "launcher_arrow_outline_ltr_"+marker_sufix, marker_size}, + {&arrow_empty_btt, "launcher_arrow_outline_btt_"+marker_sufix, marker_size}, {&pip_ltr, "launcher_pip_ltr_"+marker_sufix, marker_size}, + {&pip_btt, "launcher_pip_btt_"+marker_sufix, marker_size}, {&progress_bar_trough, "progress_bar_trough", icon_size}, {&progress_bar_fill, "progress_bar_fill", image_size - (icon_size - image_size)}, }; @@ -327,8 +331,12 @@ struct IconRenderer::LocalTextures BaseTexturePtr icon_shine; BaseTexturePtr arrow_ltr; BaseTexturePtr arrow_rtl; + BaseTexturePtr arrow_btt; + BaseTexturePtr arrow_ttb; BaseTexturePtr arrow_empty_ltr; + BaseTexturePtr arrow_empty_btt; BaseTexturePtr pip_ltr; + BaseTexturePtr pip_btt; BaseTexturePtr progress_bar_trough; BaseTexturePtr progress_bar_fill; @@ -439,10 +447,20 @@ void IconRenderer::PreprocessIcons(std::list<RenderArg>& args, nux::Geometry con UpdateIconTransform(launcher_icon, ViewProjectionMatrix, geo, x, y, w, h, z, ui::IconTextureSource::TRANSFORM_GLOW); - w = geo.width + 2; - h = icon_size + spacing; - if (i == (int) args.size() - 1) - h += 4; + if (Settings::Instance().launcher_position() == LauncherPosition::LEFT) + { + w = geo.width + 2; + h = icon_size + spacing; + if (i == (int) args.size() - 1) + h += 4; + } + else + { + h = geo.height + 2; + w = icon_size + spacing; + if (i == (int) args.size() - 1) + w += 4; + } x = it->logical_center.x - w / 2.0f; y = it->logical_center.y - h / 2.0f; z = it->logical_center.z; @@ -1023,23 +1041,38 @@ void IconRenderer::RenderIndicators(nux::GraphicsEngine& GfxContext, float alpha, nux::Geometry const& geo) { - int markerCenter = (int) arg.render_center.y; - markerCenter -= (int)(arg.rotation.x / (2 * M_PI) * icon_size); + int markerCenter = 0; + bool switcher_mode = (pip_style != OUTSIDE_TILE); + bool left_markers = (switcher_mode || Settings::Instance().launcher_position() == LauncherPosition::LEFT); - if (running > 0) + if (left_markers) + { + markerCenter = (int) arg.render_center.y; + markerCenter -= (int)(arg.rotation.x / (2 * M_PI) * icon_size); + } + else { - int markerX; + markerCenter = (int) arg.render_center.x; if (pip_style == OUTSIDE_TILE) + markerCenter += (int)(arg.rotation.y / (2 * M_PI) * icon_size); + } + + if (running > 0) + { + int markerX = 0; + if (left_markers) { - markerX = geo.x; - } - else - { - auto const& bounds = arg.icon->GetTransform(ui::IconTextureSource::TRANSFORM_TILE, monitor); - markerX = bounds[0].x + 1; + if (pip_style == OUTSIDE_TILE) + { + markerX = geo.x; + } + else + { + auto const& bounds = arg.icon->GetTransform(ui::IconTextureSource::TRANSFORM_TILE, monitor); + markerX = bounds[0].x + 1; + } } - nux::TexCoordXForm texxform; nux::Color color = nux::color::LightGrey; @@ -1059,41 +1092,87 @@ void IconRenderer::RenderIndicators(nux::GraphicsEngine& GfxContext, if (!arg.running_on_viewport) { markers[0] = markerCenter; - texture = local_textures_->arrow_empty_ltr; + if (left_markers) + texture = local_textures_->arrow_empty_ltr; + else + texture = local_textures_->arrow_empty_btt; } else if (running == 1) { markers[0] = markerCenter; - texture = local_textures_->arrow_ltr; + if (left_markers) + texture = local_textures_->arrow_ltr; + else + texture = local_textures_->arrow_btt; } else if (running == 2) { - texture = local_textures_->pip_ltr; - - double default_tex_height = local::MARKER_SIZES[local::IconSize::SMALL]; - int offset = std::max(1.0, std::round(2.0 * texture->GetHeight() / default_tex_height)); + int texture_size = 0; + if (left_markers) + { + texture = local_textures_->pip_ltr; + texture_size = texture->GetHeight(); + } + else + { + texture = local_textures_->pip_btt; + texture_size = texture->GetWidth(); + } + + double default_tex_size = local::MARKER_SIZES[local::IconSize::SMALL]; + int offset = std::max(1.0, std::round(2.0 * texture_size / default_tex_size)); markers[0] = markerCenter - offset; markers[1] = markerCenter + offset; } else { - texture = local_textures_->pip_ltr; - - double default_tex_height = local::MARKER_SIZES[local::IconSize::SMALL]; - int offset = std::max(1.0, std::round(4.0 * texture->GetHeight() / default_tex_height)); + int texture_size = 0; + if (left_markers) + { + texture = local_textures_->pip_ltr; + texture_size = texture->GetHeight(); + } + else + { + texture = local_textures_->pip_btt; + texture_size = texture->GetWidth(); + } + + double default_tex_size = local::MARKER_SIZES[local::IconSize::SMALL]; + int offset = std::max(1.0, std::round(4.0 * texture_size / default_tex_size)); markers[0] = markerCenter - offset; markers[1] = markerCenter; markers[2] = markerCenter + offset; } + int markerY = 0; + if (!left_markers) + { + if (pip_style == OUTSIDE_TILE) + { + markerY = (geo.y + geo.height) - texture->GetHeight(); + } + else + { + auto const& bounds = arg.icon->GetTransform(ui::IconTextureSource::TRANSFORM_TILE, monitor); + + markerY = (bounds[2].y - (texture->GetHeight()*scale)); + } + } + for (int i = 0; i < 3; i++) { int center = markers[i]; if (center == -100) break; + if (left_markers) + markerY = center - std::round(texture->GetHeight() / 2.0f); + else + markerX = center - std::round(texture->GetWidth() / 2.0f); + GfxContext.QRP_1Tex(markerX, - center - std::round(texture->GetHeight() / 2.0f), + markerY, texture->GetWidth(), texture->GetHeight(), texture->GetDeviceTexture(), @@ -1106,15 +1185,29 @@ void IconRenderer::RenderIndicators(nux::GraphicsEngine& GfxContext, { nux::TexCoordXForm texxform; - auto const& arrow_rtl = local_textures_->arrow_rtl; nux::Color color = nux::color::LightGrey * alpha; - GfxContext.QRP_1Tex((geo.x + geo.width) - arrow_rtl->GetWidth(), - markerCenter - std::round(arrow_rtl->GetHeight() / 2.0f), - arrow_rtl->GetWidth(), - arrow_rtl->GetHeight(), - arrow_rtl->GetDeviceTexture(), - texxform, - color); + if (left_markers) + { + auto const& arrow_rtl = local_textures_->arrow_rtl; + GfxContext.QRP_1Tex((geo.x + geo.width) - arrow_rtl->GetWidth(), + markerCenter - std::round(arrow_rtl->GetHeight() / 2.0f), + arrow_rtl->GetWidth(), + arrow_rtl->GetHeight(), + arrow_rtl->GetDeviceTexture(), + texxform, + color); + } + else + { + auto const& arrow_ttb = local_textures_->arrow_ttb; + GfxContext.QRP_1Tex(markerCenter - std::round(arrow_ttb->GetWidth() / 2.0f), + geo.y, + arrow_ttb->GetWidth(), + arrow_ttb->GetHeight(), + arrow_ttb->GetDeviceTexture(), + texxform, + color); + } } } @@ -1267,8 +1360,12 @@ void IconRenderer::GetInverseScreenPerspectiveMatrix(nux::Matrix4& ViewMatrix, n float y_cs = -CameraToScreenDistance * tanf(0.5f * Fovy/* *M_PI/180.0f*/); float x_cs = y_cs * AspectRatio; - ViewMatrix = nux::Matrix4::TRANSLATE(-x_cs, y_cs, CameraToScreenDistance) * - nux::Matrix4::SCALE(2.0f * x_cs / ViewportWidth, -2.0f * y_cs / ViewportHeight, -2.0f * 3 * y_cs / ViewportHeight /* or -2.0f * x_cs/ViewportWidth*/); + if (Settings::Instance().launcher_position() == LauncherPosition::LEFT) + ViewMatrix = nux::Matrix4::TRANSLATE(-x_cs, y_cs, CameraToScreenDistance) * + nux::Matrix4::SCALE(2.0f * x_cs / ViewportWidth, -2.0f * y_cs / ViewportHeight, -2.0f * 3 * y_cs / ViewportHeight /* or -2.0f * x_cs/ViewportWidth*/); + else + ViewMatrix = nux::Matrix4::TRANSLATE(-x_cs, y_cs, CameraToScreenDistance) * + nux::Matrix4::SCALE(2.0f * x_cs / ViewportWidth, -2.0f * y_cs / ViewportHeight, -2.0f * x_cs / ViewportWidth); PerspectiveMatrix.Perspective(Fovy, AspectRatio, NearClipPlane, FarClipPlane); } diff --git a/unity-shared/OverlayRenderer.cpp b/unity-shared/OverlayRenderer.cpp index 7f84f6fc0..2b5aba5ce 100644 --- a/unity-shared/OverlayRenderer.cpp +++ b/unity-shared/OverlayRenderer.cpp @@ -26,7 +26,9 @@ #include "DashStyle.h" #include "unity-shared/BackgroundEffectHelper.h" +#include "unity-shared/PanelStyle.h" #include "unity-shared/UnitySettings.h" +#include "unity-shared/UScreen.h" #include "unity-shared/WindowManager.h" @@ -75,19 +77,19 @@ public: std::unique_ptr<nux::TextureLayer> bg_refine_gradient_; - nux::ObjectPtr<nux::BaseTexture> bottom_texture_; - nux::ObjectPtr<nux::BaseTexture> bottom_texture_mask_; + nux::ObjectPtr<nux::BaseTexture> horizontal_texture_; + nux::ObjectPtr<nux::BaseTexture> horizontal_texture_mask_; nux::ObjectPtr<nux::BaseTexture> right_texture_; nux::ObjectPtr<nux::BaseTexture> right_texture_mask_; nux::ObjectPtr<nux::BaseTexture> left_texture_; - nux::ObjectPtr<nux::BaseTexture> top_texture_; + nux::ObjectPtr<nux::BaseTexture> top_bottom_texture_; nux::ObjectPtr<nux::BaseTexture> corner_; nux::ObjectPtr<nux::BaseTexture> corner_mask_; nux::ObjectPtr<nux::BaseTexture> left_corner_; nux::ObjectPtr<nux::BaseTexture> left_corner_mask_; - nux::ObjectPtr<nux::BaseTexture> top_corner_; - nux::ObjectPtr<nux::BaseTexture> top_corner_mask_; + nux::ObjectPtr<nux::BaseTexture> right_corner_; + nux::ObjectPtr<nux::BaseTexture> right_corner_mask_; // temporary variable that stores the number of backgrounds we have rendered int bgs; @@ -116,7 +118,9 @@ OverlayRendererImpl::OverlayRendererImpl(OverlayRenderer *parent_) { parent->scale = Settings::Instance().em()->DPIScale(); parent->scale.changed.connect(sigc::hide(sigc::mem_fun(this, &OverlayRendererImpl::LoadScaledTextures))); + parent->owner.changed.connect(sigc::hide(sigc::mem_fun(this, &OverlayRendererImpl::LoadScaledTextures))); Settings::Instance().low_gfx_changed.connect(sigc::mem_fun(this, &OverlayRendererImpl::UpdateTextures)); + Settings::Instance().launcher_position.changed.connect(sigc::hide(sigc::mem_fun(this, &OverlayRendererImpl::LoadScaledTextures))); UpdateTextures(); LoadScaledTextures(); @@ -126,19 +130,25 @@ void OverlayRendererImpl::LoadScaledTextures() { double scale = parent->scale; auto& style = dash::Style::Instance(); - bottom_texture_ = style.GetDashBottomTile(scale); - bottom_texture_mask_ = style.GetDashBottomTileMask(scale); + bool dash_at_bottom; + if (Settings::Instance().launcher_position() == LauncherPosition::BOTTOM && parent->owner() == OverlayOwner::Dash) + dash_at_bottom = true; + else + dash_at_bottom = false; + + horizontal_texture_ = style.GetDashHorizontalTile(scale, dash_at_bottom); + horizontal_texture_mask_ = style.GetDashHorizontalTileMask(scale, dash_at_bottom); right_texture_ = style.GetDashRightTile(scale); right_texture_mask_ = style.GetDashRightTileMask(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); - top_corner_ = style.GetDashTopCorner(scale); - top_corner_mask_ = style.GetDashTopCornerMask(scale); + top_bottom_texture_ = style.GetDashTopOrBottomTile(scale, dash_at_bottom); + + corner_ = style.GetDashCorner(scale, dash_at_bottom); + corner_mask_ = style.GetDashCornerMask(scale, dash_at_bottom); + left_corner_ = style.GetDashLeftCorner(scale, dash_at_bottom); + left_corner_mask_ = style.GetDashLeftCornerMask(scale, dash_at_bottom); + right_corner_ = style.GetDashRightCorner(scale, dash_at_bottom); + right_corner_mask_ = style.GetDashRightCornerMask(scale, dash_at_bottom); } void OverlayRendererImpl::OnBgColorChanged(nux::Color const& new_color) @@ -598,7 +608,21 @@ void OverlayRendererImpl::Draw(nux::GraphicsEngine& gfx_context, nux::Geometry c if (Settings::Instance().form_factor() != FormFactor::NETBOOK || force_edges) { - nux::Geometry geo_border(content_geo.x, content_geo.y, larger_absolute_geo.width - content_geo.x, larger_absolute_geo.height); + int monitor = unity::UScreen::GetDefault()->GetMonitorWithMouse(); + nux::Geometry const& monitor_geo = unity::UScreen::GetDefault()->GetMonitorGeometry(monitor); + int launcher_size = Settings::Instance().LauncherSize(monitor); + int panel_height = panel::Style::Instance().PanelHeight(monitor); + + bool dash_at_bottom = false; + int border_y = content_geo.y; + int border_height = larger_absolute_geo.height; + if (Settings::Instance().launcher_position() == LauncherPosition::BOTTOM && !force_edges) + { + border_y = panel_height; + border_height = monitor_geo.height - launcher_size; + dash_at_bottom = true; + } + nux::Geometry geo_border(content_geo.x, border_y, larger_absolute_geo.width - content_geo.x, border_height); gfx_context.PushClippingRectangle(geo_border); // Paint the edges @@ -608,8 +632,8 @@ void OverlayRendererImpl::Draw(nux::GraphicsEngine& gfx_context, nux::Geometry c gfx_context.GetRenderStates().SetPremultipliedBlend(nux::SRC_OVER); nux::TexCoordXForm texxform; - auto const& bottom = bottom_texture_; - auto const& bottom_mask = bottom_texture_mask_; + auto const& horizontal = horizontal_texture_; + auto const& horizontal_mask = horizontal_texture_mask_; auto const& right = right_texture_; auto const& right_mask = right_texture_mask_; auto const& corner = corner_; @@ -617,14 +641,14 @@ void OverlayRendererImpl::Draw(nux::GraphicsEngine& gfx_context, nux::Geometry c auto const& left_corner = left_corner_; auto const& left_corner_mask = left_corner_mask_; auto const& left_tile = left_texture_; - auto const& top_corner = top_corner_; - auto const& top_corner_mask = top_corner_mask_; - auto const& top_tile = top_texture_; + auto const& right_corner = right_corner_; + auto const& right_corner_mask = right_corner_mask_; + auto const& top_tile = top_bottom_texture_; int left_corner_offset = LEFT_CORNER_OFFSET.CP(scale); int top_corner_offset = TOP_CORNER_OFFSET.CP(scale); nux::Size corner_size(corner->GetWidth(), corner->GetHeight()); - nux::Size top_corner_size(top_corner->GetWidth(), top_corner->GetHeight()); + nux::Size right_corner_size(right_corner->GetWidth(), right_corner->GetHeight()); nux::Size left_corner_size(left_corner->GetWidth(), left_corner->GetHeight()); geo.width += corner_size.width - left_corner_offset; @@ -633,10 +657,15 @@ void OverlayRendererImpl::Draw(nux::GraphicsEngine& gfx_context, nux::Geometry c // Corner texxform.SetTexCoordType(nux::TexCoordXForm::OFFSET_COORD); texxform.SetWrap(nux::TEXWRAP_CLAMP_TO_BORDER, nux::TEXWRAP_CLAMP_TO_BORDER); + int corner_y = 0; + if (dash_at_bottom) + corner_y = geo.y - corner_size.height + top_corner_offset; + else + corner_y = geo.y + (geo.height - corner_size.height); // Selectively erase blur region in the curbe gfx_context.QRP_ColorModTexAlpha(geo.x + (geo.width - corner_size.width), - geo.y + (geo.height - corner_size.height), + corner_y, corner_size.width, corner_size.height, corner_mask->GetDeviceTexture(), @@ -647,7 +676,7 @@ void OverlayRendererImpl::Draw(nux::GraphicsEngine& gfx_context, nux::Geometry c gfx_context.GetRenderStates().SetBlend(false); gfx_context.GetRenderStates().SetColorMask(false, false, false, true); RenderInverseMask(gfx_context, geo.x + (geo.width - corner_size.width), - geo.y + (geo.height - corner_size.height), + corner_y, corner_size.width, corner_size.height, corner_mask->GetDeviceTexture(), @@ -659,7 +688,7 @@ void OverlayRendererImpl::Draw(nux::GraphicsEngine& gfx_context, nux::Geometry c gfx_context.GetRenderStates().SetColorMask(true, true, true, true); gfx_context.QRP_1Tex(geo.x + (geo.width - corner_size.width), - geo.y + (geo.height - corner_size.height), + corner_y, corner_size.width, corner_size.height, corner->GetDeviceTexture(), @@ -667,19 +696,24 @@ void OverlayRendererImpl::Draw(nux::GraphicsEngine& gfx_context, nux::Geometry c nux::color::White); } { - // Bottom repeated texture + // Horizontal repeated texture int real_width = geo.width - (left_corner_size.width - left_corner_offset) - corner_size.width; - int offset = real_width % bottom->GetWidth(); + int offset = real_width % horizontal->GetWidth(); + int horizontal_y = 0; + if (dash_at_bottom) + horizontal_y = geo.y - horizontal->GetHeight() + top_corner_offset; + else + horizontal_y = geo.y + (geo.height - horizontal->GetHeight()); texxform.SetTexCoordType(nux::TexCoordXForm::OFFSET_COORD); texxform.SetWrap(nux::TEXWRAP_REPEAT, nux::TEXWRAP_REPEAT); // Selectively erase blur region in the curbe gfx_context.QRP_ColorModTexAlpha(left_corner_size.width - left_corner_offset - offset, - geo.y + (geo.height - bottom->GetHeight()), + horizontal_y, real_width + offset, - bottom->GetHeight(), - bottom_mask->GetDeviceTexture(), + horizontal->GetHeight(), + horizontal_mask->GetDeviceTexture(), texxform, nux::color::Black); @@ -687,10 +721,10 @@ void OverlayRendererImpl::Draw(nux::GraphicsEngine& gfx_context, nux::Geometry c gfx_context.GetRenderStates().SetBlend(false); gfx_context.GetRenderStates().SetColorMask(false, false, false, true); RenderInverseMask(gfx_context, left_corner_size.width - left_corner_offset - offset, - geo.y + (geo.height - bottom->GetHeight()), + horizontal_y, real_width + offset, - bottom->GetHeight(), - bottom_mask->GetDeviceTexture(), + horizontal->GetHeight(), + horizontal_mask->GetDeviceTexture(), texxform, nux::color::White); @@ -699,21 +733,26 @@ void OverlayRendererImpl::Draw(nux::GraphicsEngine& gfx_context, nux::Geometry c gfx_context.GetRenderStates().SetColorMask(true, true, true, true); gfx_context.QRP_1Tex(left_corner_size.width - left_corner_offset - offset, - geo.y + (geo.height - bottom->GetHeight()), + horizontal_y, real_width + offset, - bottom->GetHeight(), - bottom->GetDeviceTexture(), + horizontal->GetHeight(), + horizontal->GetDeviceTexture(), texxform, nux::color::White); } { - // Bottom left corner + // Bottom left or top left corner texxform.SetTexCoordType(nux::TexCoordXForm::OFFSET_COORD); texxform.SetWrap(nux::TEXWRAP_CLAMP_TO_BORDER, nux::TEXWRAP_CLAMP_TO_BORDER); + int left_corner_y = 0; + if (dash_at_bottom) + left_corner_y = geo.y - left_corner_size.height + top_corner_offset; + else + left_corner_y = geo.y + (geo.height - left_corner_size.height); // Selectively erase blur region in the curbe gfx_context.QRP_ColorModTexAlpha(geo.x - left_corner_offset, - geo.y + (geo.height - left_corner_size.height), + left_corner_y, left_corner_size.width, left_corner_size.height, left_corner_mask->GetDeviceTexture(), @@ -724,7 +763,7 @@ void OverlayRendererImpl::Draw(nux::GraphicsEngine& gfx_context, nux::Geometry c gfx_context.GetRenderStates().SetBlend(false); gfx_context.GetRenderStates().SetColorMask(false, false, false, true); RenderInverseMask(gfx_context, geo.x - left_corner_offset, - geo.y + (geo.height - left_corner_size.height), + left_corner_y, left_corner_size.width, left_corner_size.height, left_corner_mask->GetDeviceTexture(), @@ -736,7 +775,7 @@ void OverlayRendererImpl::Draw(nux::GraphicsEngine& gfx_context, nux::Geometry c gfx_context.GetRenderStates().SetColorMask(true, true, true, true); gfx_context.QRP_1Tex(geo.x - left_corner_offset, - geo.y + (geo.height - left_corner_size.height), + left_corner_y, left_corner_size.width, left_corner_size.height, left_corner->GetDeviceTexture(), @@ -748,12 +787,27 @@ void OverlayRendererImpl::Draw(nux::GraphicsEngine& gfx_context, nux::Geometry c nux::Geometry real_geo = geometry; int real_height = real_geo.height - geo.height; int offset = real_height % left_tile->GetHeight(); + int left_texture_y = 0; + if (dash_at_bottom) + { + left_texture_y = panel_height; + real_height = monitor_geo.height - launcher_size - content_geo.height - left_corner->GetHeight() - panel_height + top_corner_offset; + } + else if (Settings::Instance().launcher_position() == LauncherPosition::BOTTOM) + { + left_texture_y = geo.y + geo.height; + real_height -= launcher_size; + } + else + { + left_texture_y = geo.y + geo.height; + } texxform.SetTexCoordType(nux::TexCoordXForm::OFFSET_COORD); texxform.SetWrap(nux::TEXWRAP_REPEAT, nux::TEXWRAP_REPEAT); gfx_context.QRP_1Tex(geo.x - left_corner_offset, - geo.y + geo.height, + left_texture_y, left_tile->GetWidth(), real_height + offset, left_tile->GetDeviceTexture(), @@ -764,12 +818,17 @@ void OverlayRendererImpl::Draw(nux::GraphicsEngine& gfx_context, nux::Geometry c // Right edge texxform.SetTexCoordType(nux::TexCoordXForm::OFFSET_COORD); texxform.SetWrap(nux::TEXWRAP_REPEAT, nux::TEXWRAP_REPEAT); + int right_edge_y = 0; + if (dash_at_bottom) + right_edge_y = geo.y + top_corner_offset; + else + right_edge_y = geo.y + right_corner_size.height - top_corner_offset; // Selectively erase blur region in the curbe gfx_context.QRP_ColorModTexAlpha(geo.x + geo.width - right->GetWidth(), - geo.y + top_corner_size.height - top_corner_offset, + right_edge_y, right->GetWidth(), - geo.height - corner_size.height - (top_corner_size.height - top_corner_offset), + geo.height - corner_size.height - (right_corner_size.height - top_corner_offset), right_mask->GetDeviceTexture(), texxform, nux::color::Black); @@ -778,9 +837,9 @@ void OverlayRendererImpl::Draw(nux::GraphicsEngine& gfx_context, nux::Geometry c gfx_context.GetRenderStates().SetBlend(false); gfx_context.GetRenderStates().SetColorMask(false, false, false, true); RenderInverseMask(gfx_context, geo.x + geo.width - right->GetWidth(), - geo.y + top_corner_size.height - top_corner_offset, + right_edge_y, right->GetWidth(), - geo.height - corner_size.height - (top_corner_size.height - top_corner_offset), + geo.height - corner_size.height - (right_corner_size.height - top_corner_offset), right_mask->GetDeviceTexture(), texxform, nux::color::White); @@ -790,24 +849,29 @@ void OverlayRendererImpl::Draw(nux::GraphicsEngine& gfx_context, nux::Geometry c gfx_context.GetRenderStates().SetColorMask(true, true, true, true); gfx_context.QRP_1Tex(geo.x + geo.width - right->GetWidth(), - geo.y + top_corner_size.height - top_corner_offset, + right_edge_y, right->GetWidth(), - geo.height - corner_size.height - (top_corner_size.height - top_corner_offset), + geo.height - corner_size.height - (right_corner_size.height - top_corner_offset), right->GetDeviceTexture(), texxform, nux::color::White); } { - // Top right corner + // Top right or bottom right corner texxform.SetTexCoordType(nux::TexCoordXForm::OFFSET_COORD); texxform.SetWrap(nux::TEXWRAP_CLAMP_TO_BORDER, nux::TEXWRAP_CLAMP_TO_BORDER); + int right_corner_y = 0; + if (dash_at_bottom) + right_corner_y = geo.y + content_geo.height - right_corner_size.height + top_corner_offset; + else + right_corner_y = geo.y - top_corner_offset; // Selectively erase blur region in the curbe gfx_context.QRP_ColorModTexAlpha(geo.x + geo.width - right->GetWidth(), - geo.y - top_corner_offset, - top_corner_size.width, - top_corner_size.height, - top_corner_mask->GetDeviceTexture(), + right_corner_y, + right_corner_size.width, + right_corner_size.height, + right_corner_mask->GetDeviceTexture(), texxform, nux::color::Black); @@ -815,10 +879,10 @@ void OverlayRendererImpl::Draw(nux::GraphicsEngine& gfx_context, nux::Geometry c gfx_context.GetRenderStates().SetBlend(false); gfx_context.GetRenderStates().SetColorMask(false, false, false, true); RenderInverseMask(gfx_context, geo.x + geo.width - right->GetWidth(), - geo.y - top_corner_offset, - top_corner_size.width, - top_corner_size.height, - top_corner_mask->GetDeviceTexture(), + right_corner_y, + right_corner_size.width, + right_corner_size.height, + right_corner_mask->GetDeviceTexture(), texxform, nux::color::White); @@ -826,21 +890,26 @@ void OverlayRendererImpl::Draw(nux::GraphicsEngine& gfx_context, nux::Geometry c gfx_context.GetRenderStates().SetPremultipliedBlend(nux::SRC_OVER); gfx_context.GetRenderStates().SetColorMask(true, true, true, true); gfx_context.QRP_1Tex(geo.x + geo.width - right->GetWidth(), - geo.y - top_corner_offset, - top_corner_size.width, - top_corner_size.height, - top_corner->GetDeviceTexture(), + right_corner_y, + right_corner_size.width, + right_corner_size.height, + right_corner->GetDeviceTexture(), texxform, nux::color::White); } { - // Top edge + // Top or bottom edge texxform.SetTexCoordType(nux::TexCoordXForm::OFFSET_COORD); texxform.SetWrap(nux::TEXWRAP_REPEAT, nux::TEXWRAP_REPEAT); + int y = 0; + if (dash_at_bottom) + y = geo.y + content_geo.height - top_tile->GetHeight() + top_corner_offset; + else + y = geo.y - top_corner_offset; gfx_context.GetRenderStates().SetPremultipliedBlend(nux::SRC_OVER); gfx_context.QRP_1Tex(geo.x + geo.width, - geo.y - top_corner_offset, + y, geometry.width - (geo.x + geo.width), top_tile->GetHeight(), top_tile->GetDeviceTexture(), diff --git a/unity-shared/OverlayRenderer.h b/unity-shared/OverlayRenderer.h index c043aae6c..943448ed1 100644 --- a/unity-shared/OverlayRenderer.h +++ b/unity-shared/OverlayRenderer.h @@ -29,6 +29,12 @@ namespace unity { +enum class OverlayOwner +{ + Dash = 0, + Hud +}; + class OverlayRendererImpl; class OverlayRenderer { @@ -40,6 +46,7 @@ public: nux::Property<int> x_offset; nux::Property<int> y_offset; nux::Property<double> scale; + nux::Property<OverlayOwner> owner; OverlayRenderer(); ~OverlayRenderer(); diff --git a/unity-shared/SpreadFilter.cpp b/unity-shared/SpreadFilter.cpp index e1bc8bf49..fa7d33147 100644 --- a/unity-shared/SpreadFilter.cpp +++ b/unity-shared/SpreadFilter.cpp @@ -55,7 +55,7 @@ Filter::Filter() auto& settings = Settings::Instance(); auto const& work_area = wm.GetWorkAreaGeometry(0); int monitor = wm.MonitorGeometryIn(work_area); - int launcher_width = settings.LauncherWidth(monitor); + int launcher_width = settings.LauncherSize(monitor); auto const& cv = settings.em(monitor); search_bar_ = SearchBar::Ptr(new SearchBar()); @@ -81,7 +81,10 @@ Filter::Filter() view_window_->SetOpacity(0.0f); view_window_->SetEnterFocusInputArea(search_bar_.GetPointer()); view_window_->SetInputFocus(); - view_window_->SetXY(OFFSET_X.CP(cv) + std::max(work_area.x, launcher_width), OFFSET_Y.CP(cv) + work_area.y); + if (Settings::Instance().launcher_position() == LauncherPosition::LEFT) + view_window_->SetXY(OFFSET_X.CP(cv) + std::max(work_area.x, launcher_width), OFFSET_Y.CP(cv) + work_area.y); + else + view_window_->SetXY(OFFSET_X.CP(cv) + work_area.x, OFFSET_Y.CP(cv) + work_area.y); fade_animator_.updated.connect([this] (double opacity) { view_window_->SetOpacity(opacity); }); nux::GetWindowCompositor().SetKeyFocusArea(search_bar_->text_entry()); diff --git a/unity-shared/UnitySettings.cpp b/unity-shared/UnitySettings.cpp index 66dd23354..7109ebdf3 100644 --- a/unity-shared/UnitySettings.cpp +++ b/unity-shared/UnitySettings.cpp @@ -40,6 +40,9 @@ const std::string FORM_FACTOR = "form-factor"; const std::string DOUBLE_CLICK_ACTIVATE = "double-click-activate"; const std::string DESKTOP_TYPE = "desktop-type"; +const std::string LAUNCHER_SETTINGS = "com.canonical.Unity.Launcher"; +const std::string LAUNCHER_POSITION = "launcher-position"; + const std::string LIM_SETTINGS = "com.canonical.Unity.IntegratedMenus"; const std::string CLICK_MOVEMENT_THRESHOLD = "click-movement-threshold"; const std::string DOUBLE_CLICK_WAIT = "double-click-wait"; @@ -63,7 +66,7 @@ const std::string GNOME_TEXT_SCALE_FACTOR = "text-scaling-factor"; const std::string REMOTE_CONTENT_SETTINGS = "com.canonical.Unity.Lenses"; const std::string REMOTE_CONTENT_KEY = "remote-content-search"; -const int DEFAULT_LAUNCHER_WIDTH = 64; +const int DEFAULT_LAUNCHER_SIZE = 64; const int MINIMUM_DESKTOP_HEIGHT = 800; const int GNOME_SETTINGS_CHANGED_WAIT_SECONDS = 1; const double DEFAULT_DPI = 96.0f; @@ -78,12 +81,14 @@ public: Impl(Settings* owner) : parent_(owner) , usettings_(g_settings_new(SETTINGS_NAME.c_str())) + , launcher_settings_(g_settings_new(LAUNCHER_SETTINGS.c_str())) , lim_settings_(g_settings_new(LIM_SETTINGS.c_str())) , ui_settings_(g_settings_new(UI_SETTINGS.c_str())) , ubuntu_ui_settings_(g_settings_new(UBUNTU_UI_SETTINGS.c_str())) , gnome_ui_settings_(g_settings_new(GNOME_UI_SETTINGS.c_str())) , remote_content_settings_(g_settings_new(REMOTE_CONTENT_SETTINGS.c_str())) - , launcher_widths_(monitors::MAX, DEFAULT_LAUNCHER_WIDTH) + , launcher_sizes_(monitors::MAX, DEFAULT_LAUNCHER_SIZE) + , cached_launcher_position_(LauncherPosition::LEFT) , cached_form_factor_(FormFactor::DESKTOP) , cursor_scale_(1.0) , cached_double_click_activate_(true) @@ -95,6 +100,8 @@ public: parent_->form_factor.SetSetterFunction(sigc::mem_fun(this, &Impl::SetFormFactor)); parent_->double_click_activate.SetGetterFunction(sigc::mem_fun(this, &Impl::GetDoubleClickActivate)); parent_->remote_content.SetGetterFunction(sigc::mem_fun(this, &Impl::GetRemoteContentEnabled)); + parent_->launcher_position.SetGetterFunction(sigc::mem_fun(this, &Impl::GetLauncherPosition)); + parent_->launcher_position.SetSetterFunction(sigc::mem_fun(this, &Impl::SetLauncherPosition)); parent_->desktop_type.SetGetterFunction(sigc::mem_fun(this, &Impl::GetDesktopType)); for (unsigned i = 0; i < monitors::MAX; ++i) @@ -109,6 +116,11 @@ public: parent_->double_click_activate.changed.emit(cached_double_click_activate_); }); + signals_.Add<void, GSettings*, const gchar*>(launcher_settings_, "changed::" + LAUNCHER_POSITION, [this] (GSettings*, const gchar*) { + CacheLauncherPosition(); + parent_->launcher_position.changed.emit(cached_launcher_position_); + }); + signals_.Add<void, GSettings*, const gchar*>(ubuntu_ui_settings_, "changed::" + SCALE_FACTOR, [this] (GSettings*, const gchar* t) { UpdateDPI(); }); @@ -164,6 +176,7 @@ public: CacheFormFactor(); CacheDoubleClickActivate(); UpdateRemoteContentSearch(); + CacheLauncherPosition(); } void CacheFormFactor() @@ -197,6 +210,11 @@ public: cached_double_click_activate_ = g_settings_get_boolean(usettings_, DOUBLE_CLICK_ACTIVATE.c_str()); } + void CacheLauncherPosition() + { + cached_launcher_position_ = static_cast<LauncherPosition>(g_settings_get_enum(launcher_settings_, LAUNCHER_POSITION.c_str())); + } + void UpdateLimSetting() { parent_->lim_movement_thresold = g_settings_get_uint(lim_settings_, CLICK_MOVEMENT_THRESHOLD.c_str()); @@ -220,6 +238,17 @@ public: return cached_double_click_activate_; } + LauncherPosition GetLauncherPosition() const + { + return cached_launcher_position_; + } + + bool SetLauncherPosition(LauncherPosition launcherPosition) + { + g_settings_set_enum(launcher_settings_, LAUNCHER_POSITION.c_str(), static_cast<int>(launcherPosition)); + return false; + } + DesktopType GetDesktopType() const { return static_cast<DesktopType>(g_settings_get_enum(usettings_, DESKTOP_TYPE.c_str())); @@ -353,6 +382,7 @@ public: Settings* parent_; glib::Object<GSettings> usettings_; + glib::Object<GSettings> launcher_settings_; glib::Object<GSettings> lim_settings_; glib::Object<GSettings> ui_settings_; glib::Object<GSettings> ubuntu_ui_settings_; @@ -361,7 +391,8 @@ public: glib::Source::UniquePtr changing_gnome_settings_timeout_; glib::SignalManager signals_; std::vector<EMConverter::Ptr> em_converters_; - std::vector<int> launcher_widths_; + std::vector<int> launcher_sizes_; + LauncherPosition cached_launcher_position_; FormFactor cached_form_factor_; double cursor_scale_; bool cached_double_click_activate_; @@ -423,19 +454,19 @@ EMConverter::Ptr const& Settings::em(int monitor) const return pimpl->em(monitor); } -void Settings::SetLauncherWidth(int launcher_width, int monitor) +void Settings::SetLauncherSize(int launcher_size, int monitor) { if (monitor < 0 || monitor >= (int)monitors::MAX) { - LOG_ERROR(logger) << "Invalid monitor index: " << monitor << ". Not updating laucher width."; + LOG_ERROR(logger) << "Invalid monitor index: " << monitor << ". Not updating launcher size."; } else { - pimpl->launcher_widths_[monitor] = launcher_width; + pimpl->launcher_sizes_[monitor] = launcher_size; } } -int Settings::LauncherWidth(int monitor) const +int Settings::LauncherSize(int monitor) const { if (monitor < 0 || monitor >= (int)monitors::MAX) { @@ -443,7 +474,7 @@ int Settings::LauncherWidth(int monitor) const return 0; } - return pimpl->launcher_widths_[monitor]; + return pimpl->launcher_sizes_[monitor]; } } // namespace unity diff --git a/unity-shared/UnitySettings.h b/unity-shared/UnitySettings.h index f34570f5c..268cf3474 100644 --- a/unity-shared/UnitySettings.h +++ b/unity-shared/UnitySettings.h @@ -35,10 +35,16 @@ enum class FormFactor TV }; +enum class LauncherPosition +{ + LEFT = 0, + BOTTOM +}; + enum class DesktopType { - UBUNTU, - UBUNTUKYLIN + UBUNTU, + UBUNTUKYLIN }; class Settings @@ -52,8 +58,8 @@ public: void SetLowGfxMode(const bool low_gfx); EMConverter::Ptr const& em(int monitor = 0) const; - void SetLauncherWidth(int launcher_width, int monitor); - int LauncherWidth(int monitor) const; + void SetLauncherSize(int launcher_size, int monitor); + int LauncherSize(int mointor) const; nux::RWProperty<FormFactor> form_factor; nux::Property<bool> is_standalone; @@ -64,6 +70,7 @@ public: nux::Property<bool> lim_unfocused_popup; nux::Property<double> font_scaling; nux::ROProperty<bool> remote_content; + nux::RWProperty<LauncherPosition> launcher_position; sigc::signal<void> dpi_changed; sigc::signal<void> low_gfx_changed; |
