krootpixmap.cpp
00001 /* vi: ts=8 sts=4 sw=4 00002 * 00003 * 00004 * This file is part of the KDE project, module tdeui. 00005 * Copyright (C) 1999,2000 Geert Jansen <jansen@kde.org> 00006 * 00007 * You can Freely distribute this program under the GNU Library 00008 * General Public License. See the file "COPYING.LIB" for the exact 00009 * licensing terms. 00010 */ 00011 00012 #include <tqwidget.h> 00013 #include <tqtimer.h> 00014 #include <tqrect.h> 00015 #include <tqimage.h> 00016 00017 #include <tdeapplication.h> 00018 #include <kimageeffect.h> 00019 #include <kpixmapio.h> 00020 #include <twinmodule.h> 00021 #include <twin.h> 00022 #include <kdebug.h> 00023 #include <netwm.h> 00024 #include <dcopclient.h> 00025 #include <dcopref.h> 00026 00027 #include <ksharedpixmap.h> 00028 #include <krootpixmap.h> 00029 00030 00031 static TQString wallpaperForDesktop(int desktop) 00032 { 00033 return DCOPRef("kdesktop", "KBackgroundIface").call("currentWallpaper", desktop); 00034 } 00035 00036 class KRootPixmapData 00037 { 00038 public: 00039 TQWidget *toplevel; 00040 #ifdef Q_WS_X11 00041 KWinModule *twin; 00042 #endif 00043 }; 00044 00045 00046 KRootPixmap::KRootPixmap( TQWidget *widget, const char *name ) 00047 : TQObject(widget, name ? name : "KRootPixmap" ), m_Desk(0), m_pWidget(widget) 00048 { 00049 init(); 00050 } 00051 00052 KRootPixmap::KRootPixmap( TQWidget *widget, TQObject *parent, const char *name ) 00053 : TQObject( parent, name ? name : "KRootPixmap" ), m_Desk(0), m_pWidget(widget) 00054 { 00055 init(); 00056 } 00057 00058 void KRootPixmap::init() 00059 { 00060 d = new KRootPixmapData; 00061 m_Fade = 0; 00062 m_BlurRadius = 0; 00063 m_BlurSigma = 0; 00064 m_pPixmap = new TDESharedPixmap; //ordinary KPixmap on win32 00065 m_pTimer = new TQTimer( this ); 00066 m_bInit = false; 00067 m_bActive = false; 00068 m_bCustomPaint = false; 00069 00070 connect(kapp, TQT_SIGNAL(backgroundChanged(int)), TQT_SLOT(slotBackgroundChanged(int))); 00071 connect(m_pTimer, TQT_SIGNAL(timeout()), TQT_SLOT(repaint())); 00072 #ifdef Q_WS_X11 00073 connect(m_pPixmap, TQT_SIGNAL(done(bool)), TQT_SLOT(slotDone(bool))); 00074 00075 d->twin = new KWinModule( this ); 00076 connect(d->twin, TQT_SIGNAL(windowChanged(WId, unsigned int)), TQT_SLOT(desktopChanged(WId, unsigned int))); 00077 connect(d->twin, TQT_SIGNAL(currentDesktopChanged(int)), TQT_SLOT(desktopChanged(int))); 00078 #endif 00079 00080 d->toplevel = m_pWidget->topLevelWidget(); 00081 d->toplevel->installEventFilter(this); 00082 m_pWidget->installEventFilter(this); 00083 } 00084 00085 KRootPixmap::~KRootPixmap() 00086 { 00087 delete m_pPixmap; 00088 delete d; 00089 } 00090 00091 00092 int KRootPixmap::currentDesktop() const 00093 { 00094 #ifdef Q_WS_X11 00095 NETRootInfo rinfo( tqt_xdisplay(), NET::CurrentDesktop ); 00096 rinfo.activate(); 00097 return rinfo.currentDesktop(); 00098 #else 00099 //OK? 00100 return TQApplication::desktop()->screenNumber(m_pWidget); 00101 #endif 00102 } 00103 00104 00105 void KRootPixmap::start() 00106 { 00107 if (m_bActive) 00108 return; 00109 00110 m_bActive = true; 00111 if ( !isAvailable() ) 00112 { 00113 // We will get a KIPC message when the shared pixmap is available. 00114 enableExports(); 00115 return; 00116 } 00117 if (m_bInit) 00118 repaint(true); 00119 } 00120 00121 00122 void KRootPixmap::stop() 00123 { 00124 m_bActive = false; 00125 m_pTimer->stop(); 00126 } 00127 00128 00129 void KRootPixmap::setFadeEffect(double fade, const TQColor &color) 00130 { 00131 if (fade < 0) 00132 m_Fade = 0; 00133 else if (fade > 1) 00134 m_Fade = 1; 00135 else 00136 m_Fade = fade; 00137 m_FadeColor = color; 00138 00139 if ( m_bActive && m_bInit ) repaint(true); 00140 } 00141 00142 void KRootPixmap::setBlurEffect(double radius, double sigma) 00143 { 00144 m_BlurRadius = radius; 00145 m_BlurSigma = sigma; 00146 } 00147 00148 bool KRootPixmap::eventFilter(TQObject *, TQEvent *event) 00149 { 00150 // Initialise after the first show or paint event on the managed widget. 00151 if (!m_bInit && ((event->type() == TQEvent::Show) || (event->type() == TQEvent::Paint))) 00152 { 00153 m_bInit = true; 00154 m_Desk = currentDesktop(); 00155 } 00156 00157 if (!m_bActive) 00158 return false; 00159 00160 switch (event->type()) 00161 { 00162 case TQEvent::Resize: 00163 case TQEvent::Move: 00164 m_pTimer->start(100, true); 00165 break; 00166 00167 case TQEvent::Paint: 00168 m_pTimer->start(0, true); 00169 break; 00170 00171 case TQEvent::Reparent: 00172 d->toplevel->removeEventFilter(this); 00173 d->toplevel = m_pWidget->topLevelWidget(); 00174 d->toplevel->installEventFilter(this); 00175 break; 00176 00177 default: 00178 break; 00179 } 00180 00181 return false; // always continue processing 00182 } 00183 00184 void KRootPixmap::desktopChanged(int desktop) 00185 { 00186 if (wallpaperForDesktop(m_Desk) == wallpaperForDesktop(desktop) && 00187 !wallpaperForDesktop(m_Desk).isNull()) 00188 return; 00189 00190 #ifdef Q_WS_X11 00191 if (KWin::windowInfo(m_pWidget->topLevelWidget()->winId()).desktop() == NET::OnAllDesktops && 00192 pixmapName(m_Desk) != pixmapName(desktop)) 00193 #endif 00194 repaint(true); 00195 } 00196 00197 void KRootPixmap::desktopChanged( WId window, unsigned int properties ) 00198 { 00199 #ifdef Q_WS_X11 00200 if( !(properties & NET::WMDesktop) || 00201 (window != m_pWidget->topLevelWidget()->winId())) 00202 return; 00203 #endif 00204 00205 kdDebug() << k_funcinfo << endl; 00206 repaint(true); 00207 } 00208 00209 void KRootPixmap::repaint() 00210 { 00211 repaint(false); 00212 } 00213 00214 00215 void KRootPixmap::repaint(bool force) 00216 { 00217 TQPoint p1 = m_pWidget->mapToGlobal(m_pWidget->rect().topLeft()); 00218 TQPoint p2 = m_pWidget->mapToGlobal(m_pWidget->rect().bottomRight()); 00219 if (!force && (m_Rect == TQRect(p1, p2))) 00220 return; 00221 00222 // Due to northwest bit gravity, we don't need to do anything if the 00223 // bottom right corner of the widget is moved inward. 00224 // That said, konsole clears the background when it is resized, so 00225 // we have to reset the background pixmap. 00226 if ((p1 == m_Rect.topLeft()) && (m_pWidget->width() < m_Rect.width()) && 00227 (m_pWidget->height() < m_Rect.height()) 00228 ) 00229 { 00230 m_Rect = TQRect(p1, p2); 00231 updateBackground( m_pPixmap ); 00232 return; 00233 } 00234 m_Rect = TQRect(p1, p2); 00235 #ifdef Q_WS_X11 00236 m_Desk = KWin::windowInfo(m_pWidget->topLevelWidget()->winId()).desktop(); 00237 if ((m_Desk == NET::OnAllDesktops) || (m_Desk == 0)) { 00238 m_Desk = currentDesktop(); 00239 } 00240 00241 // TDESharedPixmap will correctly generate a tile for us. 00242 m_pPixmap->loadFromShared(pixmapName(m_Desk), m_Rect); 00243 #else 00244 m_Desk = currentDesktop(); 00245 // !x11 note: tile is not generated! 00246 // TODO: pixmapName() is a nonsense now! 00247 m_pPixmap->load( pixmapName(m_Desk) ); 00248 if (!m_pPixmap->isNull()) { 00249 m_pPixmap->resize( m_Rect.size() ); 00250 slotDone(true); 00251 } 00252 #endif 00253 } 00254 00255 bool KRootPixmap::isAvailable() const 00256 { 00257 #ifdef Q_WS_X11 00258 return m_pPixmap->isAvailable(pixmapName(m_Desk)); 00259 #else 00260 return m_pPixmap->isNull(); 00261 #endif 00262 } 00263 00264 TQString KRootPixmap::pixmapName(int desk) { 00265 TQString pattern = TQString("DESKTOP%1"); 00266 #ifdef Q_WS_X11 00267 int screen_number = DefaultScreen(tqt_xdisplay()); 00268 if (screen_number) { 00269 pattern = TQString("SCREEN%1-DESKTOP").arg(screen_number) + "%1"; 00270 } 00271 #endif 00272 return pattern.arg( desk ); 00273 } 00274 00275 00276 void KRootPixmap::enableExports() 00277 { 00278 #ifdef Q_WS_X11 00279 kdDebug(270) << k_lineinfo << "activating background exports.\n"; 00280 DCOPClient *client = kapp->dcopClient(); 00281 if (!client->isAttached()) 00282 client->attach(); 00283 TQByteArray data; 00284 TQDataStream args( data, IO_WriteOnly ); 00285 args << 1; 00286 00287 TQCString appname( "kdesktop" ); 00288 int screen_number = DefaultScreen(tqt_xdisplay()); 00289 if ( screen_number ) 00290 appname.sprintf("kdesktop-screen-%d", screen_number ); 00291 00292 client->send( appname, "KBackgroundIface", "setExport(int)", data ); 00293 #endif 00294 } 00295 00296 00297 void KRootPixmap::slotDone(bool success) 00298 { 00299 if (!success) 00300 { 00301 kdWarning(270) << k_lineinfo << "loading of desktop background failed.\n"; 00302 return; 00303 } 00304 00305 // We need to test active as the pixmap might become available 00306 // after the widget has been destroyed. 00307 if ( m_bActive ) 00308 updateBackground( m_pPixmap ); 00309 } 00310 00311 void KRootPixmap::updateBackground( TDESharedPixmap *spm ) 00312 { 00313 TQPixmap pm = *spm; 00314 00315 if (m_Fade > 1e-6) 00316 { 00317 KPixmapIO io; 00318 TQImage img = io.convertToImage(pm); 00319 img = KImageEffect::fade(img, m_Fade, m_FadeColor); 00320 pm = io.convertToPixmap(img); 00321 } 00322 00323 if ((m_BlurRadius > 1e-6) || (m_BlurSigma > 1e-6)) 00324 { 00325 KPixmapIO io; 00326 TQImage img = io.convertToImage(pm); 00327 img = KImageEffect::blur(img, m_BlurRadius, m_BlurSigma); 00328 pm = io.convertToPixmap(img); 00329 } 00330 00331 if ( !m_bCustomPaint ) 00332 m_pWidget->setBackgroundPixmap( pm ); 00333 else { 00334 emit backgroundUpdated( pm ); 00335 } 00336 } 00337 00338 00339 void KRootPixmap::slotBackgroundChanged(int desk) 00340 { 00341 if (!m_bInit || !m_bActive) 00342 return; 00343 00344 if (desk == m_Desk) 00345 repaint(true); 00346 } 00347 00348 #include "krootpixmap.moc"