summaryrefslogtreecommitdiff
diff options
-rw-r--r--decorations/CMakeLists.txt1
-rw-r--r--decorations/DecoratedWindow.cpp65
-rw-r--r--decorations/DecorationsManager.cpp27
-rw-r--r--decorations/DecorationsPriv.h6
-rw-r--r--decorations/DecorationsShape.cpp102
-rw-r--r--decorations/DecorationsShape.h43
-rw-r--r--plugins/unityshell/src/unityshell.cpp2
-rw-r--r--unity-shared/CompizUtils.cpp6
8 files changed, 241 insertions, 11 deletions
diff --git a/decorations/CMakeLists.txt b/decorations/CMakeLists.txt
index d7fb53c4a..fe71565bb 100644
--- a/decorations/CMakeLists.txt
+++ b/decorations/CMakeLists.txt
@@ -35,6 +35,7 @@ set (DECORATION_SOURCES
DecorationsMenuDropdown.cpp
DecorationsForceQuitDialog.cpp
DecorationsDataPool.cpp
+ DecorationsShape.cpp
)
add_library (decorations-lib STATIC ${DECORATION_SOURCES})
diff --git a/decorations/DecoratedWindow.cpp b/decorations/DecoratedWindow.cpp
index 93b50d27e..d88ed20e8 100644
--- a/decorations/DecoratedWindow.cpp
+++ b/decorations/DecoratedWindow.cpp
@@ -31,6 +31,8 @@
#include "WindowManager.h"
#include "UnitySettings.h"
+#include <X11/extensions/shape.h>
+
namespace unity
{
namespace decoration
@@ -506,9 +508,9 @@ GLTexture* Window::Impl::ShadowTexture() const
{
auto const& mi = manager_->impl_;
if (active() || parent_->scaled())
- return mi->active_shadow_pixmap_->texture();
+ return win_->region().numRects() > 1 ? shaped_shadow_pixmap_->texture() : mi->active_shadow_pixmap_->texture();
- return mi->inactive_shadow_pixmap_->texture();
+ return win_->region().numRects() > 1 ? shaped_shadow_pixmap_->texture() : mi->inactive_shadow_pixmap_->texture();
}
unsigned Window::Impl::ShadowRadius() const
@@ -676,6 +678,53 @@ void Window::Impl::ComputeShadowQuads()
}
}
+void Window::Impl::ComputeShapedShadowQuad()
+{
+ if (!(deco_elements_ & cu::DecorationElement::SHADOW))
+ {
+ if (!last_shadow_rect_.isEmpty())
+ last_shadow_rect_.setGeometry(0, 0, 0, 0);
+
+ return;
+ }
+
+ nux::Color color = active() ? manager_->active_shadow_color() : manager_->inactive_shadow_color();
+ unsigned int radius = active() ? manager_->active_shadow_radius() : manager_->inactive_shadow_radius();
+ DecorationsShape shape;
+ shape.initShape(win_->id());
+ shaped_shadow_pixmap_ = manager_->impl_->BuildShapedShadowTexture(radius, color, shape);
+
+ const auto* texture = ShadowTexture();
+
+ if (!texture || !texture->width() || !texture->height())
+ return;
+
+ CompRect border = win_->borderRect();
+ nux::Point2D<int> shadow_offset = manager_->shadow_offset();
+// ideally it would be -radius for the *2 part see comment in Manager::Impl::BuildShapedShadowTexture
+// in DecorationsManager.cpp Make sure to keep these factors in sync.
+ int x = border.x() + shadow_offset.x - radius * 2 + shape.getXoffs();
+ int y = border.y() + shadow_offset.y - radius * 2 + shape.getYoffs();
+ int width = texture->width();
+ int height = texture->height();
+
+ auto* quad = &shadow_quads_[Quads::Pos(0)];
+ quad->box.setGeometry(x, y, width, height);
+ quad->matrix = texture->matrix();
+ quad->matrix.x0 = -COMP_TEX_COORD_X(quad->matrix, quad->box.x1());
+ quad->matrix.y0 = -COMP_TEX_COORD_Y(quad->matrix, quad->box.y1());
+
+ CompRect shaped_shadow_rect(x, y, width, height);
+ if (shaped_shadow_rect != last_shadow_rect_) {
+ auto const& win_region = win_->region();
+ quad->region = CompRegion(quad->box) - win_region;
+
+ last_shadow_rect_ = shaped_shadow_rect;
+ win_->updateWindowOutputExtents();
+ }
+ cwin_->addDamage(true);
+}
+
void Window::Impl::Paint(GLMatrix const& transformation,
GLWindowPaintAttrib const& attrib,
CompRegion const& region, unsigned mask)
@@ -714,7 +763,12 @@ void Window::Impl::Draw(GLMatrix const& transformation,
glwin_->vertexBuffer()->begin();
- for (unsigned i = 0; i < shadow_quads_.size(); ++i)
+ // numRects is != 1 when the window is shaped
+ unsigned int num_quads = shadow_quads_.size();
+ if (win_->region().numRects() != 1)
+ num_quads = 1;
+
+ for (unsigned int i = 0; i < num_quads; ++i)
{
auto& quad = shadow_quads_[Quads::Pos(i)];
glwin_->glAddGeometry(quad.matrices, quad.region, clip_region);
@@ -949,7 +1003,10 @@ void Window::Undecorate()
void Window::UpdateDecorationPosition()
{
impl_->UpdateMonitor();
- impl_->ComputeShadowQuads();
+ if (impl_->win_->region().numRects() > 1)
+ impl_->ComputeShapedShadowQuad();
+ else
+ impl_->ComputeShadowQuads();
impl_->UpdateWindowEdgesGeo();
impl_->UpdateDecorationTextures();
impl_->UpdateForceQuitDialogPosition();
diff --git a/decorations/DecorationsManager.cpp b/decorations/DecorationsManager.cpp
index 4be19cb33..5e3e652b0 100644
--- a/decorations/DecorationsManager.cpp
+++ b/decorations/DecorationsManager.cpp
@@ -23,6 +23,8 @@
#include <NuxGraphics/CairoGraphics.h>
#include <UnityCore/DBusIndicators.h>
#include <X11/Xatom.h>
+#include <X11/extensions/shape.h>
+
#include "WindowManager.h"
namespace unity
@@ -80,6 +82,31 @@ cu::PixmapTexture::Ptr Manager::Impl::BuildShadowTexture(unsigned radius, nux::C
return shadow_ctx;
}
+cu::PixmapTexture::Ptr Manager::Impl::BuildShapedShadowTexture(unsigned int radius, nux::Color const& color, DecorationsShape const& shape) {
+ //Ideally it would be shape.getWidth + radius * 2 but Cairographics::BlurSurface isn't bounded by the radius
+ //and we need to compensate by using a larger texture. Make sure to modify Window::Impl::ComputeShapedShadowQuad in
+ //DecoratedWindow.cpp if you change the factor.
+ int blur_margin_factor = 2;
+ int img_width = shape.getWidth() + radius * 2 * blur_margin_factor;
+ int img_height = shape.getHeight() + radius * 2 * blur_margin_factor;
+ nux::CairoGraphics img(CAIRO_FORMAT_ARGB32, img_width, img_height);
+ auto* img_ctx = img.GetInternalContext();
+
+ for (int i=0; i<shape.getRectangleCount(); i++) {
+ XRectangle rect = shape.getRectangle(i);
+ cairo_rectangle(img_ctx, rect.x + radius * blur_margin_factor - shape.getXoffs(), rect.y + radius * blur_margin_factor - shape.getYoffs(), rect.width, rect.height);
+ cairo_set_source_rgba(img_ctx, color.red, color.green, color.blue, color.alpha);
+ cairo_fill(img_ctx);
+ }
+ img.BlurSurface(radius);
+
+ cu::CairoContext shadow_ctx(img_width, img_height);
+ cairo_set_source_surface(shadow_ctx, img.GetSurface(), 0, 0);
+ cairo_paint(shadow_ctx);
+
+ return shadow_ctx;
+}
+
void Manager::Impl::BuildActiveShadowTexture()
{
active_shadow_pixmap_ = BuildShadowTexture(manager_->active_shadow_radius(), manager_->active_shadow_color());
diff --git a/decorations/DecorationsPriv.h b/decorations/DecorationsPriv.h
index c39e9c5dd..5c5cfb2d6 100644
--- a/decorations/DecorationsPriv.h
+++ b/decorations/DecorationsPriv.h
@@ -28,8 +28,8 @@
#include <core/core.h>
#include <opengl/opengl.h>
#include <composite/composite.h>
-#include <X11/extensions/shape.h>
+#include "DecorationsShape.h"
#include "DecorationsDataPool.h"
#include "DecorationsManager.h"
#include "DecorationsInputMixer.h"
@@ -121,6 +121,7 @@ private:
std::string const& GetMenusPanelID() const;
void ComputeShadowQuads();
+ void ComputeShapedShadowQuad();
void UpdateDecorationTextures();
void UpdateWindowEdgesGeo();
void UpdateForceQuitDialogPosition();
@@ -165,6 +166,8 @@ private:
Item::Ptr edge_borders_;
EMConverter::Ptr cv_;
+
+ cu::PixmapTexture::Ptr shaped_shadow_pixmap_;
};
struct Manager::Impl : sigc::trackable
@@ -189,6 +192,7 @@ private:
void BuildActiveShadowTexture();
void BuildInactiveShadowTexture();
cu::PixmapTexture::Ptr BuildShadowTexture(unsigned radius, nux::Color const&);
+ cu::PixmapTexture::Ptr BuildShapedShadowTexture(unsigned int radius, nux::Color const& color, DecorationsShape const& shape);
void OnShadowOptionsChanged(bool active);
void OnWindowFrameChanged(bool, ::Window, std::weak_ptr<decoration::Window> const&);
bool OnMenuKeyActivated(std::string const&);
diff --git a/decorations/DecorationsShape.cpp b/decorations/DecorationsShape.cpp
new file mode 100644
index 000000000..af73c9a6a
--- /dev/null
+++ b/decorations/DecorationsShape.cpp
@@ -0,0 +1,102 @@
+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
+/*
+ * Copyright (C) 2016 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: Eleni Maria Stea <elenimaria.stea@canonical.com>
+ */
+
+#include <string.h>
+#include <X11/extensions/shape.h>
+#include "DecoratedWindow.h"
+#include "DecorationsShape.h"
+
+bool DecorationsShape::initShape(XID win)
+{
+ Bool buse, cuse;
+ int bx, by, cx, cy;
+ unsigned int bw, bh, cw, ch;
+ Display *dpy = screen->dpy();
+
+ XShapeQueryExtents(dpy, win, &buse, &bx, &by, &bw, &bh, &cuse, &cx, &cy, &cw, &ch);
+
+ int kind;
+ if (buse) {
+ width = bw;
+ height = bh;
+ xoffs = bx;
+ yoffs = by;
+ kind = ShapeBounding;
+ }
+ else if (cuse) {
+ width = cw;
+ height = ch;
+ xoffs = cx;
+ yoffs = cy;
+ kind = ShapeClip;
+ }
+ else {
+ fprintf(stderr, "XShapeQueryExtend returned no extends.\n");
+ return false;
+ }
+
+ int rect_count, rect_order;
+ XRectangle *rectangles;
+ if (!(rectangles = XShapeGetRectangles(dpy, win, kind, &rect_count, &rect_order))) {
+ fprintf(stderr, "Failed to get shape rectangles\n");
+ return false;
+ }
+
+ for (int i=0; i< rect_count; i++) {
+ rects.push_back(rectangles[i]);
+ }
+
+ XFree(rectangles);
+ return true;
+}
+
+const XRectangle& DecorationsShape::getRectangle(int idx) const
+{
+ return rects[idx];
+}
+
+int DecorationsShape::getRectangleCount() const
+{
+ return (int)rects.size();
+}
+
+int DecorationsShape::getWidth() const
+{
+ return width;
+}
+
+int DecorationsShape::getHeight() const
+{
+ return height;
+}
+
+int DecorationsShape::getXoffs() const
+{
+ return xoffs;
+}
+
+int DecorationsShape::getYoffs() const
+{
+ return yoffs;
+}
+void DecorationsShape::clear()
+{
+ width = height = 0;
+ rects.clear();
+}
diff --git a/decorations/DecorationsShape.h b/decorations/DecorationsShape.h
new file mode 100644
index 000000000..0ca4c2ac3
--- /dev/null
+++ b/decorations/DecorationsShape.h
@@ -0,0 +1,43 @@
+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
+/*
+ * Copyright (C) 2016 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: Eleni Maria Stea <elenimaria.stea@canonical.com>
+ */
+
+#ifndef DECORATIONS_SHAPE_H_
+#define DECORATIONS_SHAPE_H_
+
+#include "WindowManager.h"
+#include "DecoratedWindow.h"
+
+class DecorationsShape
+{
+private:
+ std::vector<XRectangle> rects;
+ int width, height;
+ int xoffs, yoffs;
+
+public:
+ bool initShape(XID win);
+ const XRectangle& getRectangle(int idx) const;
+ int getRectangleCount() const;
+ int getWidth() const;
+ int getHeight() const;
+ int getXoffs() const;
+ int getYoffs() const;
+ void clear();
+};
+#endif //DECORATIONS_SHAPE_H_
diff --git a/plugins/unityshell/src/unityshell.cpp b/plugins/unityshell/src/unityshell.cpp
index 9f0a57ef7..7a18dc471 100644
--- a/plugins/unityshell/src/unityshell.cpp
+++ b/plugins/unityshell/src/unityshell.cpp
@@ -3013,9 +3013,9 @@ bool UnityWindow::glPaint(const GLWindowPaintAttrib& attrib,
wAttrib.opacity = 0.0;
int old_index = gWindow->glPaintGetCurrentIndex();
gWindow->glPaintSetCurrentIndex(MAXSHORT);
+ deco_win_->Paint(matrix, wAttrib, region, mask);
bool ret = gWindow->glPaint(wAttrib, matrix, region, mask);
gWindow->glPaintSetCurrentIndex(old_index);
- deco_win_->Paint(matrix, wAttrib, region, mask);
return ret;
}
}
diff --git a/unity-shared/CompizUtils.cpp b/unity-shared/CompizUtils.cpp
index acd1e15a3..96baaa8a4 100644
--- a/unity-shared/CompizUtils.cpp
+++ b/unity-shared/CompizUtils.cpp
@@ -211,11 +211,7 @@ unsigned WindowDecorationElements(CompWindow* win, WindowFilter wf)
}
}
- if (region.boundingRect() != win->geometry()) // Shaped windows
- return elements;
-
- if (rectangular)
- elements |= DecorationElement::SHADOW;
+ elements |= DecorationElement::SHADOW;
if (!win->overrideRedirect() &&
(win->type() & DECORABLE_WINDOW_TYPES) &&