]> granicus.if.org Git - transmission/commitdiff
(trunk gtk) #2500 "Torrent details window should be single-instance per torrent"...
authorCharles Kerr <charles@transmissionbt.com>
Tue, 8 Dec 2009 20:34:46 +0000 (20:34 +0000)
committerCharles Kerr <charles@transmissionbt.com>
Tue, 8 Dec 2009 20:34:46 +0000 (20:34 +0000)
gtk/main.c

index cde8d708456dd2c36eb6e9612d41ec83b12ff9d1..0137959860f4e7c68e056116cbe4b4ee541961b6 100644 (file)
@@ -88,6 +88,105 @@ struct cbdata
     GtkTreeSelection  * sel;
 };
 
+/**
+***
+**/
+
+static int
+compareInts( const void * a, const void * b )
+{
+    return *(int*)a - *(int*)b;
+}
+
+static char*
+getDetailsDialogKey( GSList * id_list )
+{
+    int i;
+    int n;
+    int * ids;
+    GSList * l;
+    GString * gstr = g_string_new( NULL );
+
+    n = g_slist_length( id_list );
+    ids = g_new( int, n );
+    i = 0;
+    for( l=id_list; l!=NULL; l=l->next )
+        ids[i++] = GPOINTER_TO_INT( l->data );
+    g_assert( i == n );
+    qsort( ids, n, sizeof(int), compareInts );
+
+    for( i=0; i<n; ++i )
+        g_string_append_printf( gstr, "%d ", ids[i] );
+
+    g_free( ids );
+    return g_string_free( gstr, FALSE );
+}
+
+struct DetailsDialogHandle
+{
+    char * key;
+    GtkWidget * dialog;
+};
+
+static GSList*
+getSelectedTorrentIds( struct cbdata * data )
+{
+    GtkTreeSelection * s;
+    GtkTreeModel * model;
+    GSList * ids = NULL;
+    GList * selrows = NULL;
+    GList * l;
+
+    /* build a list of the selected torrents' ids */
+    s = tr_window_get_selection( data->wind );
+    for( selrows=l=gtk_tree_selection_get_selected_rows(s,&model); l; l=l->next ) {
+        GtkTreeIter iter;
+        if( gtk_tree_model_get_iter( model, &iter, l->data ) ) {
+            tr_torrent * tor;
+            gtk_tree_model_get( model, &iter, MC_TORRENT_RAW, &tor, -1 );
+            ids = g_slist_append( ids, GINT_TO_POINTER( tr_torrentId( tor ) ) );
+        }
+    }
+
+    return ids;
+}
+
+static struct DetailsDialogHandle*
+findDetailsDialogFromIds( struct cbdata * cbdata, GSList * ids )
+{
+    GSList * l;
+    struct DetailsDialogHandle * ret = NULL;
+    char * key = getDetailsDialogKey( ids );
+
+    for( l=cbdata->details; l!=NULL && ret==NULL; l=l->next ) {
+        struct DetailsDialogHandle * h = l->data;
+        if( !strcmp( h->key, key ) )
+            ret = h;
+    }
+
+    g_free( key );
+    return ret;
+}
+
+static struct DetailsDialogHandle*
+findDetailsDialogFromWidget( struct cbdata * cbdata, gpointer w )
+{
+    GSList * l;
+    struct DetailsDialogHandle * ret = NULL;
+
+    for( l=cbdata->details; l!=NULL && ret==NULL; l=l->next ) {
+        struct DetailsDialogHandle * h = l->data;
+        if( h->dialog == w )
+            ret = h;
+    }
+
+    return ret;
+}
+
+/***
+****
+***/
+
 static void           appsetup( TrWindow * wind,
                                 GSList *   args,
                                 struct     cbdata *,
@@ -247,34 +346,6 @@ refreshActions( struct cbdata * data )
     }
 }
 
-static void
-refreshDetailsDialog( struct cbdata * data, GtkWidget * details )
-{
-    GtkTreeSelection * s;
-    GtkTreeModel * model;
-    GSList * ids = NULL;
-    GList * selrows = NULL;
-    GList * l;
-
-    /* build a list of the selected torrents' ids */
-    s = tr_window_get_selection( data->wind );
-    for( selrows=l=gtk_tree_selection_get_selected_rows(s,&model); l; l=l->next ) {
-        GtkTreeIter iter;
-        if( gtk_tree_model_get_iter( model, &iter, l->data ) ) {
-            tr_torrent * tor;
-            gtk_tree_model_get( model, &iter, MC_TORRENT_RAW, &tor, -1 );
-            ids = g_slist_append( ids, GINT_TO_POINTER( tr_torrentId( tor ) ) );
-        }
-    }
-
-    torrent_inspector_set_torrents( details, ids );
-
-    /* cleanup */
-    g_slist_free( ids );
-    g_list_foreach( selrows, (GFunc)gtk_tree_path_free, NULL );
-    g_list_free( selrows );
-}
-
 static void
 selectionChangedCB( GtkTreeSelection * s UNUSED, gpointer data )
 {
@@ -707,10 +778,20 @@ onSessionClosed( gpointer gdata )
     struct cbdata * cbdata = gdata;
 
     /* shutdown the gui */
-    if( cbdata->details ) {
-        g_slist_foreach( cbdata->details, (GFunc)gtk_widget_destroy, NULL );
+    if( cbdata->details != NULL )
+    {
+        GSList * l;
+        for( l=cbdata->details; l!=NULL; l=l->next )
+        {
+            struct DetailsDialogHandle * h = l->data;
+            gtk_widget_destroy( h->dialog );
+            g_free( h->key );
+            g_free( h );
+        }
         g_slist_free( cbdata->details );
+        cbdata->details = NULL;
     }
+
     if( cbdata->prefs )
         gtk_widget_destroy( GTK_WIDGET( cbdata->prefs ) );
     if( cbdata->wind )
@@ -1399,7 +1480,14 @@ static void
 detailsClosed( gpointer gdata, GObject * dead )
 {
     struct cbdata * data = gdata;
-    data->details = g_slist_remove( data->details, dead );
+    struct DetailsDialogHandle * h = findDetailsDialogFromWidget( data, dead );
+
+    if( h != NULL )
+    {
+        data->details = g_slist_remove( data->details, h );
+        g_free( h->key );
+        g_free( h );
+    }
 }
 
 static void
@@ -1488,11 +1576,20 @@ doAction( const char * action_name, gpointer user_data )
     }
     else if( !strcmp( action_name, "show-torrent-properties" ) )
     {
-        GtkWidget * w = torrent_inspector_new( GTK_WINDOW( data->wind ), data->core );
-        data->details = g_slist_prepend( data->details, w );
-        g_object_weak_ref( G_OBJECT( w ), detailsClosed, data );
-        refreshDetailsDialog( data, w );
-        gtk_widget_show( w );
+        GtkWidget * w;
+        GSList * ids = getSelectedTorrentIds( data );
+        struct DetailsDialogHandle * h = findDetailsDialogFromIds( data, ids );
+        if( h != NULL )
+            w = h->dialog;
+        else {
+            h = g_new( struct DetailsDialogHandle, 1 );
+            h->key = getDetailsDialogKey( ids );
+            h->dialog = w = torrent_inspector_new( GTK_WINDOW( data->wind ), data->core );
+            torrent_inspector_set_torrents( w, ids );
+            data->details = g_slist_append( data->details, h );
+            g_object_weak_ref( G_OBJECT( w ), detailsClosed, data );
+        }
+        gtk_window_present( GTK_WINDOW( w ) );
     }
     else if( !strcmp( action_name, "update-tracker" ) )
     {