From 487783d1e2833495f2f8cda0d6a2465bc79e315a Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Tue, 27 Apr 2010 03:10:32 +0000 Subject: [PATCH] (trunk qt) #2840 "opening magnets with qt client opens new instances" -- fixed in trunk for 2.00 --- qt/app.cc | 84 ++++++++++++++++++++++++++++++++++++++++++---- qt/app.h | 5 +++ qt/dbus-adaptor.cc | 34 +++++++++++++++++++ qt/dbus-adaptor.h | 37 ++++++++++++++++++++ qt/mainwin.cc | 9 ++++- qt/mainwin.h | 3 ++ qt/qtr.pro | 6 ++-- qt/session.cc | 49 ++++++++++++++++++--------- 8 files changed, 200 insertions(+), 27 deletions(-) create mode 100644 qt/dbus-adaptor.cc create mode 100644 qt/dbus-adaptor.h diff --git a/qt/app.cc b/qt/app.cc index 3b5199967..431bc432d 100644 --- a/qt/app.cc +++ b/qt/app.cc @@ -14,6 +14,9 @@ #include #include +#include +#include +#include #include #include #include @@ -26,6 +29,7 @@ #include #include "app.h" +#include "dbus-adaptor.h" #include "mainwin.h" #include "options.h" #include "prefs.h" @@ -37,6 +41,10 @@ namespace { + const char * DBUS_SERVICE ( "com.transmissionbt.Transmission" ); + const char * DBUS_OBJECT_PATH ( "/com/transmissionbt/Transmission" ); + const char * DBUS_INTERFACE ( "com.transmissionbt.Transmission" ); + const char * MY_NAME( "transmission" ); const tr_option opts[] = @@ -218,6 +226,14 @@ MyApp :: MyApp( int& argc, char ** argv ): for( QStringList::const_iterator it=filenames.begin(), end=filenames.end(); it!=end; ++it ) mySession->addTorrent( *it ); + + // register as the dbus handler for Transmission + new TrDBusAdaptor( this ); + QDBusConnection bus = QDBusConnection::sessionBus(); + if (!bus.registerService("com.transmissionbt.Transmission")) + fprintf(stderr, "%s\n", qPrintable(bus.lastError().message())); + if( !bus.registerObject( "/com/transmissionbt/Transmission", this )) + fprintf(stderr, "%s\n", qPrintable(bus.lastError().message())); } void @@ -298,19 +314,29 @@ MyApp :: refreshTorrents( ) } } +/*** +**** +***/ + void -MyApp :: addTorrent( const QString& filename ) +MyApp :: addTorrent( const QString& key ) { - if( myPrefs->getBool( Prefs :: OPTIONS_PROMPT ) ) { - Options * o = new Options( *mySession, *myPrefs, filename, myWindow ); + if( !myPrefs->getBool( Prefs :: OPTIONS_PROMPT ) ) + mySession->addTorrent( key ); + else if( !QFile( key ).exists( ) ) + myWindow->openURL( key ); + else { + Options * o = new Options( *mySession, *myPrefs, key, myWindow ); o->show( ); - QApplication :: alert( o ); - } else { - mySession->addTorrent( filename ); - QApplication :: alert ( myWindow ); } + raise( ); } +void +MyApp :: raise( ) +{ + QApplication :: alert ( myWindow ); +} /*** **** @@ -319,6 +345,50 @@ MyApp :: addTorrent( const QString& filename ) int main( int argc, char * argv[] ) { + // find .torrents, URLs, magnet links, etc in the command-line args + int c; + QStringList addme; + const char * optarg; + char ** argvv = argv; + while( ( c = tr_getopt( getUsage( ), argc, (const char **)argvv, opts, &optarg ) ) ) + if( c == TR_OPT_UNK ) + addme.append( optarg ); + + // try to delegate the work to an existing copy of Transmission + // before starting ourselves... + bool delegated = false; + QDBusConnection bus = QDBusConnection::sessionBus(); + for( int i=0, n=addme.size(); i arguments; + arguments.push_back( QVariant( key ) ); + request.setArguments( arguments ); + + QDBusMessage response = bus.call( request ); + arguments = response.arguments( ); + delegated |= (arguments.size()==1) && arguments[0].toBool(); + } + if( addme.empty() ) + { + QDBusMessage request = QDBusMessage::createMethodCall( DBUS_SERVICE, + DBUS_OBJECT_PATH, + DBUS_INTERFACE, + "PresentWindow" ); + QDBusMessage response = bus.call( request ); + QList arguments = response.arguments( ); + delegated |= (arguments.size()==1) && arguments[0].toBool(); + } + + if( delegated ) + return 0; + + tr_optind = 1; MyApp app( argc, argv ); return app.exec( ); } diff --git a/qt/app.h b/qt/app.h index 4e02caeff..4d8b2c052 100644 --- a/qt/app.h +++ b/qt/app.h @@ -30,6 +30,9 @@ class MyApp: public QApplication MyApp( int& argc, char ** argv ); virtual ~MyApp( ); + public: + void raise( ); + private: Prefs * myPrefs; Session * mySession; @@ -45,6 +48,8 @@ class MyApp: public QApplication void consentGiven( ); void refreshPref( int key ); void refreshTorrents( ); + + public slots: void addTorrent( const QString& ); private: diff --git a/qt/dbus-adaptor.cc b/qt/dbus-adaptor.cc new file mode 100644 index 000000000..624a6c548 --- /dev/null +++ b/qt/dbus-adaptor.cc @@ -0,0 +1,34 @@ +/* + * This file Copyright (C) 2010 Mnemosyne LLC + * + * This file is licensed by the GPL version 2. Works owned by the + * Transmission project are granted a special exemption to clause 2(b) + * so that the bulk of its code can remain under the MIT license. + * This exemption does not extend to derived works not owned by + * the Transmission project. + * + * $Id:$ + */ + +#include "app.h" +#include "dbus-adaptor.h" + +TrDBusAdaptor :: TrDBusAdaptor( MyApp* app ): + QDBusAbstractAdaptor( app ), + myApp( app ) +{ +} + +bool +TrDBusAdaptor :: PresentWindow( ) +{ + myApp->raise( ); + return true; +} + +bool +TrDBusAdaptor :: AddMetainfo( const QString& str ) +{ + myApp->addTorrent( str ); + return true; +} diff --git a/qt/dbus-adaptor.h b/qt/dbus-adaptor.h new file mode 100644 index 000000000..da94e9fef --- /dev/null +++ b/qt/dbus-adaptor.h @@ -0,0 +1,37 @@ +/* + * This file Copyright (C) 2010 Mnemosyne LLC + * + * This file is licensed by the GPL version 2. Works owned by the + * Transmission project are granted a special exemption to clause 2(b) + * so that the bulk of its code can remain under the MIT license. + * This exemption does not extend to derived works not owned by + * the Transmission project. + * + * $Id:$ + */ + +#ifndef QTR_DBUS_ADAPTOR_H +#define QTR_DBUS_ADAPTOR_H + +class MyApp; + +#include + +class TrDBusAdaptor: public QDBusAbstractAdaptor +{ + Q_OBJECT + Q_CLASSINFO( "D-Bus Interface", "com.transmissionbt.Transmission" ) + + private: + MyApp * myApp; + + public: + TrDBusAdaptor( MyApp* ); + virtual ~TrDBusAdaptor() { } + + public slots: + bool PresentWindow(); + bool AddMetainfo( const QString& ); +}; + +#endif diff --git a/qt/mainwin.cc b/qt/mainwin.cc index cbd1fe05a..2f333a7f0 100644 --- a/qt/mainwin.cc +++ b/qt/mainwin.cc @@ -1114,13 +1114,20 @@ TrMainWindow :: openTorrent( ) void TrMainWindow :: openURL( ) +{ + QString tmp; + openURL( tmp ); +} + +void +TrMainWindow :: openURL( QString url ) { bool ok; const QString key = QInputDialog::getText( this, tr( "Add URL or Magnet Link" ), tr( "Add URL or Magnet Link" ), QLineEdit::Normal, - QString( ), + url, &ok ); if( ok && !key.isEmpty( ) ) mySession.addTorrent( key ); diff --git a/qt/mainwin.h b/qt/mainwin.h index 2d4096ada..537145a4b 100644 --- a/qt/mainwin.h +++ b/qt/mainwin.h @@ -91,6 +91,9 @@ class TrMainWindow: public QMainWindow void updateNetworkIcon( ); QWidgetList myHidden; + public slots: + void openURL( QString ); + private slots: void onDetailsDestroyed( ); void onShowModeClicked( ); diff --git a/qt/qtr.pro b/qt/qtr.pro index f87baafbe..140957b43 100644 --- a/qt/qtr.pro +++ b/qt/qtr.pro @@ -7,7 +7,7 @@ LICENSE = "GPL" target.path = /bin INSTALLS += target -CONFIG += qt thread debug link_pkgconfig +CONFIG += qt qdbus thread debug link_pkgconfig QT += network PKGCONFIG = fontconfig libcurl openssl @@ -23,8 +23,8 @@ TRANSLATIONS += transmission_en.ts transmission_ru.ts FORMS += mainwin.ui RESOURCES += application.qrc -SOURCES += about.cc app.cc details.cc file-tree.cc filters.cc hig.cc \ - license.cc mainwin.cc make-dialog.cc options.cc prefs.cc \ +SOURCES += about.cc app.cc dbus-adaptor.cc details.cc file-tree.cc filters.cc \ + hig.cc license.cc mainwin.cc make-dialog.cc options.cc prefs.cc \ prefs-dialog.cc qticonloader.cc relocate.cc session.cc \ session-dialog.cc squeezelabel.cc stats-dialog.cc torrent.cc \ torrent-delegate.cc torrent-delegate-min.cc torrent-filter.cc \ diff --git a/qt/session.cc b/qt/session.cc index bd6e0eeed..ae80017ea 100644 --- a/qt/session.cc +++ b/qt/session.cc @@ -858,6 +858,17 @@ Session :: addTorrent( QString filename ) addTorrent( filename, myPrefs.getString( Prefs::DOWNLOAD_DIR ) ); } +namespace +{ + bool isLink( const QString& str ) + { + return str.startsWith( "magnet:?" ) + || str.startsWith( "http://" ) + || str.startsWith( "https://" ) + || str.startsWith( "ftp://" ); + } +} + void Session :: addTorrent( QString key, QString localPath ) { @@ -868,23 +879,29 @@ Session :: addTorrent( QString key, QString localPath ) tr_bencDictAddStr( args, "download-dir", qPrintable(localPath) ); tr_bencDictAddBool( args, "paused", !myPrefs.getBool( Prefs::START ) ); - // if "key" is a readable local file, add it as metadata... - // otherwise it's probably a URL or magnet link, so pass it along - // for the daemon to handle - QFile file( key ); - file.open( QIODevice::ReadOnly ); - const QByteArray raw( file.readAll( ) ); - file.close( ); - if( !raw.isEmpty( ) ) - { - int b64len = 0; - char * b64 = tr_base64_encode( raw.constData(), raw.size(), &b64len ); - tr_bencDictAddRaw( args, "metainfo", b64, b64len ); - tr_free( b64 ); - } - else - { + // figure out what to do with "key".... + bool keyHandled = false; + if( !keyHandled && isLink( key )) { tr_bencDictAddStr( args, "filename", key.toUtf8().constData() ); + keyHandled = true; // it's a URL or magnet link... + } + if( !keyHandled ) { + QFile file( key ); + file.open( QIODevice::ReadOnly ); + const QByteArray raw( file.readAll( ) ); + file.close( ); + if( !raw.isEmpty( ) ) { + int b64len = 0; + char * b64 = tr_base64_encode( raw.constData(), raw.size(), &b64len ); + tr_bencDictAddRaw( args, "metainfo", b64, b64len ); + tr_free( b64 ); + keyHandled = true; // it's a local file... + } + } + if( !keyHandled ) { + const QByteArray tmp = key.toUtf8(); + tr_bencDictAddRaw( args, "metainfo", tmp.constData(), tmp.length() ); + keyHandled; // treat it as base64 } exec( &top );