[Patch:] KClipboard / klipper / kpaint bug fixes

Helge Deller deller at gmx.de
Mon Oct 28 19:52:32 GMT 2002


Hi,

the following patches fixes a few bugs and problems with the KDE clipboard,
the klipper application and copy&paste problems in kpaint.

To reproduce the problem this patches try to fix, start klipper and kpaint,
mark and copy a few text pieces with the mouse (this moves the text to the 
selection and/or clipboard-"clipboard") and then mark and copy some 
graphics pieces with kpaint.

klipper will try to show your copied graphics as "text" which of course fails 
and thus it displays you some weird strings instead.

The follwing patches to 
- kdelibs/kdecore/kclipboard.[cpp|h], 
- kdebase/klipper/toplevel.[cpp|h] and
- kdegraphics/kpaint/

fixes those problems for me and as a feature it also fixes a few generic copy&paste 
problems in kpaint (and maybe other apps) by

- introducing a new static function KClipboard::provides( const char *mimetype ) which
heavily increases the speed if you want to know if the clipboard provides a special mimetype
data (example: image/* or text/*)
- moves the clipboard syncronisation to kclipboard.cpp only. There should be no such code in klipper.cpp.
- fixes klipper to use the new qt3.1 clipboard interfaces (makes the code a lot easier to understand)
- and adds a few further checks in kpaint before trying to do any copy&paste operations

This code applies to CVS head and works for me now since a few days.

I would like to apply this code if I get your OK.

Thanks,
Helge

-------------- next part --------------
Index: kdecore//kclipboard.cpp
===================================================================
RCS file: /home/kde/kdelibs/kdecore/kclipboard.cpp,v
retrieving revision 1.33
diff -u -p -r1.33 kclipboard.cpp
--- kdecore//kclipboard.cpp	2002/10/24 22:23:44	1.33
+++ kdecore//kclipboard.cpp	2002/10/28 19:30:09
@@ -23,67 +23,10 @@
 #include "kclipboard.h"
 
 
-class KClipboard::MimeSource : public QMimeSource
-{
-public:
-    MimeSource( const QMimeSource * src )
-        : QMimeSource(),
-          m_formats( true ) // deep copies!
-    {
-        m_formats.setAutoDelete( true );
-        m_data.setAutoDelete( true );
-
-        if ( src )
-        {
-            QByteArray *byteArray;
-            const char *format;
-            int i = 0;
-            while ( (format = src->format( i++ )) )
-            {
-                byteArray = new QByteArray();
-                *byteArray = src->encodedData( format ).copy();
-                m_data.append( byteArray );
-                m_formats.append( format );
-            }
-        }
-    }
-
-    ~MimeSource() {}
-
-    virtual const char *format( int i ) const {
-        if ( i < (int) m_formats.count() )
-            return m_formats.at( i );
-        else
-            return 0L;
-    }
-    virtual bool provides( const char *mimeType ) const {
-        return ( m_formats.find( mimeType ) > -1 );
-    }
-    virtual QByteArray encodedData( const char *format ) const
-    {
-        int index = m_formats.find( format );
-        if ( index > -1 )
-        {
-            // grmbl, gcc (2.95.3 at least) doesn't let me call m_data.at(),
-            // due to it being non-const. Even if mutable.
-            QPtrList<QByteArray> *list =
-                const_cast<QPtrList<QByteArray> *>( &m_data );
-            return *(list->at( index ));
-        }
-
-        return QByteArray();
-    }
-
-private:
-    mutable QStrList m_formats;
-    QPtrList<QByteArray> m_data;
-};
-
-
 KClipboard * KClipboard::s_self = 0L;
 bool KClipboard::s_sync = false;
 bool KClipboard::s_implicitSelection = true;
-bool KClipboard::s_blocked = false;
+int KClipboard::s_blocked = 0;
 
 KClipboard * KClipboard::self()
 {
@@ -126,7 +69,7 @@ void KClipboard::slotSelectionChanged()
 
     if ( s_sync )
     {
-        setClipboard( new MimeSource( clip->data( QClipboard::Selection) ),
+        setClipboard( clip->text( QClipboard::Selection ),
                       QClipboard::Clipboard );
     }
 }
@@ -135,35 +78,51 @@ void KClipboard::slotClipboardChanged()
 {
     QClipboard *clip = QApplication::clipboard();
 
-//     qDebug("*** clip changed : %i (implicit: %i, ownz: clip: %i, selection: %i)", s_blocked, s_implicitSelection, clip->ownsClipboard(), clip->ownsSelection());
+//     qDebug("*** clip changed : %i (implicit: %i, ownz: clip: %i, selection: %i)",
+//     s_blocked, s_implicitSelection, clip->ownsClipboard(), clip->ownsSelection());
     if ( s_blocked || !clip->ownsClipboard() )
         return;
 
-    if ( s_implicitSelection || s_sync )
+    /* syncronize selection to clipboard only when it's mimetype is "text*" */
+    if ( (s_implicitSelection || s_sync) && provides("text/") )
     {
-        setClipboard( new MimeSource( clip->data( QClipboard::Clipboard ) ),
+        setClipboard( clip->text( QClipboard::Clipboard ),
                       QClipboard::Selection );
     }
 }
 
-void KClipboard::setClipboard( QMimeSource *data, QClipboard::Mode mode )
+void KClipboard::setClipboard( const QString & text, QClipboard::Mode mode )
 {
 //     qDebug("---> setting clipboard: %p", data);
 
     QClipboard *clip = QApplication::clipboard();
 
-    s_blocked = true;
+    s_blocked++;
+    clip->setText( text, mode );
+    s_blocked--;
+}
 
-    if ( mode == QClipboard::Clipboard )
-    {
-        clip->setData( data, QClipboard::Clipboard );
-    }
-    else if ( mode == QClipboard::Selection )
-    {
-        clip->setData( data, QClipboard::Selection );
-    }
+bool KClipboard::provides( const char *mimetype )
+{
+    QClipboard *clip = QApplication::clipboard();
+    if (!clip || !mimetype)
+	return false;
 
-    s_blocked = false;
+    const QMimeSource *ms = clip->data( QClipboard::Clipboard );
+    if (!ms)
+	return false;
+
+    int i = 0;
+    const char *fmt;
+    do {
+	fmt = ms->format(i);
+	// qDebug("*** klipper: clipboard has format %s (%i)", fmt, i);
+	if (!fmt)
+		return false;
+	if (!strncmp(fmt, mimetype, strlen(mimetype)))
+		return true;
+	i++;
+    } while (1);
 }
 
 // private, called by KApplication
Index: kdecore//kclipboard.h
===================================================================
RCS file: /home/kde/kdelibs/kdecore/kclipboard.h,v
retrieving revision 1.20
diff -u -p -r1.20 kclipboard.h
--- kdecore//kclipboard.h	2002/10/24 22:23:44	1.20
+++ kdecore//kclipboard.h	2002/10/28 19:30:10
@@ -94,7 +94,7 @@ public:
     }
 
     /**
-     * Checks whether the  Clipboard buffer will be copied to the Selection
+     * Checks whether the Clipboard buffer will be copied to the Selection
      * buffer upon changes.
      * @returns whether the Clipboard buffer will be copied to the Selection
      * buffer upon changes.
@@ -105,6 +105,13 @@ public:
         return s_implicitSelection;
     }
 
+    /**
+     * Checks whether the Clipboard buffer provides contents of a given mimetype.
+     * @returns whether the Clipboard buffer provides this mimetype content.
+     * @param mimetype string (e.g. "text/plain", "text/" or "image/")
+     */
+    static bool provides( const char *mimetype );
+
 protected:
     ~KClipboard();
 
@@ -115,15 +122,12 @@ private slots:
 private:
     KClipboard( QObject *parent = 0, const char *name = 0L );
 
-    // does not restore the old selection mode.
-    static void setClipboard( QMimeSource* data, QClipboard::Mode mode );
+    static void setClipboard( const QString & text, QClipboard::Mode mode );
 
     static KClipboard *s_self;
     static bool s_sync;
     static bool s_implicitSelection;
-    static bool s_blocked;
-
-    class MimeSource;
+    static int s_blocked;
 
 private:
     // needed by klipper
-------------- next part --------------
    QClipboard *clip = QApplication::clipboard();
    if (!clip || !mimetype)
	return false;

    const QMimeSource *ms = clip->data( QClipboard::Clipboard );
    if (!ms)
	return false;

    int i = 0;
    const char *fmt;
    do {
	fmt = ms->format(i);
	// qDebug("*** klipper: clipboard has format %s (%i)", fmt, i);
	if (!fmt)
		return false;
	if (strncmp(fmt, mimetype, strlen(mimetype)))
		return true;
	i++;
    } while (1);
-------------- next part --------------
Index: klipper/toplevel.cpp
===================================================================
RCS file: /home/kde/kdebase/klipper/toplevel.cpp,v
retrieving revision 1.112
diff -u -p -r1.112 toplevel.cpp
--- klipper/toplevel.cpp	2002/09/30 12:16:02	1.112
+++ klipper/toplevel.cpp	2002/10/28 19:29:54
@@ -126,9 +126,10 @@ QString KlipperWidget::getClipboardConte
     return clipboardContents();
 }
 
-void KlipperWidget::setClipboardContents(QString s)
+void KlipperWidget::setClipboardContents(const QString& s)
 {
-    setClipboard( s, Clipboard | Selection);
+    setClipboard( s, QClipboard::Selection );
+    setClipboard( s, QClipboard::Clipboard );
     newClipData();
 }
 
@@ -212,8 +213,10 @@ void KlipperWidget::clickedMenu(int id)
             if ( it != m_clipDict.end() && it.data() != QSempty )
             {
                 QString data = it.data();
-                setClipboard( data, Clipboard | Selection );
+    		setClipboard( data, QClipboard::Selection );
+		setClipboard( data, QClipboard::Clipboard );
 
+
 		if (bURLGrabber && bReplayActionInHistory)
 		    myURLGrabber->checkNewData( data );
 
@@ -291,7 +294,8 @@ void KlipperWidget::readProperties(KConf
           m_lastSelection = dataList.first();
           m_lastClipboard = dataList.first();
           m_lastString    = dataList.first();
-          setClipboard( m_lastString, Clipboard | Selection );
+          setClipboard( m_lastString, QClipboard::Selection );
+          setClipboard( m_lastString, QClipboard::Clipboard );
       }
   }
 
@@ -544,25 +548,20 @@ void KlipperWidget::slotClearClipboard()
         m_popup->setItemEnabled(m_selectedItem, false);
 }
 
-QString KlipperWidget::clipboardContents( bool *isSelection )
+QString KlipperWidget::clipboardContents( QClipboard::Mode *mode )
 {
-    clip->setSelectionMode( true );
-
-    QString contents = clip->text();
+    if (mode) *mode = QClipboard::Selection;
+    QString contents = clip->text(QClipboard::Selection);
 
-    if ( contents == m_lastSelection )
+    if ( contents == m_lastSelection && KClipboard::provides("text/") )
     {
-        clip->setSelectionMode( false );
-        QString clipContents = clip->text();
-        if ( clipContents != m_lastClipboard )
+        QString clipContents = clip->text(QClipboard::Clipboard);
+        if ( clipContents != m_lastClipboard ) {
             contents = clipContents;
-        else
-            clip->setSelectionMode( true );
+	    if (mode) *mode = QClipboard::Clipboard;
+	}
     }
 
-    if ( isSelection )
-        *isSelection = clip->selectionModeEnabled();
-
     return contents;
 }
 
@@ -616,53 +615,44 @@ void KlipperWidget::slotMoveSelectedToTo
 // clipboard polling for legacy apps
 void KlipperWidget::newClipData()
 {
-    bool selectionMode;
-    QString clipContents = clipboardContents( &selectionMode );
-//     qDebug("**** newClipData polled: %s", clipContents.latin1());
-    checkClipData( clipContents, selectionMode );
+    QClipboard::Mode mode;
+    QString clipContents = clipboardContents( &mode );
+    checkClipData( clipContents, mode );
 }
 
-void KlipperWidget::clipboardSignalArrived( bool selectionMode )
+void KlipperWidget::clipboardSignalArrived( QClipboard::Mode mode )
 {
-//     qDebug("*** clipboardSignalArrived: %i", selectionMode);
-
-    clip->setSelectionMode( selectionMode );
-    QString text = clip->text();
-//     qDebug("-> text is: %s", text.latin1());
+    bool check;
 
-    checkClipData( text, selectionMode );
+    if (mode == QClipboard::Selection)
+	check = true;
+    else
+	check = KClipboard::provides("text/");
+    
+    if (check) {
+	QString text = clip->text(mode);
+	checkClipData( text, mode );
+    }
     m_checkTimer->start(1000);
 }
 
-void KlipperWidget::checkClipData( const QString& text, bool selectionMode )
+void KlipperWidget::checkClipData( const QString& text, QClipboard::Mode mode )
 {
-   clip->setSelectionMode( selectionMode );
+    QString lastClipRef = (mode == QClipboard::Selection) ? m_lastSelection : m_lastClipboard;
 
     if ( ignoreClipboardChanges() ) // internal to klipper, ignoring QSpinBox selections
     {
         // keep our old clipboard, thanks
-        setClipboard( selectionMode ? m_lastSelection : m_lastClipboard,
-                      selectionMode );
+        setClipboard( lastClipRef, mode );
         return;
     }
 
-
     bool clipEmpty = (clip->data()->format() == 0L);
-//     qDebug("checkClipData(%i): %s, empty: %i (lastClip: %s, lastSel: %s)", selectionMode, text.latin1(), clipEmpty, m_lastClipboard.latin1(), m_lastSelection.latin1() );
-
-//     const char *format;
-//     int i = 0;
-//     while ( (format = clip->data()->format( i++ )) )
-//     {
-//         qDebug( "    format: %s", format);
-//     }
 
-    QString lastClipRef = selectionMode ? m_lastSelection : m_lastClipboard;
-
     if ( text != lastClipRef ) {
         // keep old clipboard after someone set it to null
         if ( clipEmpty && bNoNullClipboard )
-            setClipboard( lastClipRef, selectionMode );
+            setClipboard( lastClipRef, mode );
         else
             lastClipRef = text;
     }
@@ -671,7 +661,7 @@ void KlipperWidget::checkClipData( const
 
 
     // this must be below the "bNoNullClipboard" handling code!
-    if ( selectionMode && bIgnoreSelection )
+    if ( mode == QClipboard::Selection && bIgnoreSelection )
         return;
 
 
@@ -689,8 +679,8 @@ void KlipperWidget::checkClipData( const
     }
 
     // store old contents:
-    if ( selectionMode )
-        m_lastSelection = lastClipRef;
+    if ( mode == QClipboard::Selection )
+	m_lastSelection = lastClipRef;
     else
         m_lastClipboard = lastClipRef;
 
@@ -698,34 +688,15 @@ void KlipperWidget::checkClipData( const
         applyClipChanges( lastClipRef );
     }
 }
-
-void KlipperWidget::setClipboard( const QString& text, bool selectionMode )
-{
-    setClipboard( text, selectionMode ? Selection : Clipboard );
-}
 
-void KlipperWidget::setClipboard( const QString& text, int mode )
+void KlipperWidget::setClipboard( const QString& text, QClipboard::Mode mode )
 {
     bool blocked = clip->signalsBlocked();
     clip->blockSignals( true ); // ### this might break other kicker applets
-
-    KClipboard *klip = KClipboard::self();
-    bool implicit = klip->implicitSelection();
-    bool synchronize = klip->isSynchronizing();
-    klip->setImplicitSelection( false );
-    klip->setSynchronizing( false );
-
-    if ( mode & Selection ) {
-        clip->setSelectionMode( true );
-        clip->setText( text );
-    }
-    if ( mode & Clipboard ) {
-        clip->setSelectionMode( false );
-        clip->setText( text );
-    }
 
-    klip->setImplicitSelection( implicit );
-    klip->setSynchronizing( synchronize );
+// w�rde beides setzen !!!
+    // KClipboard::setClipboard() does the locking for us.
+    KClipboard::setClipboard( text, mode );
 
     clip->blockSignals( blocked );
 }
Index: klipper/toplevel.h
===================================================================
RCS file: /home/kde/kdebase/klipper/toplevel.h,v
retrieving revision 1.39
diff -u -p -r1.39 toplevel.h
--- klipper/toplevel.h	2002/09/30 12:16:02	1.39
+++ klipper/toplevel.h	2002/10/28 19:29:54
@@ -19,8 +19,8 @@
 #include <qtimer.h>
 #include <qpixmap.h>
 #include <dcopobject.h>
+#include <qclipboard.h>
 
-class QClipboard;
 class KToggleAction;
 class URLGrabber;
 
@@ -31,7 +31,7 @@ class KlipperWidget : public QWidget, pu
 
 k_dcop:
     QString getClipboardContents();
-    void setClipboardContents(QString s);
+    void setClipboardContents(const QString& s);
     void clearClipboardContents();
 
 public:
@@ -56,17 +56,16 @@ protected:
      * @returns the contents of the selection or, if empty, the contents of
      * the clipboard.
      */
-    QString clipboardContents( bool *isSelection = 0L );
+    QString clipboardContents( QClipboard::Mode *mode = 0L );
 
     void removeFromHistory( const QString& text );
     void setEmptyClipboard();
 
-    void clipboardSignalArrived( bool selectionMode );
-    void checkClipData( const QString& text, bool selectionMode );
+    void clipboardSignalArrived( QClipboard::Mode mode );
+    void checkClipData( const QString& text, QClipboard::Mode mode );
     void applyClipChanges( const QString& text );
 
-    void setClipboard( const QString& text, int mode );
-    void setClipboard( const QString& text, bool selectionMode );
+    void setClipboard( const QString& text, QClipboard::Mode mode );
     bool ignoreClipboardChanges() const;
     
     KConfig* config() const { return m_config; }
@@ -89,16 +88,14 @@ private slots:
     void slotMoveSelectedToTop();
 
     void slotSelectionChanged() {
-        clipboardSignalArrived( true );
+        clipboardSignalArrived( QClipboard::Selection );
     }
     void slotClipboardChanged() {
-        clipboardSignalArrived( false );
+        clipboardSignalArrived( QClipboard::Clipboard );
     }
 
 
 private:
-    enum SelectionMode { Clipboard = 1, Selection = 2 };
-
     QClipboard *clip;
 
     QString m_lastString;


More information about the kde-core-devel mailing list