[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-core-devel
Subject:    KIconLoader improvements: icon server
From:       Gustavo Pichorim Boiko <gustavo.boiko () kdemail ! net>
Date:       2005-06-14 13:33:43
Message-ID: 200506141034.01944.gustavo.boiko () kdemail ! net
[Download RAW message or body]

[Attachment #2 (multipart/mixed)]


Hi

There has been a discussion on kde-optimize about KIconLoader improvements. 
I'm working to create an icon server that is used to share icons between 
applications. The original idea and its initial implementation is from Lubos 
Lunak. 
The idea is to have a daemon running which publishes icons and stay 
refcounting their usage. When an application requests an icon to KIconLoader, 
it checks for the icon in a cache file which contains just the key and the X 
resource id for the icon. If the icon is there, it creates a pixmap using the 
given resource id (sharing the pixmap in the X server). If the icon is not 
there, it queue the icon to be sent to the server. 

One problem I had (and I want a little help on that) is when using 
KUniqueApplication. When it forks, there is a race condition on the DCOP 
calls (when the KIconLoader is created, it checks for the iconserver to be 
running using a DCOP call). Simply commenting the dc->setPriorityCall(true) 
lines in kuniqueapplication.cpp solved the problem, but I don't think that is 
the best way of doing it, help is appreciated.

I have been playing with it and it is quite stable. I have some results (I 
didn't measure memory usage yet, just time for loading icons) that I want you 
to take a look:

test1: 369 icons (32x32)
w/o disk cache: 3628 ms
cached: 361 ms
iconserver: 74 ms
------------------------
test2: 222 icons (48x48)
w/o disk cache: 2262 ms
cached: 322 ms
iconserver: 35ms
------------------------
test3: 774 icons (32x32)
w/o disk cache: 4974 ms
cached: 1170 ms
iconserver: 709 ms

The patch for this icon server is attached.
Please take it a look and give me a feedback about that.

Thanks in advance

-- 
 Gustavo Pichorim Boiko
 -----------------------------------------------------
  KDE Developer		Computer Science - UFPR    
  Mandriva Labs		gustavo . boiko @ kdemail . net 
 -----------------------------------------------------

["kdecore_iconserver.patch" (text/x-diff)]

Index: iconserver/bla.cpp
===================================================================
--- iconserver/bla.cpp	(revisão 0)
+++ iconserver/bla.cpp	(revisão 0)
@@ -0,0 +1,49 @@
+#include <kcmdlineargs.h>
+#include <kapplication.h>
+#include <dcopclient.h>
+#include <kiconserver.h>
+
+int write_fd = -1;
+    
+void parent_wait()
+    {
+    int fds[ 2 ];
+    if( pipe( fds ) < 0 )
+        exit( 1 );
+    switch( fork())
+        {
+        case -1:
+          exit( 1 );
+        case 0:
+            {
+            write_fd = fds[ 1 ];
+            close( fds[ 0 ] );
+          return; // ok, continue
+            }
+        default:
+            {
+            close( fds[ 1 ] );
+            char tmp;
+            read( fds[ 0 ], &tmp, 1 ); // wait for parent to finish initialization
+            exit( 0 );
+            }
+        }
+    }
+int main( int argc, char* argv[] )
+    {
+    parent_wait();
+//    KCmdLineArgs::init( argc, argv, "a", "b", "c" );
+    // tohle s KUniqueApp nefunguje
+    if( KApplication::dcopClient()->isApplicationRegistered( "iconserver" ))
+        return 0;
+//    KApplication app;
+    QApplication app( argc, argv );
+    KInstance inst( "a" );
+    KIconServer server;
+//    app.disableSessionManagement();
+    char tmp;
+    write( write_fd, &tmp, 1 ); // tell parent init is done
+    return app.exec();
+    // CHECKME zajistit, at ostatni cekaji, dokud se nenahraji vsechny ikony
+    }
+ 
Index: iconserver/kiconserver.h
===================================================================
--- iconserver/kiconserver.h	(revisão 0)
+++ iconserver/kiconserver.h	(revisão 0)
@@ -0,0 +1,81 @@
+/****************************************************************************
+
+ $Id: iconserver.h,v 1.11 2001/08/29 15:25:38 bero Exp $
+
+ Copyright (C) 2001 Lubos Lunak        <llunak@suse.cz>
+
+ This file is part of the KDE libraries
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB.  If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+****************************************************************************/
+
+#ifndef __KICONSERVER_H
+#define __KICONSERVER_H
+
+#include <dcopobject.h>
+#include <qcstring.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qobject.h>
+
+#include <kiconserverclient_p.h>
+
+#include <kdelibs_export.h>
+
+#include <X11/Xlib.h>
+
+#define appref_h "appref.h"
+#include appref_h // avoid including it in stub generated from this .h file
+#undef appref_h
+
+class KDECORE_EXPORT KIconServer
+    : public QObject, public DCOPObject
+    {
+    Q_OBJECT
+    K_DCOP
+    k_dcop:
+        bool serverRunning();
+        ASYNC newIcons( KIconSendDataList icons ); // means also refIcons
+        ASYNC refIcons( QValueList< QCString > keys );
+        ASYNC derefIcons( QValueList< QCString > keys );
+    public:
+        KIconServer();
+        ~KIconServer();
+    private slots:
+        void flushIcons();
+        void ageIcons();
+        void app_reg( const QCString& );
+        void app_rem( const QCString& );
+        void app_ren( const QCString&, const QCString& );
+    private:
+        void createIconsFile( const QString& path_P );
+        bool readOldIconsFile( const QString& path_P );
+        int makeKeySizes();
+        bool publishIcons( const QString& path_P, int mmap_size_P );
+        void defaultIcons();
+        void addIcon( const QString& name, int group, int size, int state );
+        bool splitKey( const QString& key, QString& name, int& size ) const;
+        void app_ref_deref( const QCString& app_id_P, const QValueList< QCString >& \
keys_P ,bool ref_P ); +        QTimer update_timer;
+        QTimer age_timer;
+        int old_icons_count; // number of icons scheduled for removal ( no longer \
published ) +        IconsMap icons;
+        typedef QValueList< KIconAppRef > AppRefList;
+        AppRefList app_ref_list;
+    };
+
+#endif
Index: iconserver/appref.h
===================================================================
--- iconserver/appref.h	(revisão 0)
+++ iconserver/appref.h	(revisão 0)
@@ -0,0 +1,122 @@
+/****************************************************************************
+
+ $Id: iconserver.h,v 1.11 2001/08/29 15:25:38 bero Exp $
+
+ Copyright (C) 2001 Lubos Lunak        <llunak@suse.cz>
+
+ This file is part of the KDE libraries
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB.  If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+****************************************************************************/
+
+#ifndef __APP_REF_H
+#define __APP_REF_H
+
+#include <qcstring.h>
+
+#include "kicondata.h"
+
+struct KIconAppRefData
+    {
+    QCString key;
+    int count;
+    bool operator==( const KIconAppRefData& r_P ) const;
+    bool operator<( const KIconAppRefData& r_P ) const;
+    bool operator>( const KIconAppRefData& r_P ) const;
+    bool operator!=( const KIconAppRefData& r_P ) const;
+    bool operator<=( const KIconAppRefData& r_P ) const;
+    bool operator>=( const KIconAppRefData& r_P ) const;
+    static int cmp( const QCString& l_P, const QCString& r_P );
+    };
+    
+class KIconAppRef
+    {
+    public:
+        KIconAppRef( const QCString& app_id_P );
+        KIconAppRef(); // only for QValueList
+        KIconAppRef( const KIconAppRef& src_P ); // only for QValueList
+        ~KIconAppRef();
+        void ref( const QValueList< QCString > keys_P );
+        void deref( const QValueList< QCString > keys_P );
+        void free( IconsMap& icons );
+        void change_app_id( const QCString& app_id_P );
+        const QCString& app_id() const;
+    private:
+        void resize( unsigned int new_size_P );
+        QCString _app_id;
+        mutable KIconAppRefData* arr; // mutable only because of KIconAppRef( const \
KIconAppRef& ); +        int used_size;
+        int allocated_size;
+    };
+
+// Inline
+
+inline
+KIconAppRef::KIconAppRef()
+    {
+    }
+    
+inline
+void KIconAppRef::change_app_id( const QCString& app_id_P )
+    {
+    _app_id = app_id_P;
+    }
+    
+inline
+const QCString& KIconAppRef::app_id() const
+    {
+    return _app_id;
+    }
+
+inline
+bool KIconAppRefData::operator==( const KIconAppRefData& r_P ) const
+    {
+    return cmp( key, r_P.key ) == 0;
+    }
+    
+inline
+bool KIconAppRefData::operator<( const KIconAppRefData& r_P ) const
+    {
+    return cmp( key, r_P.key ) < 0;
+    }
+    
+inline
+bool KIconAppRefData::operator>( const KIconAppRefData& r_P ) const
+    {
+    return cmp( key, r_P.key ) > 0;
+    }
+    
+inline
+bool KIconAppRefData::operator!=( const KIconAppRefData& r_P ) const
+    {
+    return cmp( key, r_P.key ) != 0;
+    }
+    
+inline
+bool KIconAppRefData::operator<=( const KIconAppRefData& r_P ) const
+    {
+    return cmp( key, r_P.key ) <= 0;
+    }
+    
+inline
+bool KIconAppRefData::operator>=( const KIconAppRefData& r_P ) const
+    {
+    return cmp( key, r_P.key ) >= 0;
+    }
+    
+    
+#endif
Index: iconserver/kicondata.h
===================================================================
--- iconserver/kicondata.h	(revisão 0)
+++ iconserver/kicondata.h	(revisão 0)
@@ -0,0 +1,97 @@
+/****************************************************************************
+
+ $Id: iconserver.h,v 1.11 2001/08/29 15:25:38 bero Exp $
+
+ Copyright (C) 2001 Lubos Lunak        <llunak@suse.cz>
+
+ This file is part of the KDE libraries
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB.  If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+****************************************************************************/
+
+#ifndef __KICONDATA_H
+#define __KICONDATA_H
+
+#include <qcstring.h>
+
+#include <kiconserverclient_p.h>
+
+struct KIconData
+    {
+    public:
+        KIconData();
+        KIconData( const QPixmap& pm_P, int group_P, int state_P, int usage_P );
+        bool ref(); // true if was old before ref()
+        bool deref(); // false if became unused
+        bool in_use() const;
+        bool age(); // return true if became old
+        bool old() const; // scheduled for removal
+        bool too_old() const;
+        KIconDataPixmap pixmap;
+        int group;
+        int state;
+        int key_pos; // used only when saving
+    private:
+        int usage; // >0 = refcount, <0 = age
+    };
+
+typedef QMap< QCString, KIconData > IconsMap;
+
+// Inline
+
+inline
+KIconData::KIconData()
+    {
+    }
+
+inline
+KIconData::KIconData( const QPixmap& pm_P, int group_P, int state_P, int usage_P )
+    : pixmap( pm_P ), group( group_P ), state( state_P ), usage( usage_P )
+    {
+    }
+    
+inline
+bool KIconData::deref()
+    {
+    return usage > 0 && --usage == 0;
+    }
+    
+inline
+bool KIconData::in_use() const
+    {
+    return usage > 0;
+    }
+    
+inline
+bool KIconData::age()
+    {
+    return usage <= 0 && --usage == -5;  // <= -5 = old
+    }
+
+inline
+bool KIconData::old() const
+    {
+    return usage <= -5; // < -5 = old
+    }
+
+inline
+bool KIconData::too_old() const
+    {
+    return usage <= -10; // <= - 10 = too old
+    }
+
+#endif
Index: iconserver/icontest.cpp
===================================================================
--- iconserver/icontest.cpp	(revisão 0)
+++ iconserver/icontest.cpp	(revisão 0)
@@ -0,0 +1,51 @@
+/****************************************************************************
+
+ $Id: iconserver.h,v 1.11 2001/08/29 15:25:38 bero Exp $
+
+ Copyright (C) 2001 Lubos Lunak        <llunak@suse.cz>
+
+ This file is part of the KDE libraries
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB.  If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+****************************************************************************/
+
+#include <kcmdlineargs.h>
+#include <kapplication.h>
+#include <qpixmap.h>
+#include <kiconloader.h>
+#include <kglobal.h>
+#include <dcopclient.h>
+#include <qlabel.h>
+
+int main( int argc, char* argv[] )
+    {
+    KCmdLineArgs::init( argc, argv, "a", "b", "c" );
+    KApplication app;
+    app.dcopClient()->attach();
+    QPixmap pm = DesktopIcon( "go" );
+    QWidget w;
+    w.setGeometry( 10, 10, 100, 100 );
+    QLabel l( &w );
+    l.resize( pm.width(), pm.height());
+    l.setPixmap( pm );
+    l.move( 10, 10 );
+    w.show();
+    app.setMainWidget( &w );
+    return app.exec();
+    }
+    
+//#include "iconserver.moc"
Index: iconserver/Makefile.am
===================================================================
--- iconserver/Makefile.am	(revisão 0)
+++ iconserver/Makefile.am	(revisão 0)
@@ -0,0 +1,33 @@
+INCLUDES = $(all_includes) -I$(srcdir)/..
+
+bin_PROGRAMS = kiconserver
+lib_LTLIBRARIES = kiconserver.la
+
+kiconserver_la_SOURCES = kiconserver.cpp kiconserver.skel appref.cpp
+kiconserver_la_LDFLAGS = $(all_libraries) -module -avoid-version
+kiconserver_la_LIBADD = $(LIB_KDECORE)
+
+kiconserver_SOURCES = dummy.cpp
+kiconserver_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+kiconserver_LDADD = kiconserver.la
+
+noinst_HEADERS = kiconserver.h appref.h kicondata.h
+
+#kde_module_LTLIBRARIES = libkded_iconserver.la
+
+#libkded_iconserver_la_SOURCES = iconserver.cpp iconserver.skel iconserver.h
+#libkded_iconserver_la_LDFLAGS = $(all_libraries) -module -avoid-version
+#libkded_iconserver_la_LIBADD = $(LIB_KDECORE)
+
+METASOURCES = AUTO
+
+#servicesdir = $(kde_servicesdir)/kded
+#services_DATA = kiconserver.desktop
+
+check_PROGRAMS = icontest
+icontest_SOURCES = icontest.cpp
+icontest_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+icontest_LDADD = $(LIB_KDECORE)
+
+dummy.cpp:
+	echo >dummy.cpp
Index: iconserver/kiconserver.cpp
===================================================================
--- iconserver/kiconserver.cpp	(revisão 0)
+++ iconserver/kiconserver.cpp	(revisão 0)
@@ -0,0 +1,491 @@
+/****************************************************************************
+
+ $Id: iconserver.h,v 1.11 2001/08/29 15:25:38 bero Exp $
+
+ Copyright (C) 2001 Lubos Lunak        <llunak@suse.cz>
+
+ This file is part of the KDE libraries
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB.  If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef HAVE_MMAP
+#error This works only with HAVE_MMAP
+#endif
+
+#include "kiconserver.h"
+
+#include <kiconserverclient_p.h>
+
+#include <qfile.h>
+#include <qpixmap.h>
+#include <qbitmap.h>
+#include <kglobal.h>
+#include <kstandarddirs.h>
+#include <ksavefile.h>
+#include <kiconloader.h>
+#include <kicontheme.h>
+#include <kdebug.h>
+#include <kapplication.h>
+#include <dcopclient.h>
+
+#include <unistd.h>
+#include <stdlib.h>
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+
+// CHECKME chybi tu osetreni NO_XRENDER
+    
+KIconServer::KIconServer()
+    : DCOPObject( "iconserver" ), old_icons_count( 0 )
+    {
+
+    kdDebug( 179 ) << k_funcinfo << "starting up" << endl;
+    ( void ) KGlobal::iconLoader(); // trigger iconloader ( and iconserverclient ) \
creation +    // register as iconserver here, so we don't ask ourselves for loading \
icons +    kapp->dcopClient()->registerAs( "iconserver", false );
+    kapp->dcopClient()->setNotifications( true );
+    kdDebug( 197) << k_funcinfo << "added DCOP calls" << endl;
+    connect( kapp->dcopClient(), SIGNAL( applicationRegistered( const QCString& )),
+        SLOT( app_reg( const QCString& )));
+    connect( kapp->dcopClient(), SIGNAL( applicationRemoved( const QCString& )),
+        SLOT( app_rem( const QCString& )));
+    connect( kapp->dcopClient(), SIGNAL( applicationRenamed( const QCString&, const \
QCString& )), +        SLOT( app_ren( const QCString&, const QCString& )));
+    connect( &update_timer, SIGNAL( timeout()), this, SLOT( flushIcons()));
+    connect( &age_timer, SIGNAL( timeout()), this, SLOT( ageIcons()));
+    age_timer.start( 20000 ); // 20s * 5 = 100s before becomes old and another 100s \
before removed +// CHECKME hledat nejnovejsi kiconsfile a z nej nacist seznam pro \
nahrani +    QString path = KGlobal::dirs()->saveLocation("tmp") + "kiconsfile-" + \
getenv( "DISPLAY" ); +    if( !QFile::exists( path ) || !readOldIconsFile( path ))
+        defaultIcons();
+    createIconsFile( path );
+    kdDebug(179) << k_funcinfo << "running" << endl;
+    }
+
+KIconServer::~KIconServer()
+    {
+    }
+
+bool KIconServer::serverRunning()
+    {
+    return true;
+    }
+
+bool KIconServer::readOldIconsFile( const QString& path_P )
+    { // from KIconLoader
+    QFile* icons_file = new QFile( path_P );
+    if( !icons_file->open( IO_ReadOnly ))
+        return false;
+    int mmap_size = icons_file->size();
+    KIconsFile* icons_mmap = reinterpret_cast< KIconsFile* >( mmap( 0, mmap_size,
+        PROT_READ, MAP_PRIVATE, icons_file->handle(), 0 ));
+    if( icons_mmap == NULL )
+        {
+        return false;
+        }
+    if( icons_mmap->version != KICONSFILEVERSION )
+        {
+        munmap( (char*) icons_mmap, mmap_size );
+        delete icons_file;
+        return false;
+        }
+    kdDebug( 179 ) << "reading old icons file, size=" << icons_mmap->count << endl;
+    for( int i = 0;
+         i < icons_mmap->count;
+         ++i )
+        {
+        KIconFileEntry& data = icons_mmap->entries[ i ];
+        const char* key = reinterpret_cast< char* >( icons_mmap ) + data.key_ref;
+        QString name;
+        int size;
+        if( !splitKey( QString::fromUtf8( key ), name, size ))
+            continue;
+        // CHECKME zkusit ze vsech images udelat jednu velkou qimage a pak z ni \
jednu qpixmap? +        KIconDataPixmap pm = KGlobal::iconLoader()->loadIcon( name, \
KIcon::Group(data.group), size, data.state, +            NULL, true );
+        if( pm.isNull())
+            {
+            kdDebug( 179 ) << "cannot load old icon " << key << endl;
+            continue;
+            }
+        if( pm.width() != pm.height())
+            {
+            kdWarning( 179 ) << "icon \"" << key << "\" has size " << pm.width() << \
"x" << pm.height() << endl; +            continue;
+            }
+        kdDebug( 179 ) << "reading icon from old file \"" << key << "\" ("
+            << pm.handle() << "/" << pm.maskHandle() << "/" << pm.alphaHandle() << \
")" << endl; +        icons[ key ] = KIconData( pm, data.group, data.state, 0 );
+        }
+    munmap( (char*) icons_mmap, mmap_size );
+    delete icons_file;
+    return true;
+    }
+
+bool KIconServer::splitKey( const QString& key, QString& name, int& size ) const
+{
+    QString k = key.mid( 6 ); // strip leading "$kico_"
+    int pos = k.find( ':' );
+    if( pos < 1 )
+        return false;
+    name = k.left( pos ); // name
+    k = k.mid( pos + 1 );
+    pos = k.find( '_' );
+    if( pos < 1 )
+        return false;
+    size = k.left( pos ).toInt(); // size
+    return true;    
+}
+
+
+void KIconServer::createIconsFile( const QString& path_P )
+    {
+    int mmap_size = makeKeySizes();
+    if( !publishIcons( path_P, mmap_size ))
+        kapp->quit(); // oops CHECKME tohle se nesmi, musi zustat bezet, dokud je \
refcount +    }
+
+int KIconServer::makeKeySizes()
+    {
+    int pos = sizeof( KIconsFile ) + ( icons.size() - old_icons_count - 1 ) * \
sizeof( KIconFileEntry ); +    for( IconsMap::Iterator it = icons.begin();
+         it != icons.end();
+         ++it )
+        {
+        ( *it ).key_pos = pos;
+        pos += it.key().length() + 1;
+        }
+    return pos;
+    }
+
+bool KIconServer::publishIcons( const QString& path_P, int mmap_size_P )
+    {
+    bool ok = true;
+    KIconsFile* file_data = static_cast< KIconsFile* >( operator new( mmap_size_P \
)); +    file_data->version = KICONSFILEVERSION;
+    file_data->depth = QPixmap::defaultDepth();
+    int pos = -1;
+    for( IconsMap::Iterator it = icons.begin();
+         it != icons.end();
+         ++it )
+        {
+        if( ( *it ).old()) // scheduled for removal
+            continue;
+        ++pos;
+#if 0
+        kdDebug( 179 ) << "putting " << it.key() << " ("
+            << ( *it ).pixmap.handle() << "/" << ( *it ).pixmap.maskHandle()
+            << "/" << ( *it ).pixmap.alphaHandle() << ")" << endl;
+#endif
+        file_data->entries[ pos ].key_ref = ( *it ).key_pos;
+        file_data->entries[ pos ].xid = ( *it ).pixmap.handle();
+        file_data->entries[ pos ].mask_xid = ( *it ).pixmap.maskHandle();
+        file_data->entries[ pos ].alpha_xid = ( *it ).pixmap.alphaHandle();
+#ifdef KICON_SHARE_XRENDER
+        file_data->entries[ pos ].pic = ( *it ).pixmap.x11RenderHandle();
+        file_data->entries[ pos ].mask_pic = ( *it ).pixmap.maskX11RenderHandle();
+        file_data->entries[ pos ].alpha_pic = ( *it ).pixmap.alphaX11RenderHandle();
+#endif        
+        file_data->entries[ pos ].size = ( *it ).pixmap.width();
+        file_data->entries[ pos ].group = ( *it ).group;
+        file_data->entries[ pos ].state = ( *it ).state;
+        }
+    char* keys = reinterpret_cast< char* >( file_data ) + sizeof( KIconsFile )
+        + ( icons.size() - old_icons_count - 1 ) * sizeof( KIconFileEntry );
+    for( IconsMap::Iterator it = icons.begin();
+         it != icons.end();
+         ++it )
+        {
+        strcpy( keys, it.key().data());
+        keys += it.key().length() + 1;
+        }
+    file_data->count = icons.size() - old_icons_count;
+    kdDebug( 179 ) << "saving icons file, published=" << icons.size() - \
old_icons_count +        << ", hidden=" << old_icons_count << endl;
+    KSaveFile file( path_P );
+    if( file.status() != 0 )
+        ok = false;
+    else
+        {
+        file.file()->writeBlock( reinterpret_cast< char* >( file_data ), mmap_size_P \
); +        operator delete( file_data );
+        ok = file.close();
+        }
+    // notify ALL applications
+    QByteArray data;
+    QDataStream stream( data, IO_WriteOnly );
+    stream << ok;
+    // je tohle ok i pro 2 klienty v jedne app ?
+    kdDebug( 179 ) << "sending update to apps (" << ok << ")" << endl;
+    kapp->dcopClient()->send( "*", "iconserverclient*", "iconsFileChanged(bool)", \
data ); +    return ok;
+    }    
+
+// only for adding often used icons ... such icons won't age
+void KIconServer::addIcon( const QString& name, int group, int size, int state )
+    {
+    KIconDataPixmap pm = KGlobal::iconLoader()->loadIcon( name, KIcon::Group(group), \
size, state, NULL, true ); +    if( pm.isNull())
+        return;
+    if( size == 0 )
+        size = IconSize( KIcon::Group(group) );
+    QString dummy;
+    QCString key = KGlobal::iconLoader()->makeKey( name, group, size, state, dummy \
).utf8(); +    if( pm.width() != pm.height())
+        {
+        kdWarning( 179 ) << "icon \"" << key << "\" has size " << pm.width() << "x" \
<< pm.height() << endl; +        return;
+        }
+    icons[ key ] = KIconData( pm, group, state, 1 ); // 1 => prevent aging
+    kdDebug( 179 ) << "added icon: " << pm.handle() << "(" << key << ") ("
+            << pm.handle() << "/" << pm.maskHandle() << "/" << pm.alphaHandle() << \
")" << endl; +    }
+
+// CHECKME mit nejaky timeout pri ruseni pixmap, kdyz aplikace pouzije jeste stary
+// index file
+    
+void KIconServer::defaultIcons()
+    {
+//    addIcon( "go", KIcon::Desktop, 0, KIcon::DefaultState );
+    // TODO
+    }
+
+
+// CHECKME pak jeste kontrola toho, ze ta aplikace mezitim nespadla
+void KIconServer::newIcons( KIconSendDataList icons_P )
+    {
+    kdDebug( 179 ) << "got new icons from app" << endl;
+    bool added = false;
+    QValueList< QCString > keys;
+    for( KIconSendDataList::ConstIterator it = icons_P.begin();
+         it != icons_P.end();
+         ++it )
+        {
+        const KIconSendData& data = ( *it );
+        kdDebug( 179 ) << "checking new icon " << data.key << endl;
+        if( icons.contains( data.key ))
+            {
+            kdDebug( 179 ) << "increasing refcount" << endl;
+            if( icons[ data.key ].ref())
+                --old_icons_count;
+            continue;
+            }
+        // holder_pix must be destroyed before holder_alpha and holder_mask
+        // all three of them must be destroyed before pix
+        KIconPixmapHolder holder_mask, holder_alpha, holder_pix;
+        KIconPixmap pix( data.size, data.size, data.xid, data.mask_xid, \
data.alpha_xid +#ifdef KICON_SHARE_XRENDER
+            , data.pic, data.mask_pic, data.alpha_pic
+#endif
+            );
+        if( pix.isNull()) // just in case... ?
+            continue;
+        holder_pix = pix; // prevent QPixmap from freeing the client's pixmap
+        if( pix.mask() != NULL )
+            holder_mask = *pix.mask();
+        if( pix.alpha() != NULL )
+            holder_alpha = *pix.alpha();
+        QPixmap pix_copy( pix );
+        pix_copy.detach();          // force creating a deep copy of the pixmap
+        if( pix.mask() != NULL )    // X pixmap handles we got from the client
+            {                       // will become invalid after the client exits
+            QBitmap bm_copy( *pix.mask());
+            bm_copy.detach();
+            pix_copy.setMask( bm_copy );
+            }
+#ifndef NDEBUG
+        Q_ASSERT( data.xid != pix_copy.handle());
+        Q_ASSERT( pix_copy.mask() == NULL || pix_copy.mask()->handle() != \
data.mask_xid ); +        KIconDataPixmap dt( pix_copy );
+        Q_ASSERT( pix.alpha() == NULL || dt.alphaHandle() != data.alpha_xid );
+#ifdef KICON_SHARE_XRENDER
+        Q_ASSERT( pix_copy.x11RenderHandle() == None || pix_copy.x11RenderHandle() \
!= data.pic ); +        Q_ASSERT( dt.maskX11RenderHandle() == None
+            || dt.maskX11RenderHandle() != data.mask_pic );
+        Q_ASSERT( dt.alphaX11RenderHandle() == None
+            || dt.alphaX11RenderHandle() != data.alpha_pic );
+#endif
+#endif
+        icons[ data.key ] = KIconData( pix_copy, data.group, data.state, 1 ); // 1 = \
used by the app +        kdDebug( 179 ) << "icon added" << endl;
+        keys.prepend( data.key );
+        added = true;
+        }
+    refIcons( keys );
+    if( added && !update_timer.isActive())
+        update_timer.start( 10000, true ); // CHECKME 10 secs ?
+        // asi spis 20 sekund prvni a dalsi 5 sekund
+    }
+
+void KIconServer::flushIcons()
+    {
+    QString path = KGlobal::dirs()->saveLocation("tmp") + "kiconsfile-" + getenv( \
"DISPLAY" ); +    createIconsFile( path );
+    }
+    
+void KIconServer::refIcons( QValueList< QCString > keys_P )
+    {
+    kdDebug( 179 ) << "refIcons" << endl;
+    if( keys_P.empty())
+        return;
+    for( QValueList< QCString >::ConstIterator it = keys_P.begin();
+         it != keys_P.end();
+         ++it )
+        {
+        if( icons.contains( *it ))
+            {
+            kdDebug( 179 ) << "increasing refcount: " << *it << endl;
+            if( icons[ *it ].ref())
+                --old_icons_count;
+            continue;
+            }
+        kdWarning( 179 ) << "unknown icon in refIcons" << endl;
+        }
+    app_ref_deref( kapp->dcopClient()->senderId(), keys_P, true );
+    }
+    
+void KIconServer::derefIcons( QValueList< QCString > keys_P )
+    {
+    kdDebug( 179 ) << "derefIcons" << endl;
+    if( keys_P.empty())
+        return;
+    for( QValueList< QCString >::ConstIterator it = keys_P.begin();
+         it != keys_P.end();
+         ++it )
+        {
+        if( icons.contains( *it ))
+            {
+            if( icons[ *it ].deref())
+                kdDebug( 179 ) << "no longer in use: " << *it << endl;
+            continue;
+            }
+        kdWarning( 179 ) << "unknown icon in refIcons" << endl;
+        }
+    app_ref_deref( kapp->dcopClient()->senderId(), keys_P, false );
+    }
+    
+void KIconServer::ageIcons()
+    {
+// CHECKME TODO delat jen kdyz je ikon moc
+    bool flush = false;
+    for( IconsMap::Iterator it = icons.begin();
+         it != icons.end();
+         )
+        {
+        if( ( *it ).in_use())
+            {
+            ++it;
+            continue;
+            }
+        if( ( *it ).age())
+            {
+            kdDebug( 179 ) << "hiding icon:" << it.key() << endl;
+            ++old_icons_count;
+            flush = true;
+            }
+        if( ( *it ).too_old())
+            {
+            kdDebug( 179 ) << "deleting icon:" << it.key() << endl;
+            --old_icons_count;
+            IconsMap::Iterator it2 = it;
+            ++it2;
+            icons.remove( it );
+            it = it2;
+            continue;
+            }
+        ++it;
+        }
+    if( flush && !update_timer.isActive())
+        update_timer.start( 10000, true ); // CHECKME 10 secs ?
+    }
+
+void KIconServer::app_reg( const QCString& app_id_P )
+    {
+    for( AppRefList::ConstIterator it = app_ref_list.begin();
+         it != app_ref_list.end();
+         ++it )
+        if( ( *it ).app_id() == app_id_P )
+            return;
+    app_ref_list.prepend( KIconAppRef( app_id_P ));
+    }
+    
+void KIconServer::app_rem( const QCString& app_id_P )
+    {
+    for( AppRefList::Iterator it = app_ref_list.begin();
+         it != app_ref_list.end();
+         ++it )
+        if( ( *it ).app_id() == app_id_P )
+            {
+            ( *it ).free( icons );
+            app_ref_list.remove( it );
+            return;
+            }
+// CHECKME tady bude problem, kdyz aplikace udela dcop detach, ale zustane bezet
+    }
+    
+void KIconServer::app_ren( const QCString& old_app_id_P, const QCString& \
new_app_id_P ) +    {
+    for( AppRefList::Iterator it = app_ref_list.begin();
+         it != app_ref_list.end();
+         ++it )
+        if( ( *it ).app_id() == old_app_id_P )
+            {
+            ( *it ).change_app_id( new_app_id_P );
+            return;
+            }
+    }
+
+void KIconServer::app_ref_deref( const QCString& app_id_P, const QValueList< \
QCString >& keys_P ,bool ref_P ) +    {
+    for( AppRefList::Iterator it = app_ref_list.begin();
+         it != app_ref_list.end();
+         ++it )
+        {
+        if( ( *it ).app_id() == app_id_P )
+            {
+            kdDebug( 179 ) << "(de)ref-ing in " << app_id_P << endl;
+            if( ref_P )
+                ( *it ).ref( keys_P );
+            else
+                ( *it ).deref( keys_P );
+            return;
+            }
+        }
+    if( ref_P )
+        {
+        app_ref_list.prepend( KIconAppRef( app_id_P ));
+        app_ref_list.front().ref( keys_P );
+        }
+    }
+    
+bool KIconData::ref()
+    {
+    bool ret = ( usage <= -5 );
+    if( usage < 0 )
+        usage = 1;
+    else
+        ++usage;
+    return ret;
+    }
+    
+#include "kiconserver.moc"
Index: iconserver/configure.in.in
===================================================================
--- iconserver/configure.in.in	(revisão 0)
+++ iconserver/configure.in.in	(revisão 0)
@@ -0,0 +1,10 @@
+AC_TRY_COMPILE([],
+    [
+    #ifdef HAVE_MMAP
+    return 0;
+    #else
+    return 1;
+    #endif
+    ], [ ICONSERVER_COMPILE=iconserver
+         AC_SUBST( ICONSERVER_COMPILE ) ]
+    )
Index: iconserver/appref.cpp
===================================================================
--- iconserver/appref.cpp	(revisão 0)
+++ iconserver/appref.cpp	(revisão 0)
@@ -0,0 +1,157 @@
+/****************************************************************************
+
+ $Id: iconserver.h,v 1.11 2001/08/29 15:25:38 bero Exp $
+
+ Copyright (C) 2001 Lubos Lunak        <llunak@suse.cz>
+
+ This file is part of the KDE libraries
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB.  If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "appref.h"
+
+#include <kdebug.h>
+
+KIconAppRef::KIconAppRef( const QCString& app_id_P )
+    : _app_id( app_id_P ), arr( NULL ), used_size( 0 ), allocated_size( 0 )
+    {
+    }
+    
+KIconAppRef::KIconAppRef( const KIconAppRef& src_P )
+    : _app_id( src_P._app_id ), arr( src_P.arr ), used_size( src_P.used_size ),
+        allocated_size( src_P.allocated_size )
+    {
+    kdDebug( 174 ) << "copy (" << (void*)this << "<-" << (void*)&src_P << ") :" << \
arr << endl; +    src_P.arr = NULL; // copies will be created only when passing to \
QValueList +    }
+    
+KIconAppRef::~KIconAppRef()
+    {
+    kdDebug( 174 ) << "deleting (" << (void*)this << ") :" << (void*)arr << endl;
+    delete[] arr;
+    }
+
+void KIconAppRef::free( IconsMap& icons )
+    {
+    for( KIconAppRefData* pos = arr;
+         pos != arr + used_size;
+         ++pos )
+        {
+        if( pos->key.isNull())
+            continue;
+        KIconData& ref = icons[ pos->key ];
+        kdDebug( 174 ) << "appderef: " << pos->key << endl;
+        for( int i = 0;
+             i < pos->count;
+             ++i )
+            ref.deref();
+        }
+    used_size = 0;
+    }
+
+void KIconAppRef::ref( const QValueList< QCString > keys_P )
+    {
+    QValueList< QCString > keys( keys_P );
+    qHeapSort( keys );
+    resize( keys.count() + used_size );
+    KIconAppRefData* pos = arr;
+    for( QValueList< QCString >::ConstIterator it = keys.begin();
+         it != keys.end();
+         ++it )
+        {
+        int dif;
+        kdDebug( 174 ) << "appref: " << *it << endl;
+        while(( dif = KIconAppRefData::cmp( pos->key, *it ) ) < 0 )
+            ++pos;
+        if( dif == 0 )
+            ++pos->count;
+        else
+            {
+            arr[ used_size ].key = ( *it );
+            arr[ used_size ].count = 1;
+            ++used_size;
+            }
+        }
+    qHeapSort( arr, arr + used_size );
+    kdDebug( 174 ) << "KIconAppRef: refs : " << used_size << endl;
+    }
+    
+void KIconAppRef::deref( const QValueList< QCString > keys_P )
+    {
+    QValueList< QCString > keys( keys_P );
+    qHeapSort( keys );
+    KIconAppRefData* pos = arr;
+    for( QValueList< QCString >::ConstIterator it = keys.begin();
+         it != keys.end();
+         ++it )
+        {
+        int dif;
+        while(( dif = KIconAppRefData::cmp( pos->key, *it )) < 0 )
+            ++pos;
+        if( dif == 0 )
+            {
+            kdDebug( 174 ) << "appderef: " << pos->key << endl;
+            if( --pos->count == 0 )
+                {
+                pos->key = QCString();
+                ++pos; // position after this one
+                }
+            }
+        else
+            kdDebug( 174 ) << "KIconAppRef::deref(): key not found:" << *it << endl;
+        }
+    qHeapSort( arr, arr + used_size );
+    while( used_size > 0 && arr[ used_size - 1 ].key.isNull())
+        --used_size;
+    kdDebug( 174 ) << "KIconAppRef: derefs : " << used_size << endl;
+    }
+
+void KIconAppRef::resize( unsigned int new_size_P )
+    {
+    unsigned int old_size = allocated_size;
+    unsigned int new_size = old_size;
+    if( new_size == 0 )
+        new_size = 4;
+    while( new_size < new_size_P )
+        new_size *= 2;
+    if( new_size == old_size )
+        return;
+    KIconAppRefData* new_arr = new KIconAppRefData[ new_size ];
+    KIconAppRefData* src = arr;
+    KIconAppRefData* dst = new_arr;
+    while( old_size-- > 0 )
+        *dst++ = *src++;
+    delete[] arr;
+    arr = new_arr;
+    allocated_size = new_size;
+    }
+    
+int KIconAppRefData::cmp( const QCString& l_P, const QCString& r_P )
+    {
+    if( !l_P.isNull() && !r_P.isNull() )
+        return strcmp( l_P, r_P );
+    if( !l_P.isNull())
+        return -1; // NULL keys go last, not first
+    if( !r_P.isNull())
+        return 1; // NULL keys go last, not first
+    return 0;
+    }
Index: kiconpixmap_p.h
===================================================================
--- kiconpixmap_p.h	(revisão 0)
+++ kiconpixmap_p.h	(revisão 0)
@@ -0,0 +1,94 @@
+/****************************************************************************
+
+ $Id: iconserver.h,v 1.11 2001/08/29 15:25:38 bero Exp $
+
+****************************************************************************/
+
+#ifndef __KICONPIXMAP_H
+#define __KICONPIXMAP_H
+
+#include <kdelibs_export.h>
+
+#include <qpixmap.h>
+#include <qbitmap.h>
+
+#include <X11/Xlib.h>
+
+#ifndef QT_NO_XRENDER // CHECKME
+#include <X11/extensions/Xrender.h>
+#endif
+
+// CHECKME musi byt natvrdo na jedno nastaveno
+#define KICON_SHARE_XRENDER
+
+class KDECORE_EXPORT KIconPixmap
+    : public QPixmap
+    {
+    public:
+        KIconPixmap( int w_P, int h_P, Pixmap pm_P, Pixmap mask_P, Pixmap alpha_P
+#ifdef KICON_SHARE_XRENDER
+            , Picture pic_P, Picture mask_pic_P, Picture alpha_pic_P
+#endif
+            );
+        const QPixmap* alpha() const;
+    };
+    
+class KDECORE_EXPORT KIconBitmap
+    : public QBitmap
+    {
+    public:
+        KIconBitmap( int w_P, int h_P, Pixmap pixmap_P
+#ifdef KICON_SHARE_XRENDER
+            , Picture pic_P
+#endif
+            );
+    };
+    
+class KDECORE_EXPORT KIconAlpha
+    : public QPixmap
+    {
+    public:
+        KIconAlpha( int w_P, int h_P, Pixmap pixmap_P
+#ifdef KICON_SHARE_XRENDER
+            , Picture pic_P
+#endif
+            );
+    };
+
+class KDECORE_EXPORT KIconDataPixmap
+    : public QPixmap
+    {
+    public:    
+        KIconDataPixmap( const QPixmap& pm_P );
+        KIconDataPixmap() {}; // for QValueList
+        const QPixmap* alpha() const;
+        Pixmap maskHandle() const;
+        Pixmap alphaHandle() const;
+#ifdef KICON_SHARE_XRENDER
+        Picture maskX11RenderHandle() const;
+        Picture alphaX11RenderHandle() const;
+#endif
+    };
+
+// prevents freeing the X pixmap and XRender handle
+class KDECORE_EXPORT KIconPixmapHolder
+    : public QPixmap
+    {
+    public:
+        KIconPixmapHolder();
+        KIconPixmapHolder( const QPixmap& pm_P );
+        KIconPixmapHolder& operator=( const QPixmap& pm_P );
+        virtual ~KIconPixmapHolder();
+    };
+
+class KDECORE_EXPORT KIconSharedPixmap
+    : public QPixmap
+    {
+    public:
+        KIconSharedPixmap( const QCString& key_P, const QPixmap& pm_P );
+        virtual ~KIconSharedPixmap();
+        bool unused() const;
+        QCString key;
+    };
+
+#endif
Index: Makefile.am
===================================================================
--- Makefile.am	(revisão 412784)
+++ Makefile.am	(cópia de trabalho)
@@ -27,7 +27,7 @@
 SVGICON_LIB=svgicons/libkdesvgicons.la
 endif
 
-SUBDIRS = malloc network $(SVGICONS) . kconfig_compiler tests
+SUBDIRS = malloc network $(SVGICONS) . kconfig_compiler iconserver tests
 
 # For the future: examine if condensing the tons of *_LDFLAGS variables
 # into $(all_libraries) isn't better
@@ -81,7 +81,7 @@
 	kregpriv.h kshortcutmenu.h ksycocadict.h ksycocafactory.h netsupp.h \
 	kcheckaccelerators.h kcalendarsystemgregorian.h \
 	kcalendarsystemhijri.h kcalendarsystemhebrew.h kcalendarsystemjalali.h \
-	kprotocolinfofactory.h
+	kprotocolinfofactory.h kiconserverclient_p.h kiconpixmap_p.h
 
 libkdecore_la_SOURCES = libintl.cpp kapplication.cpp \
 	kdebug.cpp netwm.cpp kconfigbase.cpp kconfig.cpp  ksimpleconfig.cpp \
@@ -112,7 +112,8 @@
 	kcalendarsystemfactory.cpp kmacroexpander.cpp kidna.cpp \
 	ktempdir.cpp kshell.cpp kmountpoint.cpp kcalendarsystemjalali.cpp \
 	kprotocolinfo_kdecore.cpp kprotocolinfofactory.cpp kxerrorhandler.cpp \
-	kuser.cpp kconfigskeleton.cpp kconfigdialogmanager.cpp klockfile.cpp
+	kuser.cpp kconfigskeleton.cpp kconfigdialogmanager.cpp klockfile.cpp \
+    kiconserverclient.cpp kiconserver.stub kiconserverclient_p.skel kiconpixmap.cpp
 
 libkdecore_la_LDFLAGS = $(QT_LDFLAGS) $(KDE_RPATH) $(KDE_MT_LDFLAGS) $(X_LDFLAGS) \
$(USER_LDFLAGS) -version-info 6:0:2 -no-undefined  libkdecore_la_LIBADD = \
malloc/libklmalloc.la network/libkdecorenetwork.la $(SVGICON_LIB) ../dcop/libDCOP.la \
../libltdl/libltdlc.la $(LIB_XEXT) $(LIBRESOLV) $(LIBUTIL) $(LIBART_LIBS) $(LIB_IDN) \
../kdefx/libkdefx.la @@ -124,6 +125,8 @@
 
 SRCDOC_DEST=$(kde_htmldir)/en/kdelibs/kdecore
 
+kiconserver_DIR = $(srcdir)/iconserver
+
 kdebugdir = $(kde_confdir)
 kdebug_DATA = kdebug.areas kdebugrc language.codes
 
Index: kiconpixmap.cpp
===================================================================
--- kiconpixmap.cpp	(revisão 0)
+++ kiconpixmap.cpp	(revisão 0)
@@ -0,0 +1,322 @@
+/****************************************************************************
+
+ $Id: iconserver.h,v 1.11 2001/08/29 15:25:38 bero Exp $
+
+****************************************************************************/
+
+#warning license problem
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qapplication.h>
+
+#include "kiconpixmap_p.h"
+
+#include <assert.h>
+#include <stdio.h>
+
+#ifndef QT_NO_XRENDER
+#include <X11/extensions/Xrender.h>
+#endif
+
+extern bool qt_use_xrender;
+
+/*
+ The code here is based on QPixmap code from Qt (actually often just copy&pasted).
+*/
+
+// Based on QPixmap::init() and QPixmap::setMask()
+KIconPixmap::KIconPixmap( int w, int h, Pixmap pm_P, Pixmap mask_P, Pixmap alpha_P
+#ifdef KICON_SHARE_XRENDER
+    , Picture pic_P, Picture mask_pic_P, Picture alpha_pic_P
+#endif
+    )
+    : QPixmap( 0, 0, -1 )
+{
+    data->w = w;
+    data->uninit = false;
+    data->h = h;
+    assert( pm_P != None );
+    hd = pm_P;
+
+
+#ifndef QT_NO_XRENDER
+    if (qt_use_xrender) {
+#ifdef KICON_SHARE_XRENDER
+        rendhd = pic_P;
+#else
+	XRenderPictFormat *format = 0;
+	XRenderPictFormat req;
+	ulong mask = PictFormatType | PictFormatDepth;
+
+	req.type = PictTypeDirect;
+	req.depth = data->d;
+
+	if (data->d == 1) {
+	    req.direct.alpha = 0;
+	    req.direct.alphaMask = 1;
+	    mask |= PictFormatAlpha | PictFormatAlphaMask;
+	} else {
+	    format = XRenderFindVisualFormat(x11Display(), (Visual *) x11Visual());
+	}
+
+	if (! format)
+	    format = XRenderFindFormat(x11Display(), mask, &req, 0);
+	if (format)
+	    rendhd = XRenderCreatePicture(x11Display(), hd, format, 0, 0);
+#endif
+    }
+#endif // QT_NO_XRENDER
+
+    data->selfmask = FALSE;
+    if( mask_P != None ) {
+        KIconBitmap* newmaskcopy;
+        newmaskcopy = new KIconBitmap( w, h, mask_P
+#ifdef KICON_SHARE_XRENDER
+            , mask_pic_P
+#endif
+            );
+#ifdef Q_WS_X11
+        newmaskcopy->x11SetScreen( x11Screen() ); // CHECKME
+#endif
+        data->mask = newmaskcopy;
+    }
+
+    if( alpha_P != None ) {    
+#ifndef QT_NO_XRENDER
+	if (qt_use_xrender) {
+            KIconAlpha* alpha = new KIconAlpha( w, h, alpha_P
+#ifdef KICON_SHARE_XRENDER
+                , alpha_pic_P
+#endif
+                );
+	    data->alphapm = alpha;
+        }
+#endif
+    }
+}
+
+// Once again for bitmap
+
+// Based on QPixmap::init()
+KIconBitmap::KIconBitmap( int w, int h, Pixmap pm_P
+#ifdef KICON_SHARE_XRENDER
+    , Picture pic_P
+#endif
+    )
+    : QBitmap( 0, 0 )
+{
+    data->uninit = false;
+    data->w = w;
+    data->h = h;
+    hd = pm_P;
+
+#ifndef QT_NO_XRENDER
+    if (qt_use_xrender) {
+#ifdef KICON_SHARE_XRENDER
+        rendhd = pic_P;
+#else
+	XRenderPictFormat *format = 0;
+	XRenderPictFormat req;
+	ulong mask = PictFormatType | PictFormatDepth;
+
+	req.type = PictTypeDirect;
+	req.depth = data->d;
+
+	if (data->d == 1) {
+	    req.direct.alpha = 0;
+	    req.direct.alphaMask = 1;
+	    mask |= PictFormatAlpha | PictFormatAlphaMask;
+	} else {
+	    format = XRenderFindVisualFormat(x11Display(), (Visual *) x11Visual());
+	}
+
+	if (! format)
+	    format = XRenderFindFormat(x11Display(), mask, &req, 0);
+	if (format)
+	    rendhd = XRenderCreatePicture(x11Display(), hd, format, 0, 0);
+#endif
+    }
+#endif // QT_NO_XRENDER
+
+}
+
+// Once again for alpha pixmap
+
+// Based on QPixmap::convertFromImage()
+KIconAlpha::KIconAlpha( int w, int h, Pixmap pm_P
+#ifdef KICON_SHARE_XRENDER
+    , Picture pic_P
+#endif
+    )
+    : QPixmap( 0, 0, 8 )
+{
+    data->uninit = false;
+#ifndef QT_NO_XRENDER
+    if(qt_use_xrender) {
+	    // setup pixmap data
+	    data->w = w;
+	    data->h = h;
+
+            hd = pm_P;
+            
+#ifdef KICON_SHARE_XRENDER
+            rendhd = pic_P;
+#else
+	    XRenderPictFormat *format = 0;
+	    XRenderPictFormat req;
+	    ulong mask = PictFormatType | PictFormatDepth | PictFormatAlphaMask;
+	    req.type = PictTypeDirect;
+	    req.depth = 8;
+	    req.direct.alphaMask = 0xff;
+	    format = XRenderFindFormat(x11Display(), mask, &req, 0);
+	    if (format)
+		rendhd =
+		    XRenderCreatePicture(x11Display(), hd, format, 0, 0);
+#endif
+    }
+#endif // QT_NO_XRENDER
+}
+
+KIconDataPixmap::KIconDataPixmap( const QPixmap& pm_P )
+    : QPixmap( pm_P )
+    {
+    }
+    
+Pixmap KIconDataPixmap::maskHandle() const
+    {
+    return mask() != NULL ? mask()->handle() : None;
+    }
+
+Pixmap KIconDataPixmap::alphaHandle() const
+    {
+    return data->alphapm != NULL ? data->alphapm->handle() : None;
+    }
+
+#ifdef KICON_SHARE_XRENDER
+Picture KIconDataPixmap::maskX11RenderHandle() const
+    {
+    return mask() != NULL ? mask()->x11RenderHandle() : None;
+    }
+
+Picture KIconDataPixmap::alphaX11RenderHandle() const
+    {
+    return data->alphapm != NULL ? data->alphapm->x11RenderHandle() : None;
+    }
+#endif
+
+const QPixmap* KIconDataPixmap::alpha() const
+    {
+    return data->alphapm;
+    }
+
+const QPixmap* KIconPixmap::alpha() const
+    {
+    return data->alphapm;
+    }
+
+KIconPixmapHolder::KIconPixmapHolder()
+    {
+    }
+    
+// just attach to the shared QPixmapData, it doesn't matter if it's
+// QPixmap or QBitmap
+KIconPixmapHolder::KIconPixmapHolder( const QPixmap& pm_P )
+    : QPixmap( pm_P )
+    {
+    }
+
+// just attach to the shared QPixmapData, it doesn't matter if it's
+// QPixmap or QBitmap
+KIconPixmapHolder& KIconPixmapHolder::operator=( const QPixmap& pm_P )
+    {
+    QPixmap::operator=( pm_P );
+    return *this;
+    }
+    
+// based on QPixmap::deref()
+KIconPixmapHolder::~KIconPixmapHolder()
+    {
+    if( data->count > 1 )         // if it's still in use
+        {
+        // it looks like most KDE apps don't delete their widgets, so complain only \
if the app +        // is not quiting
+        if( !QApplication::closingDown())
+            fprintf( stderr, "KIconPixmapHolder: Cannot free pixmap holder \
(count==%d)\n", data->count );; +        ++data->count;     // prevent QPixmap from \
freeing the X pixmap +        }
+    else {
+	if ( qApp && hd) {
+
+#ifndef QT_NO_XRENDER
+	    if (rendhd) {
+#ifndef KICON_SHARE_XRENDER
+		XRenderFreePicture(x11Display(), rendhd);
+#endif
+		rendhd = 0;
+	    }
+#endif // QT_NO_XRENDER
+
+	    hd = 0;
+	}
+    }
+    }
+
+KIconSharedPixmap::KIconSharedPixmap( const QCString& key_P, const QPixmap& pm_P )
+    : QPixmap( pm_P ), key( key_P )
+    {
+    }
+
+class QPixmapDataHack
+    : public QBitmap
+    {
+    public:
+        bool unused() const { return data->count == 1; }
+    };
+    
+bool KIconSharedPixmap::unused() const
+    {
+    return data->count == 1
+        && ( data->mask == NULL || static_cast< QPixmapDataHack* >( data->mask \
)->unused() == 1 ) +        && ( data->alphapm == NULL || static_cast< \
QPixmapDataHack* >( data->alphapm )->unused() == 1 ); +    }
+    
+KIconSharedPixmap::~KIconSharedPixmap()
+    {
+    if( !unused())         // if it's still in use
+        {
+        // it looks like most KDE apps don't delete their widgets, so complain only \
if the app +        // is not quiting
+        if( !QApplication::closingDown())
+            fprintf( stderr, "KIconSharedPixmap: Cannot free pixmap holder \
(count==%d)\n", data->count );; +        ++data->count;     // prevent QPixmap from \
freeing the X pixmaps +        return;
+        }
+    if( data->alphapm != NULL )
+        {
+        KIconPixmapHolder hold( *data->alphapm );
+        delete data->alphapm;
+        data->alphapm = NULL;
+        }
+    if( data->mask != NULL )
+        {
+        KIconPixmapHolder hold( *data->mask );
+        delete data->mask;
+        data->mask = NULL;
+        }
+    if ( qApp && hd) {
+
+#ifndef QT_NO_XRENDER
+	    if (rendhd) {
+#ifndef KICON_SHARE_XRENDER
+		XRenderFreePicture(x11Display(), rendhd);
+#endif
+		rendhd = 0;
+	    }
+#endif // QT_NO_XRENDER
+
+	    hd = 0;
+	}
+    }
Index: kiconloader.cpp
===================================================================
--- kiconloader.cpp	(revisão 412784)
+++ kiconloader.cpp	(cópia de trabalho)
@@ -36,6 +36,7 @@
 #include <kicontheme.h>
 #include <kiconloader.h>
 #include <kiconeffect.h>
+#include <kiconserverclient_p.h>
 
 #include <sys/types.h>
 #include <stdlib.h>	//for abs
@@ -134,6 +135,7 @@
     QPtrList<KIconThemeNode> links;
     bool extraDesktopIconsLoaded :1;
     bool delayedLoading :1;
+    KIconServerClient* iconClient;
 };
 
 #define KICONLOADER_CHECKS
@@ -197,6 +199,21 @@
     else
 	d->mpDirs = KGlobal::dirs();
 
+    d->iconClient = NULL;
+    if( d->mpDirs == KGlobal::dirs())
+    {
+        KConfigGroupSaver saver( KGlobal::config(), "Icons" );
+        if( KGlobal::config()->readBoolEntry( "UseIconServer", true ))
+            {
+            d->iconClient = new KIconServerClient;
+            if( !d->iconClient->isActive()) // some startup problem
+                {
+                delete d->iconClient;
+                d->iconClient = NULL;
+                }
+            }
+    }
+        
     // If this is unequal to 0, the iconloader is initialized
     // successfully.
     d->mpThemeRoot = 0L;
@@ -292,6 +309,7 @@
        deleted when the elements of d->links are deleted */
     d->mpThemeRoot=0;
     delete[] d->mpGroups;
+    delete d->iconClient;
     delete d;
 }
 
@@ -687,31 +705,20 @@
     }
     favIconOverlay = favIconOverlay && size > 22;
 
-    // Generate a unique cache key for the icon.
-
-    key = "$kico_";
-    key += name; key += '_';
-    key += QString::number(size); key += '_';
-
-    QString overlayStr = QString::number( overlay );
-
-    QString noEffectKey = key + '_' + overlayStr;
-
-    if (group >= 0)
-    {
-	key += d->mpEffect.fingerprint(group, state);
-	if (d->mpGroups[group].dblPixels)
-	    key += QString::fromLatin1(":dblsize");
-    } else
-	key += QString::fromLatin1("noeffect");
-    key += '_';
-    key += overlayStr;
-
+    QString noEffectKey;
+    key = makeKey( name, group, size, state | overlay, noEffectKey );
+    
     // Is the icon in the cache?
     bool inCache = QPixmapCache::find(key, pix);
     if (inCache && (path_store == 0L))
 	return pix;
 
+    if( d->iconClient && d->iconClient->iconServerCheck( key, pix ))
+    {
+        QPixmapCache::insert(key, pix);
+        return pix;
+    }
+        
     QImage *img = 0;
     int iconType;
     int iconThreshold;
@@ -736,7 +743,7 @@
             {
                 // Try "User" icon too. Some apps expect this.
                 if (!name.isEmpty())
-                    pix = loadIcon(name, KIcon::User, size, state, path_store, \
true); +                    pix = loadIcon(name, KIcon::User, size, state | overlay, \
path_store, true);  if (!pix.isNull() || canReturnNull)
                     return pix;
 
@@ -870,9 +877,39 @@
     }
 
     QPixmapCache::insert(key, pix);
+    
+    if( d->iconClient )
+        d->iconClient->iconServerAdd( key, pix, group, state | overlay );
+    
     return pix;
 }
 
+QString KIconLoader::makeKey( const QString& name, int group, int size, int state,
+    QString& noEffectKey ) const
+{
+    int overlay = (state & KIcon::OverlayMask);
+    state &= ~KIcon::OverlayMask;
+
+    QString key = "$kico_";
+    key += name; key += ':';
+    key += QString::number(size); key += '_';
+
+    QString overlayStr = QString::number( overlay );
+
+    noEffectKey = key + '_' + overlayStr;
+
+    if (group >= 0)
+    {
+	key += d->mpEffect.fingerprint(group, state);
+	if (d->mpGroups[group].dblPixels)
+	    key += QString::fromLatin1(":dblsize");
+    } else
+	key += QString::fromLatin1("noeffect");
+    key += '_';
+    key += overlayStr;
+    return key;
+    }
+
 QImage *KIconLoader::loadOverlay(const QString &name, int size) const
 {
     QString key = name + '_' + QString::number(size);
Index: kiconserverstructs.h
===================================================================
--- kiconserverstructs.h	(revisão 0)
+++ kiconserverstructs.h	(revisão 0)
@@ -0,0 +1,71 @@
+#ifndef KICONSERVERSTRUCTS_H
+#define KICONSERVERSTRUCTS_H
+
+struct KIconFileEntry
+    {
+    int key_ref;
+    Pixmap xid;
+    Pixmap mask_xid;
+    Pixmap alpha_xid;
+#ifdef KICON_SHARE_XRENDER
+    Picture pic;
+    Picture mask_pic;
+    Picture alpha_pic;
+#endif
+    int size;
+    int group;
+    int state;
+    };
+        
+struct KIconsFile
+    {
+    int version;
+    int depth;
+    int count;
+    KIconFileEntry entries[ 1 ]; // will grow
+    }; // + keys
+    
+const int KICONSFILEVERSION = 1;
+
+// KIconLoader saves these for sending them to iconserver later
+struct KIconNewData
+    {
+    KIconNewData( const QString& key_P, const QPixmap& pix_P, int group_P, int \
state_P ); +    KIconNewData() {}; // for QValueList
+    QString key;
+    KIconDataPixmap pix;
+    int group;
+    int state;
+    };
+
+typedef QValueList< KIconNewData > KIconNewDataList;
+
+inline
+KIconNewData::KIconNewData( const QString& key_P, const QPixmap& pix_P, int group_P, \
int state_P ) +    : key( key_P ), pix( pix_P ), group( group_P ), state( state_P )
+    {
+    }
+
+// for the newIcons DCOP call
+struct KIconSendData
+    {
+    KIconSendData( const KIconNewData& data_P );
+    KIconSendData() {}; // for QValueList
+    QCString key;
+    Pixmap xid;
+    Pixmap mask_xid;
+    Pixmap alpha_xid;
+#ifdef KICON_SHARE_XRENDER
+    Picture pic;
+    Picture mask_pic;
+    Picture alpha_pic;
+#endif
+    int size;
+    int group;
+    int state;
+    };
+    
+KDECORE_EXPORT QDataStream& operator<<( QDataStream& stream_P, const KIconSendData& \
data_P ); +KDECORE_EXPORT QDataStream& operator>>( QDataStream& stream_P, \
KIconSendData& data_P ); +
+#endif
Index: kiconloader.h
===================================================================
--- kiconloader.h	(revisão 412784)
+++ kiconloader.h	(cópia de trabalho)
@@ -337,6 +337,13 @@
     bool isDelayedIconSetLoadingEnabled() const;
 
 
+    /**
+     * Generate a unique cache key for the icon.
+     * @internal
+     */
+    QString makeKey( const QString& name, int group, int size, int state,
+        QString& noEffectKey ) const;
+
  private:
     /**
      * @internal
Index: kiconserverclient_p.h
===================================================================
--- kiconserverclient_p.h	(revisão 0)
+++ kiconserverclient_p.h	(revisão 0)
@@ -0,0 +1,92 @@
+/****************************************************************************
+
+ $Id: iconserver.h,v 1.11 2001/08/29 15:25:38 bero Exp $
+
+ Copyright (C) 2001 Lubos Lunak        <llunak@suse.cz>
+
+ This file is part of the KDE libraries
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB.  If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+****************************************************************************/
+
+#ifndef __KICONSERVERCLIENT_H
+#define __KICONSERVERCLIENT_H
+
+#include <kdelibs_export.h>
+
+#include <qvaluelist.h>
+#include <qobject.h>
+#include <qtimer.h>
+#include <dcopobject.h>
+#include <qpixmap.h>
+#include <qbitmap.h>
+
+#include <kiconpixmap_p.h>
+#include <kiconserverstructs.h>
+
+#include <X11/X.h>
+
+class QFile;
+
+// int: count
+// *count : int xid
+//          int key_ref
+// *count : char[] key
+
+
+typedef QValueList< KIconSendData > KIconSendDataList;
+
+class KIconSharedPixmap;
+
+class KDECORE_EXPORT KIconServerClient
+    : public QObject, public DCOPObject
+    {
+    Q_OBJECT
+    K_DCOP
+    k_dcop:
+        void iconsFileChanged( bool serverRunning );
+    public:
+        KIconServerClient();
+        virtual ~KIconServerClient();
+        bool iconServerCheck( const QString& key_P, QPixmap& pix_O );
+        void iconServerAdd( const QString& key_P, QPixmap& pix_P, int group_P, int \
state_P ); +        bool isActive() const;
+    private:
+        bool openIconsFile();
+        void closeIconsFile();
+        bool iconServerRunning();
+    private slots:
+        void sendIconsToServer();    
+        void refDerefIcons();
+        void checkUnusedIcons();
+    private:
+        static void init_icons_holder();
+        static void finish_icons_holder();
+        bool active;
+        const KIconsFile* icons_mmap;
+        int icons_size;
+        QFile* icons_file;
+        QTimer send_timer;
+        QTimer ref_timer;
+        QTimer unused_check_timer;
+        KIconNewDataList icons_send;
+        QValueList< QCString > ref_icons;
+        QValueList< QCString > deref_icons;
+        static QValueList< KIconSharedPixmap* >* icons_holder; // CHECKME static ?
+    };
+
+#endif
Index: kdebug.areas
===================================================================
--- kdebug.areas	(revisão 412784)
+++ kdebug.areas	(cópia de trabalho)
@@ -22,6 +22,7 @@
 176        kdecore (KWin)
 177        kdecore (KConfigSkeleton)
 178        kdecore (KConfigDialogManager)
+179        kdecore (KIconServer)
 180        kdecore (kdelibs)
 200        kdeui (KMainWindow)
 220        kdeui (KToolBar)
Index: kiconserverclient.cpp
===================================================================
--- kiconserverclient.cpp	(revisão 0)
+++ kiconserverclient.cpp	(revisão 0)
@@ -0,0 +1,345 @@
+/****************************************************************************
+
+ $Id: iconserver.h,v 1.11 2001/08/29 15:25:38 bero Exp $
+
+ Copyright (C) 2001 Lubos Lunak        <llunak@suse.cz>
+
+ This file is part of the KDE libraries
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB.  If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+****************************************************************************/
+
+//#define NDEBUG
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qbitmap.h>
+#include <qfile.h>
+#include <kconfig.h>
+#include <kglobal.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <dcopclient.h>
+#include <kstandarddirs.h>
+
+#include <unistd.h>
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+
+#include <kiconserver_stub.h>
+
+#include <X11/Xlib.h>
+
+#include "kiconserverclient_p.h"
+#include "kiconpixmap_p.h"
+
+
+// CHECKME co to bude delat na multihead, bude to fungovat ?
+
+KIconServerClient::KIconServerClient()
+    : DCOPObject( "iconserverclient" ), active( false ), icons_mmap( NULL )
+    // co kdyz budou dva klienti ?
+    {
+// CHECKME tohle asi nebude fungovat s multihead !? ( ruzne bpp )
+//    shared_icons.setAutoDelete( true ); // CHECKME
+    KConfigGroupSaver saver( KGlobal::config(), "Icons" );
+    if( !KGlobal::config()->readBoolEntry( "UseIconServer", true ))
+        return;
+    if( !kapp->dcopClient()->isAttached()) // apps usually automatically register \
with DCOP, +        return;                            // so if this one has it \
turned off, don't attach either +    KIconServer_stub stub( "iconserver", \
"iconserver" ); // CHECKME kded ? +    bool ok = stub.serverRunning() && stub.ok();
+//  CHECKME  jen lokalni iconserver ??
+    if( !ok )
+        {
+        kdDebug( 174 ) << "no icon server available" << endl;
+        return;
+        }
+    if( !openIconsFile())
+        return;
+    connect( &send_timer, SIGNAL( timeout()), this, SLOT( sendIconsToServer()));
+    connect( &ref_timer, SIGNAL( timeout()), this, SLOT( refDerefIcons()));
+    connect( &unused_check_timer, SIGNAL( timeout()), this, SLOT( \
checkUnusedIcons())); +    unused_check_timer.start( 30000 ); // CHECKME 30s ?
+    active = true;
+    }
+    
+KIconServerClient::~KIconServerClient()
+    {
+    closeIconsFile();
+    }
+    
+bool KIconServerClient::openIconsFile()
+    {
+#ifndef HAVE_MMAP
+    return false; // sorry
+#else
+    Q_ASSERT( icons_mmap == NULL );
+    QString path = KGlobal::dirs()->saveLocation("tmp") + "kiconsfile-" + getenv( \
"DISPLAY" ); +    icons_file = new QFile( path );
+    if( !icons_file->open( IO_ReadOnly ))
+        {
+        delete icons_file;
+        return false;
+        }
+    icons_size = icons_file->size();
+    icons_mmap = reinterpret_cast< KIconsFile* >( mmap( 0, icons_size,
+        PROT_READ, MAP_PRIVATE, icons_file->handle(), 0 ));
+    if( icons_mmap == NULL )
+        {
+        kdDebug( 174 ) << "mmap failed. (length = " << icons_size << ")" << endl;
+        delete icons_file;
+        return false; // sorry
+        }
+    if( icons_mmap->version != KICONSFILEVERSION )
+        {
+        kdDebug( 174 ) << "icons file version doesn't match (found " << \
icons_mmap->version +            << ", expected " << KICONSFILEVERSION << ")" << \
endl; +        closeIconsFile();
+        return false;
+        }
+    if( icons_mmap->depth != QPixmap::defaultDepth())
+        {
+        kdDebug( 174 ) << "icons file depth doesn't match (found " << \
icons_mmap->depth +            << ", depth is " << QPixmap::defaultDepth() << ")" << \
endl; +        closeIconsFile();
+        return false;
+        }
+    return true;
+#endif
+    }
+    
+void KIconServerClient::closeIconsFile()
+    {
+    if( icons_mmap == NULL )
+        return;    
+#ifdef HAVE_MMAP
+    munmap( (char*) icons_mmap, icons_size );
+    icons_mmap = NULL;
+    delete icons_file;
+#endif
+    }
+
+bool KIconServerClient::iconServerCheck( const QString& key_P, QPixmap& pix_O )
+    {
+    if( !active )
+        return false;
+#if 0
+    kdDebug( 174 ) << "checking for \"" << key_P << "\" icon in iconserver" <<endl;
+#endif
+    int min = 0, max = icons_mmap->count - 1;
+    QCString key = key_P.utf8();
+    int index = -1;
+    while( min <= max )
+        {
+        int pos = ( min + max ) / 2;
+        const char* pos_key = reinterpret_cast< const char* >( icons_mmap )
+            + icons_mmap->entries[ pos ].key_ref;
+        int dif = qstrcmp( key, pos_key );
+        if( dif < 0 )
+            max = pos - 1;
+        else if( dif > 0 )
+            min = pos + 1;
+        else // key == pos_key
+            {
+            index = pos;
+            break;
+            }
+        }
+    if( index < 0 )
+        return false;
+    const KIconFileEntry& data = icons_mmap->entries[ index ];
+#if 0
+    kdDebug( 174 ) << "getting icon from iconserver: " << data.xid << "/"
+        << data.mask_xid << "/" << data.alpha_xid << endl;
+#endif
+#ifdef KICON_SHARE_XRENDER
+#if 0
+    kdDebug( 174 ) << "pics: " << data.pic << "/" << data.mask_pic << "/" << \
data.alpha_pic << endl; +#endif
+#endif
+    KIconPixmap pix( data.size, data.size, data.xid,
+        data.mask_xid, data.alpha_xid
+#ifdef KICON_SHARE_XRENDER
+        , data.pic, data.mask_pic, data.alpha_pic
+#endif
+        );
+    pix_O = pix;
+    init_icons_holder();
+    icons_holder->prepend( new KIconSharedPixmap( key, pix ));
+    ref_icons.prepend( key );
+    if( !ref_timer.isActive())
+        ref_timer.start( 10000, true ); // CHECKME 10 sec ?
+    return true;
+    }
+
+void KIconServerClient::iconServerAdd( const QString& key_P, QPixmap& pix_P, int \
group_P, int state_P ) +    {
+    if( !active )
+        return;
+    if( pix_P.width() != pix_P.height())
+        {
+        kdWarning( 174 ) << "icon \"" << key_P << "\" has size "
+            << pix_P.width() << "x" << pix_P.height() << endl;
+        return;
+        }
+    icons_send.append( KIconNewData( key_P, pix_P, group_P, state_P ));
+    if( !send_timer.isActive())
+        send_timer.start( 10000, true ); // CHECKME 10 sec ?
+    }
+
+void KIconServerClient::sendIconsToServer()
+    {
+    if( icons_send.empty())
+        return;
+    kdDebug( 174 ) << "sending icons to icon server" << endl;
+    KIconSendDataList send_data;
+    for( KIconNewDataList::ConstIterator it = icons_send.begin();
+         it != icons_send.end();
+         ++it )
+        {
+        send_data.append( KIconSendData( *it ));
+        KIconDataPixmap pix( ( *it ).pix );
+#if 0
+        kdDebug( 174 ) << "sending icon \"" << ( *it ).key << "\"" << endl;
+#endif
+        init_icons_holder();
+        icons_holder->prepend( new KIconSharedPixmap( ( *it ).key.utf8(), pix )); // \
CHECKME utf8 ? +        }
+    KIconServer_stub stub( "iconserver", "iconserver" ); // CHECKME kded ?
+    stub.newIcons( send_data );    
+    // CHECKME tohle dole az s delay, at si stihne iconserver vsechno precist
+    // nebo kdyby tahle app spadla
+    icons_send.clear();
+    }
+
+void KIconServerClient::iconsFileChanged( bool server_running_P )
+    {
+    if( !active )
+        return;
+    if( server_running_P )
+        {
+        kdDebug( 174 ) << "reloading index file" << endl;
+        closeIconsFile();
+        if( !openIconsFile())
+            active = false;
+        }
+    else
+        {
+        kdDebug( 174 ) << "shutting down icon client" << endl;
+        closeIconsFile();
+        active = false;
+        }
+    }
+    
+void KIconServerClient::refDerefIcons()
+    {
+    KIconServer_stub stub( "iconserver", "iconserver" ); // CHECKME kded ?
+    if( !ref_icons.empty())
+        {
+        stub.refIcons( ref_icons );    
+        ref_icons.clear();
+        }
+    if( !deref_icons.empty())
+        {
+        stub.derefIcons( deref_icons );    
+        deref_icons.clear();
+        }
+    }
+
+void KIconServerClient::checkUnusedIcons()
+    {
+    if( icons_holder == NULL )
+        return;
+    for( QValueList< KIconSharedPixmap* >::Iterator it = icons_holder->begin();
+         it != icons_holder->end();
+         )
+        {
+        if( ( *it )->unused())
+            {
+            deref_icons.prepend( ( *it )->key );
+            if( !ref_timer.isActive())
+                ref_timer.start( 10000, true ); // CHECKME 10 sec ?
+            delete *it; // must delete manually (QValueList is used)
+            it = icons_holder->remove( it );
+            continue;
+            }
+        ++it;
+        }
+    }
+        
+bool KIconServerClient::isActive() const
+    {
+    return active;
+    }
+            
+QDataStream& operator<<( QDataStream& stream_P, const KIconSendData& data_P )
+    {
+    return stream_P << data_P.key << data_P.xid << data_P.mask_xid << \
data_P.alpha_xid +#ifdef KICON_SHARE_XRENDER
+        << data_P.pic << data_P.mask_pic << data_P.alpha_pic
+#endif
+        << data_P.size << data_P.group << data_P.state;
+    }
+    
+QDataStream& operator>>( QDataStream& stream_P, KIconSendData& data_P )
+    {
+    return stream_P >> data_P.key >> data_P.xid >> data_P.mask_xid >> \
data_P.alpha_xid +#ifdef KICON_SHARE_XRENDER
+        >> data_P.pic >> data_P.mask_pic >> data_P.alpha_pic
+#endif
+        >> data_P.size >> data_P.group >> data_P.state;
+    }
+
+KIconSendData::KIconSendData( const KIconNewData& data_P )
+    :   key( data_P.key.utf8()),
+        xid( data_P.pix.handle()),
+        mask_xid( data_P.pix.maskHandle()),
+        alpha_xid( data_P.pix.alphaHandle()),
+#ifdef KICON_SHARE_XRENDER
+        pic( data_P.pix.x11RenderHandle()),
+        mask_pic( data_P.pix.maskX11RenderHandle()),
+        alpha_pic( data_P.pix.alphaX11RenderHandle()),
+#endif
+        size( data_P.pix.width()),
+        group( data_P.group ),
+        state( data_P.state )
+    {
+    }
+
+// asi mit i nejake casove cisteni
+QValueList< KIconSharedPixmap* >* KIconServerClient::icons_holder = NULL;
+
+void KIconServerClient::init_icons_holder()
+    {
+    if( icons_holder != NULL )
+        return;
+    icons_holder = new QValueList< KIconSharedPixmap* >;
+    qAddPostRoutine( finish_icons_holder );
+    }
+
+void KIconServerClient::finish_icons_holder()
+    {
+    if( icons_holder == NULL )
+        return;
+    delete icons_holder;
+    icons_holder = NULL;
+    }
+    
+#include "kiconserverclient_p.moc"


[Attachment #6 (application/pgp-signature)]

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic