Revision 66e4aea59df588aa3f5108e82fbc80140c55301d

sadrul at pidgin.im sadrul at pidgin.im
Sat Mar 31 23:49:49 EDT 2007


o     -----------------------------------------------------------------
|\    Revision: 66e4aea59df588aa3f5108e82fbc80140c55301d
| |   Ancestor: e23bc35af900cf0925d85813b5896e19f73645d2
| |   Ancestor: ed972b3dfab31a2b23f4b191bfe7d4dcab7cc765
| |   Author: sadrul at pidgin.im
| |   Date: 2007-04-01T03:47:50
| |   Branch: im.pidgin.pidgin
| |   
| |   Modified files:
| |           ChangeLog.API finch/libgnt/gnttree.c libpurple/Makefile.am
| |           libpurple/Makefile.mingw libpurple/nat-pmp.c
| |           libpurple/nat-pmp.h libpurple/network.c libpurple/network.h
| |           libpurple/protocols/silc/util.c libpurple/proxy.c
| |           libpurple/upnp.c libpurple/upnp.h
| |   
| |   ChangeLog: 
| |   
| |   merge of 'e23bc35af900cf0925d85813b5896e19f73645d2'
| |        and 'ed972b3dfab31a2b23f4b191bfe7d4dcab7cc765'
| |   
| |   ============================================================
| |   --- ChangeLog.API	7d5b4a3e76e446081d5930f73284b1973e3a7a45
| |   +++ ChangeLog.API	c39013970ce25d0a576e86272b2ae8fea8af2bf5
| |   @@ -416,6 +416,7 @@ version 2.0.0:
| |    	* "gtkblist-hiding"
| |    	* "gtkblist-unhiding"
| |    	* "log-displaying"
| |   +	* "network-configuration-changed"
| |    	* "savedstatus-changed"
| |    	* "sendto-extended-menu"
| |    	* "uri-handler"
| |   ============================================================
| |   --- libpurple/Makefile.am	02143704a0dd9f1a16d987b4c722b762c2fb58e6
| |   +++ libpurple/Makefile.am	532f08086b6418786f8eb71439ffacf79862f3fa
| |   @@ -49,6 +49,7 @@ purple_coresources = \
| |    	imgstore.c \
| |    	log.c \
| |    	mime.c \
| |   +	nat-pmp.c \
| |    	network.c \
| |    	ntlm.c \
| |    	notify.c \
| |   @@ -99,6 +100,7 @@ purple_coreheaders = \
| |    	imgstore.h \
| |    	log.h \
| |    	mime.h \
| |   +	nat-pmp.h \
| |    	network.h \
| |    	notify.h \
| |    	ntlm.h \
| |   ============================================================
| |   --- libpurple/Makefile.mingw	306f3ff607b2623deffaff628cec01f31e33ab1a
| |   +++ libpurple/Makefile.mingw	29dd04c6bcd90c84763c1d29675b0e260b2522b8
| |   @@ -48,6 +48,7 @@ C_SRC =	\
| |    			imgstore.c \
| |    			log.c \
| |    			mime.c \
| |   +			nat-pmp.c \
| |    			network.c \
| |    			notify.c \
| |    			ntlm.c \
| |   ============================================================
| |   --- libpurple/nat-pmp.c	0cc6b65d22e43ee71a150d303771e55a580a794a
| |   +++ libpurple/nat-pmp.c	564503dcbb4533b54dc161e381b948dfd621358c
| |   @@ -30,24 +30,28 @@
| |    
| |    #include "nat-pmp.h"
| |    #include "debug.h"
| |   +#include "signals.h"
| |   +#include "network.h"
| |    
| |   +#include <sys/types.h>
| |   +#ifndef _WIN32
| |    #include <arpa/inet.h>
| |    #include <netinet/in.h>
| |   -#include <sys/types.h>
| |    #include <sys/socket.h>
| |    #include <sys/sysctl.h>
| |    
| |   +#include <net/if.h>
| |    #include <net/route.h>
| |    
| |    #include <netdb.h>
| |   +#include <err.h>
| |   +#endif
| |   +
| |    #include <stdio.h>
| |    #include <stdlib.h>
| |    #include <string.h>
| |   -#include <err.h>
| |    
| |    #include <errno.h>
| |   -#include <sys/types.h>
| |   -#include <net/if.h>
| |    
| |    #ifdef NET_RT_DUMP
| |    
| |   @@ -87,6 +91,20 @@ typedef struct _PurplePmpMapResponse Pur
| |    
| |    typedef struct _PurplePmpMapResponse PurplePmpMapResponse;
| |    
| |   +typedef enum {
| |   +	PURPLE_PMP_STATUS_UNDISCOVERED = -1,
| |   +	PURPLE_PMP_STATUS_UNABLE_TO_DISCOVER,
| |   +	PURPLE_PMP_STATUS_DISCOVERING,
| |   +	PURPLE_PMP_STATUS_DISCOVERED
| |   +} PurpleUPnPStatus;
| |   +
| |   +typedef struct {
| |   +	PurpleUPnPStatus status;
| |   +	gchar *publicip;
| |   +} PurplePmpInfo;
| |   +
| |   +static PurplePmpInfo pmp_info = {PURPLE_PMP_STATUS_UNDISCOVERED, NULL};
| |   +
| |    /*
| |     *	Thanks to R. Matthew Emerson for the fixes on this
| |     */
| |   @@ -240,11 +258,32 @@ purple_pmp_get_public_ip()
| |    char *
| |    purple_pmp_get_public_ip()
| |    {
| |   -	struct sockaddr_in *gateway = default_gw();
| |   +	struct sockaddr_in addr, *gateway, *publicsockaddr = NULL;
| |   +	struct timeval req_timeout;
| |   +	socklen_t len;
| |    
| |   +	PurplePmpIpRequest req;
| |   +	PurplePmpIpResponse resp;
| |   +	int sendfd;
| |   +	
| |   +	if (pmp_info.status == PURPLE_PMP_STATUS_UNABLE_TO_DISCOVER)
| |   +		return NULL;
| |   +	
| |   +	if ((pmp_info.status == PURPLE_PMP_STATUS_DISCOVERED) && (pmp_info.publicip != NULL))
| |   +	{
| |   +#ifdef PMP_DEBUG
| |   +		purple_debug_info("nat-pmp", "Returning cached publicip %s",pmp_info.publicip);
| |   +#endif
| |   +		return pmp_info.publicip;
| |   +	}
| |   +
| |   +	gateway = default_gw();
| |   +
| |    	if (!gateway)
| |    	{
| |    		purple_debug_info("nat-pmp", "Cannot request public IP from a NULL gateway!\n");
| |   +		/* If we get a NULL gateway, don't try again next time */
| |   +		pmp_info.status = PURPLE_PMP_STATUS_UNABLE_TO_DISCOVER;
| |    		return NULL;
| |    	}
| |    
| |   @@ -252,12 +291,6 @@ purple_pmp_get_public_ip()
| |    	if (gateway->sin_port != PMP_PORT)
| |    		gateway->sin_port = htons(PMP_PORT);
| |    
| |   -	int sendfd;
| |   -	struct timeval req_timeout;
| |   -	PurplePmpIpRequest req;
| |   -	PurplePmpIpResponse resp;
| |   -	struct sockaddr_in *publicsockaddr = NULL;
| |   -
| |    	req_timeout.tv_sec = 0;
| |    	req_timeout.tv_usec = PMP_TIMEOUT;
| |    
| |   @@ -274,20 +307,19 @@ purple_pmp_get_public_ip()
| |    	 * With the recommended timeout of 0.25 seconds, we're talking 511.5 seconds (8.5 minutes).
| |    	 * 
| |    	 * This seems really silly... if this were nonblocking, a couple retries might be in order, but it's not at present.
| |   -	 * XXX Make this nonblocking.
| |    	 */
| |    #ifdef PMP_DEBUG
| |    	purple_debug_info("nat-pmp", "Attempting to retrieve the public ip address for the NAT device at: %s\n", inet_ntoa(gateway->sin_addr));
| |    	purple_debug_info("nat-pmp", "\tTimeout: %ds %dus\n", req_timeout.tv_sec, req_timeout.tv_usec);
| |    #endif
| |   -	struct sockaddr_in addr;
| |   -	socklen_t len = sizeof(struct sockaddr_in);
| |    
| |    	/* TODO: Non-blocking! */
| |   +	
| |    	if (sendto(sendfd, &req, sizeof(req), 0, (struct sockaddr *)(gateway), sizeof(struct sockaddr)) < 0)
| |    	{
| |    		purple_debug_info("nat-pmp", "There was an error sending the NAT-PMP public IP request! (%s)\n", strerror(errno));
| |    		g_free(gateway);
| |   +		pmp_info.status = PURPLE_PMP_STATUS_UNABLE_TO_DISCOVER;
| |    		return NULL;
| |    	}
| |    
| |   @@ -295,16 +327,19 @@ purple_pmp_get_public_ip()
| |    	{
| |    		purple_debug_info("nat-pmp", "There was an error setting the socket's options! (%s)\n", strerror(errno));
| |    		g_free(gateway);
| |   +		pmp_info.status = PURPLE_PMP_STATUS_UNABLE_TO_DISCOVER;
| |    		return NULL;
| |    	}		
| |    
| |    	/* TODO: Non-blocking! */
| |   +	len = sizeof(struct sockaddr_in);
| |    	if (recvfrom(sendfd, &resp, sizeof(PurplePmpIpResponse), 0, (struct sockaddr *)(&addr), &len) < 0)
| |    	{			
| |    		if (errno != EAGAIN)
| |    		{
| |    			purple_debug_info("nat-pmp", "There was an error receiving the response from the NAT-PMP device! (%s)\n", strerror(errno));
| |    			g_free(gateway);
| |   +			pmp_info.status = PURPLE_PMP_STATUS_UNABLE_TO_DISCOVER;
| |    			return NULL;
| |    		}
| |    	}
| |   @@ -315,11 +350,15 @@ purple_pmp_get_public_ip()
| |    	{
| |    		purple_debug_info("nat-pmp", "Response was not received from our gateway! Instead from: %s\n", inet_ntoa(addr.sin_addr));
| |    		g_free(gateway);
| |   +
| |   +		pmp_info.status = PURPLE_PMP_STATUS_UNABLE_TO_DISCOVER;
| |    		return NULL;
| |    	}
| |    
| |    	if (!publicsockaddr) {
| |    		g_free(gateway);
| |   +		
| |   +		pmp_info.status = PURPLE_PMP_STATUS_UNABLE_TO_DISCOVER;
| |    		return NULL;
| |    	}
| |    
| |   @@ -338,6 +377,10 @@ purple_pmp_get_public_ip()
| |    
| |    	g_free(gateway);
| |    
| |   +	g_free(pmp_info.publicip);
| |   +	pmp_info.publicip = g_strdup(inet_ntoa(publicsockaddr->sin_addr));
| |   +	pmp_info.status = PURPLE_PMP_STATUS_DISCOVERED;
| |   +
| |    	return inet_ntoa(publicsockaddr->sin_addr);
| |    }
| |    
| |   @@ -458,6 +501,30 @@ purple_pmp_destroy_map(PurplePmpType typ
| |    
| |    	return success;
| |    }
| |   +
| |   +static void
| |   +purple_pmp_network_config_changed_cb(void *data)
| |   +{
| |   +	pmp_info.status = PURPLE_PMP_STATUS_UNDISCOVERED;
| |   +	g_free(pmp_info.publicip);
| |   +	pmp_info.publicip = NULL;
| |   +}
| |   +
| |   +static void*
| |   +purple_pmp_get_handle(void)
| |   +{
| |   +	static int handle;
| |   +
| |   +	return &handle;	
| |   +}
| |   +
| |   +void
| |   +purple_pmp_init()
| |   +{
| |   +	purple_signal_connect(purple_network_get_handle(), "network-configuration-changed",
| |   +		  purple_pmp_get_handle(), PURPLE_CALLBACK(purple_pmp_network_config_changed_cb),
| |   +		  GINT_TO_POINTER(0));	
| |   +}
| |    #else /* #ifdef NET_RT_DUMP */
| |    char *
| |    purple_pmp_get_public_ip()
| |   @@ -476,4 +543,10 @@ purple_pmp_destroy_map(PurplePmpType typ
| |    {
| |    	return FALSE;
| |    }
| |   +
| |   +void
| |   +purple_pmp_init()
| |   +{
| |   +
| |   +}
| |    #endif /* #ifndef NET_RT_DUMP */
| |   ============================================================
| |   --- libpurple/nat-pmp.h	5f2cac238513429f0a46ff2bcf9374b5f61270c3
| |   +++ libpurple/nat-pmp.h	babf3b7b64824b54cbdad492f8d25f8f5eb82662
| |   @@ -36,27 +36,20 @@
| |    
| |    #define PURPLE_PMP_LIFETIME	3600	/* 3600 seconds */
| |    
| |   -/*
| |   - *	uint8_t:	version, opcodes
| |   - *	uint16_t:	resultcode
| |   - *	unint32_t:	epoch (seconds since mappings reset)
| |   - */
| |   -
| |    typedef enum {
| |    	PURPLE_PMP_TYPE_UDP,
| |    	PURPLE_PMP_TYPE_TCP
| |    } PurplePmpType;
| |    
| |    /**
| |   - *
| |   + * Initialize nat-pmp
| |     */
| |   +void purple_pmp_init(void);
| |    
| |   -/*
| |   - * TODO: This should probably cache the result of this lookup requests
| |   - *       so that subsequent calls to this function do not require a
| |   - *       round-trip exchange with the local router.
| |   +/**
| |   + *
| |     */
| |   -char *purple_pmp_get_public_ip();
| |   +char *purple_pmp_get_public_ip(void);
| |    
| |    /**
| |     * Remove the NAT-PMP mapping for a specified type on a specified port
| |   @@ -79,5 +72,6 @@ gboolean purple_pmp_destroy_map(PurplePm
| |     * @returns TRUE if succesful; FALSE if unsuccessful
| |     */
| |    gboolean purple_pmp_destroy_map(PurplePmpType type, unsigned short privateport);
| |   -	
| |   +
| |    #endif
| |   +
| |   ============================================================
| |   --- libpurple/network.c	60335f4bd92f820defa3407a93d944941ae7dc91
| |   +++ libpurple/network.c	eb2bd60ce146f635283a73a30a8f825238c68211
| |   @@ -42,17 +42,12 @@
| |    
| |    #include "debug.h"
| |    #include "account.h"
| |   +#include "nat-pmp.h"
| |    #include "network.h"
| |    #include "prefs.h"
| |    #include "stun.h"
| |    #include "upnp.h"
| |    
| |   -/* #define ENABLE_NAT_PMP 1 */
| |   -
| |   -#ifdef ENABLE_NAT_PMP
| |   -#include "nat-pmp.h"
| |   -#endif
| |   -
| |    /*
| |     * Calling sizeof(struct ifreq) isn't always correct on
| |     * Mac OS X (and maybe others).
| |   @@ -198,12 +193,10 @@ purple_network_get_my_ip(int fd)
| |    	if (ip != NULL)
| |    	  return ip;
| |    
| |   -#ifdef ENABLE_NAT_PMP
| |    	/* Attempt to get the IP from a NAT device using NAT-PMP */
| |    	ip = purple_pmp_get_public_ip();
| |    	if (ip != NULL)
| |    		return ip;
| |   -#endif
| |    
| |    	/* Just fetch the IP of the local system */
| |    	return purple_network_get_local_system_ip(fd);
| |   @@ -250,7 +243,6 @@ purple_network_set_upnp_port_mapping_cb(
| |    	purple_network_listen_cancel(listen_data);
| |    }
| |    
| |   -#ifdef ENABLE_NAT_PMP
| |    static gboolean
| |    purple_network_finish_pmp_map_cb(gpointer data)
| |    {
| |   @@ -265,7 +257,6 @@ purple_network_finish_pmp_map_cb(gpointe
| |    
| |    	return FALSE;
| |    }
| |   -#endif
| |    
| |    static PurpleNetworkListenData *
| |    purple_network_do_listen(unsigned short port, int socket_type, PurpleNetworkListenCallback cb, gpointer cb_data)
| |   @@ -361,7 +352,6 @@ purple_network_do_listen(unsigned short 
| |    	listen_data->cb = cb;
| |    	listen_data->cb_data = cb_data;
| |    
| |   -#ifdef ENABLE_NAT_PMP
| |    	/* Attempt a NAT-PMP Mapping, which will return immediately */
| |    	if (purple_pmp_create_map(((socket_type == SOCK_STREAM) ? PURPLE_PMP_TYPE_TCP : PURPLE_PMP_TYPE_UDP),
| |    							  actual_port, actual_port, PURPLE_PMP_LIFETIME))
| |   @@ -371,7 +361,6 @@ purple_network_do_listen(unsigned short 
| |    		purple_timeout_add(0, purple_network_finish_pmp_map_cb, listen_data);
| |    	}
| |    	else
| |   -#endif
| |    	{
| |    		/* Attempt a UPnP Mapping */
| |    		listen_data->mapping_data = purple_upnp_set_port_mapping(
| |   @@ -508,6 +497,8 @@ static gboolean wpurple_network_change_t
| |    
| |    	purple_debug_info("network", "Received Network Change Notification. Current network count is %d, previous count was %d.\n", new_count, current_network_count);
| |    
| |   +	purple_signal_emit(purple_network_get_handle(), "network-configuration-changed", NULL);
| |   +
| |    	if (new_count > 0 && ui_ops != NULL && ui_ops->network_connected != NULL) {
| |    		ui_ops->network_connected();
| |    	} else if (new_count == 0 && current_network_count > 0 &&
| |   @@ -616,6 +607,8 @@ nm_callback_func(libnm_glib_ctx* ctx, gp
| |    	current = libnm_glib_get_network_state(ctx);
| |    	purple_debug_info("network","Entering nm_callback_func!\n");
| |    
| |   +	purple_signal_emit(purple_network_get_handle(), "network-configuration-changed", NULL);
| |   +
| |    	switch(current)
| |    	{
| |    	case LIBNM_ACTIVE_NETWORK_CONNECTION:
| |   @@ -641,6 +634,14 @@ nm_callback_func(libnm_glib_ctx* ctx, gp
| |    }
| |    #endif
| |    
| |   +void *
| |   +purple_network_get_handle(void)
| |   +{
| |   +	static int handle;
| |   +	
| |   +	return &handle;
| |   +}
| |   +
| |    void
| |    purple_network_init(void)
| |    {
| |   @@ -673,6 +674,12 @@ purple_network_init(void)
| |    	if(nm_context)
| |    		nm_callback_idx = libnm_glib_register_callback(nm_context, nm_callback_func, NULL, g_main_context_default());
| |    #endif
| |   +
| |   +	purple_signal_register(purple_network_get_handle(), "network-configuration-changed",
| |   +						   purple_marshal_VOID, NULL, 0);
| |   +	
| |   +	purple_pmp_init();
| |   +	purple_upnp_init();
| |    }
| |    
| |    void
| |   ============================================================
| |   --- libpurple/network.h	6f8979bf0ba8b30e517d718148b5365ac3d09700
| |   +++ libpurple/network.h	858b42c7c54f71c5f2008e9a66f1c9b6387de90f
| |   @@ -197,6 +197,13 @@ gboolean purple_network_is_available(voi
| |    gboolean purple_network_is_available(void);
| |    
| |    /**
| |   + * Get the handle for the network system
| |   + *
| |   + * @return the handle to the network system
| |   + */
| |   +void *purple_network_get_handle(void);
| |   +
| |   +/**
| |     * Initializes the network subsystem.
| |     */
| |    void purple_network_init(void);
| |   ============================================================
| |   --- libpurple/protocols/silc/util.c	1d27c0189a9067f9039f92bc2f5f57084c705d27
| |   +++ libpurple/protocols/silc/util.c	5fb822bee02f987875c9258540b591bf9b50be1a
| |   @@ -444,8 +444,6 @@ void silcpurple_get_chmode_string(SilcUI
| |    		strcat(buf, "[private] ");
| |    	if (mode & SILC_CHANNEL_MODE_SECRET)
| |    		strcat(buf, "[secret] ");
| |   -	if (mode & SILC_CHANNEL_MODE_SECRET)
| |   -		strcat(buf, "[secret] ");
| |    	if (mode & SILC_CHANNEL_MODE_PRIVKEY)
| |    		strcat(buf, "[private key] ");
| |    	if (mode & SILC_CHANNEL_MODE_INVITE)
| |   ============================================================
| |   --- libpurple/proxy.c	9769957800439d7bc54643d0fc1afe4964a33884
| |   +++ libpurple/proxy.c	c5e8a6f8c90f4832272cbf2cc5332581bee040f5
| |   @@ -87,6 +87,12 @@ static void try_connect(PurpleProxyConne
| |    
| |    static void try_connect(PurpleProxyConnectData *connect_data);
| |    
| |   +/*
| |   + * TODO: Eventually (GObjectification) this bad boy will be removed, because it is
| |   + *       a gross fix for a crashy problem.
| |   + */
| |   +#define PURPLE_PROXY_CONNECT_DATA_IS_VALID(connect_data) g_slist_find(handles, connect_data)
| |   +
| |    /**************************************************************************
| |     * Proxy structure API
| |     **************************************************************************/
| |   @@ -389,6 +395,12 @@ socket_ready_cb(gpointer data, gint sour
| |    	int error = 0;
| |    	int ret;
| |    
| |   +	/* If the socket-connected message had already been triggered when connect_data
| |   + 	 * was destroyed via purple_proxy_connect_cancel(), we may get here with a freed connect_data.
| |   + 	 */
| |   +	if (!PURPLE_PROXY_CONNECT_DATA_IS_VALID(connect_data))
| |   +		return;
| |   +	
| |    	purple_debug_info("proxy", "Connected to %s:%d.\n",
| |    					connect_data->host, connect_data->port);
| |    
| |   ============================================================
| |   --- libpurple/upnp.c	96621a5920d0f7ffc49169a7327f4dc3345d3acc
| |   +++ libpurple/upnp.c	f425a77b17efb304f7aa61c8d638d4d575282bb8
| |   @@ -24,15 +24,16 @@
| |     */
| |    #include "internal.h"
| |    
| |   +#include "upnp.h"
| |   +
| |    #include "debug.h"
| |   -#include "util.h"
| |   +#include "eventloop.h"
| |   +#include "network.h"
| |    #include "proxy.h"
| |   +#include "signals.h"
| |   +#include "util.h"
| |    #include "xmlnode.h"
| |   -#include "network.h"
| |   -#include "eventloop.h"
| |   -#include "upnp.h"
| |    
| |   -
| |    /***************************************************************
| |    ** General Defines                                             *
| |    ****************************************************************/
| |   @@ -1026,3 +1027,32 @@ purple_upnp_remove_port_mapping(unsigned
| |    	do_port_mapping_cb(TRUE, ar);
| |    	return ar;
| |    }
| |   +
| |   +static void
| |   +purple_upnp_network_config_changed_cb(void *data)
| |   +{
| |   +	/* Reset the control_info to default values */
| |   +	control_info.status = PURPLE_UPNP_STATUS_UNDISCOVERED;
| |   +	g_free(control_info.control_url);
| |   +	control_info.control_url = NULL;
| |   +	control_info.service_type[0] = '\0';
| |   +	control_info.publicip[0] = '\0';
| |   +	control_info.internalip[0] = '\0';
| |   +	control_info.lookup_time = 0;
| |   +}
| |   +
| |   +static void*
| |   +purple_upnp_get_handle(void)
| |   +{
| |   +	static int handle;
| |   +	
| |   +	return &handle;	
| |   +}
| |   +
| |   +void
| |   +purple_upnp_init()
| |   +{
| |   +	purple_signal_connect(purple_network_get_handle(), "network-configuration-changed",
| |   +						  purple_upnp_get_handle(), PURPLE_CALLBACK(purple_upnp_network_config_changed_cb),
| |   +						  GINT_TO_POINTER(0));		
| |   +}
| |   ============================================================
| |   --- libpurple/upnp.h	528c77de4eda81ff204682df262574a00c3dfec1
| |   +++ libpurple/upnp.h	7fc0680c51662700ad6ff20b2b618736c1f0aebe
| |   @@ -41,7 +41,14 @@ typedef void (*PurpleUPnPCallback) (gboo
| |    
| |    typedef void (*PurpleUPnPCallback) (gboolean success, gpointer data);
| |    
| |   +
| |    /**
| |   + * Initialize UPnP
| |   + */
| |   +void purple_upnp_init(void);
| |   +
| |   +
| |   +/**
| |     * Sends a discovery request to search for a UPnP enabled IGD that
| |     * contains the WANIPConnection service that will allow us to recieve the
| |     * public IP address of the IGD, and control it for forwarding ports.
| |   ============================================================
| |   --- finch/libgnt/gnttree.c	51c46e82f4470a67b577a42df252f182ee1fffd2
| |   +++ finch/libgnt/gnttree.c	4073129f51c0c4abc120a9ac28309380a39a0183
| |   @@ -223,7 +223,11 @@ update_row_text(GntTree *tree, GntTreeRo
| |    	GList *iter;
| |    	int i;
| |    	gboolean notfirst = FALSE;
| |   +	int lastvisible = tree->ncol;
| |    
| |   +	while (lastvisible && tree->columns[lastvisible].invisible)
| |   +		lastvisible--;
| |   +
| |    	for (i = 0, iter = row->columns; i < tree->ncol && iter; i++, iter = iter->next)
| |    	{
| |    		GntTreeCol *col = iter->data;
| |   @@ -231,10 +235,16 @@ update_row_text(GntTree *tree, GntTreeRo
| |    		int len = gnt_util_onscreen_width(col->text, NULL);
| |    		int fl = 0;
| |    		gboolean cut = FALSE;
| |   +		int width;
| |    
| |    		if (tree->columns[i].invisible)
| |    			continue;
| |    
| |   +		if (i == lastvisible)
| |   +			width = GNT_WIDGET(tree)->priv.width - gnt_util_onscreen_width(string->str, NULL);
| |   +		else
| |   +			width = tree->columns[i].width;
| |   +
| |    		if (i == 0)
| |    		{
| |    			if (row->choice)
| |   @@ -269,8 +279,8 @@ update_row_text(GntTree *tree, GntTreeRo
| |    
| |    		notfirst = TRUE;
| |    
| |   -		if (len > tree->columns[i].width) {
| |   -			len = tree->columns[i].width - 1;
| |   +		if (len > width) {
| |   +			len = width - 1;
| |    			cut = TRUE;
| |    		}
| |    		text = gnt_util_onscreen_width_to_pointer(col->text, len - fl, NULL);
| |   @@ -284,7 +294,7 @@ update_row_text(GntTree *tree, GntTreeRo
| |    		}
| |    
| |    		if (len < tree->columns[i].width && iter->next)
| |   -			g_string_append_printf(string, "%*s", tree->columns[i].width - len, "");
| |   +			g_string_append_printf(string, "%*s", width - len, "");
| |    	}
| |    	return g_string_free(string, FALSE);
| |    }
| |   @@ -557,6 +567,23 @@ static gboolean
| |    }
| |    
| |    static gboolean
| |   +action_move_parent(GntBindable *bind, GList *null)
| |   +{
| |   +	GntTree *tree = GNT_TREE(bind);
| |   +	GntTreeRow *row = tree->current;
| |   +	if (row->parent) {
| |   +		int dist;
| |   +		tree->current = row->parent;
| |   +		if ((dist = get_distance(tree->current, tree->top)) > 0)
| |   +			gnt_tree_scroll(tree, -dist);
| |   +		else
| |   +			redraw_tree(tree);
| |   +		tree_selection_changed(tree, row, tree->current);
| |   +	}
| |   +	return TRUE;
| |   +}
| |   +
| |   +static gboolean
| |    action_up(GntBindable *bind, GList *list)
| |    {
| |    	int dist;
| |   @@ -835,6 +862,8 @@ gnt_tree_class_init(GntTreeClass *klass)
| |    	gnt_bindable_class_register_action(bindable, "move-down", action_down,
| |    				GNT_KEY_DOWN, NULL);
| |    	gnt_bindable_register_binding(bindable, "move-down", GNT_KEY_CTRL_N, NULL);
| |   +	gnt_bindable_class_register_action(bindable, "move-parent", action_move_parent,
| |   +				GNT_KEY_BACKSPACE, NULL);
| |    	gnt_bindable_class_register_action(bindable, "page-up", action_page_up,
| |    				GNT_KEY_PGUP, NULL);
| |    	gnt_bindable_class_register_action(bindable, "page-down", action_page_down,
| |   @@ -1496,10 +1525,13 @@ void gnt_tree_adjust_columns(GntTree *tr
| |    			int w = gnt_util_onscreen_width(col->text, NULL);
| |    			if (i == 0 && row->choice)
| |    				w += 4;
| |   +			if (i == 0) {
| |   +				w += find_depth(row) * TAB_SIZE;
| |   +			}
| |    			if (widths[i] < w)
| |    				widths[i] = w;
| |    		}
| |   -		row = row->next;
| |   +		row = get_next(row);
| |    	}
| |    
| |    	twidth = 1 + 2 * (!GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(tree), GNT_WIDGET_NO_BORDER));

To get the patch for this revision, please do this:
mtn log --last 1 --diffs --from 66e4aea59df588aa3f5108e82fbc80140c55301d


More information about the Commits mailing list