From f50ce50331053efe6b06b3917bf07a5a64398736 Mon Sep 17 00:00:00 2001 From: tpearson Date: Sat, 13 Aug 2011 02:31:25 +0000 Subject: Add Xorg composition support to kdm KDM composition can be enabled in the control center When enabled, it provides seamless composited logins to Trinity sessions It also gets rid of the remaining artifacts in the themed kdm login screen git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdebase@1246834 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- kdm/config.def | 10 ++++ kdm/kfrontend/kgapp.cpp | 120 ++++++++++++++++++++++++++++++++++--- kdm/kfrontend/kgapp.h | 1 + kdm/kfrontend/kgreeter.h | 4 +- kdm/kfrontend/themer/kdmitem.cpp | 30 +++++++++- kdm/kfrontend/themer/kdmpixmap.cpp | 51 +++++++++++++--- kdm/kfrontend/themer/kdmrect.cpp | 25 +++++--- kdm/kfrontend/themer/kdmthemer.cpp | 40 +++++++++---- kdm/kfrontend/themer/kdmthemer.h | 1 + 9 files changed, 246 insertions(+), 36 deletions(-) (limited to 'kdm') diff --git a/kdm/config.def b/kdm/config.def index 1dfb26ba6..a90d75efd 100644 --- a/kdm/config.def +++ b/kdm/config.def @@ -1986,6 +1986,16 @@ Description: Specify the widget style for the greeter. Empty means to use the built-in default which currently is Plastik. +Key: Compositor +Type: string +Default: "" +User: greeter +Instance: #*/"" +Comment: + Compositor binary name, if compositing is desired. "" means no compositing support. +Description: + Specify the Xorg compositing manager. Currently only kompmgr is supported. + Key: UseAdminSession Type: bool Default: false diff --git a/kdm/kfrontend/kgapp.cpp b/kdm/kfrontend/kgapp.cpp index 2e40d07ef..7c158bc42 100644 --- a/kdm/kfrontend/kgapp.cpp +++ b/kdm/kfrontend/kgapp.cpp @@ -22,6 +22,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include + #include "kdm_greet.h" #include "kdmshutdown.h" #include "kdmconfig.h" @@ -52,6 +54,15 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #include +#ifdef HAVE_XCOMPOSITE +#include +#include +#endif + +#include + +bool argb_visual_available = false; + static int ignoreXError( Display *dpy ATTR_UNUSED, XErrorEvent *event ATTR_UNUSED ) { @@ -82,6 +93,20 @@ GreeterApp::GreeterApp() } } +GreeterApp::GreeterApp(Display *dpy) : KApplication(dpy) +{ + pingInterval = _isLocal ? 0 : _pingInterval; + if (pingInterval) { + struct sigaction sa; + sigemptyset( &sa.sa_mask ); + sa.sa_flags = 0; + sa.sa_handler = sigAlarm; + sigaction( SIGALRM, &sa, 0 ); + alarm( pingInterval * 70 ); // sic! give the "proper" pinger enough time + startTimer( pingInterval * 60000 ); + } +} + void GreeterApp::timerEvent( TQTimerEvent * ) { @@ -145,13 +170,65 @@ kg_main( const char *argv0 ) kde_have_kipc = false; KApplication::disableAutoDcopRegistration(); KCrash::setSafer( true ); - GreeterApp app; + +#ifdef HAVE_XCOMPOSITE + // Begin ARGB initialization + XSetErrorHandler( ignoreXError ); + argb_visual_available = false; + char *display = 0; + + Display *dpyi = XOpenDisplay( display ); + if ( !dpyi ) { + kdError() << "cannot connect to X server " << display << endl; + exit( 1 ); + } + + int screen = DefaultScreen( dpyi ); + Colormap colormap = 0; + Visual *visual = 0; + int event_base, error_base; + + if ( XRenderQueryExtension( dpyi, &event_base, &error_base ) ) { + int nvi; + XVisualInfo templ; + templ.screen = screen; + templ.depth = 32; + templ.c_class = TrueColor; + XVisualInfo *xvi = XGetVisualInfo( dpyi, VisualScreenMask | VisualDepthMask + | VisualClassMask, &templ, &nvi ); + + for ( int i = 0; i < nvi; i++ ) { + XRenderPictFormat *format = XRenderFindVisualFormat( dpyi, xvi[i].visual ); + if ( format->type == PictTypeDirect && format->direct.alphaMask ) { + visual = xvi[i].visual; + colormap = XCreateColormap( dpyi, RootWindow( dpyi, screen ), visual, AllocNone ); + kdDebug() << "found visual with alpha support" << endl; + argb_visual_available = true; + break; + } + } + } + XSetErrorHandler( (XErrorHandler)0 ); + + GreeterApp *app; + if( argb_visual_available ) { + app = new GreeterApp(dpyi); + } + else { + app = new GreeterApp(); + } + // End ARGB initialization +#else + GreeterApp *app = new GreeterApp(); +#endif + XSetIOErrorHandler( xIOErr ); + TQString login_user; Display *dpy = qt_xdisplay(); if (!_GUIStyle.isEmpty()) - app.setStyle( _GUIStyle ); + app->setStyle( _GUIStyle ); // Load up the systemwide ICC profile TQString iccConfigFile = TQString(KDE_CONFDIR); @@ -168,14 +245,15 @@ kg_main( const char *argv0 ) if (!_colorScheme.isEmpty()) { KSimpleConfig config( _colorScheme, true ); config.setGroup( "Color Scheme" ); - app.setPalette( app.createApplicationPalette( &config, 7 ) ); + app->setPalette( app->createApplicationPalette( &config, 7 ) ); } - app.setFont( _normalFont ); + app->setFont( _normalFont ); setup_modifiers( dpy, _numLockStatus ); SecureDisplay( dpy ); KProcess *proc = 0; + KProcess *comp = 0; if (!_grabServer) { if (_useBackground) { proc = new KProcess; @@ -187,10 +265,16 @@ kg_main( const char *argv0 ) GRecvInt(); } + if (!_compositor.isEmpty()) { + comp = new KProcess; + *comp << TQCString( argv0, strrchr( argv0, '/' ) - argv0 + 2 ) + _compositor.ascii(); + comp->start(KProcess::NotifyOnExit, KProcess::Stdin); + } + GSendInt( G_Ready ); kdDebug() << timestamp() << " main1" << endl; - setCursor( dpy, app.desktop()->winId(), XC_left_ptr ); + setCursor( dpy, app->desktop()->winId(), XC_left_ptr ); for (;;) { int rslt, cmd = GRecvInt(); @@ -214,7 +298,7 @@ kg_main( const char *argv0 ) } KProcess *proc2 = 0; - app.setOverrideCursor( Qt::WaitCursor ); + app->setOverrideCursor( Qt::WaitCursor ); FDialog *dialog; #ifdef XDMCP if (cmd == G_Choose) { @@ -247,7 +331,7 @@ kg_main( const char *argv0 ) proc2->start(); } } - app.restoreOverrideCursor(); + app->restoreOverrideCursor(); Debug( "entering event loop\n" ); // Qt4 has a nasty habit of generating BadWindow errors in normal operation, so we simply ignore them // This also prevents the user from being dropped to a console login if Xorg glitches or is buggy @@ -255,6 +339,9 @@ kg_main( const char *argv0 ) rslt = dialog->exec(); XSetErrorHandler( (XErrorHandler)0 ); Debug( "left event loop\n" ); + + login_user = static_cast(dialog)->curUser; + delete dialog; delete proc2; #ifdef XDMCP @@ -274,11 +361,30 @@ kg_main( const char *argv0 ) KGVerify::done(); + if (comp) { + if (_compositor == "kompmgr") { + // Change process UID + // Get user UID + passwd* userinfo = getpwnam(login_user.ascii()); + TQString newuid = TQString("%1").arg(userinfo->pw_uid); + // kompmgr allows us to change its uid in this manner: + // 1.) Send SIGUSER1 + // 2.) Send the new UID to it on the command line + comp->kill(SIGUSR1); + comp->writeStdin(newuid.ascii(), newuid.length()); + usleep(50000); // Give the above function some time to execute. Note that on REALLY slow systems this could fail, leaving kompmgr running as root. TODO: Look into ways to make this more robust. + } + comp->closeStdin(); + comp->detach(); + delete comp; + } delete proc; UnsecureDisplay( dpy ); restore_modifiers(); XSetInputFocus( qt_xdisplay(), PointerRoot, PointerRoot, CurrentTime ); + + delete app; } } // extern "C" diff --git a/kdm/kfrontend/kgapp.h b/kdm/kfrontend/kgapp.h index f01ba1baa..38c73d3c1 100644 --- a/kdm/kfrontend/kgapp.h +++ b/kdm/kfrontend/kgapp.h @@ -34,6 +34,7 @@ class GreeterApp : public KApplication { public: GreeterApp(); + GreeterApp(Display *dpy); virtual bool x11EventFilter( XEvent * ); protected: diff --git a/kdm/kfrontend/kgreeter.h b/kdm/kfrontend/kgreeter.h index fdbd56209..8675f052a 100644 --- a/kdm/kfrontend/kgreeter.h +++ b/kdm/kfrontend/kgreeter.h @@ -72,6 +72,9 @@ class KGreeter : public KGDialog, public KGVerifyHandler { void slotSessionSelected( int ); void slotUserEntered(); + public: + TQString curUser, dName; + protected: void readFacesList(); void installUserList(); @@ -82,7 +85,6 @@ class KGreeter : public KGDialog, public KGVerifyHandler { virtual void pluginSetup(); void setPrevWM( int ); - TQString curUser, dName; KSimpleConfig *stsFile; UserListView *userView; TQStringList *userList; diff --git a/kdm/kfrontend/themer/kdmitem.cpp b/kdm/kfrontend/themer/kdmitem.cpp index 88e5a7489..eb5283cd9 100644 --- a/kdm/kfrontend/themer/kdmitem.cpp +++ b/kdm/kfrontend/themer/kdmitem.cpp @@ -38,6 +38,8 @@ #include #include +extern bool argb_visual_available; + KdmItem::KdmItem( KdmItem *parent, const TQDomNode &node, const char *name ) : TQObject( parent, name ) , boxManager( 0 ) @@ -289,11 +291,13 @@ KdmItem::paint( TQPainter *p, const TQRect &rect ) if (myWidget || (myLayoutItem && myLayoutItem->widget())) { // KListView because it's missing a Q_OBJECT' - // FIXME: This is a nice idea intheory, but in practice it is + // FIXME: This is a nice idea in theory, but in practice it is // very confusing for the user not to see the empty list box // delineated from the rest of the greeter. // Maybe set a darker version of the background instead of an exact copy? if ( myWidget && myWidget->isA( "KListView" ) ) { + if ((_compositor.isEmpty()) || (!argb_visual_available)) { + // Software blend only (no compositing support) TQPixmap copy( myWidget->size() ); kdDebug() << myWidget->tqgeometry() << " " << area << " " << myWidget->size() << endl; bitBlt( ©, TQPoint( 0, 0), p->device(), myWidget->geometry(), TQt::CopyROP ); @@ -327,6 +331,30 @@ KdmItem::paint( TQPainter *p, const TQRect &rect ) copy = lightVersion; // Set it myWidget->setPaletteBackgroundPixmap( copy ); + } + else { + // We have compositing support! + TQRgb blend_color = tqRgba(m_backgroundModifier, m_backgroundModifier, m_backgroundModifier, 0); // RGBA overlay + float alpha = tqAlpha(blend_color) / 255.; + int pixel = tqAlpha(blend_color) << 24 | + int(tqRed(blend_color) * alpha) << 16 | + int(tqGreen(blend_color) * alpha) << 8 | + int(tqBlue(blend_color) * alpha); + + TQImage img( myWidget->size(), 32 ); + img = img.convertDepth(32); + img.setAlphaBuffer(true); + register uchar * rd = img.bits(); + for( int y = 0; y < img.height(); ++y ) + { + for( short int x = 0; x < img.width(); ++x ) + { + *reinterpret_cast(rd) = blend_color; + rd += 4; + } + } + myWidget->setPaletteBackgroundPixmap( img ); + } } return; } diff --git a/kdm/kfrontend/themer/kdmpixmap.cpp b/kdm/kfrontend/themer/kdmpixmap.cpp index af64714b8..436483c48 100644 --- a/kdm/kfrontend/themer/kdmpixmap.cpp +++ b/kdm/kfrontend/themer/kdmpixmap.cpp @@ -37,6 +37,8 @@ #include #include +extern bool argb_visual_available; + KdmPixmap::KdmPixmap( KdmItem *parent, const TQDomNode &node, const char *name ) : KdmItem( parent, node, name ) { @@ -47,6 +49,7 @@ KdmPixmap::KdmPixmap( KdmItem *parent, const TQDomNode &node, const char *name ) pixmap.normal.alpha = 0.0; pixmap.active.present = false; pixmap.prelight.present = false; + bool true_transparency = false; // Read PIXMAP ID // it rarely happens that a pixmap can be a button too! @@ -66,13 +69,20 @@ KdmPixmap::KdmPixmap( KdmItem *parent, const TQDomNode &node, const char *name ) pixmap.normal.alpha = el.attribute( "alpha", "1.0" ).toFloat(); if (el.attribute( "file", "" ) == "@@@KDMBACKGROUND@@@") { - // Use the preset KDM background... - KStandardDirs *m_pDirs = KGlobal::dirs(); - KSimpleConfig *config = new KSimpleConfig( TQFile::decodeName( _backgroundCfg ) ); - config->setGroup("Desktop0"); - pixmap.normal.fullpath = m_pDirs->findResource("wallpaper", config->readPathEntry("Wallpaper")); - // TODO: Detect when there is no wallpaper and use the background settings instead - delete config; + if ((_compositor.isEmpty()) || (!argb_visual_available)) { + // Software blend only (no compositing support) + // Use the preset KDM background... + KStandardDirs *m_pDirs = KGlobal::dirs(); + KSimpleConfig *config = new KSimpleConfig( TQFile::decodeName( _backgroundCfg ) ); + config->setGroup("Desktop0"); + pixmap.normal.fullpath = m_pDirs->findResource("wallpaper", config->readPathEntry("Wallpaper")); + // TODO: Detect when there is no wallpaper and use the background settings instead + delete config; + } + else { + true_transparency = true; + pixmap.normal.alpha = 0.0; + } } } else if (tagName == "active") { @@ -189,7 +199,6 @@ KdmPixmap::drawContents( TQPainter *p, const TQRect &r ) kdDebug() << "draw " << id << " " << pClass->pixmap.isNull() << endl; if (pClass->pixmap.isNull()) { - if (pClass->fullpath.isEmpty()) // if neither is set, we're empty return; @@ -246,7 +255,7 @@ KdmPixmap::drawContents( TQPainter *p, const TQRect &r ) if (haveTint || haveAlpha) { scaledImage = pClass->pixmap.convertToImage(); - // enforce rgba values for the later + // enforce rgba values for the latter scaledImage = scaledImage.convertDepth( 32 ); } else @@ -275,7 +284,31 @@ KdmPixmap::drawContents( TQPainter *p, const TQRect &r ) ls[x] = tqRgba( r, g, b, a ); } } + } + if ((_compositor.isEmpty()) || (!argb_visual_available)) { + // Software blend only (no compositing support) + } + else { + // We have a compositor! + // Apply the alpha in the same manner as above, exept we are now + // using the hardware blending engine for all painting + scaledImage = pClass->readyPixmap; + scaledImage = scaledImage.convertDepth( 32 ); + int w = scaledImage.width(); + int h = scaledImage.height(); + for (int y = 0; y < h; ++y) { + QRgb *ls = (QRgb *)scaledImage.scanLine( y ); + for (int x = 0; x < w; ++x) { + QRgb l = ls[x]; + float alpha_adjust = (tqAlpha( l )/256.0); + int r = int( tqRed( l ) * alpha_adjust ); + int g = int( tqGreen( l ) * alpha_adjust ); + int b = int( tqBlue( l ) * alpha_adjust ); + int a = int( tqAlpha( l ) * 1 ); + ls[x] = tqRgba( r, g, b, a ); + } + } } if (!scaledImage.isNull()) { diff --git a/kdm/kfrontend/themer/kdmrect.cpp b/kdm/kfrontend/themer/kdmrect.cpp index 1d854d213..1db128da0 100644 --- a/kdm/kfrontend/themer/kdmrect.cpp +++ b/kdm/kfrontend/themer/kdmrect.cpp @@ -21,6 +21,7 @@ #include "kdmrect.h" #include "kdmthemer.h" +#include "kdmconfig.h" #include #include @@ -30,6 +31,8 @@ #include #include +extern bool argb_visual_available; + KdmRect::KdmRect( KdmItem *parent, const TQDomNode &node, const char *name ) : KdmItem( parent, node, name ) { @@ -103,14 +106,20 @@ KdmRect::drawContents( TQPainter *p, const TQRect &r ) if (rClass->alpha == 1) p->fillRect( area, TQBrush( rClass->color ) ); else { - TQRect backRect = r; - backRect.moveBy( area.x(), area.y() ); - TQPixmap backPixmap( backRect.size() ); - bitBlt( &backPixmap, TQPoint( 0, 0 ), p->device(), backRect ); - TQImage backImage = backPixmap.convertToImage(); - KImageEffect::blend( rClass->color, backImage, rClass->alpha ); - p->drawImage( backRect.x(), backRect.y(), backImage ); - // area.moveBy(1,1); +// if ((_compositor.isEmpty()) || (!argb_visual_available)) { + // Software blend only (no compositing support) + TQRect backRect = r; + backRect.moveBy( area.x(), area.y() ); + TQPixmap backPixmap( backRect.size() ); + bitBlt( &backPixmap, TQPoint( 0, 0 ), p->device(), backRect ); + TQImage backImage = backPixmap.convertToImage(); + KImageEffect::blend( rClass->color, backImage, rClass->alpha ); + p->drawImage( backRect.x(), backRect.y(), backImage ); + // area.moveBy(1,1); +// } +// else { +// // We have compositing support! +// } } } diff --git a/kdm/kfrontend/themer/kdmthemer.cpp b/kdm/kfrontend/themer/kdmthemer.cpp index d6b2e6e0e..39a1abe81 100644 --- a/kdm/kfrontend/themer/kdmthemer.cpp +++ b/kdm/kfrontend/themer/kdmthemer.cpp @@ -46,6 +46,8 @@ #include +extern bool argb_visual_available; + /* * KdmThemer. The main theming interface */ @@ -159,17 +161,35 @@ KdmThemer::widgetEvent( TQEvent *e ) TQRect paintRect = TQT_TQPAINTEVENT(e)->rect(); kdDebug() << timestamp() << " paint on: " << paintRect << endl; - if (!backBuffer) - backBuffer = new TQPixmap( widget()->size() ); - if (backBuffer->size() != widget()->size()) - backBuffer->resize( widget()->size() ); - - TQPainter p; - p.begin( backBuffer ); - rootItem->paint( &p, paintRect ); - p.end(); + if ((_compositor.isEmpty()) || (!argb_visual_available)) { + // Software blend only (no compositing support) + if (!backBuffer) + backBuffer = new TQPixmap( widget()->size() ); + if (backBuffer->size() != widget()->size()) + backBuffer->resize( widget()->size() ); + + TQPainter p; + p.begin( backBuffer ); + rootItem->paint( &p, paintRect ); + p.end(); + + bitBlt( widget(), paintRect.topLeft(), backBuffer, paintRect ); + } + else { + // We have compositing support! + TQRgb blend_color = tqRgba(0, 0, 0, 0); // RGBA + float alpha = tqAlpha(blend_color) / 255.; + int pixel = tqAlpha(blend_color) << 24 | + int(tqRed(blend_color) * alpha) << 16 | + int(tqGreen(blend_color) * alpha) << 8 | + int(tqBlue(blend_color) * alpha); + TQPainter p1; + p1.begin( widget() ); + p1.fillRect( paintRect, TQColor(blend_color, pixel) ); + rootItem->paint( &p1, paintRect ); + p1.end(); + } - bitBlt( widget(), paintRect.topLeft(), backBuffer, paintRect ); } break; default: diff --git a/kdm/kfrontend/themer/kdmthemer.h b/kdm/kfrontend/themer/kdmthemer.h index e5228973e..e6e5efdb4 100644 --- a/kdm/kfrontend/themer/kdmthemer.h +++ b/kdm/kfrontend/themer/kdmthemer.h @@ -24,6 +24,7 @@ #include #include +#include class KdmThemer; class KdmItem; -- cgit v1.2.1