From e2158a0f0b1957b8b3eef886edbd7c5939bfc805 Mon Sep 17 00:00:00 2001 From: Michele Calgaro Date: Thu, 28 Jan 2021 21:37:43 +0900 Subject: Fixed random SEGV in Konqueror caused by klipper when the clipboard was being cleared. This resolves issue #147. Signed-off-by: Michele Calgaro --- klipper/toplevel.cpp | 66 +++++++++++++++++++++++++++++++++++++++++----------- klipper/toplevel.h | 4 ++++ 2 files changed, 56 insertions(+), 14 deletions(-) diff --git a/klipper/toplevel.cpp b/klipper/toplevel.cpp index a338216d9..ecdac5af7 100644 --- a/klipper/toplevel.cpp +++ b/klipper/toplevel.cpp @@ -146,6 +146,7 @@ KlipperWidget::KlipperWidget( TQWidget *parent, TDEConfig* config ) connect( &m_overflowClearTimer, TQT_SIGNAL( timeout()), TQT_SLOT( slotClearOverflow())); m_overflowClearTimer.start( 1000 ); connect( &m_pendingCheckTimer, TQT_SIGNAL( timeout()), TQT_SLOT( slotCheckPending())); + connect( &m_setClipboardTimer, TQT_SIGNAL( timeout()), TQT_SLOT( slotDelayedSetClipboard())); m_history = new History( this, "main_history" ); @@ -809,6 +810,41 @@ void KlipperWidget::slotCheckPending() newClipData( true ); // always selection } +void KlipperWidget::slotDelayedSetClipboard() +{ + const HistoryItem *top = history()->first(); + if (top) + { + if (bCheckForEmpty) + { + TQMimeSource *data = clip->data( bSavedSelectionMode ? TQClipboard::Selection : TQClipboard::Clipboard ); + if ( !data ) + { + kdWarning("No data in clipboard. This is not supposed to happen." ); + return; + } + + bool clipEmpty = ( data->format() == 0L ); + if ( clipEmpty && bNoNullClipboard ) + { + // keep old clipboard after someone set it to null +#ifdef NOISY_KLIPPER + kdDebug() << "Resetting clipboard (Prevent empty clipboard)" << endl; +#endif + setClipboard( *top, bSavedSelectionMode ? Selection : Clipboard ); + return; + } + } + else + { +#ifdef NOISY_KLIPPER + kdDebug() << "Syncing selection and clipboard" << endl; +#endif + setClipboard( *top, bSavedSelectionMode ? Selection : Clipboard ); + } + } +} + void KlipperWidget::checkClipData( bool selectionMode ) { if ( ignoreClipboardChanges() ) // internal to klipper, ignoring TQSpinBox selections @@ -868,15 +904,14 @@ void KlipperWidget::checkClipData( bool selectionMode ) bool changed = data->serialNumber() != lastSerialNo; bool clipEmpty = ( data->format() == 0L ); - if ( changed && clipEmpty && bNoNullClipboard ) { - const HistoryItem* top = history()->first(); - if ( top ) { - // keep old clipboard after someone set it to null -#ifdef NOISY_KLIPPER - kdDebug() << "Resetting clipboard (Prevent empty clipboard)" << endl; -#endif - setClipboard( *top, selectionMode ? Selection : Clipboard ); - } + if ( changed && clipEmpty && bNoNullClipboard ) + { + // Make sure to call setClipboard() through the event loop. + // Using a direct call may crash another application that was + // changing the clipboard at the same time. + bSavedSelectionMode = selectionMode; + bCheckForEmpty = true; + m_setClipboardTimer.start(100, TRUE); return; } @@ -945,11 +980,14 @@ void KlipperWidget::checkClipData( bool selectionMode ) #ifdef NOISY_KLIPPER kdDebug() << "Synchronize?" << ( bSynchronize ? "yes" : "no" ) << endl; #endif - if ( bSynchronize ) { - const HistoryItem* topItem = history()->first(); - if ( topItem ) { - setClipboard( *topItem, selectionMode ? Clipboard : Selection ); - } + if ( bSynchronize ) + { + // Make sure to call setClipboard() through the event loop. + // Using a direct call may crash another application that was + // changing the clipboard at the same time. + bSavedSelectionMode = !selectionMode; // inverted in order to sync + bCheckForEmpty = false; + m_setClipboardTimer.start(100, TRUE); } } diff --git a/klipper/toplevel.h b/klipper/toplevel.h index 3dbdf440c..e48ab9d83 100644 --- a/klipper/toplevel.h +++ b/klipper/toplevel.h @@ -154,6 +154,7 @@ private slots: void slotClearOverflow(); void slotCheckPending(); + void slotDelayedSetClipboard(); private: @@ -186,6 +187,8 @@ private: bool bSynchronize :1; bool bSelectionTextOnly :1; bool bIgnoreImages :1; + bool bSavedSelectionMode :1; + bool bCheckForEmpty :1; /** * Avoid reacting to our own changes, using this @@ -201,6 +204,7 @@ private: TDEConfig* m_config; TQTimer m_overflowClearTimer; TQTimer m_pendingCheckTimer; + TQTimer m_setClipboardTimer; bool m_pendingContentsCheck; ClipboardPoll* poll; static TDEAboutData* about_data; -- cgit v1.2.3