diff options
35 files changed, 857 insertions, 201 deletions
diff --git a/UnityCore/DBusIndicators.cpp b/UnityCore/DBusIndicators.cpp index 2e3df31ce..49250973f 100644 --- a/UnityCore/DBusIndicators.cpp +++ b/UnityCore/DBusIndicators.cpp @@ -48,7 +48,7 @@ const std::string SERVICE_IFACE("com.canonical.Unity.Panel.Service"); class DBusIndicators::Impl { public: - Impl(DBusIndicators* owner); + Impl(std::string const& dbus_name, DBusIndicators* owner); void CheckLocalService(); void RequestSyncAll(); @@ -84,9 +84,9 @@ public: // Public Methods -DBusIndicators::Impl::Impl(DBusIndicators* owner) +DBusIndicators::Impl::Impl(std::string const& dbus_name, DBusIndicators* owner) : owner_(owner) - , gproxy_(SERVICE_NAME, SERVICE_PATH, SERVICE_IFACE, + , gproxy_(dbus_name, SERVICE_PATH, SERVICE_IFACE, G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES) { gproxy_.Connect("ReSync", sigc::mem_fun(this, &DBusIndicators::Impl::OnReSync)); @@ -276,6 +276,8 @@ void DBusIndicators::Impl::Sync(GVariant* args) return; std::map<Indicator::Ptr, Indicator::Entries> indicators; + int wantedIndex = 0; + bool anyIndexDifferent = false; g_variant_get(args, "(a(ssssbbusbbi))", &iter); while (g_variant_iter_loop(iter, "(ssssbbusbbi)", @@ -305,7 +307,18 @@ void DBusIndicators::Impl::Sync(GVariant* args) // Null entries (entry_id == "") are empty indicators. if (entry != "") { - Entry::Ptr e = indicator->GetEntry(entry_id); + Entry::Ptr e; + if (!anyIndexDifferent) + { + // Indicators can only add or remove entries, so if + // there is a index change we can't reuse the existing ones + // after that index + int existingEntryIndex = indicator->EntryIndex(entry_id); + if (wantedIndex == existingEntryIndex) + e = indicator->GetEntry(entry_id); + else + anyIndexDifferent = true; + } if (!e) { @@ -321,6 +334,7 @@ void DBusIndicators::Impl::Sync(GVariant* args) } entries.push_back(e); + wantedIndex++; } } g_variant_iter_free(iter); @@ -393,12 +407,21 @@ void DBusIndicators::Impl::SyncGeometries(std::string const& name, } DBusIndicators::DBusIndicators() - : pimpl(new Impl(this)) + : pimpl(new Impl(SERVICE_NAME, this)) +{} + +DBusIndicators::DBusIndicators(std::string const& dbus_name) + : pimpl(new Impl(dbus_name, this)) {} DBusIndicators::~DBusIndicators() {} +bool DBusIndicators::IsConnected() const +{ + return pimpl->gproxy_.IsConnected(); +} + void DBusIndicators::SyncGeometries(std::string const& name, EntryLocationMap const& locations) { diff --git a/UnityCore/DBusIndicators.h b/UnityCore/DBusIndicators.h index 13bf445eb..5ac1111c8 100644 --- a/UnityCore/DBusIndicators.h +++ b/UnityCore/DBusIndicators.h @@ -50,6 +50,10 @@ public: virtual void OnShowAppMenu(unsigned int xid, int x, int y, unsigned int timestamp); +protected: + DBusIndicators(std::string const& dbus_name); + bool IsConnected() const; + private: class Impl; std::unique_ptr<Impl> pimpl; diff --git a/UnityCore/Indicator.cpp b/UnityCore/Indicator.cpp index c5eb9f127..8fe03252c 100644 --- a/UnityCore/Indicator.cpp +++ b/UnityCore/Indicator.cpp @@ -115,6 +115,21 @@ Entry::Ptr Indicator::GetEntry(std::string const& entry_id) const return Entry::Ptr(); } +int Indicator::EntryIndex(std::string const& entry_id) const +{ + int i = 0; + for (auto entry : entries_) + { + if (entry->id() == entry_id) + { + return i; + } + ++i; + } + + return -1; +} + void Indicator::OnEntryShowMenu(std::string const& entry_id, unsigned int xid, int x, int y, unsigned int button, unsigned int timestamp) { diff --git a/UnityCore/Indicator.h b/UnityCore/Indicator.h index 1fe8f1c27..23b4bd575 100644 --- a/UnityCore/Indicator.h +++ b/UnityCore/Indicator.h @@ -48,6 +48,7 @@ public: void Sync(Entries const& new_entries); Entry::Ptr GetEntry(std::string const& entry_id) const; + int EntryIndex(std::string const& entry_id) const; Entries GetEntries() const; // Signals diff --git a/dash/LensView.cpp b/dash/LensView.cpp index 3dab2dd1d..444905b50 100755 --- a/dash/LensView.cpp +++ b/dash/LensView.cpp @@ -308,7 +308,7 @@ void LensView::OnCategoryAdded(Category const& category) if (existing_group->GetCategoryIndex() == index) return; } - PlacesGroup* group = new PlacesGroup(); + PlacesGroup* group = new PlacesGroup(dash::Style::Instance()); AddChild(group); group->SetName(name); group->SetIcon(icon_hint); diff --git a/dash/PlacesGroup.cpp b/dash/PlacesGroup.cpp index 47e7d0e65..43031695e 100755 --- a/dash/PlacesGroup.cpp +++ b/dash/PlacesGroup.cpp @@ -31,8 +31,6 @@ #include <UnityCore/GLibWrapper.h> #include "unity-shared/StaticCairoText.h" -#include "unity-shared/DashStyle.h" -#include "unity-shared/LineSeparator.h" #include "unity-shared/ubus-server.h" #include "unity-shared/UBusMessages.h" @@ -112,8 +110,9 @@ protected: NUX_IMPLEMENT_OBJECT_TYPE(PlacesGroup); -PlacesGroup::PlacesGroup() +PlacesGroup::PlacesGroup(dash::StyleInterface& style) : nux::View(NUX_TRACKER_LOCATION), + _style(style), _child_view(nullptr), _is_expanded(false), _n_visible_items_in_unexpand_mode(0), @@ -122,15 +121,13 @@ PlacesGroup::PlacesGroup() _coverflow_enabled(false), disabled_header_count_(false) { - dash::Style& style = dash::Style::Instance(); - SetAcceptKeyNavFocusOnMouseDown(false); SetAcceptKeyNavFocusOnMouseEnter(false); - nux::BaseTexture* arrow = style.GetGroupUnexpandIcon(); + nux::BaseTexture* arrow = _style.GetGroupExpandIcon(); - _background = style.GetCategoryBackground(); - _background_nofilters = style.GetCategoryBackgroundNoFilters(); + _background = _style.GetCategoryBackground(); + _background_nofilters = _style.GetCategoryBackgroundNoFilters(); nux::ROPConfig rop; rop.Blend = true; @@ -154,7 +151,7 @@ PlacesGroup::PlacesGroup() _group_layout->AddView(_header_view, 0, nux::MINOR_POSITION_TOP, nux::MINOR_SIZE_FULL); _header_layout = new nux::HLayout(NUX_TRACKER_LOCATION); - _header_layout->SetLeftAndRightPadding(style.GetCategoryHeaderLeftPadding(), 0); + _header_layout->SetLeftAndRightPadding(_style.GetCategoryHeaderLeftPadding(), 0); _header_layout->SetSpaceBetweenChildren(10); _header_view->SetLayout(_header_layout); @@ -449,7 +446,7 @@ long PlacesGroup::ComputeContentSize() // only the width matters if (_cached_geometry.GetWidth() != geo.GetWidth()) { - _focus_layer.reset(dash::Style::Instance().FocusOverlay(geo.width - kHighlightLeftPadding - kHighlightRightPadding, kHighlightHeight)); + _focus_layer.reset(_style.FocusOverlay(geo.width - kHighlightLeftPadding - kHighlightRightPadding, kHighlightHeight)); _cached_geometry = geo; } return ret; @@ -552,11 +549,10 @@ PlacesGroup::SetExpanded(bool is_expanded) Refresh(); - dash::Style& style = dash::Style::Instance(); if (_is_expanded) - _expand_icon->SetTexture(style.GetGroupUnexpandIcon()); + _expand_icon->SetTexture(_style.GetGroupUnexpandIcon()); else - _expand_icon->SetTexture(style.GetGroupExpandIcon()); + _expand_icon->SetTexture(_style.GetGroupExpandIcon()); expanded.emit(this); } diff --git a/dash/PlacesGroup.h b/dash/PlacesGroup.h index a7c10dae6..6f068b952 100644 --- a/dash/PlacesGroup.h +++ b/dash/PlacesGroup.h @@ -28,6 +28,7 @@ #include <sigc++/sigc++.h> +#include "unity-shared/DashStyleInterface.h" #include "unity-shared/IconTexture.h" #include "unity-shared/Introspectable.h" #include "unity-shared/StaticCairoText.h" @@ -53,7 +54,7 @@ class PlacesGroup : public nux::View, public debug::Introspectable NUX_DECLARE_OBJECT_TYPE(PlacesGroup, nux::View); public: - PlacesGroup(); + PlacesGroup(dash::StyleInterface& style); void SetIcon(std::string const& icon); void SetName(std::string const& name); @@ -114,6 +115,8 @@ private: void RefreshLabel(); private: + dash::StyleInterface& _style; + nux::VLayout* _group_layout; nux::View* _header_view; nux::HLayout* _header_layout; diff --git a/dash/previews/ActionButton.cpp b/dash/previews/ActionButton.cpp index 7c392787f..76582f6a4 100644 --- a/dash/previews/ActionButton.cpp +++ b/dash/previews/ActionButton.cpp @@ -199,7 +199,7 @@ void ActionButton::RedrawTheme(nux::Geometry const& geom, cairo_t* cr, nux::Butt void ActionButton::RedrawFocusOverlay(nux::Geometry const& geom, cairo_t* cr) { - Style::Instance().ButtonFocusOverlay(cr); + Style::Instance().ButtonFocusOverlay(cr, 0.20f); } long ActionButton::ComputeContentSize() diff --git a/dash/previews/SocialPreviewContent.cpp b/dash/previews/SocialPreviewContent.cpp index f1f476241..7b224e686 100644 --- a/dash/previews/SocialPreviewContent.cpp +++ b/dash/previews/SocialPreviewContent.cpp @@ -38,14 +38,19 @@ namespace previews namespace { nux::logging::Logger logger("unity.dash.previews.socialpreviewcontent"); + +const int BUBBLE_WIDTH = 300; +const int BUBBLE_HEIGHT = 250; +const int TAIL_HEIGHT = 50; +const int TAIL_POS_FROM_RIGHT = 60; } inline nux::Geometry GetBubbleGeometry(nux::Geometry const& geo) { - return nux::Geometry(geo.x + geo.width*0.1, - geo.y + geo.height*0.1, - geo.width - 2*(geo.width*0.1), - geo.height - 2*(geo.height*0.1)); + int width = MIN(BUBBLE_WIDTH, geo.width); + int height = MIN(BUBBLE_HEIGHT + TAIL_HEIGHT, geo.height); + + return nux::Geometry(geo.x + (geo.width - width)/2, geo.y + (geo.height - height)/2, width, height); } NUX_IMPLEMENT_OBJECT_TYPE(SocialPreviewContent); @@ -98,7 +103,7 @@ void SocialPreviewContent::Draw(nux::GraphicsEngine& gfx_engine, bool force_draw tex->GetHeight(), tex, texxform, - nux::Color(0.2f, 0.2f, 0.2f, 0.2f)); + nux::Color(1.0f, 1.0f, 1.0f, 1.0f)); gfx_engine.GetRenderStates().SetBlend(alpha, src, dest); @@ -145,10 +150,8 @@ void SocialPreviewContent::UpdateBaloonTexture() nux::Geometry geo_cr(GetBubbleGeometry(geo)); - double tail_width = MAX(0, MIN(geo_cr.width - 2*15.0, MIN(geo_cr.width*0.125, geo_cr.height*0.125))); - int max_width = geo_cr.width - 2*(geo_cr.width*0.1); - int max_height = geo_cr.height - 2*(geo_cr.height*0.1) - tail_width; + int max_height = (geo_cr.height - TAIL_HEIGHT) - 2*((geo_cr.height - TAIL_HEIGHT)*0.1); // this will update the texture with the actual size of the text. text_->SetMaximumHeight(max_height); @@ -156,8 +159,8 @@ void SocialPreviewContent::UpdateBaloonTexture() nux::Geometry const& geo_text = text_->GetGeometry(); // center text - text_->SetBaseX(geo.x + geo.width/2 - geo_text.width/2); - text_->SetBaseY(geo.y + geo.height/2 - geo_text.height/2 - tail_width/2); + text_->SetBaseX(geo_cr.x + geo_cr.width/2 - geo_text.width/2); + text_->SetBaseY(geo_cr.y + geo_cr.height/2 - geo_text.height/2 - TAIL_HEIGHT/2); if (geo_cr.width > 0 && geo_cr.height > 0) { @@ -167,21 +170,18 @@ void SocialPreviewContent::UpdateBaloonTexture() void SocialPreviewContent::RedrawBubble(nux::Geometry const& geom, cairo_t* cr, nux::ButtonVisualState faked_state) { - double blur = 4.0; + double line_width = 6.0; + double radius = 28.0; + double x = 0.0; + double y = 0.0; - double line_width = 1.0; - double radius = 20.0; - double tailWidthPercentage = 0.125; - double tailPositionPercentage = 0.7; - double x = 0.0 + blur; - double y = 0.0 + blur; - double width = cairo_image_surface_get_width(cairo_get_target(cr)) - 2*blur; - double height = cairo_image_surface_get_height(cairo_get_target(cr)) - 2*blur; + double width = MAX(0, cairo_image_surface_get_width(cairo_get_target(cr))); + double height = MAX(0, cairo_image_surface_get_height(cairo_get_target(cr)) - TAIL_HEIGHT); + double tailPosition = x + width - TAIL_POS_FROM_RIGHT - TAIL_HEIGHT; if (width > 0 && height > 0) { - DrawBubble(cr, line_width, radius, x, y, width, height, tailPositionPercentage, tailWidthPercentage); - dash::Style::Instance().Blur(cr, blur); + DrawBubble(cr, line_width, radius, x, y, width, height, tailPosition, TAIL_HEIGHT); } } @@ -214,8 +214,8 @@ void SocialPreviewContent::DrawBubble(cairo_t* cr, double y, double width, double height, - double tailPositionPercentage, - double tailWidthPercentage) + double tailPosition, + double tailWidth) { // sanity check if (cairo_status(cr) != CAIRO_STATUS_SUCCESS && @@ -224,16 +224,6 @@ void SocialPreviewContent::DrawBubble(cairo_t* cr, cairo_set_line_width(cr, line_width); - double tailWidth = MAX(0, MIN(width - 2*radius, MIN(width*tailWidthPercentage, height*tailWidthPercentage))); - double tail_start_pos = x + tailPositionPercentage*width - tailWidth/2; - - // recitfications for outer draw. - x += line_width/2; - y += line_width/2; - height -= line_width; - height -= tailWidth; - width -= line_width; - bool odd = true; odd = line_width != double((int)line_width); @@ -262,16 +252,16 @@ void SocialPreviewContent::DrawBubble(cairo_t* cr, 0.0f * G_PI / 180.0f, 90.0f * G_PI / 180.0f); - if (tailWidth > 0.0) + if (tailWidth > 0.0 && tailPosition > 0 && tailPosition <= (x + width - tailWidth - radius)) { // tail-right, tail top - cairo_line_to(cr, _align(tail_start_pos + tailWidth, odd), _align(y + height, odd)); + cairo_line_to(cr, _align(tailPosition + tailWidth, odd), _align(y + height, odd)); // tail-right, tail bottom - cairo_line_to(cr, _align(tail_start_pos + tailWidth, odd), _align(y + height + tailWidth, odd)); + cairo_line_to(cr, _align(tailPosition + tailWidth, odd), _align(y + height + tailWidth, odd)); // tail-right, tail bottom - cairo_line_to(cr, _align(tail_start_pos, odd), _align(y + height, odd)); + cairo_line_to(cr, _align(tailPosition, odd), _align(y + height, odd)); } // bottom-left, right of the corner @@ -293,14 +283,13 @@ void SocialPreviewContent::DrawBubble(cairo_t* cr, 180.0f * G_PI / 180.0f, 270.0f * G_PI / 180.0f); + nux::Color color_fill(1.0, 1.0, 1.0, 0.2); + cairo_set_source_rgba(cr, color_fill.red, color_fill.green, color_fill.blue, color_fill.alpha); + cairo_fill_preserve(cr); - nux::Color color(0.53, 1.0, 0.66, 0.5); - if (color.alpha != 0.0) - { - cairo_set_source_rgba(cr, color.red, color.green, color.blue, color.alpha); - cairo_fill_preserve(cr); - } - cairo_set_source_rgba(cr, color.red, color.green, color.blue, color.alpha); + cairo_set_operator(cr, CAIRO_OPERATOR_DEST_OUT); + nux::Color color_stroke(1.0, 1.0, 1.0, 0.5); + cairo_set_source_rgba(cr, color_stroke.red, color_stroke.green, color_stroke.blue, color_stroke.alpha); cairo_stroke(cr); } diff --git a/dash/previews/SocialPreviewContent.h b/dash/previews/SocialPreviewContent.h index 8dedef436..308a99e32 100644 --- a/dash/previews/SocialPreviewContent.h +++ b/dash/previews/SocialPreviewContent.h @@ -66,8 +66,8 @@ protected: double y, double width, double height, - double tailPositionPercentage, - double tailWidthPercentage); + double tailPosition, + double tailWidth); virtual std::string GetName() const; virtual void AddProperties(GVariantBuilder* builder); diff --git a/launcher/Launcher.cpp b/launcher/Launcher.cpp index 29a1b5709..dffa1c375 100644 --- a/launcher/Launcher.cpp +++ b/launcher/Launcher.cpp @@ -2054,9 +2054,7 @@ void Launcher::EndIconDrag() { if (!_drag_window->Cancelled() && _model->IconIndex(_drag_icon) != _drag_icon_position) { - if (_drag_icon->GetIconType() == AbstractLauncherIcon::IconType::DEVICE) - _drag_icon->Stick(false); - + _drag_icon->Stick(false); _model->Save(); } diff --git a/launcher/TrashLauncherIcon.cpp b/launcher/TrashLauncherIcon.cpp index 865d3edfe..928474b32 100644 --- a/launcher/TrashLauncherIcon.cpp +++ b/launcher/TrashLauncherIcon.cpp @@ -127,7 +127,7 @@ void TrashLauncherIcon::UpdateTrashIconCb(GObject* source, if (info) { - glib::Object<GIcon> icon(g_file_info_get_icon(info)); + glib::Object<GIcon> icon(g_file_info_get_icon(info), glib::AddRef()); glib::String icon_string(g_icon_to_string(icon)); self->icon_name = icon_string.Str(); diff --git a/launcher/VolumeImp.cpp b/launcher/VolumeImp.cpp index 2616b5424..51b96ce3c 100644 --- a/launcher/VolumeImp.cpp +++ b/launcher/VolumeImp.cpp @@ -127,7 +127,7 @@ public: g_volume_eject_with_operation(volume_, (GMountUnmountFlags)0, mount_op, - nullptr, + cancellable_, (GAsyncReadyCallback)OnEjectReady, this); } @@ -155,7 +155,7 @@ public: g_volume_mount(volume_, (GMountMountFlags) 0, mount_op, - nullptr, + cancellable_, (GAsyncReadyCallback) &Impl::OnMountFinish, this); } @@ -195,7 +195,7 @@ public: g_drive_stop(drive, (GMountUnmountFlags)0, mount_op, - nullptr, nullptr, nullptr); + cancellable_, nullptr, nullptr); } void Unmount() @@ -209,7 +209,7 @@ public: g_mount_unmount_with_operation(mount, (GMountUnmountFlags)0, op, - nullptr, nullptr, nullptr); + cancellable_, nullptr, nullptr); } VolumeImp* parent_; diff --git a/manual-tests/Panel.txt b/manual-tests/Panel.txt index d36af4588..d7d74676a 100644 --- a/manual-tests/Panel.txt +++ b/manual-tests/Panel.txt @@ -95,3 +95,19 @@ Expected Result: At no point during the actions should the panel (or launcher) blink or flicker out of existence. + +Panel shadow overdraw +--------------------- +Setup: +#. Install Google Chrome or Chromium. + +Actions: +#. Maximize a Chrome window. +#. Open several tabs so that the titles of some tabs are not fully visible + and fade out to the right. +#. Hover the mouse over the very top part of some tabs so tooltips appear. + +Expected Result: + No part of the panel shadow should ever appear on top of the maximized + Chrome window. + diff --git a/panel/PanelController.cpp b/panel/PanelController.cpp index 250c040a7..69ed3b0b5 100644 --- a/panel/PanelController.cpp +++ b/panel/PanelController.cpp @@ -301,7 +301,8 @@ float Controller::Impl::opacity() const } Controller::Controller() - : pimpl(new Impl()) + : launcher_width(64) + , pimpl(new Impl()) { UScreen* screen = UScreen::GetDefault(); screen->changed.connect(sigc::mem_fun(this, &Controller::OnScreenChanged)); diff --git a/panel/PanelView.cpp b/panel/PanelView.cpp index ac2fad3c6..95704e3a1 100644 --- a/panel/PanelView.cpp +++ b/panel/PanelView.cpp @@ -64,7 +64,7 @@ PanelView::PanelView(NUX_FILE_LINE_DECL) , _opacity(1.0f) , _monitor(0) , _stored_dash_width(0) - , _launcher_width(0) + , _launcher_width(64) { panel::Style::Instance().changed.connect(sigc::mem_fun(this, &PanelView::ForceUpdateBackground)); diff --git a/plugins/unityshell/src/unityshell.cpp b/plugins/unityshell/src/unityshell.cpp index 306539e36..37d5c741d 100644 --- a/plugins/unityshell/src/unityshell.cpp +++ b/plugins/unityshell/src/unityshell.cpp @@ -112,7 +112,7 @@ namespace decoration const unsigned CLOSE_SIZE = 19; const unsigned ITEMS_PADDING = 5; const unsigned RADIUS = 8; -const unsigned GLOW = 20; +const unsigned GLOW = 30; const nux::Color GLOW_COLOR(221, 72, 20); } // decoration namespace } // scale namespace @@ -560,6 +560,9 @@ void UnityScreen::setPanelShadowMatrix(const GLMatrix& matrix) void UnityScreen::paintPanelShadow(const CompRegion& clip) { + if (panel_controller_->opacity() == 0.0f) + return; + if (sources_.GetSource(local::RELAYOUT_TIMEOUT)) return; @@ -585,22 +588,6 @@ void UnityScreen::paintPanelShadow(const CompRegion& clip) if (redraw.isEmpty()) return; - const CompRect& bounds(redraw.boundingRect()); - - // Sub-rectangle of the shadow needing redrawing: - float x1 = bounds.x1(); - float y1 = bounds.y1(); - float x2 = bounds.x2(); - float y2 = bounds.y2(); - - // Texture coordinates of the above rectangle: - float tx1 = (x1 - shadowX) / shadowWidth; - float ty1 = (y1 - shadowY) / shadowHeight; - float tx2 = (x2 - shadowX) / shadowWidth; - float ty2 = (y2 - shadowY) / shadowHeight; - - nuxPrologue(); - // compiz doesn't use the same method of tracking monitors as our toolkit // we need to make sure we properly associate with the right monitor int current_monitor = -1; @@ -616,8 +603,14 @@ void UnityScreen::paintPanelShadow(const CompRegion& clip) i++; } - if (!(launcher_controller_->IsOverlayOpen() && current_monitor == overlay_monitor_) - && panel_controller_->opacity() > 0.0f) + if (launcher_controller_->IsOverlayOpen() && current_monitor == overlay_monitor_) + return; + + nuxPrologue(); + + const CompRect::vector& rects = redraw.rects(); + + for (auto const& r : rects) { foreach(GLTexture * tex, _shadow_texture) { @@ -639,6 +632,18 @@ void UnityScreen::paintPanelShadow(const CompRegion& clip) (GLushort)(panel_controller_->opacity() * 0xFFFF) }; + // Sub-rectangle of the shadow needing redrawing: + float x1 = r.x1(); + float y1 = r.y1(); + float x2 = r.x2(); + float y2 = r.y2(); + + // Texture coordinates of the above rectangle: + float tx1 = (x1 - shadowX) / shadowWidth; + float ty1 = (y1 - shadowY) / shadowHeight; + float tx2 = (x2 - shadowX) / shadowWidth; + float ty2 = (y2 - shadowY) / shadowHeight; + vertexData = { x1, y1, 0, x1, y2, 0, @@ -2466,6 +2471,15 @@ bool UnityWindow::glPaint(const GLWindowPaintAttrib& attrib, } } + if (WindowManager::Default().IsScaleActive() && ScaleScreen::get(screen)->getSelectedWindow() == window->id()) + { + nux::Geometry scaled_geo = GetScaledGeometry(); + int inside_glow = scale::decoration::RADIUS/4; + scaled_geo.Expand(-inside_glow, -inside_glow); + glow::Quads const& quads = computeGlowQuads(scaled_geo, glow_texture_, scale::decoration::GLOW); + paintGlow(matrix, attrib, region, quads, glow_texture_, scale::decoration::GLOW_COLOR, mask); + } + return gWindow->glPaint(wAttrib, matrix, region, mask); } @@ -2527,17 +2541,6 @@ bool UnityWindow::glDraw(const GLMatrix& matrix, uScreen->paintPanelShadow(region); } - if (WindowManager::Default().IsScaleActive() && - ScaleScreen::get(screen)->getSelectedWindow() == window->id()) - { - if (!region.isEmpty()) - { - double scale = ScaleWindow::get(window)->getCurrentPosition().scale; - glow::Quads const& quads = computeGlowQuads(glow_texture_, scale::decoration::GLOW, scale); - paintGlow(matrix, attrib, region, quads, glow_texture_, scale::decoration::GLOW_COLOR, mask); - } - } - return ret; } diff --git a/plugins/unityshell/src/unityshell.h b/plugins/unityshell/src/unityshell.h index 3a9112df2..48e2d2f53 100644 --- a/plugins/unityshell/src/unityshell.h +++ b/plugins/unityshell/src/unityshell.h @@ -450,7 +450,7 @@ private: void DrawTexture(GLTexture::List const& textures, GLWindowPaintAttrib const&, GLMatrix const&, unsigned mask, int x, int y, double aspect = 1.0f); - glow::Quads computeGlowQuads(GLTexture::List const& texture, int glow_size, double window_aspect = 1.0f); + glow::Quads computeGlowQuads(nux::Geometry const& geo, GLTexture::List const& texture, int glow_size); void paintGlow(GLMatrix const&, GLWindowPaintAttrib const&, CompRegion const&, glow::Quads const&, GLTexture::List const&, nux::Color const&, unsigned mask); diff --git a/plugins/unityshell/src/unityshell_glow.cpp b/plugins/unityshell/src/unityshell_glow.cpp index bc150c434..004ac54b0 100644 --- a/plugins/unityshell/src/unityshell_glow.cpp +++ b/plugins/unityshell/src/unityshell_glow.cpp @@ -130,7 +130,7 @@ UnityWindow::paintGlow(GLMatrix const& transform, GLWindowPaintAttrib const& att * adjusted by the matrix scale factor (matrix->xx and matrix->yy) * */ -glow::Quads UnityWindow::computeGlowQuads(GLTexture::List const& texture, int glow_size, double window_aspect) +glow::Quads UnityWindow::computeGlowQuads(nux::Geometry const& geo, GLTexture::List const& texture, int glow_size) { glow::Quads glow_quads; @@ -139,13 +139,11 @@ glow::Quads UnityWindow::computeGlowQuads(GLTexture::List const& texture, int gl int x1, x2, y1, y2; int glow_offset; - CompRect const& border_rect = window->borderRect(); GLTexture::Matrix const& matrix = texture.front()->matrix(); CompRect *box; GLTexture::Matrix *quadMatrix; - glow_size /= window_aspect; glow_offset = (glow_size * texture::GLOW_OFFSET / texture::GLOW_SIZE) + 1; /* Top left corner */ @@ -156,8 +154,8 @@ glow::Quads UnityWindow::computeGlowQuads(GLTexture::List const& texture, int gl /* Set the desired rect dimentions * for the part of the glow we are painting */ - x1 = border_rect.x() - glow_size + glow_offset; - y1 = border_rect.y() - glow_size + glow_offset; + x1 = geo.x - glow_size + glow_offset; + y1 = geo.y - glow_size + glow_offset; /* 2x2 Matrix here, adjust both x and y scale factors * and the x and y position @@ -175,10 +173,8 @@ glow::Quads UnityWindow::computeGlowQuads(GLTexture::List const& texture, int gl quadMatrix->x0 = -(x1 * quadMatrix->xx); quadMatrix->y0 = -(y1 * quadMatrix->yy); - x2 = std::min<int>(border_rect.x() + glow_offset, - border_rect.x() + (border_rect.width() / 2)); - y2 = std::min<int>(border_rect.y() + glow_offset, - border_rect.y() + (border_rect.height() / 2)); + x2 = std::min<int>(geo.x + glow_offset, geo.x + (geo.width / 2)); + y2 = std::min<int>(geo.y + glow_offset, geo.y + (geo.height / 2)); box->setGeometry(x1, y1, x2 - x1, y2 - y1); @@ -190,9 +186,9 @@ glow::Quads UnityWindow::computeGlowQuads(GLTexture::List const& texture, int gl /* Set the desired rect dimentions * for the part of the glow we are painting */ - x1 = border_rect.x() + border_rect.width() - glow_offset; - y1 = border_rect.y() - glow_size + glow_offset; - x2 = border_rect.x() + border_rect.width() + glow_size - glow_offset; + x1 = geo.x + geo.width - glow_offset; + y1 = geo.y - glow_size + glow_offset; + x2 = geo.x + geo.width + glow_size - glow_offset; /* * 2x2 Matrix here, adjust both x and y scale factors @@ -213,10 +209,8 @@ glow::Quads UnityWindow::computeGlowQuads(GLTexture::List const& texture, int gl quadMatrix->x0 = 1.0 - (x1 * quadMatrix->xx); quadMatrix->y0 = -(y1 * quadMatrix->yy); - x1 = std::max<int>(border_rect.x() + border_rect.width() - glow_offset, - border_rect.x() + (border_rect.width() / 2)); - y2 = std::min<int>(border_rect.y() + glow_offset, - border_rect.y() + (border_rect.height() / 2)); + x1 = std::max<int>(geo.x + geo.width - glow_offset, geo.x + (geo.width / 2)); + y2 = std::min<int>(geo.y + glow_offset, geo.y + (geo.height / 2)); box->setGeometry(x1, y1, x2 - x1, y2 - y1); @@ -225,10 +219,10 @@ glow::Quads UnityWindow::computeGlowQuads(GLTexture::List const& texture, int gl glow_quads[glow::QuadPos::BOTTOMLEFT].matrix = matrix; quadMatrix = &glow_quads[glow::QuadPos::BOTTOMLEFT].matrix; - x1 = border_rect.x() - glow_size + glow_offset; - y1 = border_rect.y() + border_rect.height() - glow_offset; - x2 = border_rect.x() + glow_offset; - y2 = border_rect.y() + border_rect.height() + glow_size - glow_offset; + x1 = geo.x - glow_size + glow_offset; + y1 = geo.y + geo.height - glow_offset; + x2 = geo.x + glow_offset; + y2 = geo.y + geo.height + glow_size - glow_offset; /* 2x2 Matrix here, adjust both x and y scale factors * and the x and y position @@ -248,10 +242,8 @@ glow::Quads UnityWindow::computeGlowQuads(GLTexture::List const& texture, int gl quadMatrix->x0 = -(x1 * quadMatrix->xx); quadMatrix->y0 = 1.0f - (y1 * quadMatrix->yy); - y1 = std::max<int>(border_rect.y() + border_rect.height() - glow_offset, - border_rect.y() + (border_rect.height() / 2)); - x2 = std::min<int>(border_rect.x() + glow_offset, - border_rect.x() + (border_rect.width() / 2)); + y1 = std::max<int>(geo.y + geo.height - glow_offset, geo.y + (geo.height / 2)); + x2 = std::min<int>(geo.x + glow_offset, geo.x + (geo.width / 2)); box->setGeometry(x1, y1, x2 - x1, y2 - y1); @@ -260,10 +252,10 @@ glow::Quads UnityWindow::computeGlowQuads(GLTexture::List const& texture, int gl glow_quads[glow::QuadPos::BOTTOMRIGHT].matrix = matrix; quadMatrix = &glow_quads[glow::QuadPos::BOTTOMRIGHT].matrix; - x1 = border_rect.x() + border_rect.width() - glow_offset; - y1 = border_rect.y() + border_rect.height() - glow_offset; - x2 = border_rect.x() + border_rect.width() + glow_size - glow_offset; - y2 = border_rect.y() + border_rect.height() + glow_size - glow_offset; + x1 = geo.x + geo.width - glow_offset; + y1 = geo.y + geo.height - glow_offset; + x2 = geo.x + geo.width + glow_size - glow_offset; + y2 = geo.y + geo.height + glow_size - glow_offset; /* 2x2 Matrix here, adjust both x and y scale factors * and the x and y position @@ -281,10 +273,8 @@ glow::Quads UnityWindow::computeGlowQuads(GLTexture::List const& texture, int gl quadMatrix->x0 = 1.0 - (x1 * quadMatrix->xx); quadMatrix->y0 = 1.0 - (y1 * quadMatrix->yy); - x1 = std::max<int>(border_rect.x() + border_rect.width() - glow_offset, - border_rect.x() + (border_rect.width() / 2)); - y1 = std::max<int>(border_rect.y() + border_rect.height() - glow_offset, - border_rect.y() + (border_rect.height() / 2)); + x1 = std::max<int>(geo.x + geo.width - glow_offset, geo.x + (geo.width / 2)); + y1 = std::max<int>(geo.y + geo.height - glow_offset, geo.y + (geo.height / 2)); box->setGeometry(x1, y1, x2 - x1, y2 - y1); @@ -293,10 +283,10 @@ glow::Quads UnityWindow::computeGlowQuads(GLTexture::List const& texture, int gl glow_quads[glow::QuadPos::TOP].matrix = matrix; quadMatrix = &glow_quads[glow::QuadPos::TOP].matrix; - x1 = border_rect.x() + glow_offset; - y1 = border_rect.y() - glow_size + glow_offset; - x2 = border_rect.x() + border_rect.width() - glow_offset; - y2 = border_rect.y() + glow_offset; + x1 = geo.x + glow_offset; + y1 = geo.y - glow_size + glow_offset; + x2 = geo.x + geo.width - glow_offset; + y2 = geo.y + glow_offset; /* 2x2 Matrix here, adjust both x and y scale factors * and the x and y position @@ -321,10 +311,10 @@ glow::Quads UnityWindow::computeGlowQuads(GLTexture::List const& texture, int gl glow_quads[glow::QuadPos::BOTTOM].matrix = matrix; quadMatrix = &glow_quads[glow::QuadPos::BOTTOM].matrix; - x1 = border_rect.x() + glow_offset; - y1 = border_rect.y() + border_rect.height() - glow_offset; - x2 = border_rect.x() + border_rect.width() - glow_offset; - y2 = border_rect.y() + border_rect.height() + glow_size - glow_offset; + x1 = geo.x + glow_offset; + y1 = geo.y + geo.height - glow_offset; + x2 = geo.x + geo.width - glow_offset; + y2 = geo.y + geo.height + glow_size - glow_offset; /* 2x2 Matrix here, adjust both x and y scale factors * and the x and y position @@ -349,10 +339,10 @@ glow::Quads UnityWindow::computeGlowQuads(GLTexture::List const& texture, int gl glow_quads[glow::QuadPos::LEFT].matrix = matrix; quadMatrix = &glow_quads[glow::QuadPos::LEFT].matrix; - x1 = border_rect.x() - glow_size + glow_offset; - y1 = border_rect.y() + glow_offset; - x2 = border_rect.x() + glow_offset; - y2 = border_rect.y() + border_rect.height() - glow_offset; + x1 = geo.x - glow_size + glow_offset; + y1 = geo.y + glow_offset; + x2 = geo.x + glow_offset; + y2 = geo.y + geo.height - glow_offset; /* 2x2 Matrix here, adjust both x and y scale factors * and the x and y position @@ -377,10 +367,10 @@ glow::Quads UnityWindow::computeGlowQuads(GLTexture::List const& texture, int gl glow_quads[glow::QuadPos::RIGHT].matrix = matrix; quadMatrix = &glow_quads[glow::QuadPos::RIGHT].matrix; - x1 = border_rect.x() + border_rect.width() - glow_offset; - y1 = border_rect.y() + glow_offset; - x2 = border_rect.x() + border_rect.width() + glow_size - glow_offset; - y2 = border_rect.y() + border_rect.height() - glow_offset; + x1 = geo.x + geo.width - glow_offset; + y1 = geo.y + glow_offset; + x2 = geo.x + geo.width + glow_size - glow_offset; + y2 = geo.y + geo.height - glow_offset; /* 2x2 Matrix here, adjust both x and y scale factors * and the x and y position diff --git a/po/POTFILES.in b/po/POTFILES.in index b25d00fca..ef26966ae 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -12,6 +12,7 @@ launcher/ApplicationLauncherIcon.cpp launcher/BFBLauncherIcon.cpp launcher/DesktopLauncherIcon.cpp launcher/DeviceNotificationDisplayImp.cpp +launcher/ExpoLauncherIcon.cpp launcher/LauncherController.cpp launcher/SoftwareCenterLauncherIcon.cpp launcher/SpacerLauncherIcon.cpp diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 43d9679d1..d4fe3b703 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -110,7 +110,9 @@ if (GTEST_SRC_DIR AND test_service_lens.h test_service_main.c test_service_model.c - test_service_model.h) + test_service_model.h + test_service_panel.c + test_service_panel.c) target_link_libraries(test-gtest-service unity-shared ${LIBS}) add_dependencies (test-gtest-service unity-core-${UNITY_API_VERSION} gtest) @@ -194,6 +196,7 @@ if (GTEST_SRC_DIR AND test_utils.h test_ratings_filter.cpp test_results.cpp + test_dbus_indicators.cpp ) target_link_libraries(test-gtest-dbus gtest unity-shared ${LIBS}) add_test(UnityGTestDBus test-gtest-dbus) @@ -220,6 +223,7 @@ if (GTEST_SRC_DIR AND test_launcher_icon.cpp test_keyboard_util.cpp test_panel_style.cpp + test_places_group.cpp test_previews_application.cpp test_previews_generic.cpp test_previews_movie.cpp @@ -244,6 +248,10 @@ if (GTEST_SRC_DIR AND gmockvolume.c ${CMAKE_SOURCE_DIR}/dash/DashViewPrivate.cpp ${CMAKE_SOURCE_DIR}/dash/ResultRenderer.cpp + ${CMAKE_SOURCE_DIR}/dash/PlacesGroup.cpp + ${CMAKE_SOURCE_DIR}/dash/ResultRenderer.cpp + ${CMAKE_SOURCE_DIR}/dash/ResultRendererHorizontalTile.cpp + ${CMAKE_SOURCE_DIR}/dash/ResultRendererTile.cpp ${CMAKE_SOURCE_DIR}/dash/ResultView.cpp ${CMAKE_SOURCE_DIR}/dash/ResultViewGrid.cpp ${CMAKE_SOURCE_DIR}/dash/previews/ActionButton.cpp diff --git a/tests/autopilot/unity/tests/test_hud.py b/tests/autopilot/unity/tests/test_hud.py index 6cd171d43..2ccb3b580 100644 --- a/tests/autopilot/unity/tests/test_hud.py +++ b/tests/autopilot/unity/tests/test_hud.py @@ -417,10 +417,10 @@ class HudBehaviorTests(HudTestsBase): (x,y,w,h) = self.hud.geometry (screen_x,screen_y,screen_w,screen_h) = self.screen_geo.get_monitor_geometry(current_monitor) - + self.mouse.move(x + w + (screen_w-((screen_x-x)+w))/2, y + h + (screen_h-((screen_y-y)+h))/2) self.mouse.click() - + self.assertThat(self.hud.visible, Eventually(Equals(False))) def test_closes_then_focuses_window_on_mouse_down(self): diff --git a/tests/test_dbus_indicators.cpp b/tests/test_dbus_indicators.cpp new file mode 100644 index 000000000..f1406cf75 --- /dev/null +++ b/tests/test_dbus_indicators.cpp @@ -0,0 +1,99 @@ +#include <gtest/gtest.h> + +#include <UnityCore/GLibDBusProxy.h> +#include <UnityCore/GLibSource.h> +#include <UnityCore/GLibWrapper.h> +#include <UnityCore/DBusIndicators.h> + +#include "test_utils.h" + +using namespace unity; +using namespace unity::indicator; + +namespace +{ + +class DBusIndicatorsTest : public DBusIndicators +{ +public: + DBusIndicatorsTest() : DBusIndicators("com.canonical.Unity.Test") + { + } + + bool HasIndicators() const + { + return !GetIndicators().empty(); + } + + using DBusIndicators::IsConnected; +}; + +class TestDBusIndicators : public ::testing::Test +{ +public: + void SetUp() + { + session = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL); + g_dbus_connection_set_exit_on_close(session, FALSE); + + dbus_indicators.reset(new DBusIndicatorsTest ()); + + // wait until the dbus indicator has connected to the panel service + Utils::WaitUntil(sigc::mem_fun(*dbus_indicators, &DBusIndicatorsTest::IsConnected)); + } + + bool TriggerResync1Sent() const + { + GVariant *ret = CallPanelMethod("TriggerResync1Sent"); + return g_variant_get_boolean(g_variant_get_child_value(ret, 0)); + } + + GVariant* CallPanelMethod(std::string const& name) const + { + return g_dbus_connection_call_sync(session, + "com.canonical.Unity.Test", + "/com/canonical/Unity/Panel/Service", + "com.canonical.Unity.Panel.Service", + name.c_str(), + NULL, + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + NULL); + } + + glib::Object<GDBusConnection> session; + std::shared_ptr<DBusIndicatorsTest> dbus_indicators; +}; + +TEST_F(TestDBusIndicators, TestConstruction) +{ + EXPECT_EQ(dbus_indicators->IsConnected(), true); +} + +TEST_F(TestDBusIndicators, TestSync) +{ + // wait until the dbus indicator gets any indicator from the panel service + Utils::WaitUntil(sigc::mem_fun(*dbus_indicators, &DBusIndicatorsTest::HasIndicators)); + + EXPECT_EQ(dbus_indicators->GetIndicators().size(), 1); + EXPECT_EQ(dbus_indicators->GetIndicators().front()->GetEntries().size(), 2); + EXPECT_EQ(dbus_indicators->GetIndicators().front()->GetEntries().front()->id(), "test_entry_id"); + EXPECT_EQ(dbus_indicators->GetIndicators().front()->GetEntries().back()->id(), "test_entry_id2"); + + // Tell the service to trigger a resync and to send the entries in the reverse order + CallPanelMethod("TriggerResync1"); + + Utils::WaitUntil(sigc::mem_fun(this, &TestDBusIndicators::TriggerResync1Sent)); + // We know the resync has been sent, but it may have not been processed + // so do one interation of the main loop more + g_main_context_iteration(g_main_context_get_thread_default(), TRUE); + + EXPECT_EQ(dbus_indicators->GetIndicators().size(), 1); + EXPECT_EQ(dbus_indicators->GetIndicators().front()->GetEntries().size(), 2); + EXPECT_EQ(dbus_indicators->GetIndicators().front()->GetEntries().front()->id(), "test_entry_id2"); + EXPECT_EQ(dbus_indicators->GetIndicators().front()->GetEntries().back()->id(), "test_entry_id"); +} + +} diff --git a/tests/test_indicator.cpp b/tests/test_indicator.cpp index cb90d012d..5d3ac5aa6 100644 --- a/tests/test_indicator.cpp +++ b/tests/test_indicator.cpp @@ -35,6 +35,7 @@ TEST(TestIndicator, Construction) EXPECT_EQ(indicator.name(), "indicator-test"); EXPECT_FALSE(indicator.IsAppmenu()); EXPECT_EQ(indicator.GetEntry("test-entry"), nullptr); + EXPECT_EQ(indicator.EntryIndex("test-entry"), -1); EXPECT_TRUE(indicator.GetEntries().empty()); } @@ -76,6 +77,7 @@ TEST(TestIndicator, Syncing) indicator.Sync(sync_data); EXPECT_EQ(indicator.GetEntries().size(), 3); EXPECT_EQ(indicator.GetEntry("test-entry-2"), entry2); + EXPECT_EQ(indicator.EntryIndex("test-entry-2"), 1); EXPECT_EQ(added.size(), 3); EXPECT_EQ(added.front()->id(), "test-entry-1"); EXPECT_EQ(added.back()->id(), "test-entry-3"); @@ -91,6 +93,7 @@ TEST(TestIndicator, Syncing) indicator.Sync(sync_data); EXPECT_EQ(indicator.GetEntries().size(), 2); EXPECT_EQ(indicator.GetEntry("test-entry-2"), nullptr); + EXPECT_EQ(indicator.EntryIndex("test-entry-2"), -1); EXPECT_EQ(added.size(), 0); EXPECT_EQ(removed.size(), 1); EXPECT_EQ(removed.front(), entry2->id()); diff --git a/tests/test_launcher.cpp b/tests/test_launcher.cpp index 907395ccc..542bd2652 100644 --- a/tests/test_launcher.cpp +++ b/tests/test_launcher.cpp @@ -362,6 +362,7 @@ TEST_F(TestLauncher, DragLauncherIconSavesIconOrderIfPositionHasChanged) bool model_saved = false; model_->saved.connect([&model_saved] { model_saved = true; }); + EXPECT_CALL(*icon2, Stick(false)); ASSERT_NE(launcher_->GetDragIconPosition(), model_->IconIndex(icon2)); launcher_->EndIconDrag(); @@ -423,6 +424,25 @@ TEST_F(TestLauncher, DragLauncherIconSavesIconOrderIfPositionHasNotChanged) EXPECT_EQ(launcher_->GetDraggedIcon(), nullptr); } +TEST_F(TestLauncher, DragLauncherIconSticksApplicationIcon) +{ + auto const& icons = AddMockIcons(1); + + MockMockLauncherIcon::Ptr app(new MockMockLauncherIcon(AbstractLauncherIcon::IconType::APPLICATION)); + model_->AddIcon(app); + + // Start dragging app icon + launcher_->StartIconDrag(app); + launcher_->ShowDragWindow(); + + // Moving app icon to the beginning + auto const& center = icons[0]->GetCenter(launcher_->monitor()); + launcher_->UpdateDragWindowPosition(center.x, center.y); + + EXPECT_CALL(*app, Stick(false)); + launcher_->EndIconDrag(); +} + TEST_F(TestLauncher, DragLauncherIconSticksDeviceIcon) { auto const& icons = AddMockIcons(1); diff --git a/tests/test_places_group.cpp b/tests/test_places_group.cpp new file mode 100644 index 000000000..f70617b1f --- /dev/null +++ b/tests/test_places_group.cpp @@ -0,0 +1,103 @@ +/* + * Copyright 2012 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 3 along with this program. If not, see + * <http://www.gnu.org/licenses/> + * + * Authored by: Andrea Azzarone <andrea.azzarone@canonical.com> + * + */ + +#include "config.h" +#include <gmock/gmock.h> +using namespace testing; + +#include <Nux/Nux.h> +#include <Nux/PaintLayer.h> + +#include "PlacesGroup.h" +using namespace unity; + +namespace { + +class MockDashStyle : public dash::StyleInterface +{ +public: + MockDashStyle() + { + std::string full_path = PKGDATADIR "album_missing.png"; + glib::Object<GdkPixbuf> pixbuf(gdk_pixbuf_new_from_file_at_size(full_path.c_str(), 20, 20, nullptr)); + base_texture_.Adopt(nux::CreateTexture2DFromPixbuf(pixbuf, true)); + } + + MOCK_METHOD2(FocusOverlay, nux::AbstractPaintLayer*(int width, int height)); + MOCK_METHOD0(GetCategoryBackground, nux::BaseTexture*()); + MOCK_METHOD0(GetCategoryBackgroundNoFilters, nux::BaseTexture*()); + + MOCK_METHOD0(GetGroupExpandIcon, nux::BaseTexture*()); + MOCK_METHOD0(GetGroupUnexpandIcon, nux::BaseTexture*()); + + MOCK_CONST_METHOD0(GetCategoryHeaderLeftPadding, int()); + MOCK_CONST_METHOD0(GetPlacesGroupTopSpace, int()); + + nux::ObjectPtr<nux::BaseTexture> base_texture_; +}; + + +class TestPlacesGroup : public Test +{ +public: + void SetUp() + { + SetupMockDashStyle(); + + places_group_ = new PlacesGroup(dash_style_); + } + + void SetupMockDashStyle() + { + ON_CALL(dash_style_, FocusOverlay(_, _)) + .WillByDefault(Return(new nux::ColorLayer(nux::color::White))); + + ON_CALL(dash_style_, GetCategoryBackground()) + .WillByDefault(Return(dash_style_.base_texture_.GetPointer())); + + ON_CALL(dash_style_, GetCategoryBackgroundNoFilters()) + .WillByDefault(Return(dash_style_.base_texture_.GetPointer())); + + ON_CALL(dash_style_, GetGroupExpandIcon()) + .WillByDefault(Return(dash_style_.base_texture_.GetPointer())); + + ON_CALL(dash_style_, GetGroupUnexpandIcon()) + .WillByDefault(Return(dash_style_.base_texture_.GetPointer())); + } + + NiceMock<MockDashStyle> dash_style_; + nux::ObjectPtr<PlacesGroup> places_group_; +}; + + +TEST_F(TestPlacesGroup, Constructor) +{ + EXPECT_CALL(dash_style_, GetGroupExpandIcon()) + .Times(1); + + EXPECT_CALL(dash_style_, GetGroupUnexpandIcon()) + .Times(0); + + PlacesGroup places_group(dash_style_); + + EXPECT_FALSE(places_group.GetExpanded()); +} + +} diff --git a/tests/test_service_main.c b/tests/test_service_main.c index 921027e63..02688da98 100644 --- a/tests/test_service_main.c +++ b/tests/test_service_main.c @@ -3,6 +3,7 @@ #include "test_service_lens.h" #include "test_service_model.h" #include "test_service_hud.h" +#include "test_service_panel.h" #include "test_service_gdbus_wrapper.h" static void on_bus_aquired(GDBusConnection* conn, const gchar* name, gpointer null); @@ -37,6 +38,7 @@ static GMainLoop* loop_ = NULL; static ServiceLens* lens_ = NULL; static ServiceModel* model_ = NULL; static ServiceHud* hud_ = NULL; +static ServicePanel* panel_ = NULL; static ServiceGDBusWrapper* gdbus_wrapper_ = NULL; gint main(gint argc, gchar** argv) @@ -48,6 +50,7 @@ main(gint argc, gchar** argv) lens_ = service_lens_new(); model_ = service_model_new(); hud_ = service_hud_new(); + panel_ = service_panel_new(); gdbus_wrapper_ = service_gdbus_wrapper_new(); g_bus_own_name(G_BUS_TYPE_SESSION, @@ -65,6 +68,7 @@ main(gint argc, gchar** argv) //g_object_unref(lens_); //g_object_unref(model_); g_object_unref(hud_); + g_object_unref(panel_); g_dbus_node_info_unref(introspection_data); return 0; diff --git a/tests/test_service_panel.c b/tests/test_service_panel.c new file mode 100644 index 000000000..e5c29ffb1 --- /dev/null +++ b/tests/test_service_panel.c @@ -0,0 +1,253 @@ +#include "test_service_panel.h" +#include <unity.h> +#include <gio/gio.h> + +static const char * panel_interface = +"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +"<node name=\"/\">\n" +" <interface name=\"com.canonical.Unity.Panel.Service\">\n" +"\n" +"<!-- Begin of real methods/signals -->\n" +" <method name='Sync'>" +" <arg type='a(ssssbbusbbi)' name='state' direction='out'/>" +" </method>" +"\n" +" <signal name='ReSync'>" +" <arg type='s' name='indicator_id' />" +" </signal>" +"\n" +"<!-- Begin of test only methods/signals -->\n" +"\n" +" <method name='TriggerResync1' />" +"\n" +" <method name='TriggerResync1Sent'>" +" <arg type='b' name='sent' direction='out'/>" +" </method>" +"\n" +" </interface>\n" +"</node>\n" +; +static void bus_got_cb (GObject *object, GAsyncResult * res, gpointer user_data); +static void bus_method (GDBusConnection *connection, + const gchar *sender, + const gchar *object_path, + const gchar *interface_name, + const gchar *method_name, + GVariant *parameters, + GDBusMethodInvocation *invocation, + gpointer user_data); + +G_DEFINE_TYPE(ServicePanel, service_panel, G_TYPE_OBJECT); +static GDBusNodeInfo * node_info = NULL; +static GDBusInterfaceInfo * iface_info = NULL; +static GDBusInterfaceVTable bus_vtable = { + method_call: bus_method, + get_property: NULL, + set_property: NULL, +}; + +struct _ServicePanelPrivate +{ + GDBusConnection * bus; + GCancellable * bus_lookup; + guint bus_registration; + guint sig_emission_handle; +}; + +static void +service_panel_dispose(GObject* object) +{ + ServicePanel* self = SERVICE_PANEL(object); + if (self->priv->bus_lookup != NULL) { + g_cancellable_cancel(self->priv->bus_lookup); + g_object_unref(self->priv->bus_lookup); + self->priv->bus_lookup = NULL; + } + + if (self->priv->bus_registration != 0) { + g_dbus_connection_unregister_object(self->priv->bus, self->priv->bus_registration); + self->priv->bus_registration = 0; + } + + if (self->priv->bus != NULL) { + g_object_unref(self->priv->bus); + self->priv->bus = NULL; + } + + if (self->priv->sig_emission_handle) { + g_source_remove(self->priv->sig_emission_handle); + self->priv->sig_emission_handle = 0; + } + +} + +static void +service_panel_class_init(ServicePanelClass* klass) +{ + G_OBJECT_CLASS(klass)->dispose = service_panel_dispose; + g_type_class_add_private (klass, sizeof (ServicePanelPrivate)); + + if (node_info == NULL) + { + GError * error = NULL; + + node_info = g_dbus_node_info_new_for_xml(panel_interface, &error); + if (error != NULL) + { + g_error("Unable to parse Panel interface: %s", error->message); + g_error_free(error); + } + } + + if (node_info != NULL && iface_info == NULL) + { + iface_info = g_dbus_node_info_lookup_interface(node_info,"com.canonical.Unity.Panel.Service"); + if (iface_info == NULL) + { + g_error("Unable to find interface 'com.canonical.Unity.Panel.Service'"); + } + } + +} + +static void +service_panel_init(ServicePanel* self) +{ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, SERVICE_TYPE_PANEL, ServicePanelPrivate); + self->priv->bus = NULL; + self->priv->bus_lookup = NULL; + self->priv->bus_registration = 0; + + self->priv->bus_lookup = g_cancellable_new(); + g_bus_get(G_BUS_TYPE_SESSION, self->priv->bus_lookup, bus_got_cb, self); +} + +ServicePanel* +service_panel_new() +{ + return g_object_new(SERVICE_TYPE_PANEL, NULL); +} + +static void +bus_got_cb (GObject *object, GAsyncResult * res, gpointer user_data) +{ + GError * error = NULL; + ServicePanel * self = SERVICE_PANEL(user_data); + GDBusConnection * bus; + + bus = g_bus_get_finish(res, &error); + if (error != NULL) { + g_critical("Unable to get bus: %s", error->message); + g_error_free(error); + return; + } + + self->priv->bus = bus; + + /* Register object */ + self->priv->bus_registration = g_dbus_connection_register_object(bus, + /* path */ "/com/canonical/Unity/Panel/Service", + /* interface */ iface_info, + /* vtable */ &bus_vtable, + /* userdata */ self, + /* destroy */ NULL, + /* error */ &error); + + if (error != NULL) { + g_critical ("Unable to create bus connection object, %s", error->message); + g_error_free(error); + return; + } + + return; +} + +static void +add_entry_id(GVariantBuilder *b) +{ + g_variant_builder_add (b, "(ssssbbusbbi)", + "test_indicator_id", + "test_entry_id", + "test_entry_name_hint", + "test_entry_label", + TRUE, /* label sensitive */ + TRUE, /* label visible */ + 0, /* image type */ + "", /* image_data */ + TRUE, /* image sensitive */ + TRUE, /* image visible */ + 1 /* priority */); +} + +static void +add_entry_id_2(GVariantBuilder *b) +{ + g_variant_builder_add (b, "(ssssbbusbbi)", + "test_indicator_id", + "test_entry_id2", + "test_entry_name_hint2", + "test_entry_label2", + TRUE, /* label sensitive */ + TRUE, /* label visible */ + 0, /* image type */ + "", /* image_data */ + TRUE, /* image sensitive */ + TRUE, /* image visible */ + 1 /* priority */); +} + +static int sync_return_mode = 0; +static int trigger_resync1_sent = FALSE; + +static void +bus_method (GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *method_name, GVariant *parameters, GDBusMethodInvocation *invocation, gpointer user_data) +{ + if (g_strcmp0(method_name, "Sync") == 0) + { + GVariantBuilder b; + + g_variant_builder_init (&b, G_VARIANT_TYPE ("(a(ssssbbusbbi))")); + g_variant_builder_open (&b, G_VARIANT_TYPE ("a(ssssbbusbbi)")); + + if (sync_return_mode == 0) + { + add_entry_id(&b); + add_entry_id_2(&b); + } + else if (sync_return_mode == 1) + { + add_entry_id_2(&b); + add_entry_id(&b); + } + + g_variant_builder_close (&b); + + g_dbus_method_invocation_return_value(invocation, g_variant_builder_end (&b)); + + if (sync_return_mode == 1) + { + trigger_resync1_sent = TRUE; + } + } + else if (g_strcmp0(method_name, "TriggerResync1") == 0) + { + sync_return_mode = 1; + trigger_resync1_sent = FALSE; + + g_dbus_method_invocation_return_value(invocation, NULL); + GVariantBuilder ret_builder; + g_variant_builder_init(&ret_builder, G_VARIANT_TYPE_TUPLE); + g_variant_builder_add_value(&ret_builder, g_variant_new_string("")); + g_dbus_connection_emit_signal (connection, NULL, "/com/canonical/Unity/Panel/Service", "com.canonical.Unity.Panel.Service", "ReSync", g_variant_builder_end(&ret_builder), NULL); + } + else if (g_strcmp0(method_name, "TriggerResync1Sent") == 0) + { + GVariantBuilder ret_builder; + g_variant_builder_init(&ret_builder, G_VARIANT_TYPE ("(b)")); + g_variant_builder_add_value (&ret_builder, g_variant_new_boolean(trigger_resync1_sent)); + g_dbus_method_invocation_return_value(invocation, g_variant_builder_end (&ret_builder)); + } + + return; +} + diff --git a/tests/test_service_panel.h b/tests/test_service_panel.h new file mode 100644 index 000000000..aa160e231 --- /dev/null +++ b/tests/test_service_panel.h @@ -0,0 +1,46 @@ +#ifndef _SERVICE_PANEL_H_ +#define _SERVICE_PANEL_H_ + +#include <glib-object.h> +G_BEGIN_DECLS + +#define SERVICE_TYPE_PANEL (service_panel_get_type ()) + +#define SERVICE_PANEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\ + SERVICE_TYPE_PANEL, ServicePanel)) + +#define SERVICE_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\ + SERVICE_TYPE_PANEL, ServicePanelClass)) + +#define SERVICE_IS_PANEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),\ + SERVICE_TYPE_PANEL)) + +#define SERVICE_IS_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),\ + SERVICE_TYPE_PANEL)) + +#define ServicePanel_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\ + SERVICE_TYPE_PANEL, ServicePanelClass)) + +typedef struct _ServicePanel ServicePanel; +typedef struct _ServicePanelClass ServicePanelClass; +typedef struct _ServicePanelPrivate ServicePanelPrivate; + +struct _ServicePanel +{ + GObject parent; + + ServicePanelPrivate *priv; +}; + +struct _ServicePanelClass +{ + GObjectClass parent_class; +}; + +GType service_panel_get_type(void) G_GNUC_CONST; + +ServicePanel* service_panel_new(void); + +G_END_DECLS + +#endif /* _SERVICE_PANEL_H_ */ diff --git a/tests/test_utils.h b/tests/test_utils.h index 975acae04..9cc978048 100644 --- a/tests/test_utils.h +++ b/tests/test_utils.h @@ -46,6 +46,20 @@ public: EXPECT_TRUE(success); } + static void WaitUntil(std::function<bool()> check_function, bool result = true, unsigned int max_wait = 10) + { + bool timeout_reached = false; + guint32 timeout_id = ScheduleTimeout(&timeout_reached, max_wait * 1000); + + while (!check_function() && !timeout_reached) + g_main_context_iteration(g_main_context_get_thread_default(), TRUE); + + if (check_function()) + g_source_remove(timeout_id); + + EXPECT_EQ(check_function(), result); + } + static guint32 ScheduleTimeout(bool* timeout_reached, unsigned int timeout_duration = 10) { return g_timeout_add(timeout_duration, TimeoutCallback, timeout_reached); diff --git a/unity-shared/DashStyle.cpp b/unity-shared/DashStyle.cpp index 4e9d6220e..168a9deea 100755 --- a/unity-shared/DashStyle.cpp +++ b/unity-shared/DashStyle.cpp @@ -1760,7 +1760,7 @@ bool Style::SquareButton(cairo_t* cr, nux::ButtonVisualState state, return true; } -bool Style::ButtonFocusOverlay(cairo_t* cr) +bool Style::ButtonFocusOverlay(cairo_t* cr, float alpha) { // sanity checks if (cairo_status(cr) != CAIRO_STATUS_SUCCESS) @@ -1773,7 +1773,7 @@ bool Style::ButtonFocusOverlay(cairo_t* cr) double h = cairo_image_surface_get_height(cairo_get_target(cr)); nux::Color color(nux::color::White); - color.alpha = 0.50f; + color.alpha = alpha; cairo_set_line_width(cr, pimpl->button_label_border_size_[nux::VISUAL_STATE_NORMAL]); RoundedRect(cr, diff --git a/unity-shared/DashStyle.h b/unity-shared/DashStyle.h index 0f816a71f..2273a7175 100755 --- a/unity-shared/DashStyle.h +++ b/unity-shared/DashStyle.h @@ -20,6 +20,8 @@ #ifndef DASH_STYLE_H #define DASH_STYLE_H +#include "DashStyleInterface.h" + #include <Nux/Nux.h> #include <Nux/View.h> #include <Nux/AbstractButton.h> @@ -83,7 +85,7 @@ enum class Arrow { }; -class Style +class Style : public StyleInterface { public: Style (); @@ -104,7 +106,7 @@ public: virtual nux::AbstractPaintLayer* FocusOverlay(int width, int height); - virtual bool ButtonFocusOverlay(cairo_t* cr); + virtual bool ButtonFocusOverlay(cairo_t* cr, float alpha = 0.50f); virtual bool MultiRangeSegment(cairo_t* cr, nux::ButtonVisualState state, diff --git a/unity-shared/DashStyleInterface.h b/unity-shared/DashStyleInterface.h new file mode 100644 index 000000000..43d488bc4 --- /dev/null +++ b/unity-shared/DashStyleInterface.h @@ -0,0 +1,53 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2012 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Andrea Azzarone <andrea.azzarone@canonical.com> + */ + +#ifndef UNITYSHELL_DASH_STYLE_INTERFACE_H +#define UNITYSHELL_DASH_STYLE_INTERFACE_H + +#include <memory> + +namespace nux { + class AbstractPaintLayer; + class BaseTexture; +} + +namespace unity { +namespace dash { + +class StyleInterface +{ +public: + virtual ~StyleInterface() {}; + + virtual nux::AbstractPaintLayer* FocusOverlay(int width, int height) = 0; + + virtual nux::BaseTexture* GetCategoryBackground() = 0; + virtual nux::BaseTexture* GetCategoryBackgroundNoFilters() = 0; + + virtual nux::BaseTexture* GetGroupUnexpandIcon() = 0; + virtual nux::BaseTexture* GetGroupExpandIcon() = 0; + + virtual int GetCategoryHeaderLeftPadding() const = 0; + virtual int GetPlacesGroupTopSpace() const = 0; +}; + +} +} + +#endif diff --git a/unity-shared/IconLoader.cpp b/unity-shared/IconLoader.cpp index a5aca60ea..89f47c417 100644 --- a/unity-shared/IconLoader.cpp +++ b/unity-shared/IconLoader.cpp @@ -212,15 +212,27 @@ private: if (icon.IsType(UNITY_PROTOCOL_TYPE_ANNOTATED_ICON)) { - UnityProtocolAnnotatedIcon *anno; - anno = UNITY_PROTOCOL_ANNOTATED_ICON(icon.RawPtr()); + glib::Object<UnityProtocolAnnotatedIcon> anno(glib::object_cast<UnityProtocolAnnotatedIcon>(icon)); GIcon* base_icon = unity_protocol_annotated_icon_get_icon(anno); glib::String gicon_string(g_icon_to_string(base_icon)); + // ensure that annotated icons aren't cached by the IconLoader no_cache = true; - auto helper_slot = sigc::bind(sigc::mem_fun(this, &IconLoaderTask::BaseIconLoaded), glib::object_cast<UnityProtocolAnnotatedIcon>(icon)); - int base_icon_width = max_width > 0 ? max_width - RIBBON_PADDING * 2 : -1; - int base_icon_height = base_icon_width < 0 ? max_height - RIBBON_PADDING *2 : max_height; + + auto helper_slot = sigc::bind(sigc::mem_fun(this, &IconLoaderTask::BaseIconLoaded), anno); + int base_icon_width, base_icon_height; + if (unity_protocol_annotated_icon_get_use_small_icon(anno)) + { + // FIXME: although this pretends to be generic, we're just making + // sure that icons requested to have 96px will be 64 + base_icon_width = max_width > 0 ? max_width * 2 / 3 : max_width; + base_icon_height = max_height > 0 ? max_height * 2 / 3 : max_height; + } + else + { + base_icon_width = max_width > 0 ? max_width - RIBBON_PADDING * 2 : -1; + base_icon_height = base_icon_width < 0 ? max_height - RIBBON_PADDING *2 : max_height; + } helper_handle = impl->LoadFromGIconString(gicon_string.Str(), base_icon_width, base_icon_height, @@ -518,7 +530,7 @@ private: } void BaseIconLoaded(std::string const& base_icon_string, - int max_width, int max_height, + int base_max_width, int base_max_height, glib::Object<GdkPixbuf> const& base_pixbuf, glib::Object<UnityProtocolAnnotatedIcon> const& anno_icon) { @@ -529,16 +541,32 @@ private: "' size: " << gdk_pixbuf_get_width(base_pixbuf) << 'x' << gdk_pixbuf_get_height(base_pixbuf); + int result_width, result_height, dest_x, dest_y; + if (unity_protocol_annotated_icon_get_use_small_icon(anno_icon)) + { + result_width = max_width > 0 ? max_width : MAX(max_height, gdk_pixbuf_get_width(base_pixbuf)); + result_height = max_height > 0 ? max_height : MAX(max_width, gdk_pixbuf_get_height(base_pixbuf)); + + dest_x = (result_width - gdk_pixbuf_get_width(base_pixbuf)) / 2; + dest_y = (result_height - gdk_pixbuf_get_height(base_pixbuf)) / 2; + } + else + { + result_width = gdk_pixbuf_get_width(base_pixbuf) + RIBBON_PADDING * 2; + result_height = gdk_pixbuf_get_height(base_pixbuf); + + dest_x = RIBBON_PADDING; + dest_y = 0; + } // we need extra space for the ribbon - result = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, - gdk_pixbuf_get_width(base_pixbuf) + RIBBON_PADDING * 2, - gdk_pixbuf_get_height(base_pixbuf)); + result = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, + result_width, result_height); gdk_pixbuf_fill(result, 0x0); gdk_pixbuf_copy_area(base_pixbuf, 0, 0, gdk_pixbuf_get_width(base_pixbuf), gdk_pixbuf_get_height(base_pixbuf), result, - RIBBON_PADDING, 0); + dest_x, dest_y); // FIXME: can we composite the pixbuf in helper thread? UnityProtocolCategoryType category = unity_protocol_annotated_icon_get_category(anno_icon); auto helper_slot = sigc::bind(sigc::mem_fun(this, &IconLoaderTask::CategoryIconLoaded), anno_icon); diff --git a/unity-shared/SearchBar.cpp b/unity-shared/SearchBar.cpp index 8d63f20da..3e61f074d 100644 --- a/unity-shared/SearchBar.cpp +++ b/unity-shared/SearchBar.cpp @@ -363,6 +363,17 @@ void SearchBar::Draw(nux::GraphicsEngine& graphics_engine, bool force_draw) graphics_engine.PushClippingRectangle(base); + if (RedirectedAncestor()) + { + unsigned int alpha = 0, src = 0, dest = 0; + graphics_engine.GetRenderStates().GetBlend(alpha, src, dest); + // This is necessary when doing redirected rendering. + // Clean the area below this view before drawing anything. + graphics_engine.GetRenderStates().SetBlend(false); + graphics_engine.QRP_Color(base.x, base.y, base.width, base.height, nux::Color(0.0f, 0.0f, 0.0f, 0.0f)); + graphics_engine.GetRenderStates().SetBlend(alpha, src, dest); + } + bg_layer_->SetGeometry(nux::Geometry(base.x, base.y, last_width_, last_height_)); nux::GetPainter().RenderSinglePaintLayer(graphics_engine, bg_layer_->GetGeometry(), @@ -380,38 +391,10 @@ void SearchBar::Draw(nux::GraphicsEngine& graphics_engine, bool force_draw) if (!highlight_layer_) highlight_layer_.reset(style.FocusOverlay(geo.width, geo.height)); - if (RedirectedAncestor()) - { - unsigned int alpha = 0, src = 0, dest = 0; - graphics_engine.GetRenderStates().GetBlend(alpha, src, dest); - // This is necessary when doing redirected rendering. - // Clean the area below this view before drawing anything. - graphics_engine.GetRenderStates().SetBlend(false); - graphics_engine.QRP_Color(geo.x, geo.y, geo.width, geo.height, nux::Color(0.0f, 0.0f, 0.0f, 0.0f)); - graphics_engine.GetRenderStates().SetBlend(alpha, src, dest); - } - highlight_layer_->SetGeometry(geo); highlight_layer_->Renderlayer(graphics_engine); } - else if (expander_view_ && expander_view_->IsVisible()) - { - nux::Geometry geo(expander_view_->GetGeometry()); - - geo.y -= (HIGHLIGHT_HEIGHT- geo.height) / 2; - geo.height = HIGHLIGHT_HEIGHT; - if (RedirectedAncestor()) - { - unsigned int alpha = 0, src = 0, dest = 0; - graphics_engine.GetRenderStates().GetBlend(alpha, src, dest); - // This is necessary when doing redirected rendering. - // Clean the area below this view before drawing anything. - graphics_engine.GetRenderStates().SetBlend(false); - graphics_engine.QRP_Color(geo.x, geo.y, geo.width, geo.height, nux::Color(0.0f, 0.0f, 0.0f, 0.0f)); - graphics_engine.GetRenderStates().SetBlend(alpha, src, dest); - } - } graphics_engine.PopClippingRectangle(); } |
