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