diff --git a/configure b/configure index ebeea4092..e7c77c329 100755 --- a/configure +++ b/configure @@ -187,6 +187,11 @@ EOF then CFLAGS_GTK=`pkg-config gtk+-2.0 --cflags` LDFLAGS_GTK=`pkg-config gtk+-2.0 --libs` + if runcmd pkg-config gthread-2.0 + then + CFLAGS_GTK="$CFLAGS_GTK `pkg-config gthread-2.0 --cflags`" + LDFLAGS_GTK="$LDFLAGS_GTK `pkg-config gthread-2.0 --libs`" + fi if gettext_test then echo "yes" diff --git a/gtk/conf.h b/gtk/conf.h index dee69383d..d312a4df0 100644 --- a/gtk/conf.h +++ b/gtk/conf.h @@ -58,5 +58,6 @@ cf_freestate(benc_val_t *state); #define PREF_DIR "download-directory" #define PREF_ADDSTD "add-behavior-standard" #define PREF_ADDIPC "add-behavior-ipc" +#define PREF_MSGLEVEL "message-level" #endif /* TG_CONF_H */ diff --git a/gtk/dialogs.c b/gtk/dialogs.c index 030830322..ef66573d4 100644 --- a/gtk/dialogs.c +++ b/gtk/dialogs.c @@ -58,8 +58,6 @@ struct addcb { GtkButtonBox *altbox; }; -static void -windclosed(GtkWidget *widget SHUTUP, gpointer gdata); static void clicklimitbox(GtkWidget *widget, gpointer gdata); static void @@ -165,8 +163,8 @@ saveprefwidget(GtkWindow *parent, GtkWidget *widget) { } } -void -makeprefwindow(GtkWindow *parent, TrBackend *back, gboolean *opened) { +GtkWidget * +makeprefwindow(GtkWindow *parent, TrBackend *back) { char *title = g_strdup_printf(_("%s Preferences"), g_get_application_name()); GtkWidget *wind = gtk_dialog_new_with_buttons(title, parent, GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR, @@ -199,8 +197,6 @@ makeprefwindow(GtkWindow *parent, TrBackend *back, gboolean *opened) { GtkTreeIter iter; GtkCellRenderer *rend; - *opened = TRUE; - g_free(title); gtk_widget_set_name(wind, "TransmissionDialog"); gtk_table_set_col_spacings(GTK_TABLE(table), 8); @@ -302,15 +298,9 @@ makeprefwindow(GtkWindow *parent, TrBackend *back, gboolean *opened) { gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(wind)->vbox), table); g_signal_connect_data(wind, "response", G_CALLBACK(clickdialog), data, freedata, 0); - g_signal_connect(wind, "destroy", G_CALLBACK(windclosed), opened); gtk_widget_show_all(wind); -} -static void -windclosed(GtkWidget *widget SHUTUP, gpointer gdata) { - gboolean *preachy_gcc = gdata; - - *preachy_gcc = FALSE; + return wind; } static void diff --git a/gtk/dialogs.h b/gtk/dialogs.h index 625320fb9..d14cdd6f0 100644 --- a/gtk/dialogs.h +++ b/gtk/dialogs.h @@ -29,8 +29,8 @@ #include "tr_torrent.h" #include "util.h" -void -makeprefwindow(GtkWindow *parent, TrBackend *back, gboolean *opened); +GtkWidget * +makeprefwindow(GtkWindow *parent, TrBackend *back); /* set the upload limit based on saved prefs */ void diff --git a/gtk/main.c b/gtk/main.c index 995db01a9..1d027df18 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -38,6 +38,7 @@ #include "conf.h" #include "dialogs.h" #include "ipc.h" +#include "msgwin.h" #include "tr_backend.h" #include "tr_torrent.h" #include "tr_cell_renderer_progress.h" @@ -62,6 +63,7 @@ struct cbdata { GtkWidget **buttons; guint timer; gboolean prefsopen; + gboolean msgwinopen; GtkWidget *stupidpopuphack; gboolean closing; }; @@ -112,6 +114,8 @@ listpopup(GtkWidget *widget, gpointer gdata); void dopopupmenu(GdkEventButton *event, struct cbdata *data); void +boolwindclosed(GtkWidget *widget SHUTUP, gpointer gdata); +void actionclick(GtkWidget *widget, gpointer gdata); gint intrevcmp(gconstpointer a, gconstpointer b); @@ -138,7 +142,8 @@ void fatalsig(int sig); #define LIST_ACTION "torrent-list-action" -enum listact { ACT_OPEN, ACT_START, ACT_STOP, ACT_DELETE, ACT_INFO, ACT_PREF }; +enum listact { + ACT_OPEN, ACT_START, ACT_STOP, ACT_DELETE, ACT_INFO, ACT_PREF, ACT_DEBUG }; struct { const gchar *name; const gchar *id; enum listact act; gboolean nomenu; int avail; const char *ttext; const char *tpriv; } @@ -157,6 +162,7 @@ actionitems[] = { N_("Show additional information about a torrent"), "XXX"}, {N_("Preferences"), GTK_STOCK_PREFERENCES, ACT_PREF, TRUE, 0, N_("Customize application behavior"), "XXX"}, + {N_("Open debug window"), NULL, ACT_DEBUG, FALSE, 0, NULL, NULL}, }; #define CBDATA_PTR "callback-data-pointer" @@ -177,6 +183,7 @@ main(int argc, char **argv) { gboolean didinit, didlock; safepipe(); + msgwin_init(); argfiles = readargs(argc, argv); @@ -222,6 +229,9 @@ main(int argc, char **argv) { g_free(err); } + /* set libT message level */ + msgwin_loadpref(); + back = tr_backend_new(); /* set the upload limit */ @@ -313,6 +323,7 @@ makewind(GtkWidget *wind, TrBackend *back, benc_val_t *state, GList *args) { data->bar = GTK_STATUSBAR(status); data->buttons = NULL; data->prefsopen = FALSE; + data->msgwinopen = FALSE; data->stupidpopuphack = NULL; data->closing = FALSE; @@ -392,6 +403,10 @@ makewind_toolbar(struct cbdata *data) { data->buttons = g_new(GtkWidget*, ALEN(actionitems)); for(ii = 0; ii < ALEN(actionitems); ii++) { + if( NULL == actionitems[ii].id ) { + data->buttons[ii] = NULL; + continue; + } item = gtk_tool_button_new_from_stock(actionitems[ii].id); data->buttons[ii] = GTK_WIDGET(item); gtk_tool_button_set_label(GTK_TOOL_BUTTON(item), @@ -518,7 +533,8 @@ winclose(GtkWidget *widget SHUTUP, GdkEvent *event SHUTUP, gpointer gdata) { /* yes, start the exit timer and disable widgets */ edata->timer = g_timeout_add(EXIT_CHECK_INTERVAL, exitcheck, edata); for(ii = 0; ii < ALEN(actionitems); ii++) - gtk_widget_set_sensitive(data->buttons[ii], FALSE); + if( NULL != data->buttons[ii] ) + gtk_widget_set_sensitive(data->buttons[ii], FALSE); gtk_widget_set_sensitive(GTK_WIDGET(data->view), FALSE); } @@ -820,6 +836,9 @@ updatemodel(gpointer gdata) { if(!data->closing) tr_backend_torrents_stopped(data->back); + /* update the message window */ + msgwin_update(); + return TRUE; } @@ -904,6 +923,13 @@ dopopupmenu(GdkEventButton *event, struct cbdata *data) { gdk_event_get_time((GdkEvent*)event)); } +void +boolwindclosed(GtkWidget *widget SHUTUP, gpointer gdata) { + gboolean *preachy_gcc = gdata; + + *preachy_gcc = FALSE; +} + void actionclick(GtkWidget *widget, gpointer gdata) { struct cbdata *data = gdata; @@ -916,6 +942,7 @@ actionclick(GtkWidget *widget, gpointer gdata) { TrTorrent *tor; unsigned int actoff, status; gboolean changed; + GtkWidget * win; act = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), LIST_ACTION)); @@ -924,8 +951,20 @@ actionclick(GtkWidget *widget, gpointer gdata) { makeaddwind(data->wind, addtorrents, data); return; case ACT_PREF: - if(!data->prefsopen) - makeprefwindow(data->wind, data->back, &data->prefsopen); + if( !data->prefsopen ) { + data->prefsopen = TRUE; + win = makeprefwindow( data->wind, data->back ); + g_signal_connect( win, "destroy", G_CALLBACK( boolwindclosed ), + &data->prefsopen ); + } + return; + case ACT_DEBUG: + if( !data->msgwinopen ) { + data->msgwinopen = TRUE; + win = msgwin_create(); + g_signal_connect( win, "destroy", G_CALLBACK( boolwindclosed ), + &data->msgwinopen ); + } return; case ACT_START: case ACT_STOP: @@ -980,6 +1019,7 @@ actionclick(GtkWidget *widget, gpointer gdata) { break; case ACT_OPEN: case ACT_PREF: + case ACT_DEBUG: break; } } diff --git a/gtk/msgwin.c b/gtk/msgwin.c new file mode 100644 index 000000000..da8c6fbbf --- /dev/null +++ b/gtk/msgwin.c @@ -0,0 +1,210 @@ +/****************************************************************************** + * $Id$ + * + * Copyright (c) 2006 Transmission authors and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + *****************************************************************************/ + +#include + +#include +#include + +#include "conf.h" +#include "msgwin.h" +#include "transmission.h" +#include "util.h" + +#define COL_LVL 0 +#define COL_MSG 1 + +static void +changelevel( GtkToggleButton * button, gpointer data ); +static void +addmsg( int level, const char * msg ); + + +static GMutex * listmutex = NULL; +static GSList * messages = NULL; +static GtkTextBuffer * textbuf = NULL; + +void +msgwin_init( void ) { + if( !g_thread_supported() ) + g_thread_init( NULL ); + listmutex = g_mutex_new(); + tr_setMessageFunction( addmsg ); +} + +GtkWidget * +msgwin_create( void ) { + GtkWidget * win, * vbox, * scroll, * text; + GtkWidget * frame, * bbox, * err, * inf, * dbg; + + if( NULL == textbuf ) + textbuf = gtk_text_buffer_new( NULL ); + + win = gtk_window_new( GTK_WINDOW_TOPLEVEL ); + vbox = gtk_vbox_new( FALSE, 0 ); + scroll = gtk_scrolled_window_new( NULL, NULL ); + text = gtk_text_view_new_with_buffer( textbuf ); + frame = gtk_frame_new( NULL ); + bbox = gtk_hbutton_box_new(); + err = gtk_radio_button_new_with_label( NULL, _( "Error" ) ); + inf = gtk_radio_button_new_with_label_from_widget( + GTK_RADIO_BUTTON( err ), _( "Info" ) ); + dbg = gtk_radio_button_new_with_label_from_widget( + GTK_RADIO_BUTTON( err ), _( "Debug" ) ); + + gtk_text_view_set_editable( GTK_TEXT_VIEW( text ), FALSE ); + + gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( scroll ), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC ); + + gtk_container_add( GTK_CONTAINER( scroll ), text ); + gtk_container_add( GTK_CONTAINER( frame ), scroll ); + + gtk_frame_set_shadow_type( GTK_FRAME( frame ), GTK_SHADOW_IN ); + gtk_box_pack_start( GTK_BOX( vbox ), frame, TRUE, TRUE, 0 ); + + gtk_button_box_set_layout( GTK_BUTTON_BOX( bbox), GTK_BUTTONBOX_SPREAD ); + + gtk_container_add( GTK_CONTAINER( bbox ), err ); + gtk_container_add( GTK_CONTAINER( bbox ), inf ); + gtk_container_add( GTK_CONTAINER( bbox ), dbg ); + gtk_box_pack_start( GTK_BOX( vbox ), bbox, FALSE, FALSE, 0 ); + + gtk_container_add( GTK_CONTAINER( win ), vbox ); + + switch( tr_getMessageLevel() ) { + case TR_MSG_ERR: + gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( err ), TRUE ); + break; + case TR_MSG_INF: + gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( inf ), TRUE ); + break; + case TR_MSG_DBG: + gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( dbg ), TRUE ); + break; + } + + g_signal_connect( err, "toggled", G_CALLBACK( changelevel ), + GINT_TO_POINTER( TR_MSG_ERR ) ); + g_signal_connect( inf, "toggled", G_CALLBACK( changelevel ), + GINT_TO_POINTER( TR_MSG_INF ) ); + g_signal_connect( dbg, "toggled", G_CALLBACK( changelevel ), + GINT_TO_POINTER( TR_MSG_DBG ) ); + + gtk_widget_show_all( win ); + + return win; +} + +static void +changelevel( GtkToggleButton * button, gpointer data ) { + int level; + char * ignored; + + if( gtk_toggle_button_get_active( button ) ) { + level = GPOINTER_TO_INT( data ); + tr_setMessageLevel( level ); + switch( level ) { + case TR_MSG_ERR: + cf_setpref( PREF_MSGLEVEL, "error" ); + break; + case TR_MSG_INF: + cf_setpref( PREF_MSGLEVEL, "info" ); + break; + case TR_MSG_DBG: + cf_setpref( PREF_MSGLEVEL, "debug" ); + break; + } + cf_saveprefs( &ignored ); + g_free( ignored ); + msgwin_update(); + } +} + +void +msgwin_loadpref( void ) { + const char * pref; + + pref = cf_getpref( PREF_MSGLEVEL ); + if( NULL == pref ) + return; + + if( 0 == strcmp( "error", pref ) ) + tr_setMessageLevel( TR_MSG_ERR ); + else if( 0 == strcmp( "info", pref ) ) + tr_setMessageLevel( TR_MSG_INF ); + else if( 0 == strcmp( "debug", pref ) ) + tr_setMessageLevel( TR_MSG_DBG ); +} + +void +msgwin_update( void ) { + GSList * ii; + GtkTextIter iter; + + if( NULL == textbuf ) + return; + + g_mutex_lock( listmutex ); + + if( NULL != messages ) { + for( ii = messages; NULL != ii; ii = ii->next ) { + gtk_text_buffer_get_end_iter( textbuf, &iter ); + gtk_text_buffer_insert( textbuf, &iter, ii->data, -1 ); + g_free( ii->data ); + } + g_slist_free( messages ); + messages = NULL; + } + + g_mutex_unlock( listmutex ); +} + +static void +addmsg( int level, const char * msg ) { + char * str; + + g_mutex_lock( listmutex ); + + switch( level ) + { + case TR_MSG_ERR: + str = _( "ERR" ); + break; + case TR_MSG_INF: + str = _( "INF" ); + break; + case TR_MSG_DBG: + str = _( "DBG" ); + break; + default: + str = _( "???" ); + break; + } + + str = g_strdup_printf( "%s: %s\n", str, msg ); + messages = g_slist_append( messages, str ); + + g_mutex_unlock( listmutex ); +} diff --git a/gtk/msgwin.h b/gtk/msgwin.h new file mode 100644 index 000000000..55c3f62b6 --- /dev/null +++ b/gtk/msgwin.h @@ -0,0 +1,40 @@ +/****************************************************************************** + * $Id$ + * + * Copyright (c) 2005-2006 Transmission authors and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + *****************************************************************************/ + +#ifndef TG_MSGWIN_H +#define TG_MSGWIN_H + +void +msgwin_init( void ); + +GtkWidget * +msgwin_create( void ); + +void +msgwin_update( void ); + +void +msgwin_loadpref( void ); + +#endif /* TG_MSGWIN_H */ diff --git a/mk/gtk.mk b/mk/gtk.mk index 9430fbba8..fc29eb839 100644 --- a/mk/gtk.mk +++ b/mk/gtk.mk @@ -3,7 +3,7 @@ include ../mk/config.mk include ../mk/common.mk -SRCS = conf.c dialogs.c io.c ipc.c main.c tr_backend.c tr_torrent.c \ +SRCS = conf.c dialogs.c io.c ipc.c main.c msgwin.c tr_backend.c tr_torrent.c \ tr_cell_renderer_progress.c util.c OBJS = $(SRCS:%.c=%.o)