diff options
author | onestone <onestone> | 2006-12-13 23:49:28 +0000 |
---|---|---|
committer | onestone <onestone> | 2006-12-13 23:49:28 +0000 |
commit | 186632c36033c7080074fad72f655b00fbbb913b (patch) | |
tree | 02a757af81d14f21560ff2a33cf72a0404b71890 | |
parent | 5fe27a99f4725202c6c732733bdfd429ae165776 (diff) | |
download | aquamarine-186632c36033c7080074fad72f655b00fbbb913b.tar.gz aquamarine-186632c36033c7080074fad72f655b00fbbb913b.tar.bz2 |
aquamarine: added shadow support (currently only for decorated windows and disabled by default)
-rw-r--r-- | src/Makefile.am | 5 | ||||
-rw-r--r-- | src/aquamarine.kcfg | 36 | ||||
-rw-r--r-- | src/decorator.cpp | 4 | ||||
-rw-r--r-- | src/settings.kcfgc | 9 | ||||
-rw-r--r-- | src/window.cpp | 428 | ||||
-rw-r--r-- | src/window.h | 14 |
6 files changed, 419 insertions, 77 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 65e7a5f..46ec774 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2,6 +2,8 @@ INCLUDES = -I$(srcdir)/lib $(all_includes) bin_PROGRAMS = aquamarine +kde_kcfg_DATA = aquamarine.kcfg + aquamarine_SOURCES = aquamarine.cpp \ utils.cpp \ decorator.cpp \ @@ -9,7 +11,8 @@ aquamarine_SOURCES = aquamarine.cpp \ switcher.cpp \ KWinInterface.skel \ options.cpp \ - defaultDeco.cpp + defaultDeco.cpp \ + settings.kcfgc aquamarine_LDADD = $(LIB_KDECORE) -lkdecorations $(BERYLSETTINGS_LIBS) aquamarine_LDFLAGS = $(all_libraries) diff --git a/src/aquamarine.kcfg b/src/aquamarine.kcfg new file mode 100644 index 0000000..882789e --- /dev/null +++ b/src/aquamarine.kcfg @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE kcfg SYSTEM "http://www.kde.org/standards/kcfg/1.0/kcfg.dtd"> +<kcfg> + <kcfgfile name="aquamarinerc"/> + <group name="General"> + <entry name="DrawShadows" type="Bool"> + <label>Whether to draw drop shadows.</label> + <default>false</default> + </entry> + <entry name="ShadowRadius" type="Int"> + <label>Shadow radius for windows.</label> + <default>8</default> + <min>1</min> + <max>20</max> + </entry> + <entry name="ShadowColor" type="Color"> + <label>Shadow Color.</label> + <default>#000000</default> + </entry> + <entry name="ShadowOpacity" type="Double"> + <label>Shadow opacity (darkness).</label> + <default>.5</default> + <min>0</min> + <max>1</max> + </entry> + <entry name="ShadowOffsetX" type="Int"> + <label>Shadow X offset (distance).</label> + <default>3</default> + </entry> + <entry name="ShadowOffsetY" type="Int"> + <label>Shadow Y offset (distance).</label> + <default>3</default> + </entry> + </group> +</kcfg> + diff --git a/src/decorator.cpp b/src/decorator.cpp index ea3c6b2..6a3c160 100644 --- a/src/decorator.cpp +++ b/src/decorator.cpp @@ -40,6 +40,7 @@ #include "decorator.h" #include "options.h" #include "utils.h" +#include "settings.h" #include <stdio.h> @@ -389,6 +390,9 @@ Aquamarine::Decorator::reconfigure () { kdDebug () << k_funcinfo << endl; + Settings::self()->config()->reparseConfiguration(); + Settings::self()->readConfig(); + m_config->reparseConfiguration (); unsigned long changed = m_options->updateSettings (); diff --git a/src/settings.kcfgc b/src/settings.kcfgc new file mode 100644 index 0000000..cc09c05 --- /dev/null +++ b/src/settings.kcfgc @@ -0,0 +1,9 @@ +# Code generation options for kconfig_compiler +File=aquamarine.kcfg +ClassName=Settings +Singleton=true +Mutators=false +# Inherits=KConfigSkeleton +# IncludeFiles= +# MemberVariables=public + diff --git a/src/window.cpp b/src/window.cpp index a0bf9f4..a283897 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -29,11 +29,15 @@ #include "decorator.h" #include "options.h" #include "utils.h" +#include "settings.h" #include <X11/Xlib.h> #include <X11/Xatom.h> #include <X11/extensions/Xcomposite.h> #include <X11/extensions/shape.h> +#include <X11/extensions/Xrender.h> + +#include <math.h> #include <fixx11h.h> @@ -122,13 +126,32 @@ m_brightness_menu (0), m_saturation_menu (0), m_opacity_menu (0) m_saturation = readWindowPropertyDefault (m_wid, Atoms::saturation, 0xffff); - setPaletteBackgroundColor( QColor(QRgb (), 0x00000000)); - setEraseColor(QColor(QRgb (), 0x00000000)); + setBackgroundColor(QColor(0,0)); + + m_sradius = Settings::shadowRadius(); + QColor color = Settings::shadowColor(); + m_scolor[0] = short((color.red() / 256.0) * 0xffff); + m_scolor[1] = short((color.green() / 256.0) * 0xffff); + m_scolor[2] = short((color.blue() / 256.0) * 0xffff); + m_scolor[3] = short(Settings::shadowOpacity() * 0xffff); + + int offX = Settings::shadowOffsetX(); + int offY = Settings::shadowOffsetY(); + offX = KMAX(-m_sradius,KMIN(m_sradius,offX)); + offY = KMAX(-m_sradius,KMIN(m_sradius,offY)); + + if (Settings::drawShadows()) + m_soffset.setCoords(-m_sradius + offX,-m_sradius + offY, + m_sradius + offX,m_sradius + offY); + else + m_soffset.setCoords(0,0,0,0); + setWState (Qt::WState_Visible); updateFrame (frame); int x, y; unsigned int width, height, border, depth; + installEventFilter(this); ::Window root; XGetGeometry (qt_xdisplay (), m_wid, &root, &x, &y, &width, &height, @@ -529,33 +552,29 @@ Aquamarine::Window::setMask (const QRegion & reg, int) { kdDebug () << k_funcinfo << endl; - QRegion clear = m_shape.subtract(reg); + int top, bottom, left, right; + m_deco->borders (left, right, top, bottom); - // Decoration has no erase flag so we need to erase old regions - if (!clear.isEmpty()) - { - WId win = m_deco->widget()->handle(); - XGCValues gcv; - gcv.foreground = 0x00000000; - gcv.plane_mask = 0xffffffff; - GC gc = XCreateGC (qt_xdisplay (), win, GCForeground, &gcv); - - QMemArray < QRect > rects = clear.rects (); - QMemArray < QRect >::ConstIterator it; - for (it = rects.begin (); it != rects.end (); ++it) - { - XFillRectangle (qt_xdisplay (), win, gc, it->x (), it->y (), - it->width (), it->height ()); - } + QRegion win(left,top,m_geometry.width(),m_geometry.height()); - XFreeGC (qt_xdisplay (), gc); - } + if (m_shapeSet) + m_shapeChange += m_shape.eor(reg.subtract(win)); + else + m_shapeChange = reg.subtract(win); - m_shape = QRegion (reg); + m_shape = QRegion (reg.subtract(win)); m_shapeSet = true; + if (m_deco) + m_deco->widget()->setMask(reg); + + QRegion moved = QRegion (reg); + moved.translate(-m_soffset.left(),-m_soffset.top()); + XShapeCombineRegion (qt_xdisplay (), handle(), ShapeInput, 0, 0, - reg.handle (), ShapeSet); + moved.handle (), ShapeSet); + + //renderShadow(); } bool @@ -751,7 +770,9 @@ Aquamarine::Window::createDecoration () KDecoration * deco = Decorator::pluginManager ()->createDecoration (this); deco->init (); + deco->widget()->move(-m_soffset.left(),-m_soffset.top()); m_deco = deco; + m_deco->widget()->installEventFilter(this); resizeDecoration (); updateFrame(m_frame); @@ -763,13 +784,23 @@ Aquamarine::Window::resizeDecoration () int top, bottom, left, right; m_deco->borders (left, right, top, bottom); - move (m_geometry.x() - left, m_geometry.y() - top); - resize (m_geometry.width () + left + right, - m_geometry.height () + top + bottom); + kdDebug () << k_funcinfo << endl; + + - m_deco->resize (QSize(m_geometry.width () + left + right, - m_geometry.height () + top + bottom)); + move (m_geometry.x() - left + m_soffset.left(), + m_geometry.y() - top + m_soffset.top()); + if (m_geometry.width () + left + right + m_soffset.width() != width() || + m_geometry.height () + top + bottom + m_soffset.height() != height()) + { + m_shapeSet = false; + resize (m_geometry.width () + left + right + m_soffset.width(), + m_geometry.height () + top + bottom + m_soffset.height()); + + m_deco->resize (QSize(m_geometry.width () + left + right, + m_geometry.height () + top + bottom)); + } m_deco->widget ()->setShown (true); } @@ -790,6 +821,11 @@ Aquamarine::Window::updateWindowProperties () int w_w = m_geometry.width (); int w_h = m_geometry.height (); + int otop = top - m_soffset.top(); + int obottom = bottom + m_soffset.bottom(); + int oleft = left - m_soffset.left(); + int oright = right + m_soffset.right(); + long mdata[256]; long *data = mdata; @@ -818,12 +854,12 @@ Aquamarine::Window::updateWindowProperties () ((GRAVITY_NORTH | GRAVITY_WEST) << 4) | (0 << 8) | (0 << 10) | (XX_MASK) | (YY_MASK); - *data++ = -left; - *data++ = -top; + *data++ = -oleft; + *data++ = -otop; *data++ = 0; *data++ = 0; - *data++ = left; - *data++ = top; + *data++ = oleft; + *data++ = otop; *data++ = 0; *data++ = 0; @@ -834,12 +870,12 @@ Aquamarine::Window::updateWindowProperties () (0 << 8) | (0 << 10) | (XX_MASK) | (YY_MASK); *data++ = 0; - *data++ = -top; - *data++ = right; + *data++ = -otop; + *data++ = oright; *data++ = 0; - *data++ = right; - *data++ = top; - *data++ = left + w_w; + *data++ = oright; + *data++ = otop; + *data++ = oleft + w_w; *data++ = 0; // BOTTOM LEFT @@ -848,14 +884,14 @@ Aquamarine::Window::updateWindowProperties () ((GRAVITY_SOUTH | GRAVITY_WEST) << 4) | (0 << 8) | (0 << 10) | (XX_MASK) | (YY_MASK); - *data++ = -left; + *data++ = -oleft; *data++ = 0; *data++ = 0; - *data++ = bottom; - *data++ = left; - *data++ = bottom; + *data++ = obottom; + *data++ = oleft; + *data++ = obottom; *data++ = 0; - *data++ = w_h + top; + *data++ = w_h + otop; // BOTTOM RIGHT *data++ = @@ -865,12 +901,12 @@ Aquamarine::Window::updateWindowProperties () *data++ = 0; *data++ = 0; - *data++ = right; - *data++ = bottom; - *data++ = right; - *data++ = bottom; - *data++ = left + w_w; - *data++ = w_h + top; + *data++ = oright; + *data++ = obottom; + *data++ = oright; + *data++ = obottom; + *data++ = oleft + w_w; + *data++ = w_h + otop; // TOP CENTER *data++ = @@ -879,12 +915,12 @@ Aquamarine::Window::updateWindowProperties () (0 << 8) | (0 << 10) | (XX_MASK) | (YY_MASK); *data++ = 0; - *data++ = -top; + *data++ = -otop; *data++ = 0; *data++ = 0; *data++ = w_w; - *data++ = top; - *data++ = left; + *data++ = otop; + *data++ = oleft; *data++ = 0; *data++ = @@ -893,12 +929,12 @@ Aquamarine::Window::updateWindowProperties () (0 << 8) | (CLAMP_HORZ << 10) | (YY_MASK); *data++ = w_w; - *data++ = -top; + *data++ = -otop; *data++ = 0; *data++ = 0; *data++ = SHRT_MAX; - *data++ = top; - *data++ = left + w_w; + *data++ = otop; + *data++ = oleft + w_w; *data++ = 0; // BOTTOM CENTER @@ -910,11 +946,11 @@ Aquamarine::Window::updateWindowProperties () *data++ = 0; *data++ = 0; *data++ = 0; - *data++ = bottom; + *data++ = obottom; *data++ = w_w; - *data++ = bottom; - *data++ = left; - *data++ = w_h + top; + *data++ = obottom; + *data++ = oleft; + *data++ = w_h + otop; *data++ = ((GRAVITY_SOUTH | GRAVITY_WEST) << 0) | @@ -924,11 +960,11 @@ Aquamarine::Window::updateWindowProperties () *data++ = w_w; *data++ = 0; *data++ = 0; - *data++ = bottom; + *data++ = obottom; *data++ = SHRT_MAX; - *data++ = bottom; - *data++ = left + w_w; - *data++ = w_h + top; + *data++ = obottom; + *data++ = oleft + w_w; + *data++ = w_h + otop; //LEFT *data++ = @@ -936,28 +972,28 @@ Aquamarine::Window::updateWindowProperties () ((GRAVITY_SOUTH | GRAVITY_WEST) << 4) | (0 << 8) | (0 << 10) | (XX_MASK) | (YY_MASK); - *data++ = -left; + *data++ = -oleft; *data++ = 0; *data++ = 0; *data++ = 0; - *data++ = left; + *data++ = oleft; *data++ = w_h; *data++ = 0; - *data++ = top; + *data++ = otop; *data++ = ((GRAVITY_NORTH | GRAVITY_WEST) << 0) | ((GRAVITY_SOUTH | GRAVITY_WEST) << 4) | (0 << 8) | (CLAMP_VERT << 10) | (XX_MASK); - *data++ = -left; + *data++ = -oleft; *data++ = w_h; *data++ = 0; *data++ = 0; - *data++ = left; + *data++ = oleft; *data++ = SHRT_MAX; *data++ = 0; - *data++ = top + w_h; + *data++ = otop + w_h; //RIGHT *data++ = @@ -967,12 +1003,12 @@ Aquamarine::Window::updateWindowProperties () *data++ = 0; *data++ = 0; - *data++ = right; + *data++ = oright; *data++ = 0; - *data++ = right; + *data++ = oright; *data++ = w_h; - *data++ = w_w + left; - *data++ = top; + *data++ = w_w + oleft; + *data++ = otop; *data++ = ((GRAVITY_NORTH | GRAVITY_EAST) << 0) | @@ -981,12 +1017,12 @@ Aquamarine::Window::updateWindowProperties () *data++ = 0; *data++ = w_h; - *data++ = right; + *data++ = oright; *data++ = 0; - *data++ = right; + *data++ = oright; *data++ = SHRT_MAX; - *data++ = w_w + left; - *data++ = top + w_h; + *data++ = w_w + oleft; + *data++ = otop + w_h; Aquamarine::trapXError (); XChangeProperty (qt_xdisplay (), m_wid, @@ -1054,6 +1090,25 @@ Aquamarine::Window::reloadDecoration () { delete m_deco; m_deco = 0; + + m_sradius = Settings::shadowRadius(); + QColor color = Settings::shadowColor(); + m_scolor[0] = short((color.red() / 256.0) * 0xffff); + m_scolor[1] = short((color.green() / 256.0) * 0xffff); + m_scolor[2] = short((color.blue() / 256.0) * 0xffff); + m_scolor[3] = short(Settings::shadowOpacity() * 0xffff); + + int offX = Settings::shadowOffsetX(); + int offY = Settings::shadowOffsetY(); + offX = KMAX(-m_sradius,KMIN(m_sradius,offX)); + offY = KMAX(-m_sradius,KMIN(m_sradius,offY)); + + if (Settings::drawShadows()) + m_soffset.setCoords(-m_sradius + offX,-m_sradius + offY, + m_sradius + offX,m_sradius + offY); + else + m_soffset.setCoords(0,0,0,0); + createDecoration (); } @@ -1476,3 +1531,224 @@ void Aquamarine::Window::performMouseCommand(Options::MouseCommand command, QMou } } +#if INT_MAX != LONG_MAX +/* XRenderSetPictureFilter used to be broken on LP64. This + * works with either the broken or fixed version. + */ +static void +XRenderSetPictureFilter_wrapper (Display *dpy, + Picture picture, + char *filter, + XFixed *params, + int nparams) +{ + Aquamarine::trapXError (); + XRenderSetPictureFilter (dpy, picture, filter, params, nparams); + XSync (dpy, False); + if (Aquamarine::popXError ()) + { + long *long_params = new long[nparams]; + int i; + + for (i = 0; i < nparams; i++) + long_params[i] = params[i]; + + XRenderSetPictureFilter (dpy, picture, filter, + (XFixed *) long_params, nparams); + delete long_params; + } +} + +#define XRenderSetPictureFilter XRenderSetPictureFilter_wrapper +#endif + +#define SIGMA(r) ((r) / 2.0) +#define ALPHA(r) (r) + +void Aquamarine::Window::renderShadow () +{ + if (m_shapeChange.isEmpty() || !Settings::drawShadows()) return; + kdDebug () << k_funcinfo << endl; + + int s2 = m_sradius * 2; + + QRect rect = m_shapeChange.boundingRect(); + + rect.setLeft(rect.left() - s2); + rect.setTop(rect.top() - s2); + rect.setRight(rect.right() + s2); + rect.setBottom(rect.bottom() + s2); + + QRegion bound(rect); + bound = m_shape.intersect(bound); + + bound.translate(-rect.left(),-rect.top()); + + QPixmap qRegPix(rect.width(), rect.height(), 32); + QPixmap qTmpPix(rect.width() + s2, rect.height(), 32); + qRegPix.fill( QColor(0,0)); + + QPainter p(&qRegPix); + QBrush b(QColor(0, ((m_scolor[3] >> 8) << 24) + 0xffffff)); + p.setClipRegion(bound); + p.fillRect(0, 0, rect.width(), rect.height(), b); + + XFixed *params; + int n_params = 0; + int size; + + params = createGaussianKernel (&size); + + n_params = size + 2; + size = size / 2; + + params[0] = (n_params - 2) << 16; + params[1] = 1 << 16; + + XRenderPictFormat *format; + format = XRenderFindStandardFormat (qt_xdisplay(), PictStandardARGB32); + + char *filter = NULL; + XFilters* filters = XRenderQueryFilters (qt_xdisplay(), qRegPix.handle()); + if (filters) + { + int i; + + for (i = 0; i < filters->nfilter; i++) + { + if (strcmp (filters->filter[i], FilterConvolution) == 0) + { + filter = (char *) FilterConvolution; + break; + } + } + + XFree (filters); + } + if (!filter) + return; + + static XRenderColor white = { 0xffff, 0xffff, 0xffff, 0xffff }; + + Picture fill = XRenderCreateSolidFill (qt_xdisplay(), &white); + Picture src = XRenderCreatePicture(qt_xdisplay(), qRegPix.handle(), format, 0, NULL); + Picture tmp = XRenderCreatePicture(qt_xdisplay(), qTmpPix.handle(), format, 0, NULL); + Picture dst = XRenderCreatePicture(qt_xdisplay(), handle(), format, 0, NULL); + + setPictureTransform(src,size,0); + XRenderSetPictureFilter (qt_xdisplay(), src, filter, params, n_params); + XRenderComposite (qt_xdisplay(), PictOpSrc, fill, src, tmp, 0, 0, 0, 0, 0, 0, rect.width() + s2, rect.height()); + + XRenderFreePicture (qt_xdisplay(), fill); + + params[0] = 1 << 16; + params[1] = (n_params - 2) << 16; + + XRenderFreePicture (qt_xdisplay(), src); + XRenderColor color = { m_scolor[0], m_scolor[1], m_scolor[2], 0xffff }; + + src = XRenderCreateSolidFill (qt_xdisplay(), &color); + + setPictureTransform(tmp,0,size); + XRenderSetPictureFilter (qt_xdisplay(), tmp, filter, params, n_params); + + XRenderComposite (qt_xdisplay(), PictOpSrc, src, tmp, dst, s2, s2, s2, s2, rect.left() + s2, rect.top() + s2, rect.width() - s2, rect.height() - s2); + + XRenderFreePicture (qt_xdisplay(), src); + XRenderFreePicture (qt_xdisplay(), tmp); + XRenderFreePicture (qt_xdisplay(), dst); + + m_shapeChange = QRegion(); + + delete params; +} + +XFixed *Aquamarine::Window::createGaussianKernel (int *r_size) +{ + double sigma = m_sradius / 2.0; + double alpha = m_sradius; + double radius = m_sradius; + + XFixed *params; + double *amp, scale, x_scale, fx, sum; + int size, half_size, x, i, n; + + scale = 1.0f / (2.0f * M_PI * sigma * sigma); + half_size = int(alpha + 0.5f); + + if (half_size == 0) + half_size = 1; + + size = half_size * 2 + 1; + x_scale = 2.0f * radius / size; + + if (size < 3) + return NULL; + + n = size; + + amp = new double[n]; + if (!amp) + return NULL; + + n += 2; + + params = new XFixed[n]; + if (!params) + return NULL; + + i = 0; + sum = 0.0f; + + for (x = 0; x < size; x++) + { + fx = x_scale * (x - half_size); + + amp[i] = scale * exp ((-1.0f * (fx * fx)) / (2.0f * sigma * sigma)); + + sum += amp[i]; + + i++; + } + + /* normalize */ + if (sum != 0.0) + sum = 1.0 / sum; + + params[0] = params[1] = 0; + + for (i = 2; i < n; i++) + params[i] = XDoubleToFixed (amp[i - 2] * sum); + + delete amp; + + *r_size = size; + + return params; +} + +void Aquamarine::Window::setPictureTransform (Picture p, int dx, int dy) +{ + XTransform transform = { + { + { 1 << 16, 0, -dx << 16 }, + { 0, 1 << 16, -dy << 16 }, + { 0, 0, 1 << 16 }, + } + }; + + XRenderSetPictureTransform (qt_xdisplay(), p, &transform); +} + +bool +Aquamarine::Window::eventFilter (QObject * watched, QEvent * event) +{ + bool rv = QWidget::eventFilter (watched, event); + if (event->type () == QEvent::Paint) + { + QTimer::singleShot (0, this, SLOT(renderShadow())); + } + + return rv; +} + diff --git a/src/window.h b/src/window.h index 0eec076..917dc92 100644 --- a/src/window.h +++ b/src/window.h @@ -33,6 +33,8 @@ #include <qpixmap.h> #include <qwidget.h> +#include <X11/extensions/Xrender.h> + #include "utils.h" #include "options.h" @@ -136,6 +138,9 @@ namespace Aquamarine readWindowPropertyDefault (m_wid, Atoms::saturation, 0xffff); } + protected: + virtual bool eventFilter (QObject * watched, QEvent * event); + private: enum WindowAppearance { @@ -159,8 +164,11 @@ namespace Aquamarine void resizeDecoration (); void getWindowProtocols (); void performMouseCommand( Options::MouseCommand, QMouseEvent *qme ); + XFixed *createGaussianKernel (int *r_size); + void setPictureTransform (Picture p, int dx, int dy); private slots: + void renderShadow (); void updateWindowProperties (); void slotPopupActivated (int id); void slotPopupAboutToShow (); @@ -191,6 +199,7 @@ namespace Aquamarine // shape stuff bool m_shapeSet; QRegion m_shape; + QRegion m_shapeChange; // window handling bool m_supportDeleteWindow; @@ -209,6 +218,11 @@ namespace Aquamarine QPopupMenu *m_opacity_menu; unsigned long m_state; + + // shadow + QRect m_soffset; + int m_sradius; + short m_scolor[4]; }; } |