# This patch adds a new field to XQF's Appearance configuration: # Copy+ format. With this you can specify how server information # should be copied to the clipboard when using Copy+ (Ctrl-O). # Valid tags are listed in the preferences dialog. # # 2006-05-27, Wolfgang Frisch # See also http://weblog.frexx.de/2006/05/28/xqf-copy-patch-with-gui/ diff -ruN xqf-1.0.4.org/src/pref.c xqf-1.0.4/src/pref.c --- xqf-1.0.4.org/src/pref.c 2005-10-17 12:17:58.000000000 +0200 +++ xqf-1.0.4/src/pref.c 2006-05-28 03:58:52.000000000 +0200 @@ -113,6 +113,10 @@ int default_show_only_configured_games; char* default_icontheme; +// ---- Copy+ format string patch +char* default_copyplusformat; +// --end-- Copy+ format string patch + int maxretries; int maxsimultaneous; char* qstat_srcip; @@ -195,6 +199,10 @@ static GtkWidget *show_only_configured_games_check_button; static GtkWidget *use_custom_gtkrc_check_button; +// --begin-- Copy+ format string patch +static GtkWidget *copyplusformat_entry; +// --end-- Copy+ format string patch + static GtkWidget *pushlatency_mode_radio_buttons[3]; static GtkWidget *pushlatency_value_spinner; @@ -379,6 +387,10 @@ NULL }; +// --begin-- Copy+ format string patch +void appearance_copyplusformat_default_callback(); +// --end-- Copy+ format string patch + static void game_file_dialog(enum server_type type); static void game_dir_dialog(enum server_type type); static void game_file_activate_callback(enum server_type type); @@ -1051,6 +1063,11 @@ if (i != use_custom_gtkrc) config_set_bool ("use custom gtkrc", use_custom_gtkrc = i); + // --begin-- Copy+ format string patch + default_copyplusformat = strdup_strip (gtk_entry_get_text (GTK_ENTRY (copyplusformat_entry))); + config_set_string ("copyplusformat", (default_copyplusformat)? default_copyplusformat : "bla"); + // --end-- Copy+ format string patch + config_pop_prefix (); /* General */ @@ -3999,6 +4016,12 @@ GtkWidget *frame; GtkWidget *hbox; GtkWidget *vbox; + + // --begin-- Copy+ format string patch + GtkWidget *button; + GtkWidget *label; + // --end-- Copy+ format string patch + GSList *group = NULL; static const char *toolbar_styles[] = { N_("Icons"), N_("Text"), N_("Both") }; int i; @@ -4189,6 +4212,54 @@ gtk_widget_show (page_vbox); + // --begin-- Copy+ format string patch + frame = gtk_frame_new (_("Copy+ format")); + gtk_box_pack_start (GTK_BOX (page_vbox), frame, FALSE, FALSE, 0); + + vbox = gtk_vbox_new (FALSE, 4); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 6); + gtk_container_add (GTK_CONTAINER (frame), vbox); + + hbox = gtk_hbox_new (FALSE, 4); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + + copyplusformat_entry = gtk_entry_new (); + if(default_copyplusformat) { + gtk_entry_set_text (GTK_ENTRY (copyplusformat_entry), default_copyplusformat); + } else { + // set default format string + appearance_copyplusformat_default_callback(); + } + + button = gtk_button_new_with_label (_("Default")); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (appearance_copyplusformat_default_callback), 0); + + gtk_box_pack_start (GTK_BOX (hbox), copyplusformat_entry, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); + + label = gtk_label_new(_("Possible tags:")); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + label = gtk_label_new(" "); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + + gtk_widget_show (button); + gtk_widget_show (label); + gtk_widget_show (copyplusformat_entry); + gtk_widget_show (vbox); + gtk_widget_show (hbox); + gtk_widget_show (frame); + + gtk_widget_show (page_vbox); + // --end-- Copy+ format string patch + + return page_vbox; } @@ -4276,7 +4347,7 @@ gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); gtk_misc_set_padding(GTK_MISC(GTK_BIN(button)->child),4,0); gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (scan_maps_callback), NULL); + GTK_SIGNAL_FUNC (scan_maps_callback), NULL); gtk_widget_show (button); } @@ -5558,6 +5629,7 @@ default_resolve_on_update = config_get_bool ("resolve on update=false"); default_show_only_configured_games = config_get_bool ("show only configured games=false"); default_icontheme = config_get_string ("icontheme"); + default_copyplusformat = config_get_string ("copyplusformat"); set_style(); @@ -5657,6 +5729,14 @@ } */ +// --begin-- Copy+ format string patch +void appearance_copyplusformat_default_callback() +{ + gtk_entry_set_text(GTK_ENTRY(copyplusformat_entry), + " | : | | / players"); +} +// --end-- Copy+ format string patch + void game_file_dialog_ok_callback (GtkWidget *ok_button, gpointer data) { enum server_type type; diff -ruN xqf-1.0.4.org/src/pref.h xqf-1.0.4/src/pref.h --- xqf-1.0.4.org/src/pref.h 2005-10-07 14:55:15.000000000 +0200 +++ xqf-1.0.4/src/pref.h 2006-05-28 02:46:29.000000000 +0200 @@ -100,6 +100,10 @@ extern int default_show_only_configured_games; extern char* default_icontheme; +// --begin-- Copy+ format string patch +extern char* default_copyplusformat; +// --end-- Copy+ format string patch + extern int maxretries; extern int maxsimultaneous; extern char* qstat_srcip; diff -ruN xqf-1.0.4.org/src/rc.c xqf-1.0.4/src/rc.c --- xqf-1.0.4.org/src/rc.c 2005-09-13 18:20:02.000000000 +0200 +++ xqf-1.0.4/src/rc.c 2006-05-28 02:56:45.000000000 +0200 @@ -83,6 +83,10 @@ { "autofavorites", KEYWORD_BOOL, "/" CONFIG_FILE "/General/refresh favorites" }, + // --begin-- Copy+ format string patch + { "copyplusformat", KEYWORD_STRING, "/" CONFIG_FILE "/Appearance/copyplusformat" }, + // --end-- Copy+ format string patch + { "tb_style", KEYWORD_INT, "/" CONFIG_FILE "/Appearance/toolbar style" }, { "tb_tips", KEYWORD_BOOL, "/" CONFIG_FILE "/Appearance/toolbar tips" }, diff -ruN xqf-1.0.4.org/src/utils.c xqf-1.0.4/src/utils.c --- xqf-1.0.4.org/src/utils.c 2005-08-07 18:37:22.000000000 +0200 +++ xqf-1.0.4/src/utils.c 2006-05-28 03:57:19.000000000 +0200 @@ -1159,3 +1159,28 @@ return msg; } + +int str_replace(char* result, int maxlen, const char* source, const char* pattern, const char* replacewith) +{ + char* p; + // we have to use a temporary buffer in case of result and source overlapping + char* wbuf; + + if( maxlen <= strlen(source)+(strlen(replacewith)-strlen(pattern)) ) { + return 1; + } + if( (p=strstr(source,pattern)) == NULL) + return 0; + + wbuf = malloc(maxlen); + wbuf[0]=0; + strncpy(wbuf, source, (p-source)+1); + wbuf[p-source]=0; + strcat(wbuf, replacewith); + p+=strlen(pattern); + strcat(wbuf, p); + strcpy(result, wbuf); + free(wbuf); + + return 0; +} \ No newline at end of file diff -ruN xqf-1.0.4.org/src/utils.h xqf-1.0.4/src/utils.h --- xqf-1.0.4.org/src/utils.h 2005-08-07 11:50:41.000000000 +0200 +++ xqf-1.0.4/src/utils.h 2006-05-28 03:25:10.000000000 +0200 @@ -165,4 +165,14 @@ */ const char* copy_file(const char* src, const char* dest); +/** replace a part of a string (used by for the copy+ format strings) + @param output already allocated buffer for the result + @param maxlen length of result buffer (including trailing zero) + @param source original string + @param pattern search for this pattern + @param replacewith replace with this + @return 0 on success, 1 on failure + */ +int str_replace(char* result, int maxlen, const char* source, const char* pattern, const char* replacewith); + #endif /* __UTILS_H__ */ diff -ruN xqf-1.0.4.org/src/xqf.c xqf-1.0.4/src/xqf.c --- xqf-1.0.4.org/src/xqf.c 2005-08-23 20:22:19.000000000 +0200 +++ xqf-1.0.4/src/xqf.c 2006-05-28 04:00:40.000000000 +0200 @@ -1682,10 +1682,18 @@ static void copy_server_callback_plus (GtkWidget *widget, gpointer data) { GList *selection = server_clist->selection; struct server *s; - char buf[256]; + + // possible overflow here? increased it a bit but that won't help much ;P + char buf[4096]; int pos = 0; unsigned players; + char str_ping[16]; + char str_port[16]; + char str_players[16]; + char str_maxplayers[16]; + char* formatstring; + gtk_editable_delete_text (selection_manager, 0, -1); switch (g_list_length (selection)) { @@ -1700,10 +1708,30 @@ server_clist, GPOINTER_TO_INT(selection->data)); players = s->curplayers; if(serverlist_countbots && s->curbots <= players) - players-=s->curbots; + players-=s->curbots; + + // --begin-- Copy+ format string patch + formatstring = config_get_string_with_default("/" CONFIG_FILE "/Appearance/copyplusformat", NULL); + if(!formatstring) { + xqf_error("no formatstring defined"); + } + sprintf(str_ping,"%i",s->ping); + sprintf(str_port,"%d",s->port); + sprintf(str_players, "%i", players); + sprintf(str_maxplayers, "%i", s->maxplayers); + + strcpy(buf, formatstring); + str_replace(buf, 4096, buf, "", str_ping); + str_replace(buf, 4096, buf, "", inet_ntoa(s->host->ip)); + str_replace(buf, 4096, buf, "", str_port); + str_replace(buf, 4096, buf, "", s->name); + str_replace(buf, 4096, buf, "", s->map); + str_replace(buf, 4096, buf, "", str_players); + str_replace(buf, 4096, buf, "", str_maxplayers); + str_replace(buf, 4096, buf, "", s->game); + str_replace(buf, 4096, buf, "", s->gametype); + // --end-- Copy+ format string patch - g_snprintf (buf, 256, "%i %s:%d %s %s %i of %i%s", s->ping, inet_ntoa - (s->host->ip), s->port, s->name, s->map, players, s->maxplayers, selection->next?"\n":""); gtk_editable_insert_text (selection_manager, buf, strlen (buf), &pos); } gtk_editable_select_region (selection_manager, 0, -1);