From 79a4d6dfad2786fb412167638c5beb4af614b9e8 Mon Sep 17 00:00:00 2001 From: tpearson Date: Mon, 15 Aug 2011 01:49:14 +0000 Subject: Use true transparency when drawing menu shadows for apps that support ARGB visuals git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdelibs@1247204 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- kdecore/kapplication.cpp | 122 +++++++++++++++++++++++++++++++++------ kdecore/kapplication.h | 3 +- kdecore/kdetcompmgr.cpp | 7 ++- kdefx/kstyle.cpp | 147 +++++++++++++++++++++++++++++++++++++++-------- 4 files changed, 233 insertions(+), 46 deletions(-) diff --git a/kdecore/kapplication.cpp b/kdecore/kapplication.cpp index 3bdf0b4cc..91aa2a967 100644 --- a/kdecore/kapplication.cpp +++ b/kdecore/kapplication.cpp @@ -140,6 +140,8 @@ #include #endif +#include + #ifndef Q_WS_WIN #include #else @@ -1764,16 +1766,43 @@ public: #if defined(Q_WS_X11) && defined(COMPOSITE) bool KApplication::isCompositionManagerAvailable() { - KConfigGroup pConfig (KGlobal::config(), "General"); - return pConfig.readBoolEntry("compositingManagerAvailable", false); + bool have_manager = false; + const char *home; + struct passwd *p; + p = getpwuid(getuid()); + if (p) + home = p->pw_dir; + else + home = getenv("HOME"); + + char *filename; + const char *configfile = "/.kompmgr.available"; + int n = strlen(home)+strlen(configfile)+1; + filename = (char*)malloc(n*sizeof(char)); + memset(filename,0,n); + strcat(filename, home); + strcat(filename, configfile); + + // Now that we did all that by way of introduction...read the file! + FILE *pFile; + char buffer[255]; + pFile = fopen(filename, "r"); + int kompmgrpid = 0; + if (pFile) { + have_manager = true; + fclose(pFile); + } + + free(filename); + filename = NULL; -return false; + return have_manager; } -bool KApplication::detectCompositionManagerAvailable(bool force_available) { +bool KApplication::detectCompositionManagerAvailable(bool force_available, bool available) { bool compositing_manager_available; if (force_available) { - compositing_manager_available = true; + compositing_manager_available = available; } else { // See if compositing has been enabled @@ -1781,7 +1810,7 @@ bool KApplication::detectCompositionManagerAvailable(bool force_available) { char *displayname = 0; if ( qtargs->isSet("display")) displayname = qtargs->getOption( "display" ).data(); - + Display *dpy = XOpenDisplay( displayname ); x11_composite_error_generated = false; @@ -1807,12 +1836,39 @@ bool KApplication::detectCompositionManagerAvailable(bool force_available) { } } - KConfigGroup pConfig (KGlobal::config(), "General"); - bool cmanager_enabled = pConfig.readBoolEntry("compositingManagerAvailable", false); - if (cmanager_enabled != compositing_manager_available) { - pConfig.writeEntry("compositingManagerAvailable", compositing_manager_available, true, true); + const char *home; + struct passwd *p; + p = getpwuid(getuid()); + if (p) + home = p->pw_dir; + else + home = getenv("HOME"); + + char *filename; + const char *configfile = "/.kompmgr.available"; + int n = strlen(home)+strlen(configfile)+1; + filename = (char*)malloc(n*sizeof(char)); + memset(filename,0,n); + strcat(filename, home); + strcat(filename, configfile); + + /* now that we did all that by way of introduction...create or remove the file! */ + if (compositing_manager_available) { + FILE *pFile; + char buffer[255]; + sprintf(buffer, "available"); + pFile = fopen(filename, "w"); + if (pFile) { + fwrite(buffer,1,strlen(buffer), pFile); + fclose(pFile); + } } - pConfig.sync(); + else { + unlink(filename); + } + + free(filename); + filename = NULL; return compositing_manager_available; } @@ -1822,28 +1878,38 @@ Display* KApplication::openX11RGBADisplay() { char *display = 0; if ( qtargs->isSet("display")) display = qtargs->getOption( "display" ).data(); - + Display *dpy = XOpenDisplay( display ); if ( !dpy ) { kdError() << "cannot connect to X server " << display << endl; exit( 1 ); } - + return dpy; } Qt::HANDLE KApplication::getX11RGBAVisual(Display *dpy) { getX11RGBAInformation(dpy); - return argb_x11_visual; + if (KApplication::isCompositionManagerAvailable() == true) { + return argb_x11_visual; + } + else { + return NULL; + } } Qt::HANDLE KApplication::getX11RGBAColormap(Display *dpy) { getX11RGBAInformation(dpy); - return argb_x11_colormap; + if (KApplication::isCompositionManagerAvailable() == true) { + return argb_x11_colormap; + } + else { + return NULL; + } } bool KApplication::isX11CompositionAvailable() { - return argb_visual & isCompositionManagerAvailable(); + return (argb_visual & isCompositionManagerAvailable()); } void KApplication::getX11RGBAInformation(Display *dpy) { @@ -1851,7 +1917,7 @@ void KApplication::getX11RGBAInformation(Display *dpy) { argb_visual = false; return; } - + int screen = DefaultScreen( dpy ); Colormap colormap = 0; Visual *visual = 0; @@ -1896,6 +1962,28 @@ bool KApplication::isCompositionManagerAvailable() { } bool KApplication::detectCompositionManagerAvailable(bool force_available) { + const char *home; + struct passwd *p; + p = getpwuid(getuid()); + if (p) + home = p->pw_dir; + else + home = getenv("HOME"); + + char *filename; + const char *configfile = "/.kompmgr.available"; + int n = strlen(home)+strlen(configfile)+1; + filename = (char*)malloc(n*sizeof(char)); + memset(filename,0,n); + strcat(filename, home); + strcat(filename, configfile); + + /* now that we did all that by way of introduction...remove the file! */ + unlink(filename); + + free(filename); + filename = NULL; + return false; } diff --git a/kdecore/kapplication.h b/kdecore/kapplication.h index ee0d48f02..c16f105f2 100644 --- a/kdecore/kapplication.h +++ b/kdecore/kapplication.h @@ -914,9 +914,10 @@ public: * Note that calling this method will probably cause the screen to flicker. * @see isCompositionManagerAvailable() * @param force_available If set, force TDE to assume a composition manager is available + * @param available Whether or not the composition manager is available (only used if force_available is TRUE) * @return whether the composition manager is enabled */ - bool detectCompositionManagerAvailable(bool force_available=false); + bool detectCompositionManagerAvailable(bool force_available=false, bool available=true); /** * @internal diff --git a/kdecore/kdetcompmgr.cpp b/kdecore/kdetcompmgr.cpp index 0b143d5de..c5cbd415f 100644 --- a/kdecore/kdetcompmgr.cpp +++ b/kdecore/kdetcompmgr.cpp @@ -49,16 +49,17 @@ int main(int argc, char **argv) KApplication app; app.detectCompositionManagerAvailable(); - if (!app.isCompositionManagerAvailable()) { +// if (!app.isCompositionManagerAvailable()) { KConfig config("kwinrc", true); config.setGroup( "Notification Messages" ); if (config.readBoolEntry("UseTranslucency",false)) { - app.detectCompositionManagerAvailable(true); + app.detectCompositionManagerAvailable(true, true); return 2; } else { + app.detectCompositionManagerAvailable(true, false); return 0; } - } +// } } diff --git a/kdefx/kstyle.cpp b/kdefx/kstyle.cpp index 473a61e43..3f3f36b71 100644 --- a/kdefx/kstyle.cpp +++ b/kdefx/kstyle.cpp @@ -63,6 +63,12 @@ #undef HAVE_XRENDER #endif +#ifdef HAVE_XCOMPOSITE +#include +#include +#include +#endif + #include namespace @@ -138,6 +144,10 @@ class TransparencyHandler : public TQObject #ifdef HAVE_XRENDER void XRenderBlendToPixmap(const TQWidget* p); #endif +#ifdef HAVE_XCOMPOSITE + bool haveX11RGBASupport(); +#endif + TQImage handleRealAlpha(TQImage); void createShadowWindows(const TQWidget* p); void removeShadowWindows(const TQWidget* p); void rightShadow(TQImage& dst); @@ -1951,9 +1961,24 @@ TransparencyHandler::~TransparencyHandler() { } +bool TransparencyHandler::haveX11RGBASupport() +{ + // Simple way + if (TQPaintDevice::x11AppDepth() == 32) { + return true; + } + else { + return false; + } +} + +#define REAL_ALPHA_STRENGTH 255.0 + // This is meant to be ugly but fast. void TransparencyHandler::rightShadow(TQImage& dst) { + bool have_composite = haveX11RGBASupport(); + if (dst.depth() != 32) dst = dst.convertDepth(32); @@ -1965,34 +1990,60 @@ void TransparencyHandler::rightShadow(TQImage& dst) register unsigned char* data = dst.bits(); // Skip alpha #endif for(register int i = 0; i < 16; i++) { - *data = (unsigned char)((*data)*top_right_corner[i]); data++; - *data = (unsigned char)((*data)*top_right_corner[i]); data++; - *data = (unsigned char)((*data)*top_right_corner[i]); data++; - data++; // skip alpha + if (have_composite) { + data++; + data++; + data++; + *data = (unsigned char)(REAL_ALPHA_STRENGTH*(1.0-top_right_corner[i])); data++; + } + else { + *data = (unsigned char)((*data)*top_right_corner[i]); data++; + *data = (unsigned char)((*data)*top_right_corner[i]); data++; + *data = (unsigned char)((*data)*top_right_corner[i]); data++; + data++; // skip alpha + } } pixels -= 32; // tint right strip without rounded edges. register int c = 0; for(register int i = 0; i < pixels; i++) { - *data = (unsigned char)((*data)*shadow_strip[c]); data++; - *data = (unsigned char)((*data)*shadow_strip[c]); data++; - *data = (unsigned char)((*data)*shadow_strip[c]); data++; - data++; // skip alpha - ++c; + if (have_composite) { + data++; + data++; + data++;; + *data = (unsigned char)(REAL_ALPHA_STRENGTH*(1.0-shadow_strip[c])); data++; + } + else { + *data = (unsigned char)((*data)*shadow_strip[c]); data++; + *data = (unsigned char)((*data)*shadow_strip[c]); data++; + *data = (unsigned char)((*data)*shadow_strip[c]); data++; + data++; // skip alpha + } + ++c; c %= 4; } // tint bottom edge for(register int i = 0; i < 16; i++) { - *data = (unsigned char)((*data)*bottom_right_corner[i]); data++; - *data = (unsigned char)((*data)*bottom_right_corner[i]); data++; - *data = (unsigned char)((*data)*bottom_right_corner[i]); data++; - data++; // skip alpha + if (have_composite) { + data++; + data++; + data++; + *data = (unsigned char)(REAL_ALPHA_STRENGTH*(1.0-bottom_right_corner[i])); data++; + } + else { + *data = (unsigned char)((*data)*bottom_right_corner[i]); data++; + *data = (unsigned char)((*data)*bottom_right_corner[i]); data++; + *data = (unsigned char)((*data)*bottom_right_corner[i]); data++; + data++; // skip alpha + } } } void TransparencyHandler::bottomShadow(TQImage& dst) { + bool have_composite = haveX11RGBASupport(); + if (dst.depth() != 32) dst = dst.convertDepth(32); @@ -2011,25 +2062,59 @@ void TransparencyHandler::bottomShadow(TQImage& dst) { // Bottom-left Corner for(register int x = 0; x < 4; x++) { - *data = (unsigned char)((*data)*(*corner)); data++; - *data = (unsigned char)((*data)*(*corner)); data++; - *data = (unsigned char)((*data)*(*corner)); data++; - data++; // skip alpha + if (have_composite) { + data++; + data++; + data++; + *data = (unsigned char)(REAL_ALPHA_STRENGTH*(1.0-(*corner))); data++; + } + else { + *data = (unsigned char)((*data)*(*corner)); data++; + *data = (unsigned char)((*data)*(*corner)); data++; + *data = (unsigned char)((*data)*(*corner)); data++; + data++; // skip alpha + } corner++; } // Scanline for(register int x = 0; x < width; x++) { - *data = (unsigned char)((*data)*strip_data); data++; - *data = (unsigned char)((*data)*strip_data); data++; - *data = (unsigned char)((*data)*strip_data); data++; - data++; + if (have_composite) { + data++; + data++; + data++; + *data = (unsigned char)(REAL_ALPHA_STRENGTH*(1.0-strip_data)); data++; + } + else { + *data = (unsigned char)((*data)*strip_data); data++; + *data = (unsigned char)((*data)*strip_data); data++; + *data = (unsigned char)((*data)*strip_data); data++; + data++; // skip alpha + } } strip_data = shadow_strip[++line]; } } +TQImage TransparencyHandler::handleRealAlpha(TQImage img) { + TQImage clearImage = img.convertDepth(32); + clearImage.setAlphaBuffer(true); + + int w = clearImage.width(); + int h = clearImage.height(); + + for (int y = 0; y < h; ++y) { + TQRgb *ls = (TQRgb *)clearImage.scanLine( y ); + for (int x = 0; x < w; ++x) { + TQRgb l = ls[x]; + ls[x] = tqRgba( 0, 0, 0, 0 ); + } + } + + return clearImage; +} + // Create a shadow of thickness 4. void TransparencyHandler::createShadowWindows(const TQWidget* p) { @@ -2039,6 +2124,8 @@ void TransparencyHandler::createShadowWindows(const TQWidget* p) TQRect shadow1(x2, p->y() + 4, 4, p->height()); TQRect shadow2(p->x() + 4, y2, p->width() - 4, 4); + bool have_composite = haveX11RGBASupport(); + // Create a fake drop-down shadow effect via blended Xwindows ShadowElements se; se.w1 = new TQWidget(0, 0, (WFlags)(WStyle_Customize | WType_Popup | WX11BypassWM) ); @@ -2052,16 +2139,26 @@ void TransparencyHandler::createShadowWindows(const TQWidget* p) shadowMap()[p] = se; // Some hocus-pocus here to create the drop-shadow. - TQPixmap pix_shadow1 = TQPixmap::grabWindow(qt_xrootwin(), - shadow1.x(), shadow1.y(), shadow1.width(), shadow1.height()); - TQPixmap pix_shadow2 = TQPixmap::grabWindow(qt_xrootwin(), - shadow2.x(), shadow2.y(), shadow2.width(), shadow2.height()); + TQPixmap pix_shadow1; + TQPixmap pix_shadow2; + if (have_composite) { + pix_shadow1 = TQPixmap(shadow1.width(), shadow1.height()); + pix_shadow2 = TQPixmap(shadow2.width(), shadow2.height()); + } + else { + pix_shadow1 = TQPixmap::grabWindow(qt_xrootwin(), + shadow1.x(), shadow1.y(), shadow1.width(), shadow1.height()); + pix_shadow2 = TQPixmap::grabWindow(qt_xrootwin(), + shadow2.x(), shadow2.y(), shadow2.width(), shadow2.height()); + } TQImage img; img = pix_shadow1.convertToImage(); + if (have_composite) img = handleRealAlpha(img); rightShadow(img); pix_shadow1.convertFromImage(img); img = pix_shadow2.convertToImage(); + if (have_composite) img = handleRealAlpha(img); bottomShadow(img); pix_shadow2.convertFromImage(img); -- cgit v1.2.1