Move XRender based rendering of unstyled EffectFrame into scene_xrender
This follows how it is done for OpenGL where the renderRoundBox() got dropped some time ago. New implementation implements the box with round corners using xrender directly instead of using a QPainter on a QPixmap.
This commit is contained in:
parent
368de6842a
commit
a1ac6df20e
4 changed files with 105 additions and 66 deletions
|
@ -73,64 +73,6 @@ XRenderPicture xRenderBlendPicture(double opacity)
|
|||
return _blendPicture;
|
||||
}
|
||||
|
||||
|
||||
static XRenderPicture *_circle[4] = {NULL, NULL, NULL, NULL};
|
||||
|
||||
#define DUMP_CNR(_SECT_, _W_, _H_, _XOFF_, _YOFF_)\
|
||||
dump = QPixmap(_W_, _H_);\
|
||||
dump.fill(Qt::transparent);\
|
||||
p.begin(&dump);\
|
||||
p.drawPixmap( 0, 0, tmp, _XOFF_, _YOFF_, _W_, _H_ );\
|
||||
p.end();\
|
||||
_circle[_SECT_] = new XRenderPicture(dump);
|
||||
|
||||
#define CS 8
|
||||
|
||||
static XRenderPicture *circle(int i)
|
||||
{
|
||||
if (!_circle[0]) {
|
||||
QPixmap tmp(2 * CS, 2 * CS);
|
||||
tmp.fill(Qt::transparent);
|
||||
QPainter p(&tmp);
|
||||
p.setRenderHint(QPainter::Antialiasing);
|
||||
p.setPen(Qt::NoPen); p.setBrush(Qt::black);
|
||||
p.drawEllipse(tmp.rect());
|
||||
p.end();
|
||||
QPixmap dump;
|
||||
DUMP_CNR(0, CS, CS, 0, 0);
|
||||
DUMP_CNR(1, CS, CS, CS, 0);
|
||||
DUMP_CNR(2, CS, CS, CS, CS);
|
||||
DUMP_CNR(3, CS, CS, 0, CS);
|
||||
}
|
||||
return _circle[i];
|
||||
}
|
||||
|
||||
void xRenderRoundBox(Picture pict, const QRect &rect, int , const QColor &c)
|
||||
{
|
||||
XRenderPicture fill = xRenderFill(c);
|
||||
int op = c.alpha() == 255 ? PictOpSrc : PictOpOver;
|
||||
// TODO: implement second paramenter "roundness"
|
||||
// so rather use ?? XRenderCompositeTriFan (dpy, op, src, dst, maskFormat, xSrc, ySrc,
|
||||
//XPointFixed *points, npoint);
|
||||
// this will require "points on a circle" calculation, however...
|
||||
|
||||
int s = qMin(CS, qMin(rect.height() / 2, rect.width() / 2));
|
||||
int x, y, b, r;
|
||||
rect.getCoords(&x, &y, &r, &b);
|
||||
r -= (s - 1);
|
||||
b -= (s - 1);
|
||||
XRenderComposite(display(), PictOpOver, fill, *circle(0), pict, 0, 0, 0, 0, x, y, CS, CS);
|
||||
XRenderComposite(display(), PictOpOver, fill, *circle(1), pict, 0, 0, CS - s, 0, r, y, s, s);
|
||||
XRenderComposite(display(), PictOpOver, fill, *circle(2), pict, 0, 0, CS - s, CS - s, r, b, s, s);
|
||||
XRenderComposite(display(), PictOpOver, fill, *circle(3), pict, 0, 0, 0, CS - s, x, b, s, s);
|
||||
XRenderComposite(display(), op, fill, 0, pict, 0, 0, 0, 0, x + s, y, rect.width() - 2 * s, s);
|
||||
XRenderComposite(display(), op, fill, 0, pict, 0, 0, 0, 0, x, y + s, rect.width(), rect.height() - 2 * s);
|
||||
XRenderComposite(display(), op, fill, 0, pict, 0, 0, 0, 0, x + s, b, rect.width() - 2 * s, s);
|
||||
}
|
||||
|
||||
#undef CS
|
||||
#undef DUMP_CNR
|
||||
|
||||
// XRenderFind(Standard)Format() is a roundtrip, so cache the results
|
||||
static XRenderPictFormat* renderformats[ 33 ];
|
||||
|
||||
|
|
|
@ -39,10 +39,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
||||
namespace KWin
|
||||
{
|
||||
/**
|
||||
* draws a round box on the renderscene
|
||||
*/
|
||||
KWIN_EXPORT void xRenderRoundBox(Picture pict, const QRect &rect, int round, const QColor &c);
|
||||
/**
|
||||
* dumps a QColor into a XRenderColor
|
||||
*/
|
||||
|
|
|
@ -37,6 +37,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include <kxerrorhandler.h>
|
||||
|
||||
#include <QtGui/QPainter>
|
||||
#include <QtCore/qmath.h>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
@ -93,6 +94,7 @@ SceneXrender::~SceneXrender()
|
|||
m_overlayWindow->destroy();
|
||||
return;
|
||||
}
|
||||
SceneXrender::EffectFrame::cleanup();
|
||||
XRenderFreePicture(display(), front);
|
||||
XRenderFreePicture(display(), buffer);
|
||||
buffer = None;
|
||||
|
@ -727,6 +729,8 @@ void SceneXrender::screenGeometryChanged(const QSize &size)
|
|||
// SceneXrender::EffectFrame
|
||||
//****************************************
|
||||
|
||||
XRenderPicture *SceneXrender::EffectFrame::s_effectFrameCircle = NULL;
|
||||
|
||||
SceneXrender::EffectFrame::EffectFrame(EffectFrameImpl* frame)
|
||||
: Scene::EffectFrame(frame)
|
||||
{
|
||||
|
@ -744,6 +748,12 @@ SceneXrender::EffectFrame::~EffectFrame()
|
|||
delete m_selectionPicture;
|
||||
}
|
||||
|
||||
void SceneXrender::EffectFrame::cleanup()
|
||||
{
|
||||
delete s_effectFrameCircle;
|
||||
s_effectFrameCircle = NULL;
|
||||
}
|
||||
|
||||
void SceneXrender::EffectFrame::free()
|
||||
{
|
||||
delete m_picture;
|
||||
|
@ -792,10 +802,9 @@ void SceneXrender::EffectFrame::render(QRegion region, double opacity, double fr
|
|||
}
|
||||
|
||||
// Render the actual frame
|
||||
if (m_effectFrame->style() == EffectFrameUnstyled)
|
||||
xRenderRoundBox(effects->xrenderBufferPicture(), m_effectFrame->geometry().adjusted(-5, -5, 5, 5),
|
||||
5, QColor(0, 0, 0, int(opacity * frameOpacity * 255)));
|
||||
else if (m_effectFrame->style() == EffectFrameStyled) {
|
||||
if (m_effectFrame->style() == EffectFrameUnstyled) {
|
||||
renderUnstyled(effects->xrenderBufferPicture(), m_effectFrame->geometry(), opacity * frameOpacity);
|
||||
} else if (m_effectFrame->style() == EffectFrameStyled) {
|
||||
if (!m_picture) { // Lazy creation
|
||||
updatePicture();
|
||||
}
|
||||
|
@ -844,6 +853,95 @@ void SceneXrender::EffectFrame::render(QRegion region, double opacity, double fr
|
|||
}
|
||||
}
|
||||
|
||||
void SceneXrender::EffectFrame::renderUnstyled(xcb_render_picture_t pict, const QRect &rect, qreal opacity)
|
||||
{
|
||||
const int roundness = 5;
|
||||
const QRect area = rect.adjusted(-roundness, -roundness, roundness, roundness);
|
||||
xcb_rectangle_t rects[3];
|
||||
// center
|
||||
rects[0].x = area.left();
|
||||
rects[0].y = area.top() + roundness;
|
||||
rects[0].width = area.width();
|
||||
rects[0].height = area.height() - roundness * 2;
|
||||
// top
|
||||
rects[1].x = area.left() + roundness;
|
||||
rects[1].y = area.top();
|
||||
rects[1].width = area.width() - roundness * 2;
|
||||
rects[1].height = roundness;
|
||||
// bottom
|
||||
rects[2].x = area.left() + roundness;
|
||||
rects[2].y = area.top() + area.height() - roundness;
|
||||
rects[2].width = area.width() - roundness * 2;
|
||||
rects[2].height = roundness;
|
||||
xcb_render_color_t color = {0, 0, 0, uint16_t(opacity * 0xffff)};
|
||||
xcb_render_fill_rectangles(connection(), XCB_RENDER_PICT_OP_OVER, pict, color, 3, rects);
|
||||
|
||||
if (!s_effectFrameCircle) {
|
||||
// create the circle
|
||||
const int diameter = roundness * 2;
|
||||
xcb_pixmap_t pix = xcb_generate_id(connection());
|
||||
xcb_create_pixmap(connection(), 32, pix, rootWindow(), diameter, diameter);
|
||||
s_effectFrameCircle = new XRenderPicture(pix, 32);
|
||||
xcb_free_pixmap(connection(), pix);
|
||||
|
||||
// clear it with transparent
|
||||
xcb_rectangle_t xrect = {0, 0, diameter, diameter};
|
||||
xcb_render_color_t tranparent = {0, 0, 0, 0};
|
||||
xcb_render_fill_rectangles(connection(), XCB_RENDER_PICT_OP_SRC, *s_effectFrameCircle, tranparent, 1, &xrect);
|
||||
|
||||
static int num_segments = 80;
|
||||
static qreal theta = 2 * M_PI / qreal(num_segments);
|
||||
static qreal c = qCos(theta); //precalculate the sine and cosine
|
||||
static qreal s = qSin(theta);
|
||||
qreal t;
|
||||
|
||||
qreal x = roundness;//we start at angle = 0
|
||||
qreal y = 0;
|
||||
#define DOUBLE_TO_FIXED(d) ((xcb_render_fixed_t) ((d) * 65536))
|
||||
QVector<xcb_render_pointfix_t> points;
|
||||
xcb_render_pointfix_t point;
|
||||
point.x = DOUBLE_TO_FIXED(roundness);
|
||||
point.y = DOUBLE_TO_FIXED(roundness);
|
||||
points << point;
|
||||
for (int ii = 0; ii <= num_segments; ++ii) {
|
||||
point.x = DOUBLE_TO_FIXED(x + roundness);
|
||||
point.y = DOUBLE_TO_FIXED(y + roundness);
|
||||
points << point;
|
||||
//apply the rotation matrix
|
||||
t = x;
|
||||
x = c * x - s * y;
|
||||
y = s * t + c * y;
|
||||
}
|
||||
XRenderPicture fill = xRenderFill(Qt::black);
|
||||
xcb_render_tri_fan(connection(), XCB_RENDER_PICT_OP_OVER, fill, *s_effectFrameCircle,
|
||||
0, 0, 0, points.count(), points.constData());
|
||||
#undef DOUBLE_TO_FIXED
|
||||
}
|
||||
// TODO: merge alpha mask with SceneXrender::Window::alphaMask
|
||||
// alpha mask
|
||||
xcb_pixmap_t pix = xcb_generate_id(connection());
|
||||
xcb_create_pixmap(connection(), 8, pix, rootWindow(), 1, 1);
|
||||
XRenderPicture alphaMask(pix, 8);
|
||||
xcb_free_pixmap(connection(), pix);
|
||||
const uint32_t values[] = {true};
|
||||
xcb_render_change_picture(connection(), alphaMask, XCB_RENDER_CP_REPEAT, values);
|
||||
color.alpha = int(opacity * 0xffff);
|
||||
xcb_rectangle_t xrect = {0, 0, 1, 1};
|
||||
xcb_render_fill_rectangles(connection(), XCB_RENDER_PICT_OP_SRC, alphaMask, color, 1, &xrect);
|
||||
|
||||
// TODO: replace by lambda
|
||||
#define RENDER_CIRCLE(srcX, srcY, destX, destY) \
|
||||
xcb_render_composite(connection(), XCB_RENDER_PICT_OP_OVER, *s_effectFrameCircle, alphaMask, \
|
||||
pict, srcX, srcY, 0, 0, destX, destY, roundness, roundness)
|
||||
|
||||
RENDER_CIRCLE(0, 0, area.left(), area.top());
|
||||
RENDER_CIRCLE(0, roundness, area.left(), area.top() + area.height() - roundness);
|
||||
RENDER_CIRCLE(roundness, 0, area.left() + area.width() - roundness, area.top());
|
||||
RENDER_CIRCLE(roundness, roundness,
|
||||
area.left() + area.width() - roundness, area.top() + area.height() - roundness);
|
||||
#undef RENDER_CIRCLE
|
||||
}
|
||||
|
||||
void SceneXrender::EffectFrame::updatePicture()
|
||||
{
|
||||
delete m_picture;
|
||||
|
|
|
@ -113,15 +113,18 @@ public:
|
|||
virtual void crossFadeIcon();
|
||||
virtual void crossFadeText();
|
||||
virtual void render(QRegion region, double opacity, double frameOpacity);
|
||||
static void cleanup();
|
||||
|
||||
private:
|
||||
void updatePicture();
|
||||
void updateTextPicture();
|
||||
void renderUnstyled(xcb_render_picture_t pict, const QRect &rect, qreal opacity);
|
||||
|
||||
XRenderPicture* m_picture;
|
||||
XRenderPicture* m_textPicture;
|
||||
XRenderPicture* m_iconPicture;
|
||||
XRenderPicture* m_selectionPicture;
|
||||
static XRenderPicture* s_effectFrameCircle;
|
||||
};
|
||||
|
||||
inline
|
||||
|
|
Loading…
Reference in a new issue