diff options
| -rw-r--r-- | decorations/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | decorations/DecoratedWindow.cpp | 65 | ||||
| -rw-r--r-- | decorations/DecorationsManager.cpp | 27 | ||||
| -rw-r--r-- | decorations/DecorationsPriv.h | 6 | ||||
| -rw-r--r-- | decorations/DecorationsShape.cpp | 102 | ||||
| -rw-r--r-- | decorations/DecorationsShape.h | 43 | ||||
| -rw-r--r-- | plugins/unityshell/src/unityshell.cpp | 2 | ||||
| -rw-r--r-- | unity-shared/CompizUtils.cpp | 6 |
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) && |
