# HG changeset patch # User Sean Egan # Date 1174246695 0 # Node ID 0e3a8505ebbe37c4982d54b99513c1fece1a61a0 # Parent 317e7613e58132d7af67f2c607e961cc7a7ab48d renamed gaim-text to finch diff -r 317e7613e581 -r 0e3a8505ebbe Makefile.am --- a/Makefile.am Sun Mar 18 18:17:14 2007 +0000 +++ b/Makefile.am Sun Mar 18 19:38:15 2007 +0000 @@ -48,7 +48,7 @@ endif if ENABLE_GNT -GNT_DIR=console +GNT_DIR=finch endif SUBDIRS = libpurple doc $(GNT_DIR) $(GTK_DIR) m4macros po diff -r 317e7613e581 -r 0e3a8505ebbe configure.ac --- a/configure.ac Sun Mar 18 18:17:14 2007 +0000 +++ b/configure.ac Sun Mar 18 19:38:15 2007 +0000 @@ -1983,11 +1983,11 @@ libpurple/protocols/yahoo/Makefile libpurple/protocols/zephyr/Makefile libpurple/tests/Makefile - console/Makefile - console/libgnt/Makefile - console/libgnt/gnt.pc - console/libgnt/wms/Makefile - console/plugins/Makefile + finch/Makefile + finch/libgnt/Makefile + finch/libgnt/gnt.pc + finch/libgnt/wms/Makefile + finch/plugins/Makefile po/Makefile.in gaim.pc gaim-uninstalled.pc diff -r 317e7613e581 -r 0e3a8505ebbe console/Makefile.am --- a/console/Makefile.am Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,77 +0,0 @@ -if ENABLE_GNT - -EXTRA_DIST = \ - getopt.c \ - getopt.h \ - getopt1.c - -SUBDIRS = libgnt plugins - -bin_PROGRAMS = gaim-text - -gaim_text_SOURCES = \ - gntaccount.c \ - gntblist.c \ - gntconn.c \ - gntconv.c \ - gntdebug.c \ - gntft.c \ - gntgaim.c \ - gntidle.c \ - gntnotify.c \ - gntplugin.c \ - gntpounce.c \ - gntprefs.c \ - gntrequest.c \ - gntstatus.c \ - gntui.c - -gaim_text_headers = \ - gntaccount.h \ - gntblist.h \ - gntconn.h \ - gntconv.h \ - gntdebug.h \ - gntft.h \ - gntgaim.h \ - gntidle.h \ - gntnotify.h \ - gntplugin.h \ - gntpounce.h \ - gntprefs.h \ - gntrequest.h \ - gntstatus.h \ - gntui.h - -gaim_textincludedir=$(includedir)/gaim/gnt -gaim_textinclude_HEADERS = \ - $(gaim_text_headers) - -gaim_text_DEPENDENCIES = @LIBOBJS@ -gaim_text_LDFLAGS = -export-dynamic -gaim_text_LDADD = \ - @LIBOBJS@ \ - $(DBUS_LIBS) \ - $(INTLLIBS) \ - $(GLIB_LIBS) \ - $(LIBXML_LIBS) \ - $(GNT_LIBS) \ - ./libgnt/libgnt.la \ - $(top_builddir)/libpurple/libpurple.la - -AM_CPPFLAGS = \ - -DSTANDALONE \ - -DBR_PTHREADS=0 \ - -DDATADIR=\"$(datadir)\" \ - -DLIBDIR=\"$(libdir)/gaim/\" \ - -DLOCALEDIR=\"$(datadir)/locale\" \ - -DSYSCONFDIR=\"$(sysconfdir)\" \ - -I$(top_srcdir)/libpurple/ \ - -I$(top_srcdir) \ - -I$(srcdir)/libgnt/ \ - $(DEBUG_CFLAGS) \ - $(GLIB_CFLAGS) \ - $(DBUS_CFLAGS) \ - $(LIBXML_CFLAGS) \ - $(GNT_CFLAGS) -endif diff -r 317e7613e581 -r 0e3a8505ebbe console/getopt.c --- a/console/getopt.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,737 +0,0 @@ -/* Getopt for GNU. - NOTE: getopt is now part of the C library, so if you don't know what - "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu - before changing it! - - Gaim is the legal property of its developers, whose names are too numerous - to list here. Please refer to the COPYRIGHT file distributed with this - source distribution. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2, or (at your option) any - later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -/* NOTE!!! AIX requires this to be the first thing in the file. - Do not put ANYTHING before it! */ -#if !defined (__GNUC__) && defined (_AIX) - #pragma alloca -#endif - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -/* Alver says we need this for IRIX. */ -#if HAVE_STRING_H -#include "string.h" -#endif - -#ifdef __GNUC__ -#define alloca __builtin_alloca -#else /* not __GNUC__ */ -#if defined (HAVE_ALLOCA_H) || (defined(sparc) && (defined(sun) || (!defined(USG) && !defined(SVR4) && !defined(__svr4__)))) -#include -#else -#ifndef _AIX -char *alloca (); -#endif -#endif /* alloca.h */ -#endif /* not __GNUC__ */ - -#if !__STDC__ && !defined(const) && IN_GCC -#define const -#endif - -/* This tells Alpha OSF/1 not to define a getopt prototype in . */ -#ifndef _NO_PROTO -#define _NO_PROTO -#endif - -#include - -/* Comment out all this code if we are using the GNU C Library, and are not - actually compiling the library itself. This code is part of the GNU C - Library, but also included in many other GNU distributions. Compiling - and linking in this code is a waste when using the GNU C library - (especially if it is a shared library). Rather than having every GNU - program understand `configure --with-gnu-libc' and omit the object files, - it is simpler to just do this in the source for each such file. */ - -#if defined (_LIBC) || !defined (__GNU_LIBRARY__) - - -/* This needs to come after some library #include - to get __GNU_LIBRARY__ defined. */ -#ifdef __GNU_LIBRARY__ -#undef alloca -/* Don't include stdlib.h for non-GNU C libraries because some of them - contain conflicting prototypes for getopt. */ -#include -#else /* Not GNU C library. */ -#define __alloca alloca -#endif /* GNU C library. */ - -/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a - long-named option. Because this is not POSIX.2 compliant, it is - being phased out. */ -/* #define GETOPT_COMPAT */ - -/* This version of `getopt' appears to the caller like standard Unix `getopt' - but it behaves differently for the user, since it allows the user - to intersperse the options with the other arguments. - - As `getopt' works, it permutes the elements of ARGV so that, - when it is done, all the options precede everything else. Thus - all application programs are extended to handle flexible argument order. - - Setting the environment variable POSIXLY_CORRECT disables permutation. - Then the behavior is completely standard. - - GNU application programs can use a third alternative mode in which - they can distinguish the relative order of options and other arguments. */ - -#include "getopt.h" - -/* For communication from `getopt' to the caller. - When `getopt' finds an option that takes an argument, - the argument value is returned here. - Also, when `ordering' is RETURN_IN_ORDER, - each non-option ARGV-element is returned here. */ - -char *optarg = 0; - -/* Index in ARGV of the next element to be scanned. - This is used for communication to and from the caller - and for communication between successive calls to `getopt'. - - On entry to `getopt', zero means this is the first call; initialize. - - When `getopt' returns EOF, this is the index of the first of the - non-option elements that the caller should itself scan. - - Otherwise, `optind' communicates from one call to the next - how much of ARGV has been scanned so far. */ - -/* XXX 1003.2 says this must be 1 before any call. */ -int optind = 0; - -/* The next char to be scanned in the option-element - in which the last option character we returned was found. - This allows us to pick up the scan where we left off. - - If this is zero, or a null string, it means resume the scan - by advancing to the next ARGV-element. */ - -static char *nextchar; - -/* Callers store zero here to inhibit the error message - for unrecognized options. */ - -int opterr = 1; - -/* Set to an option character which was unrecognized. - This must be initialized on some systems to avoid linking in the - system's own getopt implementation. */ - -int optopt = '?'; - -/* Describe how to deal with options that follow non-option ARGV-elements. - - If the caller did not specify anything, - the default is REQUIRE_ORDER if the environment variable - POSIXLY_CORRECT is defined, PERMUTE otherwise. - - REQUIRE_ORDER means don't recognize them as options; - stop option processing when the first non-option is seen. - This is what Unix does. - This mode of operation is selected by either setting the environment - variable POSIXLY_CORRECT, or using `+' as the first character - of the list of option characters. - - PERMUTE is the default. We permute the contents of ARGV as we scan, - so that eventually all the non-options are at the end. This allows options - to be given in any order, even with programs that were not written to - expect this. - - RETURN_IN_ORDER is an option available to programs that were written - to expect options and other ARGV-elements in any order and that care about - the ordering of the two. We describe each non-option ARGV-element - as if it were the argument of an option with character code 1. - Using `-' as the first character of the list of option characters - selects this mode of operation. - - The special argument `--' forces an end of option-scanning regardless - of the value of `ordering'. In the case of RETURN_IN_ORDER, only - `--' can cause `getopt' to return EOF with `optind' != ARGC. */ - -static enum -{ - REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER -} ordering; - -#ifdef __GNU_LIBRARY__ -/* We want to avoid inclusion of string.h with non-GNU libraries - because there are many ways it can cause trouble. - On some systems, it contains special magic macros that don't work - in GCC. */ -#include -#define my_index strchr -#define my_bcopy(src, dst, n) memcpy ((dst), (src), (n)) -#else - -/* Avoid depending on library functions or files - whose names are inconsistent. */ - -char *getenv (); - -static char * -my_index (str, chr) - const char *str; - int chr; -{ - while (*str) - { - if (*str == chr) - return (char *) str; - str++; - } - return 0; -} - -static void -my_bcopy (from, to, size) - const char *from; - char *to; - int size; -{ - int i; - for (i = 0; i < size; i++) - to[i] = from[i]; -} -#endif /* GNU C library. */ - -/* Handle permutation of arguments. */ - -/* Describe the part of ARGV that contains non-options that have - been skipped. `first_nonopt' is the index in ARGV of the first of them; - `last_nonopt' is the index after the last of them. */ - -static int first_nonopt; -static int last_nonopt; - -/* Exchange two adjacent subsequences of ARGV. - One subsequence is elements [first_nonopt,last_nonopt) - which contains all the non-options that have been skipped so far. - The other is elements [last_nonopt,optind), which contains all - the options processed since those non-options were skipped. - - `first_nonopt' and `last_nonopt' are relocated so that they describe - the new indices of the non-options in ARGV after they are moved. */ - -static void -exchange (argv) - char **argv; -{ - int nonopts_size = (last_nonopt - first_nonopt) * sizeof (char *); - char **temp = (char **) __alloca (nonopts_size); - - /* Interchange the two blocks of data in ARGV. */ - - my_bcopy ((char *) &argv[first_nonopt], (char *) temp, nonopts_size); - my_bcopy ((char *) &argv[last_nonopt], (char *) &argv[first_nonopt], - (optind - last_nonopt) * sizeof (char *)); - my_bcopy ((char *) temp, - (char *) &argv[first_nonopt + optind - last_nonopt], - nonopts_size); - - /* Update records for the slots the non-options now occupy. */ - - first_nonopt += (optind - last_nonopt); - last_nonopt = optind; -} - -/* Scan elements of ARGV (whose length is ARGC) for option characters - given in OPTSTRING. - - If an element of ARGV starts with '-', and is not exactly "-" or "--", - then it is an option element. The characters of this element - (aside from the initial '-') are option characters. If `getopt' - is called repeatedly, it returns successively each of the option characters - from each of the option elements. - - If `getopt' finds another option character, it returns that character, - updating `optind' and `nextchar' so that the next call to `getopt' can - resume the scan with the following option character or ARGV-element. - - If there are no more option characters, `getopt' returns `EOF'. - Then `optind' is the index in ARGV of the first ARGV-element - that is not an option. (The ARGV-elements have been permuted - so that those that are not options now come last.) - - OPTSTRING is a string containing the legitimate option characters. - If an option character is seen that is not listed in OPTSTRING, - return '?' after printing an error message. If you set `opterr' to - zero, the error message is suppressed but we still return '?'. - - If a char in OPTSTRING is followed by a colon, that means it wants an arg, - so the following text in the same ARGV-element, or the text of the following - ARGV-element, is returned in `optarg'. Two colons mean an option that - wants an optional arg; if there is text in the current ARGV-element, - it is returned in `optarg', otherwise `optarg' is set to zero. - - If OPTSTRING starts with `-' or `+', it requests different methods of - handling the non-option ARGV-elements. - See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. - - Long-named options begin with `--' instead of `-'. - Their names may be abbreviated as long as the abbreviation is unique - or is an exact match for some defined option. If they have an - argument, it follows the option name in the same ARGV-element, separated - from the option name by a `=', or else the in next ARGV-element. - When `getopt' finds a long-named option, it returns 0 if that option's - `flag' field is nonzero, the value of the option's `val' field - if the `flag' field is zero. - - The elements of ARGV aren't really const, because we permute them. - But we pretend they're const in the prototype to be compatible - with other systems. - - LONGOPTS is a vector of `struct option' terminated by an - element containing a name which is zero. - - LONGIND returns the index in LONGOPT of the long-named option found. - It is only valid when a long-named option has been found by the most - recent call. - - If LONG_ONLY is nonzero, '-' as well as '--' can introduce - long-named options. */ - -int -_getopt_internal (argc, argv, optstring, longopts, longind, long_only) - int argc; - char *const *argv; - const char *optstring; - const struct option *longopts; - int *longind; - int long_only; -{ - int option_index; - - optarg = 0; - - /* Initialize the internal data when the first call is made. - Start processing options with ARGV-element 1 (since ARGV-element 0 - is the program name); the sequence of previously skipped - non-option ARGV-elements is empty. */ - - if (optind == 0) - { - first_nonopt = last_nonopt = optind = 1; - - nextchar = NULL; - - /* Determine how to handle the ordering of options and nonoptions. */ - - if (optstring[0] == '-') - { - ordering = RETURN_IN_ORDER; - ++optstring; - } - else if (optstring[0] == '+') - { - ordering = REQUIRE_ORDER; - ++optstring; - } - else if (getenv ("POSIXLY_CORRECT") != NULL) - ordering = REQUIRE_ORDER; - else - ordering = PERMUTE; - } - - if (nextchar == NULL || *nextchar == '\0') - { - if (ordering == PERMUTE) - { - /* If we have just processed some options following some non-options, - exchange them so that the options come first. */ - - if (first_nonopt != last_nonopt && last_nonopt != optind) - exchange ((char **) argv); - else if (last_nonopt != optind) - first_nonopt = optind; - - /* Now skip any additional non-options - and extend the range of non-options previously skipped. */ - - while (optind < argc - && (argv[optind][0] != '-' || argv[optind][1] == '\0') -#ifdef GETOPT_COMPAT - && (longopts == NULL - || argv[optind][0] != '+' || argv[optind][1] == '\0') -#endif /* GETOPT_COMPAT */ - ) - optind++; - last_nonopt = optind; - } - - /* Special ARGV-element `--' means premature end of options. - Skip it like a null option, - then exchange with previous non-options as if it were an option, - then skip everything else like a non-option. */ - - if (optind != argc && !strcmp (argv[optind], "--")) - { - optind++; - - if (first_nonopt != last_nonopt && last_nonopt != optind) - exchange ((char **) argv); - else if (first_nonopt == last_nonopt) - first_nonopt = optind; - last_nonopt = argc; - - optind = argc; - } - - /* If we have done all the ARGV-elements, stop the scan - and back over any non-options that we skipped and permuted. */ - - if (optind == argc) - { - /* Set the next-arg-index to point at the non-options - that we previously skipped, so the caller will digest them. */ - if (first_nonopt != last_nonopt) - optind = first_nonopt; - return EOF; - } - - /* If we have come to a non-option and did not permute it, - either stop the scan or describe it to the caller and pass it by. */ - - if ((argv[optind][0] != '-' || argv[optind][1] == '\0') -#ifdef GETOPT_COMPAT - && (longopts == NULL - || argv[optind][0] != '+' || argv[optind][1] == '\0') -#endif /* GETOPT_COMPAT */ - ) - { - if (ordering == REQUIRE_ORDER) - return EOF; - optarg = argv[optind++]; - return 1; - } - - /* We have found another option-ARGV-element. - Start decoding its characters. */ - - nextchar = (argv[optind] + 1 - + (longopts != NULL && argv[optind][1] == '-')); - } - - if (longopts != NULL - && ((argv[optind][0] == '-' - && (argv[optind][1] == '-' || long_only)) -#ifdef GETOPT_COMPAT - || argv[optind][0] == '+' -#endif /* GETOPT_COMPAT */ - )) - { - const struct option *p; - char *s = nextchar; - int exact = 0; - int ambig = 0; - const struct option *pfound = NULL; - int indfound; - - while (*s && *s != '=') - s++; - - /* Test all options for either exact match or abbreviated matches. */ - for (p = longopts, option_index = 0; p->name; - p++, option_index++) - if (!strncmp (p->name, nextchar, s - nextchar)) - { - if (s - nextchar == strlen (p->name)) - { - /* Exact match found. */ - pfound = p; - indfound = option_index; - exact = 1; - break; - } - else if (pfound == NULL) - { - /* First nonexact match found. */ - pfound = p; - indfound = option_index; - } - else - /* Second nonexact match found. */ - ambig = 1; - } - - if (ambig && !exact) - { - if (opterr) - fprintf (stderr, "%s: option `%s' is ambiguous\n", - argv[0], argv[optind]); - nextchar += strlen (nextchar); - optind++; - return '?'; - } - - if (pfound != NULL) - { - option_index = indfound; - optind++; - if (*s) - { - /* Don't test has_arg with >, because some C compilers don't - allow it to be used on enums. */ - if (pfound->has_arg) - optarg = s + 1; - else - { - if (opterr) - { - if (argv[optind - 1][1] == '-') - /* --option */ - fprintf (stderr, - "%s: option `--%s' doesn't allow an argument\n", - argv[0], pfound->name); - else - /* +option or -option */ - fprintf (stderr, - "%s: option `%c%s' doesn't allow an argument\n", - argv[0], argv[optind - 1][0], pfound->name); - } - nextchar += strlen (nextchar); - return '?'; - } - } - else if (pfound->has_arg == 1) - { - if (optind < argc) - optarg = argv[optind++]; - else - { - if (opterr) - fprintf (stderr, "%s: option `%s' requires an argument\n", - argv[0], argv[optind - 1]); - nextchar += strlen (nextchar); - return optstring[0] == ':' ? ':' : '?'; - } - } - nextchar += strlen (nextchar); - if (longind != NULL) - *longind = option_index; - if (pfound->flag) - { - *(pfound->flag) = pfound->val; - return 0; - } - return pfound->val; - } - /* Can't find it as a long option. If this is not getopt_long_only, - or the option starts with '--' or is not a valid short - option, then it's an error. - Otherwise interpret it as a short option. */ - if (!long_only || argv[optind][1] == '-' -#ifdef GETOPT_COMPAT - || argv[optind][0] == '+' -#endif /* GETOPT_COMPAT */ - || my_index (optstring, *nextchar) == NULL) - { - if (opterr) - { - if (argv[optind][1] == '-') - /* --option */ - fprintf (stderr, "%s: unrecognized option `--%s'\n", - argv[0], nextchar); - else - /* +option or -option */ - fprintf (stderr, "%s: unrecognized option `%c%s'\n", - argv[0], argv[optind][0], nextchar); - } - nextchar = (char *) ""; - optind++; - return '?'; - } - } - - /* Look at and handle the next option-character. */ - - { - char c = *nextchar++; - char *temp = my_index (optstring, c); - - /* Increment `optind' when we start to process its last character. */ - if (*nextchar == '\0') - ++optind; - - if (temp == NULL || c == ':') - { - if (opterr) - { -#if 0 - if (c < 040 || c >= 0177) - fprintf (stderr, "%s: unrecognized option, character code 0%o\n", - argv[0], c); - else - fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c); -#else - /* 1003.2 specifies the format of this message. */ - fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c); -#endif - } - optopt = c; - return '?'; - } - if (temp[1] == ':') - { - if (temp[2] == ':') - { - /* This is an option that accepts an argument optionally. */ - if (*nextchar != '\0') - { - optarg = nextchar; - optind++; - } - else - optarg = 0; - nextchar = NULL; - } - else - { - /* This is an option that requires an argument. */ - if (*nextchar != '\0') - { - optarg = nextchar; - /* If we end this ARGV-element by taking the rest as an arg, - we must advance to the next element now. */ - optind++; - } - else if (optind == argc) - { - if (opterr) - { -#if 0 - fprintf (stderr, "%s: option `-%c' requires an argument\n", - argv[0], c); -#else - /* 1003.2 specifies the format of this message. */ - fprintf (stderr, "%s: option requires an argument -- %c\n", - argv[0], c); -#endif - } - optopt = c; - if (optstring[0] == ':') - c = ':'; - else - c = '?'; - } - else - /* We already incremented `optind' once; - increment it again when taking next ARGV-elt as argument. */ - optarg = argv[optind++]; - nextchar = NULL; - } - } - return c; - } -} - -int -getopt (argc, argv, optstring) - int argc; - char *const *argv; - const char *optstring; -{ - return _getopt_internal (argc, argv, optstring, - (const struct option *) 0, - (int *) 0, - 0); -} - -#endif /* _LIBC or not __GNU_LIBRARY__. */ - -#ifdef TEST - -/* Compile with -DTEST to make an executable for use in testing - the above definition of `getopt'. */ - -int -main (argc, argv) - int argc; - char **argv; -{ - int c; - int digit_optind = 0; - - while (1) - { - int this_option_optind = optind ? optind : 1; - - c = getopt (argc, argv, "abc:d:0123456789"); - if (c == EOF) - break; - - switch (c) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (digit_optind != 0 && digit_optind != this_option_optind) - printf ("digits occur in two different argv-elements.\n"); - digit_optind = this_option_optind; - printf ("option %c\n", c); - break; - - case 'a': - printf ("option a\n"); - break; - - case 'b': - printf ("option b\n"); - break; - - case 'c': - printf ("option c with value `%s'\n", optarg); - break; - - case '?': - break; - - default: - printf ("?? getopt returned character code 0%o ??\n", c); - } - } - - if (optind < argc) - { - printf ("non-option ARGV-elements: "); - while (optind < argc) - printf ("%s ", argv[optind++]); - printf ("\n"); - } - - exit (0); -} - -#endif /* TEST */ diff -r 317e7613e581 -r 0e3a8505ebbe console/getopt.h --- a/console/getopt.h Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,136 +0,0 @@ -/* Declarations for getopt. - - NOTE: getopt is now part of the C library, so if you don't know what - "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu - before changing it! - - Gaim is the legal property of its developers, whose names are too numerous - to list here. Please refer to the COPYRIGHT file distributed with this - source distribution. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2, or (at your option) any - later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#ifndef _GETOPT_H -#define _GETOPT_H 1 - -#ifdef __cplusplus -extern "C" { -#endif - -/* For communication from `getopt' to the caller. - When `getopt' finds an option that takes an argument, - the argument value is returned here. - Also, when `ordering' is RETURN_IN_ORDER, - each non-option ARGV-element is returned here. */ - -extern char *optarg; - -/* Index in ARGV of the next element to be scanned. - This is used for communication to and from the caller - and for communication between successive calls to `getopt'. - - On entry to `getopt', zero means this is the first call; initialize. - - When `getopt' returns EOF, this is the index of the first of the - non-option elements that the caller should itself scan. - - Otherwise, `optind' communicates from one call to the next - how much of ARGV has been scanned so far. */ - -extern int optind; - -/* Callers store zero here to inhibit the error message `getopt' prints - for unrecognized options. */ - -extern int opterr; - -/* Set to an option character which was unrecognized. */ - -extern int optopt; - -/* Describe the long-named options requested by the application. - The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector - of `struct option' terminated by an element containing a name which is - zero. - - The field `has_arg' is: - no_argument (or 0) if the option does not take an argument, - required_argument (or 1) if the option requires an argument, - optional_argument (or 2) if the option takes an optional argument. - - If the field `flag' is not NULL, it points to a variable that is set - to the value given in the field `val' when the option is found, but - left unchanged if the option is not found. - - To have a long-named option do something other than set an `int' to - a compiled-in constant, such as set a value from `optarg', set the - option's `flag' field to zero and its `val' field to a nonzero - value (the equivalent single-letter option character, if there is - one). For long options that have a zero `flag' field, `getopt' - returns the contents of the `val' field. */ - -struct option -{ -#if __STDC__ - const char *name; -#else - char *name; -#endif - /* has_arg can't be an enum because some compilers complain about - type mismatches in all the code that assumes it is an int. */ - int has_arg; - int *flag; - int val; -}; - -/* Names for the values of the `has_arg' field of `struct option'. */ - -#define no_argument 0 -#define required_argument 1 -#define optional_argument 2 - -#if __STDC__ -#if defined(__GNU_LIBRARY__) -/* Many other libraries have conflicting prototypes for getopt, with - differences in the consts, in stdlib.h. To avoid compilation - errors, only prototype getopt for the GNU C library. */ -extern int getopt (int argc, char *const *argv, const char *shortopts); -#else /* not __GNU_LIBRARY__ */ -extern int getopt (); -#endif /* not __GNU_LIBRARY__ */ -extern int getopt_long (int argc, char *const *argv, const char *shortopts, - const struct option *longopts, int *longind); -extern int getopt_long_only (int argc, char *const *argv, - const char *shortopts, - const struct option *longopts, int *longind); - -/* Internal only. Users should not call this directly. */ -extern int _getopt_internal (int argc, char *const *argv, - const char *shortopts, - const struct option *longopts, int *longind, - int long_only); -#else /* not __STDC__ */ -extern int getopt (); -extern int getopt_long (); -extern int getopt_long_only (); - -extern int _getopt_internal (); -#endif /* not __STDC__ */ - -#ifdef __cplusplus -} -#endif - -#endif /* _GETOPT_H */ diff -r 317e7613e581 -r 0e3a8505ebbe console/getopt1.c --- a/console/getopt1.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,177 +0,0 @@ -/* getopt_long and getopt_long_only entry points for GNU getopt. - Gaim is the legal property of its developers, whose names are too numerous - to list here. Please refer to the COPYRIGHT file distributed with this - source distribution. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2, or (at your option) any - later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "getopt.h" - -#if !__STDC__ && !defined(const) && IN_GCC -#define const -#endif - -#include - -/* Comment out all this code if we are using the GNU C Library, and are not - actually compiling the library itself. This code is part of the GNU C - Library, but also included in many other GNU distributions. Compiling - and linking in this code is a waste when using the GNU C library - (especially if it is a shared library). Rather than having every GNU - program understand `configure --with-gnu-libc' and omit the object files, - it is simpler to just do this in the source for each such file. */ - -#if defined (_LIBC) || !defined (__GNU_LIBRARY__) - - -/* This needs to come after some library #include - to get __GNU_LIBRARY__ defined. */ -#ifdef __GNU_LIBRARY__ -#include -#else -char *getenv (); -#endif - -#ifndef NULL -#define NULL 0 -#endif - -int -getopt_long (argc, argv, options, long_options, opt_index) - int argc; - char *const *argv; - const char *options; - const struct option *long_options; - int *opt_index; -{ - return _getopt_internal (argc, argv, options, long_options, opt_index, 0); -} - -/* Like getopt_long, but '-' as well as '--' can indicate a long option. - If an option that starts with '-' (not '--') doesn't match a long option, - but does match a short option, it is parsed as a short option - instead. */ - -int -getopt_long_only (argc, argv, options, long_options, opt_index) - int argc; - char *const *argv; - const char *options; - const struct option *long_options; - int *opt_index; -{ - return _getopt_internal (argc, argv, options, long_options, opt_index, 1); -} - - -#endif /* _LIBC or not __GNU_LIBRARY__. */ - -#ifdef TEST - -#include - -int -main (argc, argv) - int argc; - char **argv; -{ - int c; - int digit_optind = 0; - - while (1) - { - int this_option_optind = optind ? optind : 1; - int option_index = 0; - static struct option long_options[] = - { - {"add", 1, 0, 0}, - {"append", 0, 0, 0}, - {"delete", 1, 0, 0}, - {"verbose", 0, 0, 0}, - {"create", 0, 0, 0}, - {"file", 1, 0, 0}, - {0, 0, 0, 0} - }; - - c = getopt_long (argc, argv, "abc:d:0123456789", - long_options, &option_index); - if (c == EOF) - break; - - switch (c) - { - case 0: - printf ("option %s", long_options[option_index].name); - if (optarg) - printf (" with arg %s", optarg); - printf ("\n"); - break; - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (digit_optind != 0 && digit_optind != this_option_optind) - printf ("digits occur in two different argv-elements.\n"); - digit_optind = this_option_optind; - printf ("option %c\n", c); - break; - - case 'a': - printf ("option a\n"); - break; - - case 'b': - printf ("option b\n"); - break; - - case 'c': - printf ("option c with value `%s'\n", optarg); - break; - - case 'd': - printf ("option d with value `%s'\n", optarg); - break; - - case '?': - break; - - default: - printf ("?? getopt returned character code 0%o ??\n", c); - } - } - - if (optind < argc) - { - printf ("non-option ARGV-elements: "); - while (optind < argc) - printf ("%s ", argv[optind++]); - printf ("\n"); - } - - exit (0); -} - -#endif /* TEST */ diff -r 317e7613e581 -r 0e3a8505ebbe console/gntaccount.c --- a/console/gntaccount.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,936 +0,0 @@ -/** - * @file gntaccount.c GNT Account API - * @ingroup gntui - * - * gaim - * - * Gaim is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "gntaccount.h" -#include "gntgaim.h" - -#include - -typedef struct -{ - GntWidget *window; - GntWidget *tree; -} GGAccountList; - -static GGAccountList accounts; - -typedef struct -{ - GaimAccount *account; /* NULL for a new account */ - - GntWidget *window; - - GntWidget *protocol; - GntWidget *screenname; - GntWidget *password; - GntWidget *alias; - - GntWidget *splits; - GList *split_entries; - - GList *prpl_entries; - GntWidget *prpls; - - GntWidget *newmail; - GntWidget *remember; -} AccountEditDialog; - -/* This is necessary to close an edit-dialog when an account is deleted */ -static GList *accountdialogs; - -static void -account_add(GaimAccount *account) -{ - gnt_tree_add_choice(GNT_TREE(accounts.tree), account, - gnt_tree_create_row(GNT_TREE(accounts.tree), - gaim_account_get_username(account), - gaim_account_get_protocol_name(account)), - NULL, NULL); - gnt_tree_set_choice(GNT_TREE(accounts.tree), account, - gaim_account_get_enabled(account, GAIM_GNT_UI)); -} - -static void -edit_dialog_destroy(AccountEditDialog *dialog) -{ - accountdialogs = g_list_remove(accountdialogs, dialog); - g_list_free(dialog->prpl_entries); - g_list_free(dialog->split_entries); - g_free(dialog); -} - -static void -save_account_cb(AccountEditDialog *dialog) -{ - GaimAccount *account; - GaimPlugin *plugin; - GaimPluginProtocolInfo *prplinfo; - const char *value; - GString *username; - - /* XXX: Do some error checking first. */ - - plugin = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(dialog->protocol)); - prplinfo = GAIM_PLUGIN_PROTOCOL_INFO(plugin); - - /* Screenname && user-splits */ - value = gnt_entry_get_text(GNT_ENTRY(dialog->screenname)); - - if (value == NULL || *value == '\0') - { - gaim_notify_error(NULL, _("Error"), _("Account was not added"), - _("Screenname of an account must be non-empty.")); - return; - } - - username = g_string_new(value); - - if (prplinfo != NULL) - { - GList *iter, *entries; - for (iter = prplinfo->user_splits, entries = dialog->split_entries; - iter && entries; iter = iter->next, entries = entries->next) - { - GaimAccountUserSplit *split = iter->data; - GntWidget *entry = entries->data; - - value = gnt_entry_get_text(GNT_ENTRY(entry)); - if (value == NULL || *value == '\0') - value = gaim_account_user_split_get_default_value(split); - g_string_append_printf(username, "%c%s", - gaim_account_user_split_get_separator(split), - value); - } - } - - if (dialog->account == NULL) - { - account = gaim_account_new(username->str, gaim_plugin_get_id(plugin)); - gaim_accounts_add(account); - } - else - { - account = dialog->account; - - /* Protocol */ - gaim_account_set_protocol_id(account, gaim_plugin_get_id(plugin)); - gaim_account_set_username(account, username->str); - } - g_string_free(username, TRUE); - - /* Alias */ - value = gnt_entry_get_text(GNT_ENTRY(dialog->alias)); - if (value && *value) - gaim_account_set_alias(account, value); - - /* Remember password and password */ - gaim_account_set_remember_password(account, - gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->remember))); - value = gnt_entry_get_text(GNT_ENTRY(dialog->password)); - if (value && *value && gaim_account_get_remember_password(account)) - gaim_account_set_password(account, value); - else - gaim_account_set_password(account, NULL); - - /* Mail notification */ - gaim_account_set_check_mail(account, - gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->newmail))); - - /* Protocol options */ - if (prplinfo) - { - GList *iter, *entries; - - for (iter = prplinfo->protocol_options, entries = dialog->prpl_entries; - iter && entries; iter = iter->next, entries = entries->next) - { - GaimAccountOption *option = iter->data; - GntWidget *entry = entries->data; - GaimPrefType type = gaim_account_option_get_type(option); - const char *setting = gaim_account_option_get_setting(option); - - if (type == GAIM_PREF_STRING) - { - const char *value = gnt_entry_get_text(GNT_ENTRY(entry)); - gaim_account_set_string(account, setting, value); - } - else if (type == GAIM_PREF_INT) - { - const char *str = gnt_entry_get_text(GNT_ENTRY(entry)); - int value = 0; - if (str) - value = atoi(str); - gaim_account_set_int(account, setting, value); - } - else if (type == GAIM_PREF_BOOLEAN) - { - gboolean value = gnt_check_box_get_checked(GNT_CHECK_BOX(entry)); - gaim_account_set_bool(account, setting, value); - } - else if (type == GAIM_PREF_STRING_LIST) - { - /* TODO: */ - } - else - { - g_assert_not_reached(); - } - } - } - - /* XXX: Proxy options */ - - gnt_widget_destroy(dialog->window); -} - -static void -update_user_splits(AccountEditDialog *dialog) -{ - GntWidget *hbox; - GaimPlugin *plugin; - GaimPluginProtocolInfo *prplinfo; - GList *iter, *entries; - char *username = NULL; - - if (dialog->splits) - { - gnt_box_remove_all(GNT_BOX(dialog->splits)); - g_list_free(dialog->split_entries); - } - else - { - dialog->splits = gnt_vbox_new(FALSE); - gnt_box_set_pad(GNT_BOX(dialog->splits), 0); - gnt_box_set_fill(GNT_BOX(dialog->splits), TRUE); - } - - dialog->split_entries = NULL; - - plugin = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(dialog->protocol)); - if (!plugin) - return; - prplinfo = GAIM_PLUGIN_PROTOCOL_INFO(plugin); - - username = dialog->account ? g_strdup(gaim_account_get_username(dialog->account)) : NULL; - - for (iter = prplinfo->user_splits; iter; iter = iter->next) - { - GaimAccountUserSplit *split = iter->data; - GntWidget *entry; - char *buf; - - hbox = gnt_hbox_new(TRUE); - gnt_box_add_widget(GNT_BOX(dialog->splits), hbox); - - buf = g_strdup_printf("%s:", gaim_account_user_split_get_text(split)); - gnt_box_add_widget(GNT_BOX(hbox), gnt_label_new(buf)); - - entry = gnt_entry_new(NULL); - gnt_box_add_widget(GNT_BOX(hbox), entry); - - dialog->split_entries = g_list_append(dialog->split_entries, entry); - g_free(buf); - } - - for (iter = g_list_last(prplinfo->user_splits), entries = g_list_last(dialog->split_entries); - iter && entries; iter = iter->prev, entries = entries->prev) - { - GntWidget *entry = entries->data; - GaimAccountUserSplit *split = iter->data; - const char *value = NULL; - char *s; - - if (dialog->account) - { - s = strrchr(username, gaim_account_user_split_get_separator(split)); - if (s != NULL) - { - *s = '\0'; - s++; - value = s; - } - } - if (value == NULL) - value = gaim_account_user_split_get_default_value(split); - - if (value != NULL) - gnt_entry_set_text(GNT_ENTRY(entry), value); - } - - if (username != NULL) - gnt_entry_set_text(GNT_ENTRY(dialog->screenname), username); - - g_free(username); -} - -static void -add_protocol_options(AccountEditDialog *dialog) -{ - GaimPlugin *plugin; - GaimPluginProtocolInfo *prplinfo; - GList *iter; - GntWidget *vbox, *box; - GaimAccount *account; - - if (dialog->prpls) - gnt_box_remove_all(GNT_BOX(dialog->prpls)); - else - { - dialog->prpls = vbox = gnt_vbox_new(FALSE); - gnt_box_set_pad(GNT_BOX(vbox), 0); - gnt_box_set_alignment(GNT_BOX(vbox), GNT_ALIGN_LEFT); - gnt_box_set_fill(GNT_BOX(vbox), TRUE); - } - - if (dialog->prpl_entries) - { - g_list_free(dialog->prpl_entries); - dialog->prpl_entries = NULL; - } - - vbox = dialog->prpls; - - plugin = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(dialog->protocol)); - if (!plugin) - return; - - prplinfo = GAIM_PLUGIN_PROTOCOL_INFO(plugin); - - account = dialog->account; - - for (iter = prplinfo->protocol_options; iter; iter = iter->next) - { - GaimAccountOption *option = iter->data; - GaimPrefType type = gaim_account_option_get_type(option); - - box = gnt_hbox_new(TRUE); - gnt_box_set_pad(GNT_BOX(box), 0); - gnt_box_add_widget(GNT_BOX(vbox), box); - - if (type == GAIM_PREF_BOOLEAN) - { - GntWidget *widget = gnt_check_box_new(gaim_account_option_get_text(option)); - gnt_box_add_widget(GNT_BOX(box), widget); - dialog->prpl_entries = g_list_append(dialog->prpl_entries, widget); - - if (account) - gnt_check_box_set_checked(GNT_CHECK_BOX(widget), - gaim_account_get_bool(account, - gaim_account_option_get_setting(option), - gaim_account_option_get_default_bool(option))); - else - gnt_check_box_set_checked(GNT_CHECK_BOX(widget), - gaim_account_option_get_default_bool(option)); - } - else - { - gnt_box_add_widget(GNT_BOX(box), - gnt_label_new(gaim_account_option_get_text(option))); - - if (type == GAIM_PREF_STRING_LIST) - { - /* TODO: Use a combobox */ - /* Don't forget to append the widget to prpl_entries */ - } - else - { - GntWidget *entry = gnt_entry_new(NULL); - gnt_box_add_widget(GNT_BOX(box), entry); - dialog->prpl_entries = g_list_append(dialog->prpl_entries, entry); - - if (type == GAIM_PREF_STRING) - { - const char *dv = gaim_account_option_get_default_string(option); - - if (account) - gnt_entry_set_text(GNT_ENTRY(entry), - gaim_account_get_string(account, - gaim_account_option_get_setting(option), dv)); - else - gnt_entry_set_text(GNT_ENTRY(entry), dv); - } - else if (type == GAIM_PREF_INT) - { - char str[32]; - int value = gaim_account_option_get_default_int(option); - if (account) - value = gaim_account_get_int(account, - gaim_account_option_get_setting(option), value); - snprintf(str, sizeof(str), "%d", value); - gnt_entry_set_flag(GNT_ENTRY(entry), GNT_ENTRY_FLAG_INT); - gnt_entry_set_text(GNT_ENTRY(entry), str); - } - else - { - g_assert_not_reached(); - } - } - } - } -} - -static void -update_user_options(AccountEditDialog *dialog) -{ - GaimPlugin *plugin; - GaimPluginProtocolInfo *prplinfo; - - plugin = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(dialog->protocol)); - if (!plugin) - return; - - prplinfo = GAIM_PLUGIN_PROTOCOL_INFO(plugin); - - if (dialog->newmail == NULL) - dialog->newmail = gnt_check_box_new(_("New mail notifications")); - if (dialog->account) - gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->newmail), - gaim_account_get_check_mail(dialog->account)); - if (!prplinfo || !(prplinfo->options & OPT_PROTO_MAIL_CHECK)) - gnt_widget_set_visible(dialog->newmail, FALSE); - else - gnt_widget_set_visible(dialog->newmail, TRUE); - - if (dialog->remember == NULL) - dialog->remember = gnt_check_box_new(_("Remember password")); - if (dialog->account) - gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->remember), - gaim_account_get_remember_password(dialog->account)); -} - -static void -prpl_changed_cb(GntWidget *combo, GaimPlugin *old, GaimPlugin *new, AccountEditDialog *dialog) -{ - update_user_splits(dialog); - add_protocol_options(dialog); - update_user_options(dialog); /* This may not be necessary here */ - gnt_box_readjust(GNT_BOX(dialog->window)); - gnt_widget_draw(dialog->window); -} - -static void -edit_account(GaimAccount *account) -{ - GntWidget *window, *hbox; - GntWidget *combo, *button, *entry; - GList *list, *iter; - AccountEditDialog *dialog; - - if (account) - { - GList *iter; - for (iter = accountdialogs; iter; iter = iter->next) - { - AccountEditDialog *dlg = iter->data; - if (dlg->account == account) - return; - } - } - - dialog = g_new0(AccountEditDialog, 1); - accountdialogs = g_list_prepend(accountdialogs, dialog); - - dialog->window = window = gnt_vbox_new(FALSE); - dialog->account = account; - gnt_box_set_toplevel(GNT_BOX(window), TRUE); - gnt_box_set_title(GNT_BOX(window), account ? _("Modify Account") : _("New Account")); - gnt_box_set_alignment(GNT_BOX(window), GNT_ALIGN_MID); - gnt_box_set_pad(GNT_BOX(window), 0); - gnt_widget_set_name(window, "edit-account"); - gnt_box_set_fill(GNT_BOX(window), TRUE); - - hbox = gnt_hbox_new(TRUE); - gnt_box_set_pad(GNT_BOX(hbox), 0); - gnt_box_add_widget(GNT_BOX(window), hbox); - - dialog->protocol = combo = gnt_combo_box_new(); - list = gaim_plugins_get_protocols(); - for (iter = list; iter; iter = iter->next) - { - gnt_combo_box_add_data(GNT_COMBO_BOX(combo), iter->data, - ((GaimPlugin*)iter->data)->info->name); - } - - if (account) - gnt_combo_box_set_selected(GNT_COMBO_BOX(combo), - gaim_plugins_find_with_id(gaim_account_get_protocol_id(account))); - else - gnt_combo_box_set_selected(GNT_COMBO_BOX(combo), list->data); - - g_signal_connect(G_OBJECT(combo), "selection-changed", G_CALLBACK(prpl_changed_cb), dialog); - - gnt_box_add_widget(GNT_BOX(hbox), gnt_label_new(_("Protocol:"))); - gnt_box_add_widget(GNT_BOX(hbox), combo); - - hbox = gnt_hbox_new(TRUE); - gnt_box_set_pad(GNT_BOX(hbox), 0); - gnt_box_add_widget(GNT_BOX(window), hbox); - - dialog->screenname = entry = gnt_entry_new(NULL); - gnt_box_add_widget(GNT_BOX(hbox), gnt_label_new(_("Screen name:"))); - gnt_box_add_widget(GNT_BOX(hbox), entry); - - /* User splits */ - update_user_splits(dialog); - gnt_box_add_widget(GNT_BOX(window), dialog->splits); - - hbox = gnt_hbox_new(TRUE); - gnt_box_set_pad(GNT_BOX(hbox), 0); - gnt_box_add_widget(GNT_BOX(window), hbox); - - dialog->password = entry = gnt_entry_new(NULL); - gnt_entry_set_masked(GNT_ENTRY(entry), TRUE); - gnt_box_add_widget(GNT_BOX(hbox), gnt_label_new(_("Password:"))); - gnt_box_add_widget(GNT_BOX(hbox), entry); - if (account) - gnt_entry_set_text(GNT_ENTRY(entry), gaim_account_get_password(account)); - - hbox = gnt_hbox_new(TRUE); - gnt_box_set_pad(GNT_BOX(hbox), 0); - gnt_box_add_widget(GNT_BOX(window), hbox); - - dialog->alias = entry = gnt_entry_new(NULL); - gnt_box_add_widget(GNT_BOX(hbox), gnt_label_new(_("Alias:"))); - gnt_box_add_widget(GNT_BOX(hbox), entry); - if (account) - gnt_entry_set_text(GNT_ENTRY(entry), gaim_account_get_alias(account)); - - /* User options */ - update_user_options(dialog); - gnt_box_add_widget(GNT_BOX(window), dialog->remember); - gnt_box_add_widget(GNT_BOX(window), dialog->newmail); - - gnt_box_add_widget(GNT_BOX(window), gnt_line_new(FALSE)); - - /* The advanced box */ - add_protocol_options(dialog); - gnt_box_add_widget(GNT_BOX(window), dialog->prpls); - - /* TODO: Add proxy options */ - - /* The button box */ - hbox = gnt_hbox_new(FALSE); - gnt_box_add_widget(GNT_BOX(window), hbox); - gnt_box_set_alignment(GNT_BOX(hbox), GNT_ALIGN_MID); - - button = gnt_button_new(_("Cancel")); - gnt_box_add_widget(GNT_BOX(hbox), button); - g_signal_connect_swapped(G_OBJECT(button), "activate", G_CALLBACK(gnt_widget_destroy), window); - - button = gnt_button_new(_("Save")); - gnt_box_add_widget(GNT_BOX(hbox), button); - g_signal_connect_swapped(G_OBJECT(button), "activate", G_CALLBACK(save_account_cb), dialog); - - g_signal_connect_swapped(G_OBJECT(window), "destroy", G_CALLBACK(edit_dialog_destroy), dialog); - - gnt_widget_show(window); - gnt_box_readjust(GNT_BOX(window)); - gnt_widget_draw(window); -} - -static void -add_account_cb(GntWidget *widget, gpointer null) -{ - edit_account(NULL); -} - -static void -modify_account_cb(GntWidget *widget, GntTree *tree) -{ - GaimAccount *account = gnt_tree_get_selection_data(tree); - if (!account) - return; - edit_account(account); -} - -static void -really_delete_account(GaimAccount *account) -{ - GList *iter; - for (iter = accountdialogs; iter; iter = iter->next) - { - AccountEditDialog *dlg = iter->data; - if (dlg->account == account) - { - gnt_widget_destroy(dlg->window); - break; - } - } - gaim_request_close_with_handle(account); /* Close any other opened delete window */ - gaim_accounts_delete(account); -} - -static void -delete_account_cb(GntWidget *widget, GntTree *tree) -{ - GaimAccount *account; - char *prompt; - - account = gnt_tree_get_selection_data(tree); - if (!account) - return; - - prompt = g_strdup_printf(_("Are you sure you want to delete %s?"), - gaim_account_get_username(account)); - - gaim_request_action(account, _("Delete Account"), prompt, NULL, 0, account, 2, - _("Delete"), really_delete_account, _("Cancel"), NULL); - g_free(prompt); -} - -static void -account_toggled(GntWidget *widget, void *key, gpointer null) -{ - GaimAccount *account = key; - - gaim_account_set_enabled(account, GAIM_GNT_UI, gnt_tree_get_choice(GNT_TREE(widget), key)); -} - -static void -reset_accounts_win(GntWidget *widget, gpointer null) -{ - accounts.window = NULL; - accounts.tree = NULL; -} - -void gg_accounts_show_all() -{ - GList *iter; - GntWidget *box, *button; - - if (accounts.window) - return; - - accounts.window = gnt_vbox_new(FALSE); - gnt_box_set_toplevel(GNT_BOX(accounts.window), TRUE); - gnt_box_set_title(GNT_BOX(accounts.window), _("Accounts")); - gnt_box_set_pad(GNT_BOX(accounts.window), 0); - gnt_box_set_alignment(GNT_BOX(accounts.window), GNT_ALIGN_MID); - gnt_widget_set_name(accounts.window, "accounts"); - - gnt_box_add_widget(GNT_BOX(accounts.window), - gnt_label_new(_("You can enable/disable accounts from the following list."))); - - gnt_box_add_widget(GNT_BOX(accounts.window), gnt_line_new(FALSE)); - - accounts.tree = gnt_tree_new_with_columns(2); - GNT_WIDGET_SET_FLAGS(accounts.tree, GNT_WIDGET_NO_BORDER); - - for (iter = gaim_accounts_get_all(); iter; iter = iter->next) - { - GaimAccount *account = iter->data; - account_add(account); - } - - g_signal_connect(G_OBJECT(accounts.tree), "toggled", G_CALLBACK(account_toggled), NULL); - - gnt_tree_set_col_width(GNT_TREE(accounts.tree), 0, 40); - gnt_tree_set_col_width(GNT_TREE(accounts.tree), 1, 10); - gnt_box_add_widget(GNT_BOX(accounts.window), accounts.tree); - - gnt_box_add_widget(GNT_BOX(accounts.window), gnt_line_new(FALSE)); - - box = gnt_hbox_new(FALSE); - - button = gnt_button_new(_("Add")); - gnt_box_add_widget(GNT_BOX(box), button); - g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(add_account_cb), NULL); - - button = gnt_button_new(_("Modify")); - gnt_box_add_widget(GNT_BOX(box), button); - g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(modify_account_cb), accounts.tree); - - button = gnt_button_new(_("Delete")); - gnt_box_add_widget(GNT_BOX(box), button); - g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(delete_account_cb), accounts.tree); - - gnt_box_add_widget(GNT_BOX(accounts.window), box); - - g_signal_connect(G_OBJECT(accounts.window), "destroy", G_CALLBACK(reset_accounts_win), NULL); - - gnt_widget_show(accounts.window); -} - -static gpointer -gg_accounts_get_handle() -{ - static int handle; - - return &handle; -} - -static void -account_added_callback(GaimAccount *account) -{ - if (accounts.window == NULL) - return; - account_add(account); - gnt_widget_draw(accounts.tree); -} - -static void -account_removed_callback(GaimAccount *account) -{ - if (accounts.window == NULL) - return; - - gnt_tree_remove(GNT_TREE(accounts.tree), account); -} - -void gg_accounts_init() -{ - GList *iter; - - gaim_signal_connect(gaim_accounts_get_handle(), "account-added", - gg_accounts_get_handle(), GAIM_CALLBACK(account_added_callback), - NULL); - gaim_signal_connect(gaim_accounts_get_handle(), "account-removed", - gg_accounts_get_handle(), GAIM_CALLBACK(account_removed_callback), - NULL); - - for (iter = gaim_accounts_get_all(); iter; iter = iter->next) { - if (gaim_account_get_enabled(iter->data, GAIM_GNT_UI)) - break; - } - if (!iter) - gg_accounts_show_all(); -} - -void gg_accounts_uninit() -{ - if (accounts.window) - gnt_widget_destroy(accounts.window); -} - -/* The following uiops stuff are copied from gtkaccount.c */ -typedef struct -{ - GaimAccount *account; - char *username; - char *alias; -} AddUserData; - -static char * -make_info(GaimAccount *account, GaimConnection *gc, const char *remote_user, - const char *id, const char *alias, const char *msg) -{ - if (msg != NULL && *msg == '\0') - msg = NULL; - - return g_strdup_printf(_("%s%s%s%s has made %s his or her buddy%s%s"), - remote_user, - (alias != NULL ? " (" : ""), - (alias != NULL ? alias : ""), - (alias != NULL ? ")" : ""), - (id != NULL - ? id - : (gaim_connection_get_display_name(gc) != NULL - ? gaim_connection_get_display_name(gc) - : gaim_account_get_username(account))), - (msg != NULL ? ": " : "."), - (msg != NULL ? msg : "")); -} - -static void -notify_added(GaimAccount *account, const char *remote_user, - const char *id, const char *alias, - const char *msg) -{ - char *buffer; - GaimConnection *gc; - - gc = gaim_account_get_connection(account); - - buffer = make_info(account, gc, remote_user, id, alias, msg); - - gaim_notify_info(NULL, NULL, buffer, NULL); - - g_free(buffer); -} - -static void -free_add_user_data(AddUserData *data) -{ - g_free(data->username); - - if (data->alias != NULL) - g_free(data->alias); - - g_free(data); -} - -static void -add_user_cb(AddUserData *data) -{ - GaimConnection *gc = gaim_account_get_connection(data->account); - - if (g_list_find(gaim_connections_get_all(), gc)) - { - gaim_blist_request_add_buddy(data->account, data->username, - NULL, data->alias); - } - - free_add_user_data(data); -} - -static void -request_add(GaimAccount *account, const char *remote_user, - const char *id, const char *alias, - const char *msg) -{ - char *buffer; - GaimConnection *gc; - AddUserData *data; - - gc = gaim_account_get_connection(account); - - data = g_new0(AddUserData, 1); - data->account = account; - data->username = g_strdup(remote_user); - data->alias = (alias != NULL ? g_strdup(alias) : NULL); - - buffer = make_info(account, gc, remote_user, id, alias, msg); - gaim_request_action(NULL, NULL, _("Add buddy to your list?"), - buffer, GAIM_DEFAULT_ACTION_NONE, data, 2, - _("Add"), G_CALLBACK(add_user_cb), - _("Cancel"), G_CALLBACK(free_add_user_data)); - g_free(buffer); -} - -/* Copied from gtkaccount.c */ -typedef struct { - GaimAccountRequestAuthorizationCb auth_cb; - GaimAccountRequestAuthorizationCb deny_cb; - void *data; - char *username; - char *alias; - GaimAccount *account; -} auth_and_add; - -static void -authorize_and_add_cb(auth_and_add *aa) -{ - aa->auth_cb(aa->data); - gaim_blist_request_add_buddy(aa->account, aa->username, - NULL, aa->alias); - - g_free(aa->username); - g_free(aa->alias); - g_free(aa); -} - -static void -deny_no_add_cb(auth_and_add *aa) -{ - aa->deny_cb(aa->data); - - g_free(aa->username); - g_free(aa->alias); - g_free(aa); -} - -static void * -gg_request_authorize(GaimAccount *account, const char *remote_user, - const char *id, const char *alias, const char *message, gboolean on_list, - GCallback auth_cb, GCallback deny_cb, void *user_data) -{ - char *buffer; - GaimConnection *gc; - void *uihandle; - - gc = gaim_account_get_connection(account); - if (message != NULL && *message == '\0') - message = NULL; - - buffer = g_strdup_printf(_("%s%s%s%s wants to add %s to his or her buddy list%s%s"), - remote_user, - (alias != NULL ? " (" : ""), - (alias != NULL ? alias : ""), - (alias != NULL ? ")" : ""), - (id != NULL - ? id - : (gaim_connection_get_display_name(gc) != NULL - ? gaim_connection_get_display_name(gc) - : gaim_account_get_username(account))), - (message != NULL ? ": " : "."), - (message != NULL ? message : "")); - if (!on_list) { - auth_and_add *aa = g_new(auth_and_add, 1); - aa->auth_cb = (GaimAccountRequestAuthorizationCb)auth_cb; - aa->deny_cb = (GaimAccountRequestAuthorizationCb)deny_cb; - aa->data = user_data; - aa->username = g_strdup(remote_user); - aa->alias = g_strdup(alias); - aa->account = account; - uihandle = gaim_request_action(NULL, _("Authorize buddy?"), buffer, NULL, - GAIM_DEFAULT_ACTION_NONE, aa, 2, - _("Authorize"), authorize_and_add_cb, - _("Deny"), deny_no_add_cb); - } else { - uihandle = gaim_request_action(NULL, _("Authorize buddy?"), buffer, NULL, - GAIM_DEFAULT_ACTION_NONE, user_data, 2, - _("Authorize"), auth_cb, - _("Deny"), deny_cb); - } - g_free(buffer); - return uihandle; -} - -static void -gg_request_close(void *uihandle) -{ - gaim_request_close(GAIM_REQUEST_ACTION, uihandle); -} - -static GaimAccountUiOps ui_ops = -{ - .notify_added = notify_added, - .status_changed = NULL, - .request_add = request_add, - .request_authorize = gg_request_authorize, - .close_account_request = gg_request_close -}; - -GaimAccountUiOps *gg_accounts_get_ui_ops() -{ - return &ui_ops; -} - diff -r 317e7613e581 -r 0e3a8505ebbe console/gntaccount.h --- a/console/gntaccount.h Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/** - * @file gntaccount.h GNT Account API - * @ingroup gntui - * - * gaim - * - * Gaim is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef _GNT_ACCOUNT_H -#define _GNT_ACCOUNT_H - -#include "account.h" - -/********************************************************************** - * @name GNT Account API - **********************************************************************/ -/*@{*/ - -/** - * Get the ui-functions. - * - * @return The GaimAccountUiOps structure populated with the appropriate functions. - */ -GaimAccountUiOps *gg_accounts_get_ui_ops(void); - -/** - * Perform necessary initializations. - */ -void gg_accounts_init(void); - -/** - * Perform necessary uninitializations. - */ -void gg_accounts_uninit(void); - -/** - * Show the account-manager dialog. - */ -void gg_accounts_show_all(void); - -/*@}*/ - -#endif diff -r 317e7613e581 -r 0e3a8505ebbe console/gntblist.c --- a/console/gntblist.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2233 +0,0 @@ -/** - * @file gntblist.c GNT BuddyList API - * @ingroup gntui - * - * gaim - * - * Gaim is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "debug.h" - -#include "gntgaim.h" -#include "gntbox.h" -#include "gntcombobox.h" -#include "gntentry.h" -#include "gntft.h" -#include "gntlabel.h" -#include "gntline.h" -#include "gntmenu.h" -#include "gntmenuitem.h" -#include "gntmenuitemcheck.h" -#include "gntpounce.h" -#include "gnttree.h" -#include "gntutils.h" -#include "gntwindow.h" - -#include "gntblist.h" -#include "gntconv.h" -#include "gntstatus.h" -#include - -#define PREF_ROOT "/gaim/gnt/blist" -#define TYPING_TIMEOUT 4000 - -typedef struct -{ - GntWidget *window; - GntWidget *tree; - - GntWidget *tooltip; - GaimBlistNode *tnode; /* Who is the tooltip being displayed for? */ - GList *tagged; /* A list of tagged blistnodes */ - - GntWidget *context; - GaimBlistNode *cnode; - - /* XXX: I am KISSing */ - GntWidget *status; /* Dropdown with the statuses */ - GntWidget *statustext; /* Status message */ - int typing; - - GntWidget *menu; - /* These are the menuitems that get regenerated */ - GntMenuItem *accounts; - GntMenuItem *plugins; -} GGBlist; - -typedef enum -{ - STATUS_PRIMITIVE = 0, - STATUS_SAVED_POPULAR, - STATUS_SAVED_ALL, - STATUS_SAVED_NEW -} StatusType; - -typedef struct -{ - StatusType type; - union - { - GaimStatusPrimitive prim; - GaimSavedStatus *saved; - } u; -} StatusBoxItem; - -GGBlist *ggblist; - -static void add_buddy(GaimBuddy *buddy, GGBlist *ggblist); -static void add_contact(GaimContact *contact, GGBlist *ggblist); -static void add_group(GaimGroup *group, GGBlist *ggblist); -static void add_chat(GaimChat *chat, GGBlist *ggblist); -static void add_node(GaimBlistNode *node, GGBlist *ggblist); -static void draw_tooltip(GGBlist *ggblist); -static gboolean remove_typing_cb(gpointer null); -static void remove_peripherals(GGBlist *ggblist); -static const char * get_display_name(GaimBlistNode *node); -static void savedstatus_changed(GaimSavedStatus *now, GaimSavedStatus *old); -static void blist_show(GaimBuddyList *list); -static void update_buddy_display(GaimBuddy *buddy, GGBlist *ggblist); -static void account_signed_on_cb(void); - -/* Sort functions */ -static int blist_node_compare_text(GaimBlistNode *n1, GaimBlistNode *n2); -static int blist_node_compare_status(GaimBlistNode *n1, GaimBlistNode *n2); -static int blist_node_compare_log(GaimBlistNode *n1, GaimBlistNode *n2); - -static gboolean -is_contact_online(GaimContact *contact) -{ - GaimBlistNode *node; - for (node = ((GaimBlistNode*)contact)->child; node; node = node->next) { - if (GAIM_BUDDY_IS_ONLINE((GaimBuddy*)node)) - return TRUE; - } - return FALSE; -} - -static gboolean -is_group_online(GaimGroup *group) -{ - GaimBlistNode *node; - for (node = ((GaimBlistNode*)group)->child; node; node = node->next) { - if (GAIM_BLIST_NODE_IS_CHAT(node)) - return TRUE; - else if (is_contact_online((GaimContact*)node)) - return TRUE; - } - return FALSE; -} - -static void -new_node(GaimBlistNode *node) -{ -} - -static void add_node(GaimBlistNode *node, GGBlist *ggblist) -{ - if (GAIM_BLIST_NODE_IS_BUDDY(node)) - add_buddy((GaimBuddy*)node, ggblist); - else if (GAIM_BLIST_NODE_IS_CONTACT(node)) - add_contact((GaimContact*)node, ggblist); - else if (GAIM_BLIST_NODE_IS_GROUP(node)) - add_group((GaimGroup*)node, ggblist); - else if (GAIM_BLIST_NODE_IS_CHAT(node)) - add_chat((GaimChat *)node, ggblist); - draw_tooltip(ggblist); -} - -static void -remove_tooltip(GGBlist *ggblist) -{ - gnt_widget_destroy(ggblist->tooltip); - ggblist->tooltip = NULL; - ggblist->tnode = NULL; -} - -static void -node_remove(GaimBuddyList *list, GaimBlistNode *node) -{ - GGBlist *ggblist = list->ui_data; - - if (ggblist == NULL || node->ui_data == NULL) - return; - - gnt_tree_remove(GNT_TREE(ggblist->tree), node); - node->ui_data = NULL; - if (ggblist->tagged) - ggblist->tagged = g_list_remove(ggblist->tagged, node); - - if (GAIM_BLIST_NODE_IS_BUDDY(node)) { - GaimContact *contact = (GaimContact*)node->parent; - if ((!gaim_prefs_get_bool(PREF_ROOT "/showoffline") && !is_contact_online(contact)) || - contact->currentsize < 1) - node_remove(list, (GaimBlistNode*)contact); - } else if (GAIM_BLIST_NODE_IS_CONTACT(node)) { - GaimGroup *group = (GaimGroup*)node->parent; - if ((!gaim_prefs_get_bool(PREF_ROOT "/showoffline") && !is_group_online(group)) || - group->currentsize < 1) - node_remove(list, node->parent); - for (node = node->child; node; node = node->next) - node->ui_data = NULL; - } - - draw_tooltip(ggblist); -} - -static void -node_update(GaimBuddyList *list, GaimBlistNode *node) -{ - /* It really looks like this should never happen ... but it does. - This will at least emit a warning to the log when it - happens, so maybe someone will figure it out. */ - g_return_if_fail(node != NULL); - - if (list->ui_data == NULL) - return; /* XXX: this is probably the place to auto-join chats */ - - if (node->ui_data != NULL) { - gnt_tree_change_text(GNT_TREE(ggblist->tree), node, - 0, get_display_name(node)); - gnt_tree_sort_row(GNT_TREE(ggblist->tree), node); - } - - if (GAIM_BLIST_NODE_IS_BUDDY(node)) { - GaimBuddy *buddy = (GaimBuddy*)node; - if (gaim_account_is_connected(buddy->account) && - (GAIM_BUDDY_IS_ONLINE(buddy) || gaim_prefs_get_bool(PREF_ROOT "/showoffline"))) - add_node((GaimBlistNode*)buddy, list->ui_data); - else - node_remove(gaim_get_blist(), node); - - node_update(list, node->parent); - } else if (GAIM_BLIST_NODE_IS_CHAT(node)) { - add_chat((GaimChat *)node, list->ui_data); - } else if (GAIM_BLIST_NODE_IS_CONTACT(node)) { - GaimContact *contact = (GaimContact*)node; - if ((!gaim_prefs_get_bool(PREF_ROOT "/showoffline") && !is_contact_online(contact)) || - contact->currentsize < 1) - node_remove(gaim_get_blist(), node); - else - add_node(node, list->ui_data); - } else if (GAIM_BLIST_NODE_IS_GROUP(node)) { - GaimGroup *group = (GaimGroup*)node; - if ((!gaim_prefs_get_bool(PREF_ROOT "/showoffline") && !is_group_online(group)) || - group->currentsize < 1) - node_remove(list, node); - } -} - -static void -new_list(GaimBuddyList *list) -{ - if (ggblist) - return; - - ggblist = g_new0(GGBlist, 1); - list->ui_data = ggblist; -} - -static void -add_buddy_cb(void *data, GaimRequestFields *allfields) -{ - const char *username = gaim_request_fields_get_string(allfields, "screenname"); - const char *alias = gaim_request_fields_get_string(allfields, "alias"); - const char *group = gaim_request_fields_get_string(allfields, "group"); - GaimAccount *account = gaim_request_fields_get_account(allfields, "account"); - const char *error = NULL; - GaimGroup *grp; - GaimBuddy *buddy; - - if (!username) - error = _("You must provide a screename for the buddy."); - else if (!group) - error = _("You must provide a group."); - else if (!account) - error = _("You must select an account."); - - if (error) - { - gaim_notify_error(NULL, _("Error"), _("Error adding buddy"), error); - return; - } - - grp = gaim_find_group(group); - if (!grp) - { - grp = gaim_group_new(group); - gaim_blist_add_group(grp, NULL); - } - - buddy = gaim_buddy_new(account, username, alias); - gaim_blist_add_buddy(buddy, NULL, grp, NULL); - gaim_account_add_buddy(account, buddy); -} - -static void -gg_request_add_buddy(GaimAccount *account, const char *username, const char *grp, const char *alias) -{ - GaimRequestFields *fields = gaim_request_fields_new(); - GaimRequestFieldGroup *group = gaim_request_field_group_new(NULL); - GaimRequestField *field; - - gaim_request_fields_add_group(fields, group); - - field = gaim_request_field_string_new("screenname", _("Screen Name"), username, FALSE); - gaim_request_field_group_add_field(group, field); - - field = gaim_request_field_string_new("alias", _("Alias"), alias, FALSE); - gaim_request_field_group_add_field(group, field); - - field = gaim_request_field_string_new("group", _("Group"), grp, FALSE); - gaim_request_field_group_add_field(group, field); - - field = gaim_request_field_account_new("account", _("Account"), NULL); - gaim_request_field_account_set_show_all(field, FALSE); - if (account) - gaim_request_field_account_set_value(field, account); - gaim_request_field_group_add_field(group, field); - - gaim_request_fields(NULL, _("Add Buddy"), NULL, _("Please enter buddy information."), - fields, _("Add"), G_CALLBACK(add_buddy_cb), _("Cancel"), NULL, NULL); -} - -static void -add_chat_cb(void *data, GaimRequestFields *allfields) -{ - GaimAccount *account; - const char *alias, *name, *group; - GaimChat *chat; - GaimGroup *grp; - GHashTable *hash = NULL; - GaimConnection *gc; - - account = gaim_request_fields_get_account(allfields, "account"); - name = gaim_request_fields_get_string(allfields, "name"); - alias = gaim_request_fields_get_string(allfields, "alias"); - group = gaim_request_fields_get_string(allfields, "group"); - - if (!gaim_account_is_connected(account) || !name || !*name) - return; - - if (!group || !*group) - group = _("Chats"); - - gc = gaim_account_get_connection(account); - - if (GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info_defaults != NULL) - hash = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info_defaults(gc, name); - - chat = gaim_chat_new(account, name, hash); - - if (chat != NULL) { - if ((grp = gaim_find_group(group)) == NULL) { - grp = gaim_group_new(group); - gaim_blist_add_group(grp, NULL); - } - gaim_blist_add_chat(chat, grp, NULL); - gaim_blist_alias_chat(chat, alias); - } -} - -static void -gg_request_add_chat(GaimAccount *account, GaimGroup *grp, const char *alias, const char *name) -{ - GaimRequestFields *fields = gaim_request_fields_new(); - GaimRequestFieldGroup *group = gaim_request_field_group_new(NULL); - GaimRequestField *field; - - gaim_request_fields_add_group(fields, group); - - field = gaim_request_field_account_new("account", _("Account"), NULL); - gaim_request_field_account_set_show_all(field, FALSE); - if (account) - gaim_request_field_account_set_value(field, account); - gaim_request_field_group_add_field(group, field); - - field = gaim_request_field_string_new("name", _("Name"), name, FALSE); - gaim_request_field_group_add_field(group, field); - - field = gaim_request_field_string_new("alias", _("Alias"), alias, FALSE); - gaim_request_field_group_add_field(group, field); - - field = gaim_request_field_string_new("group", _("Group"), grp ? grp->name : NULL, FALSE); - gaim_request_field_group_add_field(group, field); - - gaim_request_fields(NULL, _("Add Chat"), NULL, - _("You can edit more information from the context menu later."), - fields, _("Add"), G_CALLBACK(add_chat_cb), _("Cancel"), NULL, NULL); -} - -static void -add_group_cb(gpointer null, const char *group) -{ - GaimGroup *grp; - - if (!group || !*group) - { - gaim_notify_error(NULL, _("Error"), _("Error adding group"), - _("You must give a name for the group to add.")); - return; - } - - grp = gaim_find_group(group); - if (!grp) - { - grp = gaim_group_new(group); - gaim_blist_add_group(grp, NULL); - } - else - { - gaim_notify_error(NULL, _("Error"), _("Error adding group"), - _("A group with the name already exists.")); - } -} - -static void -gg_request_add_group() -{ - gaim_request_input(NULL, _("Add Group"), NULL, _("Enter the name of the group"), - NULL, FALSE, FALSE, NULL, - _("Add"), G_CALLBACK(add_group_cb), _("Cancel"), NULL, NULL); -} - -static GaimBlistUiOps blist_ui_ops = -{ - new_list, - new_node, - blist_show, - node_update, - node_remove, - NULL, - NULL, - .request_add_buddy = gg_request_add_buddy, - .request_add_chat = gg_request_add_chat, - .request_add_group = gg_request_add_group -}; - -static gpointer -gg_blist_get_handle() -{ - static int handle; - - return &handle; -} - -static void -add_group(GaimGroup *group, GGBlist *ggblist) -{ - GaimBlistNode *node = (GaimBlistNode *)group; - if (node->ui_data) - return; - node->ui_data = gnt_tree_add_row_after(GNT_TREE(ggblist->tree), group, - gnt_tree_create_row(GNT_TREE(ggblist->tree), get_display_name(node)), NULL, NULL); -} - -static const char * -get_display_name(GaimBlistNode *node) -{ - static char text[2096]; - char status[8] = " "; - const char *name = NULL; - - if (GAIM_BLIST_NODE_IS_CONTACT(node)) - node = (GaimBlistNode*)gaim_contact_get_priority_buddy((GaimContact*)node); /* XXX: this can return NULL?! */ - - if (node == NULL) - return NULL; - - if (GAIM_BLIST_NODE_IS_BUDDY(node)) - { - GaimBuddy *buddy = (GaimBuddy *)node; - GaimStatusPrimitive prim; - GaimPresence *presence; - GaimStatus *now; - gboolean ascii = gnt_ascii_only(); - - presence = gaim_buddy_get_presence(buddy); - now = gaim_presence_get_active_status(presence); - - prim = gaim_status_type_get_primitive(gaim_status_get_type(now)); - - switch(prim) - { - case GAIM_STATUS_OFFLINE: - strncpy(status, ascii ? "x" : "⊗", sizeof(status) - 1); - break; - case GAIM_STATUS_AVAILABLE: - strncpy(status, ascii ? "o" : "◯", sizeof(status) - 1); - break; - default: - strncpy(status, ascii ? "." : "⊖", sizeof(status) - 1); - break; - } - name = gaim_buddy_get_alias(buddy); - } - else if (GAIM_BLIST_NODE_IS_CHAT(node)) - { - GaimChat *chat = (GaimChat*)node; - name = gaim_chat_get_name(chat); - - strncpy(status, "~", sizeof(status) - 1); - } - else if (GAIM_BLIST_NODE_IS_GROUP(node)) - return ((GaimGroup*)node)->name; - - snprintf(text, sizeof(text) - 1, "%s %s", status, name); - - return text; -} - -static void -add_chat(GaimChat *chat, GGBlist *ggblist) -{ - GaimGroup *group; - GaimBlistNode *node = (GaimBlistNode *)chat; - if (node->ui_data) - return; - if (!gaim_account_is_connected(chat->account)) - return; - - group = gaim_chat_get_group(chat); - add_node((GaimBlistNode*)group, ggblist); - - node->ui_data = gnt_tree_add_row_after(GNT_TREE(ggblist->tree), chat, - gnt_tree_create_row(GNT_TREE(ggblist->tree), get_display_name(node)), - group, NULL); -} - -static void -add_contact(GaimContact *contact, GGBlist *ggblist) -{ - GaimGroup *group; - GaimBlistNode *node = (GaimBlistNode*)contact; - const char *name; - - if (node->ui_data) - return; - - name = get_display_name(node); - if (name == NULL) - return; - - group = (GaimGroup*)node->parent; - add_node((GaimBlistNode*)group, ggblist); - - node->ui_data = gnt_tree_add_row_after(GNT_TREE(ggblist->tree), contact, - gnt_tree_create_row(GNT_TREE(ggblist->tree), name), - group, NULL); - - gnt_tree_set_expanded(GNT_TREE(ggblist->tree), contact, FALSE); -} - -static void -add_buddy(GaimBuddy *buddy, GGBlist *ggblist) -{ - GaimContact *contact; - GaimBlistNode *node = (GaimBlistNode *)buddy; - if (node->ui_data) - return; - - contact = (GaimContact*)node->parent; - if (!contact) /* When a new buddy is added and show-offline is set */ - return; - add_node((GaimBlistNode*)contact, ggblist); - - node->ui_data = gnt_tree_add_row_after(GNT_TREE(ggblist->tree), buddy, - gnt_tree_create_row(GNT_TREE(ggblist->tree), get_display_name(node)), - contact, NULL); - if (gaim_presence_is_idle(gaim_buddy_get_presence(buddy))) { - gnt_tree_set_row_flags(GNT_TREE(ggblist->tree), buddy, GNT_TEXT_FLAG_DIM); - gnt_tree_set_row_flags(GNT_TREE(ggblist->tree), contact, GNT_TEXT_FLAG_DIM); - } else { - gnt_tree_set_row_flags(GNT_TREE(ggblist->tree), buddy, 0); - gnt_tree_set_row_flags(GNT_TREE(ggblist->tree), contact, 0); - } -} - -#if 0 -static void -buddy_signed_on(GaimBuddy *buddy, GGBlist *ggblist) -{ - add_node((GaimBlistNode*)buddy, ggblist); -} - -static void -buddy_signed_off(GaimBuddy *buddy, GGBlist *ggblist) -{ - node_remove(gaim_get_blist(), (GaimBlistNode*)buddy); -} -#endif - -GaimBlistUiOps *gg_blist_get_ui_ops() -{ - return &blist_ui_ops; -} - -static void -selection_activate(GntWidget *widget, GGBlist *ggblist) -{ - GntTree *tree = GNT_TREE(ggblist->tree); - GaimBlistNode *node = gnt_tree_get_selection_data(tree); - - if (!node) - return; - - if (GAIM_BLIST_NODE_IS_CONTACT(node)) - node = (GaimBlistNode*)gaim_contact_get_priority_buddy((GaimContact*)node); - - if (GAIM_BLIST_NODE_IS_BUDDY(node)) - { - GaimBuddy *buddy = (GaimBuddy *)node; - GaimConversation *conv = gaim_conversation_new(GAIM_CONV_TYPE_IM, - gaim_buddy_get_account(buddy), - gaim_buddy_get_name(buddy)); - gg_conversation_set_active(conv); - } - else if (GAIM_BLIST_NODE_IS_CHAT(node)) - { - GaimChat *chat = (GaimChat*)node; - serv_join_chat(chat->account->gc, chat->components); - } -} - -static void -context_menu_callback(GntMenuItem *item, gpointer data) -{ - GaimMenuAction *action = data; - GaimBlistNode *node = ggblist->cnode; - if (action) { - void (*callback)(GaimBlistNode *, gpointer); - callback = (void (*)(GaimBlistNode *, gpointer))action->callback; - if (callback) - callback(action->data, node); - else - return; - } -} - -static void -gnt_append_menu_action(GntMenu *menu, GaimMenuAction *action, gpointer parent) -{ - GList *list; - GntMenuItem *item; - - if (action == NULL) - return; - - item = gnt_menuitem_new(action->label); - if (action->callback) - gnt_menuitem_set_callback(GNT_MENUITEM(item), context_menu_callback, action); - gnt_menu_add_item(menu, GNT_MENUITEM(item)); - - if (action->children) { - GntWidget *sub = gnt_menu_new(GNT_MENU_POPUP); - gnt_menuitem_set_submenu(item, GNT_MENU(sub)); - for (list = action->children; list; list = list->next) - gnt_append_menu_action(GNT_MENU(sub), list->data, action); - } -} - -static void -append_proto_menu(GntMenu *menu, GaimConnection *gc, GaimBlistNode *node) -{ - GList *list; - GaimPluginProtocolInfo *prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl); - - if(!prpl_info || !prpl_info->blist_node_menu) - return; - - for(list = prpl_info->blist_node_menu(node); list; - list = g_list_delete_link(list, list)) - { - GaimMenuAction *act = (GaimMenuAction *) list->data; - act->data = node; - gnt_append_menu_action(menu, act, NULL); - } -} - -static void -add_custom_action(GntMenu *menu, const char *label, GaimCallback callback, - gpointer data) -{ - GaimMenuAction *action = gaim_menu_action_new(label, callback, data, NULL); - gnt_append_menu_action(menu, action, NULL); - g_signal_connect_swapped(G_OBJECT(menu), "destroy", - G_CALLBACK(gaim_menu_action_free), action); -} - -static void -chat_components_edit_ok(GaimChat *chat, GaimRequestFields *allfields) -{ - GList *groups, *fields; - - for (groups = gaim_request_fields_get_groups(allfields); groups; groups = groups->next) { - fields = gaim_request_field_group_get_fields(groups->data); - for (; fields; fields = fields->next) { - GaimRequestField *field = fields->data; - const char *id; - char *val; - - id = gaim_request_field_get_id(field); - if (gaim_request_field_get_type(field) == GAIM_REQUEST_FIELD_INTEGER) - val = g_strdup_printf("%d", gaim_request_field_int_get_value(field)); - else - val = g_strdup(gaim_request_field_string_get_value(field)); - - g_hash_table_replace(chat->components, g_strdup(id), val); /* val should not be free'd */ - } - } -} - -static void -chat_components_edit(GaimChat *chat, GaimBlistNode *selected) -{ - GaimRequestFields *fields = gaim_request_fields_new(); - GaimRequestFieldGroup *group = gaim_request_field_group_new(NULL); - GaimRequestField *field; - GList *parts, *iter; - struct proto_chat_entry *pce; - - gaim_request_fields_add_group(fields, group); - - parts = GAIM_PLUGIN_PROTOCOL_INFO(chat->account->gc->prpl)->chat_info(chat->account->gc); - - for (iter = parts; iter; iter = iter->next) { - pce = iter->data; - if (pce->is_int) { - int val; - const char *str = g_hash_table_lookup(chat->components, pce->identifier); - if (!str || sscanf(str, "%d", &val) != 1) - val = pce->min; - field = gaim_request_field_int_new(pce->identifier, pce->label, val); - } else { - field = gaim_request_field_string_new(pce->identifier, pce->label, - g_hash_table_lookup(chat->components, pce->identifier), FALSE); - } - - gaim_request_field_group_add_field(group, field); - g_free(pce); - } - - g_list_free(parts); - - gaim_request_fields(NULL, _("Edit Chat"), NULL, _("Please Update the necessary fields."), - fields, _("Edit"), G_CALLBACK(chat_components_edit_ok), _("Cancel"), NULL, chat); -} - -static void -autojoin_toggled(GntMenuItem *item, gpointer data) -{ - GaimMenuAction *action = data; - gaim_blist_node_set_bool(action->data, "gnt-autojoin", - gnt_menuitem_check_get_checked(GNT_MENUITEM_CHECK(item))); -} - -static void -create_chat_menu(GntMenu *menu, GaimChat *chat) -{ - GaimMenuAction *action = gaim_menu_action_new(_("Auto-join"), NULL, chat, NULL); - GntMenuItem *check = gnt_menuitem_check_new(action->label); - gnt_menuitem_check_set_checked(GNT_MENUITEM_CHECK(check), - gaim_blist_node_get_bool((GaimBlistNode*)chat, "gnt-autojoin")); - gnt_menu_add_item(menu, check); - gnt_menuitem_set_callback(check, autojoin_toggled, action); - g_signal_connect_swapped(G_OBJECT(menu), "destroy", - G_CALLBACK(gaim_menu_action_free), action); - - add_custom_action(menu, _("Edit Settings"), (GaimCallback)chat_components_edit, chat); -} - -static void -gg_add_buddy(GaimGroup *grp, GaimBlistNode *selected) -{ - gaim_blist_request_add_buddy(NULL, NULL, grp ? grp->name : NULL, NULL); -} - -static void -gg_add_group(GaimGroup *grp, GaimBlistNode *selected) -{ - gaim_blist_request_add_group(); -} - -static void -gg_add_chat(GaimGroup *grp, GaimBlistNode *selected) -{ - gaim_blist_request_add_chat(NULL, grp, NULL, NULL); -} - -static void -create_group_menu(GntMenu *menu, GaimGroup *group) -{ - add_custom_action(menu, _("Add Buddy"), - GAIM_CALLBACK(gg_add_buddy), group); - add_custom_action(menu, _("Add Chat"), - GAIM_CALLBACK(gg_add_chat), group); - add_custom_action(menu, _("Add Group"), - GAIM_CALLBACK(gg_add_group), group); -} - -static void -gg_blist_get_buddy_info_cb(GaimBuddy *buddy, GaimBlistNode *selected) -{ - serv_get_info(buddy->account->gc, gaim_buddy_get_name(buddy)); -} - -static void -gg_blist_menu_send_file_cb(GaimBuddy *buddy, GaimBlistNode *selected) -{ - serv_send_file(buddy->account->gc, buddy->name, NULL); -} - -static void -gg_blist_pounce_node_cb(GaimBlistNode *node, GaimBlistNode *selected) -{ - GaimBuddy *b; - if (GAIM_BLIST_NODE_IS_CONTACT(node)) - b = gaim_contact_get_priority_buddy((GaimContact *)node); - else - b = (GaimBuddy *)node; - gg_pounce_editor_show(b->account, b->name, NULL); -} - - -static void -create_buddy_menu(GntMenu *menu, GaimBuddy *buddy) -{ - GaimPluginProtocolInfo *prpl_info; - - prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(buddy->account->gc->prpl); - if (prpl_info && prpl_info->get_info) - { - add_custom_action(menu, _("Get Info"), - GAIM_CALLBACK(gg_blist_get_buddy_info_cb), buddy); - } - - add_custom_action(menu, _("Add Buddy Pounce"), - GAIM_CALLBACK(gg_blist_pounce_node_cb), buddy); - - if (prpl_info && prpl_info->send_file) - { - if (!prpl_info->can_receive_file || - prpl_info->can_receive_file(buddy->account->gc, buddy->name)) - add_custom_action(menu, _("Send File"), - GAIM_CALLBACK(gg_blist_menu_send_file_cb), buddy); - } -#if 0 - add_custom_action(tree, _("View Log"), - GAIM_CALLBACK(gg_blist_view_log_cb)), buddy); -#endif - - /* Protocol actions */ - append_proto_menu(menu, - gaim_account_get_connection(gaim_buddy_get_account(buddy)), - (GaimBlistNode*)buddy); -} - -static void -append_extended_menu(GntMenu *menu, GaimBlistNode *node) -{ - GList *iter; - - for (iter = gaim_blist_node_get_extended_menu(node); - iter; iter = g_list_delete_link(iter, iter)) - { - gnt_append_menu_action(menu, iter->data, NULL); - } -} - -/* Xerox'd from gtkdialogs.c:gaim_gtkdialogs_remove_contact_cb */ -static void -remove_contact(GaimContact *contact) -{ - GaimBlistNode *bnode, *cnode; - GaimGroup *group; - - cnode = (GaimBlistNode *)contact; - group = (GaimGroup*)cnode->parent; - for (bnode = cnode->child; bnode; bnode = bnode->next) { - GaimBuddy *buddy = (GaimBuddy*)bnode; - if (gaim_account_is_connected(buddy->account)) - gaim_account_remove_buddy(buddy->account, buddy, group); - } - gaim_blist_remove_contact(contact); -} - -static void -rename_blist_node(GaimBlistNode *node, const char *newname) -{ - const char *name = newname; - if (name && !*name) - name = NULL; - - if (GAIM_BLIST_NODE_IS_CONTACT(node)) { - GaimContact *contact = (GaimContact*)node; - GaimBuddy *buddy = gaim_contact_get_priority_buddy(contact); - gaim_blist_alias_contact(contact, name); - gaim_blist_alias_buddy(buddy, name); - serv_alias_buddy(buddy); - } else if (GAIM_BLIST_NODE_IS_BUDDY(node)) { - gaim_blist_alias_buddy((GaimBuddy*)node, name); - serv_alias_buddy((GaimBuddy*)node); - } else if (GAIM_BLIST_NODE_IS_CHAT(node)) - gaim_blist_alias_chat((GaimChat*)node, name); - else if (GAIM_BLIST_NODE_IS_GROUP(node) && (name != NULL)) - gaim_blist_rename_group((GaimGroup*)node, name); - else - g_return_if_reached(); -} - -static void -gg_blist_rename_node_cb(GaimBlistNode *node, GaimBlistNode *selected) -{ - const char *name = NULL; - char *prompt; - - if (GAIM_BLIST_NODE_IS_CONTACT(node)) - name = gaim_contact_get_alias((GaimContact*)node); - else if (GAIM_BLIST_NODE_IS_BUDDY(node)) - name = gaim_buddy_get_contact_alias((GaimBuddy*)node); - else if (GAIM_BLIST_NODE_IS_CHAT(node)) - name = gaim_chat_get_name((GaimChat*)node); - else if (GAIM_BLIST_NODE_IS_GROUP(node)) - name = ((GaimGroup*)node)->name; - else - g_return_if_reached(); - - prompt = g_strdup_printf(_("Please enter the new name for %s"), name); - - gaim_request_input(node, _("Rename"), prompt, _("Enter empty string to reset the name."), - name, FALSE, FALSE, NULL, _("Rename"), G_CALLBACK(rename_blist_node), - _("Cancel"), NULL, node); - - g_free(prompt); -} - -/* Xeroxed from gtkdialogs.c:gaim_gtkdialogs_remove_group_cb*/ -static void -remove_group(GaimGroup *group) -{ - GaimBlistNode *cnode, *bnode; - - cnode = ((GaimBlistNode*)group)->child; - - while (cnode) { - if (GAIM_BLIST_NODE_IS_CONTACT(cnode)) { - bnode = cnode->child; - cnode = cnode->next; - while (bnode) { - GaimBuddy *buddy; - if (GAIM_BLIST_NODE_IS_BUDDY(bnode)) { - buddy = (GaimBuddy*)bnode; - bnode = bnode->next; - if (gaim_account_is_connected(buddy->account)) { - gaim_account_remove_buddy(buddy->account, buddy, group); - gaim_blist_remove_buddy(buddy); - } - } else { - bnode = bnode->next; - } - } - } else if (GAIM_BLIST_NODE_IS_CHAT(cnode)) { - GaimChat *chat = (GaimChat *)cnode; - cnode = cnode->next; - if (gaim_account_is_connected(chat->account)) - gaim_blist_remove_chat(chat); - } else { - cnode = cnode->next; - } - } - - gaim_blist_remove_group(group); -} - -static void -gg_blist_remove_node(GaimBlistNode *node) -{ - if (GAIM_BLIST_NODE_IS_CONTACT(node)) { - remove_contact((GaimContact*)node); - } else if (GAIM_BLIST_NODE_IS_BUDDY(node)) { - GaimBuddy *buddy = (GaimBuddy*)node; - GaimGroup *group = gaim_buddy_get_group(buddy); - gaim_account_remove_buddy(gaim_buddy_get_account(buddy), buddy, group); - gaim_blist_remove_buddy(buddy); - } else if (GAIM_BLIST_NODE_IS_CHAT(node)) { - gaim_blist_remove_chat((GaimChat*)node); - } else if (GAIM_BLIST_NODE_IS_GROUP(node)) { - remove_group((GaimGroup*)node); - } -} - -static void -gg_blist_remove_node_cb(GaimBlistNode *node, GaimBlistNode *selected) -{ - char *primary; - const char *name, *sec = NULL; - - /* XXX: could be a contact */ - if (GAIM_BLIST_NODE_IS_CONTACT(node)) { - GaimContact *c = (GaimContact*)node; - name = gaim_contact_get_alias(c); - if (c->totalsize > 1) - sec = _("Removing this contact will also remove all the buddies in the contact"); - } else if (GAIM_BLIST_NODE_IS_BUDDY(node)) - name = gaim_buddy_get_name((GaimBuddy*)node); - else if (GAIM_BLIST_NODE_IS_CHAT(node)) - name = gaim_chat_get_name((GaimChat*)node); - else if (GAIM_BLIST_NODE_IS_GROUP(node)) - { - name = ((GaimGroup*)node)->name; - sec = _("Removing this group will also remove all the buddies in the group"); - } - else - return; - - primary = g_strdup_printf(_("Are you sure you want to remove %s?"), name); - - /* XXX: anything to do with the returned ui-handle? */ - gaim_request_action(node, _("Confirm Remove"), - primary, sec, - 1, node, 2, - _("Remove"), gg_blist_remove_node, - _("Cancel"), NULL); - g_free(primary); -} - -static void -gg_blist_toggle_tag_buddy(GaimBlistNode *node) -{ - GList *iter; - if (node == NULL) - return; - if (GAIM_BLIST_NODE_IS_CHAT(node) || GAIM_BLIST_NODE_IS_GROUP(node)) - return; - if (ggblist->tagged && (iter = g_list_find(ggblist->tagged, node)) != NULL) { - ggblist->tagged = g_list_delete_link(ggblist->tagged, iter); - } else { - ggblist->tagged = g_list_prepend(ggblist->tagged, node); - } - if (GAIM_BLIST_NODE_IS_CONTACT(node)) - node = (GaimBlistNode*)gaim_contact_get_priority_buddy((GaimContact*)node); - update_buddy_display((GaimBuddy*)node, ggblist); -} - -static void -gg_blist_place_tagged(GaimBlistNode *target) -{ - GaimGroup *tg = NULL; - GaimContact *tc = NULL; - - if (target == NULL) - return; - - /* This target resolution probably needs more clarification; for - * example, if I tag a buddy in a contact, then place on - * another buddy in the same contact, I probably intend to - * place the tagged buddy immediately after (before?) the - * target buddy -- this will simply move the tagged buddy - * within the same contact without reference to position. */ - if (GAIM_BLIST_NODE_IS_GROUP(target)) - tg = (GaimGroup*)target; - else if (GAIM_BLIST_NODE_IS_CONTACT(target)) - tc = (GaimContact*)target; - else /* Buddy or Chat */ - tc = (GaimContact*)target->parent; - - if (ggblist->tagged) { - GList *list = ggblist->tagged; - ggblist->tagged = NULL; - - while (list) { - GaimBlistNode *node = list->data; - list = g_list_delete_link(list, list); - if (tg) { - if (GAIM_BLIST_NODE_IS_CONTACT(node)) - gaim_blist_add_contact((GaimContact*)node, tg, NULL); - else - gaim_blist_add_buddy((GaimBuddy*)node, NULL, tg, NULL); - } else { - if (GAIM_BLIST_NODE_IS_BUDDY(node)) - gaim_blist_add_buddy((GaimBuddy*)node, tc, - gaim_buddy_get_group(gaim_contact_get_priority_buddy(tc)), NULL); - else if (GAIM_BLIST_NODE_IS_CONTACT(node)) - gaim_blist_merge_contact((GaimContact*)node, target); - } - } - } -} - -static void -context_menu_destroyed(GntWidget *widget, GGBlist *ggblist) -{ - ggblist->context = NULL; -} - -static void -draw_context_menu(GGBlist *ggblist) -{ - GaimBlistNode *node = NULL; - GntWidget *context = NULL; - GntTree *tree = NULL; - int x, y, top, width; - char *title = NULL; - - tree = GNT_TREE(ggblist->tree); - - node = gnt_tree_get_selection_data(tree); - - if (ggblist->tooltip) - remove_tooltip(ggblist); - - ggblist->cnode = node; - - ggblist->context = context = gnt_menu_new(GNT_MENU_POPUP); - g_signal_connect(G_OBJECT(context), "destroy", G_CALLBACK(context_menu_destroyed), ggblist); - - if (!node) { - create_group_menu(GNT_MENU(context), NULL); - title = g_strdup(_("Buddy List")); - } else if (GAIM_BLIST_NODE_IS_CONTACT(node)) { - create_buddy_menu(GNT_MENU(context), - gaim_contact_get_priority_buddy((GaimContact*)node)); - title = g_strdup(gaim_contact_get_alias((GaimContact*)node)); - } else if (GAIM_BLIST_NODE_IS_BUDDY(node)) { - GaimBuddy *buddy = (GaimBuddy *)node; - create_buddy_menu(GNT_MENU(context), buddy); - title = g_strdup(gaim_buddy_get_name(buddy)); - } else if (GAIM_BLIST_NODE_IS_CHAT(node)) { - GaimChat *chat = (GaimChat*)node; - create_chat_menu(GNT_MENU(context), chat); - title = g_strdup(gaim_chat_get_name(chat)); - } else if (GAIM_BLIST_NODE_IS_GROUP(node)) { - GaimGroup *group = (GaimGroup *)node; - create_group_menu(GNT_MENU(context), group); - title = g_strdup(group->name); - } - - append_extended_menu(GNT_MENU(context), node); - - /* These are common for everything */ - if (node) { - add_custom_action(GNT_MENU(context), _("Rename"), - GAIM_CALLBACK(gg_blist_rename_node_cb), node); - add_custom_action(GNT_MENU(context), _("Remove"), - GAIM_CALLBACK(gg_blist_remove_node_cb), node); - - if (ggblist->tagged && (GAIM_BLIST_NODE_IS_CONTACT(node) - || GAIM_BLIST_NODE_IS_GROUP(node))) { - add_custom_action(GNT_MENU(context), _("Place tagged"), - GAIM_CALLBACK(gg_blist_place_tagged), node); - } - - if (GAIM_BLIST_NODE_IS_BUDDY(node) || GAIM_BLIST_NODE_IS_CONTACT(node)) { - add_custom_action(GNT_MENU(context), _("Toggle Tag"), - GAIM_CALLBACK(gg_blist_toggle_tag_buddy), node); - } - } - - /* Set the position for the popup */ - gnt_widget_get_position(GNT_WIDGET(tree), &x, &y); - gnt_widget_get_size(GNT_WIDGET(tree), &width, NULL); - top = gnt_tree_get_selection_visible_line(tree); - - x += width; - y += top - 1; - - gnt_widget_set_position(context, x, y); - gnt_screen_menu_show(GNT_MENU(context)); - g_free(title); -} - -static void -tooltip_for_buddy(GaimBuddy *buddy, GString *str) -{ - GaimPlugin *prpl; - GaimPluginProtocolInfo *prpl_info; - GaimAccount *account; - GaimNotifyUserInfo *user_info; - const char *alias = gaim_buddy_get_alias(buddy); - char *tmp, *strip; - - user_info = gaim_notify_user_info_new(); - - account = gaim_buddy_get_account(buddy); - - if (g_utf8_collate(gaim_buddy_get_name(buddy), alias)) - gaim_notify_user_info_add_pair(user_info, _("Nickname"), alias); - - tmp = g_strdup_printf("%s (%s)", - gaim_account_get_username(account), - gaim_account_get_protocol_name(account)); - gaim_notify_user_info_add_pair(user_info, _("Account"), tmp); - g_free(tmp); - - prpl = gaim_find_prpl(gaim_account_get_protocol_id(account)); - prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(prpl); - if (prpl_info && prpl_info->tooltip_text) { - prpl_info->tooltip_text(buddy, user_info, TRUE); - } - - if (gaim_prefs_get_bool("/gaim/gnt/blist/idletime")) { - GaimPresence *pre = gaim_buddy_get_presence(buddy); - if (gaim_presence_is_idle(pre)) { - time_t idle = gaim_presence_get_idle_time(pre); - if (idle > 0) { - char *st = gaim_str_seconds_to_string(time(NULL) - idle); - gaim_notify_user_info_add_pair(user_info, _("Idle"), st); - g_free(st); - } - } - } - - tmp = gaim_notify_user_info_get_text_with_newline(user_info, "
"); - gaim_notify_user_info_destroy(user_info); - - strip = gaim_markup_strip_html(tmp); - g_string_append(str, strip); - g_free(strip); - g_free(tmp); -} - -static GString* -make_sure_text_fits(GString *string) -{ - int maxw = getmaxx(stdscr) - 3; - char *str = gnt_util_onscreen_fit_string(string->str, maxw); - string = g_string_assign(string, str); - g_free(str); - return string; -} - -static gboolean -draw_tooltip_real(GGBlist *ggblist) -{ - GaimBlistNode *node; - int x, y, top, width, w, h; - GString *str; - GntTree *tree; - GntWidget *widget, *box, *tv; - char *title = NULL; - int lastseen = 0; - - widget = ggblist->tree; - tree = GNT_TREE(widget); - - if (!gnt_widget_has_focus(ggblist->tree) || - (ggblist->context && !GNT_WIDGET_IS_FLAG_SET(ggblist->context, GNT_WIDGET_INVISIBLE))) - return FALSE; - - if (ggblist->tooltip) - { - /* XXX: Once we can properly redraw on expose events, this can be removed at the end - * to avoid the blinking*/ - remove_tooltip(ggblist); - } - - node = gnt_tree_get_selection_data(tree); - if (!node) - return FALSE; - - str = g_string_new(""); - - if (GAIM_BLIST_NODE_IS_CONTACT(node)) { - GaimBuddy *pr = gaim_contact_get_priority_buddy((GaimContact*)node); - gboolean offline = !GAIM_BUDDY_IS_ONLINE(pr); - gboolean showoffline = gaim_prefs_get_bool(PREF_ROOT "/showoffline"); - const char *name = gaim_buddy_get_name(pr); - - title = g_strdup(name); - tooltip_for_buddy(pr, str); - for (node = node->child; node; node = node->next) { - GaimBuddy *buddy = (GaimBuddy*)node; - if (offline) { - int value = gaim_blist_node_get_int(node, "last_seen"); - if (value > lastseen) - lastseen = value; - } - if (node == (GaimBlistNode*)pr) - continue; - if (!gaim_account_is_connected(buddy->account)) - continue; - if (!showoffline && !GAIM_BUDDY_IS_ONLINE(buddy)) - continue; - str = g_string_append(str, "\n----------\n"); - tooltip_for_buddy(buddy, str); - } - } else if (GAIM_BLIST_NODE_IS_BUDDY(node)) { - GaimBuddy *buddy = (GaimBuddy *)node; - tooltip_for_buddy(buddy, str); - title = g_strdup(gaim_buddy_get_name(buddy)); - if (!GAIM_BUDDY_IS_ONLINE((GaimBuddy*)node)) - lastseen = gaim_blist_node_get_int(node, "last_seen"); - } else if (GAIM_BLIST_NODE_IS_GROUP(node)) { - GaimGroup *group = (GaimGroup *)node; - - g_string_append_printf(str, _("Online: %d\nTotal: %d"), - gaim_blist_get_group_online_count(group), - gaim_blist_get_group_size(group, FALSE)); - - title = g_strdup(group->name); - } else if (GAIM_BLIST_NODE_IS_CHAT(node)) { - GaimChat *chat = (GaimChat *)node; - GaimAccount *account = chat->account; - - g_string_append_printf(str, _("Account: %s (%s)"), - gaim_account_get_username(account), - gaim_account_get_protocol_name(account)); - - title = g_strdup(gaim_chat_get_name(chat)); - } else { - g_string_free(str, TRUE); - return FALSE; - } - - if (lastseen > 0) { - char *tmp = gaim_str_seconds_to_string(time(NULL) - lastseen); - g_string_append_printf(str, _("\nLast Seen: %s ago"), tmp); - g_free(tmp); - } - - gnt_widget_get_position(widget, &x, &y); - gnt_widget_get_size(widget, &width, NULL); - top = gnt_tree_get_selection_visible_line(tree); - - x += width; - y += top - 1; - - box = gnt_box_new(FALSE, FALSE); - gnt_box_set_toplevel(GNT_BOX(box), TRUE); - GNT_WIDGET_SET_FLAGS(box, GNT_WIDGET_NO_SHADOW); - gnt_box_set_title(GNT_BOX(box), title); - - str = make_sure_text_fits(str); - gnt_util_get_text_bound(str->str, &w, &h); - h = MAX(2, h); - tv = gnt_text_view_new(); - gnt_widget_set_size(tv, w + 1, h); - gnt_box_add_widget(GNT_BOX(box), tv); - - gnt_widget_set_position(box, x, y); - GNT_WIDGET_UNSET_FLAGS(box, GNT_WIDGET_CAN_TAKE_FOCUS); - GNT_WIDGET_SET_FLAGS(box, GNT_WIDGET_TRANSIENT); - gnt_widget_draw(box); - - gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(tv), str->str, GNT_TEXT_FLAG_NORMAL); - gnt_text_view_scroll(GNT_TEXT_VIEW(tv), 0); - - g_free(title); - g_string_free(str, TRUE); - ggblist->tooltip = box; - ggblist->tnode = node; - - gnt_widget_set_name(ggblist->tooltip, "tooltip"); - return FALSE; -} - -static void -draw_tooltip(GGBlist *ggblist) -{ - /* When an account has signed off, it removes one buddy at a time. - * Drawing the tooltip after removing each buddy is expensive. On - * top of that, if the selected buddy belongs to the disconnected - * account, then retreiving the tooltip for that causes crash. So - * let's make sure we wait for all the buddies to be removed first.*/ - int id = g_timeout_add(0, (GSourceFunc)draw_tooltip_real, ggblist); - g_object_set_data_full(G_OBJECT(ggblist->window), "draw_tooltip_calback", - GINT_TO_POINTER(id), (GDestroyNotify)g_source_remove); -} - -static void -selection_changed(GntWidget *widget, gpointer old, gpointer current, GGBlist *ggblist) -{ - draw_tooltip(ggblist); -} - -static gboolean -context_menu(GntWidget *widget, GGBlist *ggblist) -{ - draw_context_menu(ggblist); - return TRUE; -} - -static gboolean -key_pressed(GntWidget *widget, const char *text, GGBlist *ggblist) -{ - if (text[0] == 27 && text[1] == 0) { - /* Escape was pressed */ - remove_peripherals(ggblist); - } else if (strcmp(text, GNT_KEY_CTRL_O) == 0) { - gaim_prefs_set_bool(PREF_ROOT "/showoffline", - !gaim_prefs_get_bool(PREF_ROOT "/showoffline")); - } else if (GNT_TREE(ggblist->tree)->search == NULL) { - if (strcmp(text, "t") == 0) { - gg_blist_toggle_tag_buddy(gnt_tree_get_selection_data(GNT_TREE(ggblist->tree))); - gnt_bindable_perform_action_named(GNT_BINDABLE(ggblist->tree), "move-down"); - } else if (strcmp(text, "a") == 0) { - gg_blist_place_tagged(gnt_tree_get_selection_data(GNT_TREE(ggblist->tree))); - } else - return FALSE; - } else - return FALSE; - - return TRUE; -} - -static void -update_buddy_display(GaimBuddy *buddy, GGBlist *ggblist) -{ - GaimContact *contact; - GntTextFormatFlags bflag = 0, cflag = 0; - - contact = gaim_buddy_get_contact(buddy); - - gnt_tree_change_text(GNT_TREE(ggblist->tree), buddy, 0, get_display_name((GaimBlistNode*)buddy)); - gnt_tree_change_text(GNT_TREE(ggblist->tree), contact, 0, get_display_name((GaimBlistNode*)contact)); - - if (ggblist->tagged && g_list_find(ggblist->tagged, buddy)) - bflag |= GNT_TEXT_FLAG_BOLD; - if (ggblist->tagged && g_list_find(ggblist->tagged, contact)) - cflag |= GNT_TEXT_FLAG_BOLD; - - if (ggblist->tnode == (GaimBlistNode*)buddy) - draw_tooltip(ggblist); - - if (gaim_presence_is_idle(gaim_buddy_get_presence(buddy))) { - gnt_tree_set_row_flags(GNT_TREE(ggblist->tree), buddy, bflag | GNT_TEXT_FLAG_DIM); - gnt_tree_set_row_flags(GNT_TREE(ggblist->tree), contact, cflag | GNT_TEXT_FLAG_DIM); - } else { - gnt_tree_set_row_flags(GNT_TREE(ggblist->tree), buddy, bflag); - gnt_tree_set_row_flags(GNT_TREE(ggblist->tree), contact, cflag); - } -} - -static void -buddy_status_changed(GaimBuddy *buddy, GaimStatus *old, GaimStatus *now, GGBlist *ggblist) -{ - update_buddy_display(buddy, ggblist); -} - -static void -buddy_idle_changed(GaimBuddy *buddy, int old, int new, GGBlist *ggblist) -{ - update_buddy_display(buddy, ggblist); -} - -static void -remove_peripherals(GGBlist *ggblist) -{ - if (ggblist->tooltip) - remove_tooltip(ggblist); - else if (ggblist->context) - gnt_widget_destroy(ggblist->context); -} - -static void -size_changed_cb(GntWidget *w, int wi, int h) -{ - int width, height; - gnt_widget_get_size(w, &width, &height); - gaim_prefs_set_int(PREF_ROOT "/size/width", width); - gaim_prefs_set_int(PREF_ROOT "/size/height", height); -} - -static void -save_position_cb(GntWidget *w, int x, int y) -{ - gaim_prefs_set_int(PREF_ROOT "/position/x", x); - gaim_prefs_set_int(PREF_ROOT "/position/y", y); -} - -static void -reset_blist_window(GntWidget *window, gpointer null) -{ - GaimBlistNode *node; - gaim_signals_disconnect_by_handle(gg_blist_get_handle()); - gaim_get_blist()->ui_data = NULL; - - node = gaim_blist_get_root(); - while (node) { - node->ui_data = NULL; - node = gaim_blist_node_next(node, TRUE); - } - - if (ggblist->typing) - g_source_remove(ggblist->typing); - remove_peripherals(ggblist); - if (ggblist->tagged) - g_list_free(ggblist->tagged); - g_free(ggblist); - ggblist = NULL; -} - -static void -populate_buddylist() -{ - GaimBlistNode *node; - GaimBuddyList *list; - - if (strcmp(gaim_prefs_get_string(PREF_ROOT "/sort_type"), "text") == 0) { - gnt_tree_set_compare_func(GNT_TREE(ggblist->tree), - (GCompareFunc)blist_node_compare_text); - } else if (strcmp(gaim_prefs_get_string(PREF_ROOT "/sort_type"), "status") == 0) { - gnt_tree_set_compare_func(GNT_TREE(ggblist->tree), - (GCompareFunc)blist_node_compare_status); - } else if (strcmp(gaim_prefs_get_string(PREF_ROOT "/sort_type"), "log") == 0) { - gnt_tree_set_compare_func(GNT_TREE(ggblist->tree), - (GCompareFunc)blist_node_compare_log); - } - - list = gaim_get_blist(); - node = gaim_blist_get_root(); - while (node) - { - node_update(list, node); - node = gaim_blist_node_next(node, FALSE); - } -} - -static void -destroy_status_list(GList *list) -{ - g_list_foreach(list, (GFunc)g_free, NULL); - g_list_free(list); -} - -static void -populate_status_dropdown() -{ - int i; - GList *iter; - GList *items = NULL; - StatusBoxItem *item = NULL; - - /* First the primitives */ - GaimStatusPrimitive prims[] = {GAIM_STATUS_AVAILABLE, GAIM_STATUS_AWAY, - GAIM_STATUS_INVISIBLE, GAIM_STATUS_OFFLINE, GAIM_STATUS_UNSET}; - - gnt_combo_box_remove_all(GNT_COMBO_BOX(ggblist->status)); - - for (i = 0; prims[i] != GAIM_STATUS_UNSET; i++) - { - item = g_new0(StatusBoxItem, 1); - item->type = STATUS_PRIMITIVE; - item->u.prim = prims[i]; - items = g_list_prepend(items, item); - gnt_combo_box_add_data(GNT_COMBO_BOX(ggblist->status), item, - gaim_primitive_get_name_from_type(prims[i])); - } - - /* Now the popular statuses */ - for (iter = gaim_savedstatuses_get_popular(6); iter; iter = iter->next) - { - item = g_new0(StatusBoxItem, 1); - item->type = STATUS_SAVED_POPULAR; - item->u.saved = iter->data; - items = g_list_prepend(items, item); - gnt_combo_box_add_data(GNT_COMBO_BOX(ggblist->status), item, - gaim_savedstatus_get_title(iter->data)); - } - - /* New savedstatus */ - item = g_new0(StatusBoxItem, 1); - item->type = STATUS_SAVED_NEW; - items = g_list_prepend(items, item); - gnt_combo_box_add_data(GNT_COMBO_BOX(ggblist->status), item, - _("New...")); - - /* More savedstatuses */ - item = g_new0(StatusBoxItem, 1); - item->type = STATUS_SAVED_ALL; - items = g_list_prepend(items, item); - gnt_combo_box_add_data(GNT_COMBO_BOX(ggblist->status), item, - _("Saved...")); - - /* The keys for the combobox are created here, and never used - * anywhere else. So make sure the keys are freed when the widget - * is destroyed. */ - g_object_set_data_full(G_OBJECT(ggblist->status), "list of statuses", - items, (GDestroyNotify)destroy_status_list); -} - -static void -redraw_blist(const char *name, GaimPrefType type, gconstpointer val, gpointer data) -{ - GaimBlistNode *node, *sel; - if (ggblist == NULL || ggblist->window == NULL) - return; - - sel = gnt_tree_get_selection_data(GNT_TREE(ggblist->tree)); - gnt_tree_remove_all(GNT_TREE(ggblist->tree)); - node = gaim_blist_get_root(); - for (; node; node = gaim_blist_node_next(node, TRUE)) - node->ui_data = NULL; - populate_buddylist(); - gnt_tree_set_selected(GNT_TREE(ggblist->tree), sel); - draw_tooltip(ggblist); -} - -void gg_blist_init() -{ - gaim_prefs_add_none(PREF_ROOT); - gaim_prefs_add_none(PREF_ROOT "/size"); - gaim_prefs_add_int(PREF_ROOT "/size/width", 20); - gaim_prefs_add_int(PREF_ROOT "/size/height", 17); - gaim_prefs_add_none(PREF_ROOT "/position"); - gaim_prefs_add_int(PREF_ROOT "/position/x", 0); - gaim_prefs_add_int(PREF_ROOT "/position/y", 0); - gaim_prefs_add_bool(PREF_ROOT "/idletime", TRUE); - gaim_prefs_add_bool(PREF_ROOT "/showoffline", FALSE); - gaim_prefs_add_string(PREF_ROOT "/sort_type", "text"); - - gaim_prefs_connect_callback(gg_blist_get_handle(), - PREF_ROOT "/showoffline", redraw_blist, NULL); - gaim_prefs_connect_callback(gg_blist_get_handle(), - PREF_ROOT "/sort_type", redraw_blist, NULL); - - gaim_signal_connect(gaim_connections_get_handle(), "signed-on", gaim_blist_get_handle(), - G_CALLBACK(account_signed_on_cb), NULL); - return; -} - -static gboolean -remove_typing_cb(gpointer null) -{ - GaimSavedStatus *current; - const char *message, *newmessage; - GaimStatusPrimitive prim, newprim; - StatusBoxItem *item; - - current = gaim_savedstatus_get_current(); - message = gaim_savedstatus_get_message(current); - prim = gaim_savedstatus_get_type(current); - - newmessage = gnt_entry_get_text(GNT_ENTRY(ggblist->statustext)); - item = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(ggblist->status)); - g_return_val_if_fail(item->type == STATUS_PRIMITIVE, FALSE); - newprim = item->u.prim; - - if (newprim != prim || ((message && !newmessage) || - (!message && newmessage) || - (message && newmessage && g_utf8_collate(message, newmessage) != 0))) - { - GaimSavedStatus *status = gaim_savedstatus_find_transient_by_type_and_message(newprim, newmessage); - /* Holy Crap! That's a LAWNG function name */ - if (status == NULL) - { - status = gaim_savedstatus_new(NULL, newprim); - gaim_savedstatus_set_message(status, newmessage); - } - - gaim_savedstatus_activate(status); - } - - gnt_box_give_focus_to_child(GNT_BOX(ggblist->window), ggblist->tree); - if (ggblist->typing) - g_source_remove(ggblist->typing); - ggblist->typing = 0; - return FALSE; -} - -static void -status_selection_changed(GntComboBox *box, StatusBoxItem *old, StatusBoxItem *now, gpointer null) -{ - gnt_entry_set_text(GNT_ENTRY(ggblist->statustext), NULL); - if (now->type == STATUS_SAVED_POPULAR) - { - /* Set the status immediately */ - gaim_savedstatus_activate(now->u.saved); - } - else if (now->type == STATUS_PRIMITIVE) - { - /* Move the focus to the entry box */ - /* XXX: Make sure the selected status can have a message */ - gnt_box_move_focus(GNT_BOX(ggblist->window), 1); - ggblist->typing = g_timeout_add(TYPING_TIMEOUT, (GSourceFunc)remove_typing_cb, NULL); - } - else if (now->type == STATUS_SAVED_ALL) - { - /* Restore the selection to reflect current status. */ - savedstatus_changed(gaim_savedstatus_get_current(), NULL); - gnt_box_give_focus_to_child(GNT_BOX(ggblist->window), ggblist->tree); - gg_savedstatus_show_all(); - } - else if (now->type == STATUS_SAVED_NEW) - { - savedstatus_changed(gaim_savedstatus_get_current(), NULL); - gnt_box_give_focus_to_child(GNT_BOX(ggblist->window), ggblist->tree); - gg_savedstatus_edit(NULL); - } - else - g_return_if_reached(); -} - -static gboolean -status_text_changed(GntEntry *entry, const char *text, gpointer null) -{ - if ((text[0] == 27 || (text[0] == '\t' && text[1] == '\0')) && ggblist->typing == 0) - return FALSE; - - if (ggblist->typing) - g_source_remove(ggblist->typing); - ggblist->typing = 0; - - if (text[0] == '\r' && text[1] == 0) - { - /* Set the status only after you press 'Enter' */ - remove_typing_cb(NULL); - return TRUE; - } - - ggblist->typing = g_timeout_add(TYPING_TIMEOUT, (GSourceFunc)remove_typing_cb, NULL); - return FALSE; -} - -static void -savedstatus_changed(GaimSavedStatus *now, GaimSavedStatus *old) -{ - GList *list; - GaimStatusPrimitive prim; - const char *message; - gboolean found = FALSE, saved = TRUE; - - if (!ggblist) - return; - - /* Block the signals we don't want to emit */ - g_signal_handlers_block_matched(ggblist->status, G_SIGNAL_MATCH_FUNC, - 0, 0, NULL, status_selection_changed, NULL); - g_signal_handlers_block_matched(ggblist->statustext, G_SIGNAL_MATCH_FUNC, - 0, 0, NULL, status_text_changed, NULL); - - prim = gaim_savedstatus_get_type(now); - message = gaim_savedstatus_get_message(now); - - /* Rebuild the status dropdown */ - populate_status_dropdown(); - - while (!found) { - list = g_object_get_data(G_OBJECT(ggblist->status), "list of statuses"); - for (; list; list = list->next) - { - StatusBoxItem *item = list->data; - if ((saved && item->type != STATUS_PRIMITIVE && item->u.saved == now) || - (!saved && item->type == STATUS_PRIMITIVE && item->u.prim == prim)) - { - char *mess = gaim_unescape_html(message); - gnt_combo_box_set_selected(GNT_COMBO_BOX(ggblist->status), item); - gnt_entry_set_text(GNT_ENTRY(ggblist->statustext), mess); - gnt_widget_draw(ggblist->status); - g_free(mess); - found = TRUE; - break; - } - } - if (!saved) - break; - saved = FALSE; - } - - g_signal_handlers_unblock_matched(ggblist->status, G_SIGNAL_MATCH_FUNC, - 0, 0, NULL, status_selection_changed, NULL); - g_signal_handlers_unblock_matched(ggblist->statustext, G_SIGNAL_MATCH_FUNC, - 0, 0, NULL, status_text_changed, NULL); -} - -static int -blist_node_compare_text(GaimBlistNode *n1, GaimBlistNode *n2) -{ - const char *s1, *s2; - char *us1, *us2; - int ret; - - g_return_val_if_fail(n1->type == n2->type, -1); - - switch (n1->type) - { - case GAIM_BLIST_GROUP_NODE: - s1 = ((GaimGroup*)n1)->name; - s2 = ((GaimGroup*)n2)->name; - break; - case GAIM_BLIST_CHAT_NODE: - s1 = gaim_chat_get_name((GaimChat*)n1); - s2 = gaim_chat_get_name((GaimChat*)n2); - break; - case GAIM_BLIST_BUDDY_NODE: - return gaim_presence_compare(gaim_buddy_get_presence((GaimBuddy*)n1), - gaim_buddy_get_presence((GaimBuddy*)n2)); - break; - case GAIM_BLIST_CONTACT_NODE: - s1 = gaim_contact_get_alias((GaimContact*)n1); - s2 = gaim_contact_get_alias((GaimContact*)n2); - break; - default: - return -1; - } - - us1 = g_utf8_strup(s1, -1); - us2 = g_utf8_strup(s2, -1); - ret = g_utf8_collate(us1, us2); - g_free(us1); - g_free(us2); - - return ret; -} - -static int -blist_node_compare_status(GaimBlistNode *n1, GaimBlistNode *n2) -{ - int ret; - - g_return_val_if_fail(n1->type == n2->type, -1); - - switch (n1->type) { - case GAIM_BLIST_CONTACT_NODE: - n1 = (GaimBlistNode*)gaim_contact_get_priority_buddy((GaimContact*)n1); - n2 = (GaimBlistNode*)gaim_contact_get_priority_buddy((GaimContact*)n2); - /* now compare the presence of the priority buddies */ - case GAIM_BLIST_BUDDY_NODE: - ret = gaim_presence_compare(gaim_buddy_get_presence((GaimBuddy*)n1), - gaim_buddy_get_presence((GaimBuddy*)n2)); - if (ret != 0) - return ret; - break; - default: - break; - } - - /* Sort alphabetically if presence is not comparable */ - ret = blist_node_compare_text(n1, n2); - - return ret; -} - -static int -get_contact_log_size(GaimBlistNode *c) -{ - int log = 0; - GaimBlistNode *node; - - for (node = c->child; node; node = node->next) { - GaimBuddy *b = (GaimBuddy*)node; - log += gaim_log_get_total_size(GAIM_LOG_IM, b->name, b->account); - } - - return log; -} - -static int -blist_node_compare_log(GaimBlistNode *n1, GaimBlistNode *n2) -{ - int ret; - GaimBuddy *b1, *b2; - - g_return_val_if_fail(n1->type == n2->type, -1); - - switch (n1->type) { - case GAIM_BLIST_BUDDY_NODE: - b1 = (GaimBuddy*)n1; - b2 = (GaimBuddy*)n2; - ret = gaim_log_get_total_size(GAIM_LOG_IM, b2->name, b2->account) - - gaim_log_get_total_size(GAIM_LOG_IM, b1->name, b1->account); - if (ret != 0) - return ret; - break; - case GAIM_BLIST_CONTACT_NODE: - ret = get_contact_log_size(n2) - get_contact_log_size(n1); - if (ret != 0) - return ret; - break; - default: - break; - } - ret = blist_node_compare_text(n1, n2); - return ret; -} - -static gboolean -blist_clicked(GntTree *tree, GntMouseEvent event, int x, int y, gpointer ggblist) -{ - if (event == GNT_RIGHT_MOUSE_DOWN) { - draw_context_menu(ggblist); - } - return FALSE; -} - -static void -plugin_action(GntMenuItem *item, gpointer data) -{ - GaimPluginAction *action = data; - if (action && action->callback) - action->callback(action); -} - -static void -build_plugin_actions(GntMenuItem *item, GaimPlugin *plugin, gpointer context) -{ - GntWidget *sub = gnt_menu_new(GNT_MENU_POPUP); - GList *actions; - GntMenuItem *menuitem; - - gnt_menuitem_set_submenu(item, GNT_MENU(sub)); - for (actions = GAIM_PLUGIN_ACTIONS(plugin, context); actions; - actions = g_list_delete_link(actions, actions)) { - if (actions->data) { - GaimPluginAction *action = actions->data; - action->plugin = plugin; - action->context = context; - menuitem = gnt_menuitem_new(action->label); - gnt_menu_add_item(GNT_MENU(sub), menuitem); - - gnt_menuitem_set_callback(menuitem, plugin_action, action); - g_object_set_data_full(G_OBJECT(menuitem), "plugin_action", - action, (GDestroyNotify)gaim_plugin_action_free); - } - } -} - -static void -reconstruct_plugins_menu() -{ - GntWidget *sub; - GntMenuItem *plg; - GList *iter; - - if (!ggblist) - return; - - if (ggblist->plugins == NULL) - ggblist->plugins = gnt_menuitem_new(_("Plugins")); - - plg = ggblist->plugins; - sub = gnt_menu_new(GNT_MENU_POPUP); - gnt_menuitem_set_submenu(plg, GNT_MENU(sub)); - - for (iter = gaim_plugins_get_loaded(); iter; iter = iter->next) { - GaimPlugin *plugin = iter->data; - GntMenuItem *item; - if (GAIM_IS_PROTOCOL_PLUGIN(plugin)) - continue; - - if (!GAIM_PLUGIN_HAS_ACTIONS(plugin)) - continue; - - item = gnt_menuitem_new(_(plugin->info->name)); - gnt_menu_add_item(GNT_MENU(sub), item); - build_plugin_actions(item, plugin, NULL); - } -} - -static void -reconstruct_accounts_menu() -{ - GntWidget *sub; - GntMenuItem *acc, *item; - GList *iter; - - if (!ggblist) - return; - - if (ggblist->accounts == NULL) - ggblist->accounts = gnt_menuitem_new(_("Accounts")); - - acc = ggblist->accounts; - sub = gnt_menu_new(GNT_MENU_POPUP); - gnt_menuitem_set_submenu(acc, GNT_MENU(sub)); - - for (iter = gaim_accounts_get_all_active(); iter; - iter = g_list_delete_link(iter, iter)) { - GaimAccount *account = iter->data; - GaimConnection *gc = gaim_account_get_connection(account); - GaimPlugin *prpl; - - if (!gc || !GAIM_CONNECTION_IS_CONNECTED(gc)) - continue; - prpl = gc->prpl; - - if (GAIM_PLUGIN_HAS_ACTIONS(prpl)) { - item = gnt_menuitem_new(gaim_account_get_username(account)); - gnt_menu_add_item(GNT_MENU(sub), item); - build_plugin_actions(item, prpl, gc); - } - } -} - -static void -account_signed_on_cb() -{ - GaimBlistNode *node; - - for (node = gaim_blist_get_root(); node; - node = gaim_blist_node_next(node, FALSE)) { - if (GAIM_BLIST_NODE_IS_CHAT(node)) { - GaimChat *chat = (GaimChat*)node; - if (gaim_blist_node_get_bool(node, "gnt-autojoin")) - serv_join_chat(gaim_account_get_connection(chat->account), chat->components); - } - } -} - -static void show_offline_cb(GntMenuItem *item, gpointer n) -{ - gaim_prefs_set_bool(PREF_ROOT "/showoffline", - !gaim_prefs_get_bool(PREF_ROOT "/showoffline")); -} - -static void sort_blist_change_cb(GntMenuItem *item, gpointer n) -{ - gaim_prefs_set_string(PREF_ROOT "/sort_type", n); -} - -/* XXX: send_im_select* -- Xerox */ -static void -send_im_select_cb(gpointer data, GaimRequestFields *fields) -{ - GaimAccount *account; - const char *username; - - account = gaim_request_fields_get_account(fields, "account"); - username = gaim_request_fields_get_string(fields, "screenname"); - - gaim_conversation_new(GAIM_CONV_TYPE_IM, account, username); -} - -static void -send_im_select(GntMenuItem *item, gpointer n) -{ - GaimRequestFields *fields; - GaimRequestFieldGroup *group; - GaimRequestField *field; - - fields = gaim_request_fields_new(); - - group = gaim_request_field_group_new(NULL); - gaim_request_fields_add_group(fields, group); - - field = gaim_request_field_string_new("screenname", _("_Name"), NULL, FALSE); - gaim_request_field_set_type_hint(field, "screenname"); - gaim_request_field_set_required(field, TRUE); - gaim_request_field_group_add_field(group, field); - - field = gaim_request_field_account_new("account", _("_Account"), NULL); - gaim_request_field_set_type_hint(field, "account"); - gaim_request_field_set_visible(field, - (gaim_connections_get_all() != NULL && - gaim_connections_get_all()->next != NULL)); - gaim_request_field_set_required(field, TRUE); - gaim_request_field_group_add_field(group, field); - - gaim_request_fields(gaim_get_blist(), _("New Instant Message"), - NULL, - _("Please enter the screen name or alias of the person " - "you would like to IM."), - fields, - _("OK"), G_CALLBACK(send_im_select_cb), - _("Cancel"), NULL, - NULL); -} - -static void -create_menu() -{ - GntWidget *menu, *sub; - GntMenuItem *item; - GntWindow *window; - - if (!ggblist) - return; - - window = GNT_WINDOW(ggblist->window); - ggblist->menu = menu = gnt_menu_new(GNT_MENU_TOPLEVEL); - gnt_window_set_menu(window, GNT_MENU(menu)); - - item = gnt_menuitem_new(_("Options")); - gnt_menu_add_item(GNT_MENU(menu), item); - - sub = gnt_menu_new(GNT_MENU_POPUP); - gnt_menuitem_set_submenu(item, GNT_MENU(sub)); - - item = gnt_menuitem_new(_("Send IM...")); - gnt_menu_add_item(GNT_MENU(sub), item); - gnt_menuitem_set_callback(GNT_MENUITEM(item), send_im_select, NULL); - - item = gnt_menuitem_check_new(_("Toggle offline buddies")); - gnt_menuitem_check_set_checked(GNT_MENUITEM_CHECK(item), - gaim_prefs_get_bool(PREF_ROOT "/showoffline")); - gnt_menu_add_item(GNT_MENU(sub), item); - gnt_menuitem_set_callback(GNT_MENUITEM(item), show_offline_cb, NULL); - - item = gnt_menuitem_new(_("Sort by status")); - gnt_menu_add_item(GNT_MENU(sub), item); - gnt_menuitem_set_callback(GNT_MENUITEM(item), sort_blist_change_cb, "status"); - - item = gnt_menuitem_new(_("Sort alphabetically")); - gnt_menu_add_item(GNT_MENU(sub), item); - gnt_menuitem_set_callback(GNT_MENUITEM(item), sort_blist_change_cb, "text"); - - item = gnt_menuitem_new(_("Sort by log size")); - gnt_menu_add_item(GNT_MENU(sub), item); - gnt_menuitem_set_callback(GNT_MENUITEM(item), sort_blist_change_cb, "log"); - - reconstruct_accounts_menu(); - gnt_menu_add_item(GNT_MENU(menu), ggblist->accounts); - - reconstruct_plugins_menu(); - gnt_menu_add_item(GNT_MENU(menu), ggblist->plugins); -} - -void gg_blist_show() -{ - blist_show(gaim_get_blist()); -} - -static void -blist_show(GaimBuddyList *list) -{ - if (ggblist == NULL) - new_list(list); - else if (ggblist->window) - return; - - ggblist->window = gnt_vwindow_new(FALSE); - gnt_widget_set_name(ggblist->window, "buddylist"); - gnt_box_set_toplevel(GNT_BOX(ggblist->window), TRUE); - gnt_box_set_title(GNT_BOX(ggblist->window), _("Buddy List")); - gnt_box_set_pad(GNT_BOX(ggblist->window), 0); - - ggblist->tree = gnt_tree_new(); - - GNT_WIDGET_SET_FLAGS(ggblist->tree, GNT_WIDGET_NO_BORDER); - gnt_widget_set_size(ggblist->tree, gaim_prefs_get_int(PREF_ROOT "/size/width"), - gaim_prefs_get_int(PREF_ROOT "/size/height")); - gnt_widget_set_position(ggblist->window, gaim_prefs_get_int(PREF_ROOT "/position/x"), - gaim_prefs_get_int(PREF_ROOT "/position/y")); - - gnt_tree_set_col_width(GNT_TREE(ggblist->tree), 0, - gaim_prefs_get_int(PREF_ROOT "/size/width") - 1); - - gnt_box_add_widget(GNT_BOX(ggblist->window), ggblist->tree); - - ggblist->status = gnt_combo_box_new(); - gnt_box_add_widget(GNT_BOX(ggblist->window), ggblist->status); - ggblist->statustext = gnt_entry_new(NULL); - gnt_box_add_widget(GNT_BOX(ggblist->window), ggblist->statustext); - - gnt_widget_show(ggblist->window); - - gaim_signal_connect(gaim_connections_get_handle(), "signed-on", gg_blist_get_handle(), - GAIM_CALLBACK(reconstruct_accounts_menu), NULL); - gaim_signal_connect(gaim_connections_get_handle(), "signed-off", gg_blist_get_handle(), - GAIM_CALLBACK(reconstruct_accounts_menu), NULL); - gaim_signal_connect(gaim_blist_get_handle(), "buddy-status-changed", gg_blist_get_handle(), - GAIM_CALLBACK(buddy_status_changed), ggblist); - gaim_signal_connect(gaim_blist_get_handle(), "buddy-idle-changed", gg_blist_get_handle(), - GAIM_CALLBACK(buddy_idle_changed), ggblist); - - gaim_signal_connect(gaim_plugins_get_handle(), "plugin-load", gg_blist_get_handle(), - GAIM_CALLBACK(reconstruct_plugins_menu), NULL); - gaim_signal_connect(gaim_plugins_get_handle(), "plugin-unload", gg_blist_get_handle(), - GAIM_CALLBACK(reconstruct_plugins_menu), NULL); - -#if 0 - gaim_signal_connect(gaim_blist_get_handle(), "buddy-signed-on", gg_blist_get_handle(), - GAIM_CALLBACK(buddy_signed_on), ggblist); - gaim_signal_connect(gaim_blist_get_handle(), "buddy-signed-off", gg_blist_get_handle(), - GAIM_CALLBACK(buddy_signed_off), ggblist); - - /* These I plan to use to indicate unread-messages etc. */ - gaim_signal_connect(gaim_conversations_get_handle(), "received-im-msg", gg_blist_get_handle(), - GAIM_CALLBACK(received_im_msg), list); - gaim_signal_connect(gaim_conversations_get_handle(), "sent-im-msg", gg_blist_get_handle(), - GAIM_CALLBACK(sent_im_msg), NULL); - - gaim_signal_connect(gaim_conversations_get_handle(), "received-chat-msg", gg_blist_get_handle(), - GAIM_CALLBACK(received_chat_msg), list); -#endif - - g_signal_connect(G_OBJECT(ggblist->tree), "selection_changed", G_CALLBACK(selection_changed), ggblist); - g_signal_connect(G_OBJECT(ggblist->tree), "key_pressed", G_CALLBACK(key_pressed), ggblist); - g_signal_connect(G_OBJECT(ggblist->tree), "context-menu", G_CALLBACK(context_menu), ggblist); - g_signal_connect_after(G_OBJECT(ggblist->tree), "clicked", G_CALLBACK(blist_clicked), ggblist); - g_signal_connect(G_OBJECT(ggblist->tree), "activate", G_CALLBACK(selection_activate), ggblist); - g_signal_connect_data(G_OBJECT(ggblist->tree), "gained-focus", G_CALLBACK(draw_tooltip), - ggblist, 0, G_CONNECT_AFTER | G_CONNECT_SWAPPED); - g_signal_connect_data(G_OBJECT(ggblist->tree), "lost-focus", G_CALLBACK(remove_peripherals), - ggblist, 0, G_CONNECT_AFTER | G_CONNECT_SWAPPED); - g_signal_connect(G_OBJECT(ggblist->tree), "size_changed", G_CALLBACK(size_changed_cb), NULL); - g_signal_connect(G_OBJECT(ggblist->window), "position_set", G_CALLBACK(save_position_cb), NULL); - g_signal_connect(G_OBJECT(ggblist->window), "destroy", G_CALLBACK(reset_blist_window), NULL); - - /* Status signals */ - gaim_signal_connect(gaim_savedstatuses_get_handle(), "savedstatus-changed", gg_blist_get_handle(), - GAIM_CALLBACK(savedstatus_changed), NULL); - g_signal_connect(G_OBJECT(ggblist->status), "selection_changed", - G_CALLBACK(status_selection_changed), NULL); - g_signal_connect(G_OBJECT(ggblist->statustext), "key_pressed", - G_CALLBACK(status_text_changed), NULL); - - create_menu(); - - populate_buddylist(); - - savedstatus_changed(gaim_savedstatus_get_current(), NULL); -} - -void gg_blist_uninit() -{ - if (ggblist == NULL) - return; - - gnt_widget_destroy(ggblist->window); - g_free(ggblist); - ggblist = NULL; -} - -gboolean gg_blist_get_position(int *x, int *y) -{ - if (!ggblist || !ggblist->window) - return FALSE; - gnt_widget_get_position(ggblist->window, x, y); - return TRUE; -} - -void gg_blist_set_position(int x, int y) -{ - gnt_widget_set_position(ggblist->window, x, y); -} - -gboolean gg_blist_get_size(int *width, int *height) -{ - if (!ggblist || !ggblist->window) - return FALSE; - gnt_widget_get_size(ggblist->window, width, height); - return TRUE; -} - -void gg_blist_set_size(int width, int height) -{ - gnt_widget_set_size(ggblist->window, width, height); -} - diff -r 317e7613e581 -r 0e3a8505ebbe console/gntblist.h --- a/console/gntblist.h Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,95 +0,0 @@ -/** - * @file gntblist.h GNT BuddyList API - * @ingroup gntui - * - * gaim - * - * Gaim is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef _GNT_BLIST_H -#define _GNT_BLIST_H - -#include "blist.h" - -/********************************************************************** - * @name GNT BuddyList API - **********************************************************************/ -/*@{*/ - -/** - * Get the ui-functions. - * - * @return The GaimBlistUiOps structure populated with the appropriate functions. - */ -GaimBlistUiOps * gg_blist_get_ui_ops(void); - -/** - * Perform necessary initializations. - */ -void gg_blist_init(void); - -/** - * Perform necessary uninitializations. - */ -void gg_blist_uninit(void); - -/** - * Show the buddy list. - */ -void gg_blist_show(void); - -/** - * Get the position of the buddy list. - * - * @param x The x-coordinate is set here if not @ NULL. - * @param y The y-coordinate is set here if not @c NULL. - * - * @return Returns @c TRUE if the values were set, @c FALSE otherwise. - */ -gboolean gg_blist_get_position(int *x, int *y); - -/** - * Set the position of the buddy list. - * - * @param x The x-coordinate of the buddy list. - * @param y The y-coordinate of the buddy list. - */ -void gg_blist_set_position(int x, int y); - -/** - * Get the size of the buddy list. - * - * @param width The width is set here if not @ NULL. - * @param height The height is set here if not @c NULL. - * - * @return Returns @c TRUE if the values were set, @c FALSE otherwise. - */ -gboolean gg_blist_get_size(int *width, int *height); - -/** - * Set the size of the buddy list. - * - * @param width The width of the buddy list. - * @param height The height of the buddy list. - */ -void gg_blist_set_size(int width, int height); - -/*@}*/ - -#endif diff -r 317e7613e581 -r 0e3a8505ebbe console/gntconn.c --- a/console/gntconn.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,75 +0,0 @@ -/** - * @file gntconn.c GNT Connection API - * @ingroup gntui - * - * gaim - * - * Gaim is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include "account.h" -#include "core.h" -#include "request.h" - -#include "gntconn.h" -#include "gntgaim.h" - -static void -gg_connection_report_disconnect(GaimConnection *gc, const char *text) -{ - char *act, *primary, *secondary; - GaimAccount *account = gaim_connection_get_account(gc); - - act = g_strdup_printf(_("%s (%s)"), gaim_account_get_username(account), - gaim_account_get_protocol_name(account)); - - primary = g_strdup_printf(_("%s disconnected."), act); - secondary = g_strdup_printf(_("%s was disconnected due to the following error:\n%s"), - act, text); - - gaim_request_action(account, _("Connection Error"), primary, secondary, 1, - account, 2, - _("OK"), NULL, - _("Connect"), - GAIM_CALLBACK(gaim_account_connect)); - - g_free(act); - g_free(primary); - g_free(secondary); -} - -static GaimConnectionUiOps ops = -{ - .connect_progress = NULL, - .connected = NULL, - .disconnected = NULL, - .notice = NULL, - .report_disconnect = gg_connection_report_disconnect -}; - -GaimConnectionUiOps *gg_connections_get_ui_ops() -{ - return &ops; -} - -void gg_connections_init() -{} - -void gg_connections_uninit() -{} - diff -r 317e7613e581 -r 0e3a8505ebbe console/gntconn.h --- a/console/gntconn.h Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -/** - * @file gntconn.h GNT Connection API - * @ingroup gntui - * - * gaim - * - * Gaim is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef _GNT_CONN_H -#define _GNT_CONN_H - -#include "connection.h" - -/********************************************************************** - * @name GNT Connection API - **********************************************************************/ -/*@{*/ - -/** - * Get the ui-functions. - * - * @return The GaimConnectionUiOps structure populated with the appropriate functions. - */ -GaimConnectionUiOps *gg_connections_get_ui_ops(void); - -/** - * Perform necessary initializations. - */ -void gg_connections_init(void); - -/** - * Perform necessary uninitializations. - */ -void gg_connections_uninit(void); - -/*@}*/ - -#endif diff -r 317e7613e581 -r 0e3a8505ebbe console/gntconv.c --- a/console/gntconv.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,760 +0,0 @@ -/** - * @file gntconv.c GNT Conversation API - * @ingroup gntui - * - * gaim - * - * Gaim is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include - -#include -#include -#include -#include - -#include "gntgaim.h" -#include "gntaccount.h" -#include "gntblist.h" -#include "gntconv.h" -#include "gntdebug.h" -#include "gntplugin.h" -#include "gntprefs.h" -#include "gntstatus.h" - -#include "gnt.h" -#include "gntbox.h" -#include "gntentry.h" -#include "gnttextview.h" - -#define PREF_ROOT "/gaim/gnt/conversations" - -#include "config.h" - -static void -send_typing_notification(GntWidget *w, GGConv *ggconv) -{ - const char *text = gnt_entry_get_text(GNT_ENTRY(ggconv->entry)); - gboolean empty = (!text || !*text); - if (gaim_prefs_get_bool("/gaim/gnt/conversations/notify_typing")) { - GaimConversation *conv = ggconv->active_conv; - GaimConvIm *im = GAIM_CONV_IM(conv); - if (!empty) { - gboolean send = (gaim_conv_im_get_send_typed_timeout(im) == 0); - - gaim_conv_im_stop_send_typed_timeout(im); - gaim_conv_im_start_send_typed_timeout(im); - if (send || (gaim_conv_im_get_type_again(im) != 0 && - time(NULL) > gaim_conv_im_get_type_again(im))) { - unsigned int timeout; - timeout = serv_send_typing(gaim_conversation_get_gc(conv), - gaim_conversation_get_name(conv), - GAIM_TYPING); - gaim_conv_im_set_type_again(im, timeout); - } - } else { - gaim_conv_im_stop_send_typed_timeout(im); - - serv_send_typing(gaim_conversation_get_gc(conv), - gaim_conversation_get_name(conv), - GAIM_NOT_TYPING); - } - } -} - -static gboolean -entry_key_pressed(GntWidget *w, const char *key, GGConv *ggconv) -{ - if (key[0] == '\r' && key[1] == 0) - { - const char *text = gnt_entry_get_text(GNT_ENTRY(ggconv->entry)); - if (*text == '/') - { - GaimConversation *conv = ggconv->active_conv; - GaimCmdStatus status; - const char *cmdline = text + 1; - char *error = NULL, *escape; - - escape = g_markup_escape_text(cmdline, -1); - status = gaim_cmd_do_command(conv, cmdline, escape, &error); - g_free(escape); - - switch (status) - { - case GAIM_CMD_STATUS_OK: - break; - case GAIM_CMD_STATUS_NOT_FOUND: - gaim_conversation_write(conv, "", _("No such command."), - GAIM_MESSAGE_NO_LOG, time(NULL)); - break; - case GAIM_CMD_STATUS_WRONG_ARGS: - gaim_conversation_write(conv, "", _("Syntax Error: You typed the wrong number of arguments " - "to that command."), - GAIM_MESSAGE_NO_LOG, time(NULL)); - break; - case GAIM_CMD_STATUS_FAILED: - gaim_conversation_write(conv, "", error ? error : _("Your command failed for an unknown reason."), - GAIM_MESSAGE_NO_LOG, time(NULL)); - break; - case GAIM_CMD_STATUS_WRONG_TYPE: - if(gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM) - gaim_conversation_write(conv, "", _("That command only works in chats, not IMs."), - GAIM_MESSAGE_NO_LOG, time(NULL)); - else - gaim_conversation_write(conv, "", _("That command only works in IMs, not chats."), - GAIM_MESSAGE_NO_LOG, time(NULL)); - break; - case GAIM_CMD_STATUS_WRONG_PRPL: - gaim_conversation_write(conv, "", _("That command doesn't work on this protocol."), - GAIM_MESSAGE_NO_LOG, time(NULL)); - break; - } - g_free(error); -#if 0 - gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(ggconv->tv), - _("Commands are not supported yet. Message was NOT sent."), - GNT_TEXT_FLAG_DIM | GNT_TEXT_FLAG_UNDERLINE); - gnt_text_view_next_line(GNT_TEXT_VIEW(ggconv->tv)); - gnt_text_view_scroll(GNT_TEXT_VIEW(ggconv->tv), 0); -#endif - } - else - { - char *escape = g_markup_escape_text(text, -1); - char *apos = gaim_strreplace(escape, "'", "'"); - g_free(escape); - escape = apos; - switch (gaim_conversation_get_type(ggconv->active_conv)) - { - case GAIM_CONV_TYPE_IM: - gaim_conv_im_send_with_flags(GAIM_CONV_IM(ggconv->active_conv), escape, GAIM_MESSAGE_SEND); - break; - case GAIM_CONV_TYPE_CHAT: - gaim_conv_chat_send(GAIM_CONV_CHAT(ggconv->active_conv), escape); - break; - default: - g_free(escape); - g_return_val_if_reached(FALSE); - } - g_free(escape); - gaim_idle_touch(); - } - gnt_entry_add_to_history(GNT_ENTRY(ggconv->entry), text); - gnt_entry_clear(GNT_ENTRY(ggconv->entry)); - return TRUE; - } - else if (key[0] == 27) - { - if (strcmp(key, GNT_KEY_DOWN) == 0) - gnt_text_view_scroll(GNT_TEXT_VIEW(ggconv->tv), 1); - else if (strcmp(key, GNT_KEY_UP) == 0) - gnt_text_view_scroll(GNT_TEXT_VIEW(ggconv->tv), -1); - else if (strcmp(key, GNT_KEY_PGDOWN) == 0) - gnt_text_view_scroll(GNT_TEXT_VIEW(ggconv->tv), ggconv->tv->priv.height - 2); - else if (strcmp(key, GNT_KEY_PGUP) == 0) - gnt_text_view_scroll(GNT_TEXT_VIEW(ggconv->tv), -(ggconv->tv->priv.height - 2)); - else - return FALSE; - return TRUE; - } - else - { - } - - return FALSE; -} - -static void -closing_window(GntWidget *window, GGConv *ggconv) -{ - GList *list = ggconv->list; - ggconv->window = NULL; - while (list) { - GaimConversation *conv = list->data; - list = list->next; - gaim_conversation_destroy(conv); - } -} - -static void -size_changed_cb(GntWidget *widget, int width, int height) -{ - int w, h; - gnt_widget_get_size(widget, &w, &h); - gaim_prefs_set_int(PREF_ROOT "/size/width", w); - gaim_prefs_set_int(PREF_ROOT "/size/height", h); -} - -static void -save_position_cb(GntWidget *w, int x, int y) -{ - gaim_prefs_set_int(PREF_ROOT "/position/x", x); - gaim_prefs_set_int(PREF_ROOT "/position/y", y); -} - -static GaimConversation * -find_conv_with_contact(GaimConversation *conv) -{ - GaimBlistNode *node; - GaimBuddy *buddy = gaim_find_buddy(conv->account, conv->name); - GaimConversation *ret = NULL; - - if (!buddy) - return NULL; - - for (node = ((GaimBlistNode*)buddy)->parent->child; node; node = node->next) { - if (node == (GaimBlistNode*)buddy) - continue; - if ((ret = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, - ((GaimBuddy*)node)->name, ((GaimBuddy*)node)->account)) != NULL) - break; - } - return ret; -} - -static char * -get_conversation_title(GaimConversation *conv, GaimAccount *account) -{ - return g_strdup_printf(_("%s (%s -- %s)"), gaim_conversation_get_title(conv), - gaim_account_get_username(account), gaim_account_get_protocol_name(account)); -} - -static void -update_buddy_typing(GaimAccount *account, const char *who, gpointer null) -{ - GaimConversation *conv; - GGConv *ggc; - GaimConvIm *im = NULL; - char *title, *str; - - conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, who, account); - - if (!conv) - return; - - im = GAIM_CONV_IM(conv); - ggc = conv->ui_data; - - if (gaim_conv_im_get_typing_state(im) == GAIM_TYPING) { - int scroll; - str = get_conversation_title(conv, account); - title = g_strdup_printf(_("%s [%s]"), str, - gnt_ascii_only() ? "T" : "\342\243\277"); - g_free(str); - - scroll = gnt_text_view_get_lines_below(GNT_TEXT_VIEW(ggc->tv)); - str = g_strdup_printf(_("\n%s is typing..."), gaim_conversation_get_name(conv)); - /* Updating is a little buggy. So just remove and add a new one */ - gnt_text_view_tag_change(GNT_TEXT_VIEW(ggc->tv), "typing", NULL, TRUE); - gnt_text_view_append_text_with_tag(GNT_TEXT_VIEW(ggc->tv), - str, GNT_TEXT_FLAG_DIM, "typing"); - g_free(str); - if (scroll <= 1) - gnt_text_view_scroll(GNT_TEXT_VIEW(ggc->tv), 0); - } else { - title = get_conversation_title(conv, account); - gnt_text_view_tag_change(GNT_TEXT_VIEW(ggc->tv), "typing", NULL, TRUE); - } - gnt_screen_rename_widget(ggc->window, title); - g_free(title); -} - -static gpointer -gg_conv_get_handle() -{ - static int handle; - return &handle; -} - -static void -gg_create_conversation(GaimConversation *conv) -{ - GGConv *ggc = conv->ui_data; - char *title; - GaimConversationType type; - GaimConversation *cc; - GaimAccount *account; - - if (ggc) - return; - - cc = find_conv_with_contact(conv); - if (cc && cc->ui_data) - ggc = cc->ui_data; - else - ggc = g_new0(GGConv, 1); - - ggc->list = g_list_prepend(ggc->list, conv); - ggc->active_conv = conv; - conv->ui_data = ggc; - - if (cc && cc->ui_data) { - gg_conversation_set_active(conv); - return; - } - - account = gaim_conversation_get_account(conv); - type = gaim_conversation_get_type(conv); - title = get_conversation_title(conv, account); - - ggc->window = gnt_box_new(FALSE, TRUE); - gnt_box_set_title(GNT_BOX(ggc->window), title); - gnt_box_set_toplevel(GNT_BOX(ggc->window), TRUE); - gnt_box_set_pad(GNT_BOX(ggc->window), 0); - gnt_widget_set_name(ggc->window, "conversation-window"); - - ggc->tv = gnt_text_view_new(); - gnt_box_add_widget(GNT_BOX(ggc->window), ggc->tv); - gnt_widget_set_name(ggc->tv, "conversation-window-textview"); - gnt_widget_set_size(ggc->tv, gaim_prefs_get_int(PREF_ROOT "/size/width"), - gaim_prefs_get_int(PREF_ROOT "/size/height")); - - ggc->entry = gnt_entry_new(NULL); - gnt_box_add_widget(GNT_BOX(ggc->window), ggc->entry); - gnt_widget_set_name(ggc->entry, "conversation-window-entry"); - gnt_entry_set_history_length(GNT_ENTRY(ggc->entry), -1); - gnt_entry_set_word_suggest(GNT_ENTRY(ggc->entry), TRUE); - gnt_entry_set_always_suggest(GNT_ENTRY(ggc->entry), FALSE); - - g_signal_connect_after(G_OBJECT(ggc->entry), "key_pressed", G_CALLBACK(entry_key_pressed), ggc); - g_signal_connect(G_OBJECT(ggc->window), "destroy", G_CALLBACK(closing_window), ggc); - - gnt_widget_set_position(ggc->window, gaim_prefs_get_int(PREF_ROOT "/position/x"), - gaim_prefs_get_int(PREF_ROOT "/position/y")); - gnt_widget_show(ggc->window); - - g_signal_connect(G_OBJECT(ggc->tv), "size_changed", G_CALLBACK(size_changed_cb), NULL); - g_signal_connect(G_OBJECT(ggc->window), "position_set", G_CALLBACK(save_position_cb), NULL); - - if (type == GAIM_CONV_TYPE_IM) { - g_signal_connect(G_OBJECT(ggc->entry), "text_changed", G_CALLBACK(send_typing_notification), ggc); - gaim_signal_connect(gaim_conversations_get_handle(), "buddy-typing", gg_conv_get_handle(), - GAIM_CALLBACK(update_buddy_typing), NULL); - gaim_signal_connect(gaim_conversations_get_handle(), "buddy-typing-stopped", gg_conv_get_handle(), - GAIM_CALLBACK(update_buddy_typing), NULL); - } - - g_free(title); -} - -static void -gg_destroy_conversation(GaimConversation *conv) -{ - /* do stuff here */ - GGConv *ggc = conv->ui_data; - ggc->list = g_list_remove(ggc->list, conv); - if (ggc->list && conv == ggc->active_conv) - ggc->active_conv = ggc->list->data; - - if (ggc->list == NULL) { - gnt_widget_destroy(ggc->window); - g_free(ggc); - } -} - -static void -gg_write_common(GaimConversation *conv, const char *who, const char *message, - GaimMessageFlags flags, time_t mtime) -{ - GGConv *ggconv = conv->ui_data; - char *strip, *newline; - GntTextFormatFlags fl = 0; - int pos; - gboolean notify; - - g_return_if_fail(ggconv != NULL); - - if (ggconv->active_conv != conv) { - if (flags & (GAIM_MESSAGE_SEND | GAIM_MESSAGE_RECV)) - gg_conversation_set_active(conv); - else - return; - } - - pos = gnt_text_view_get_lines_below(GNT_TEXT_VIEW(ggconv->tv)); - - notify = !!gnt_text_view_tag_change(GNT_TEXT_VIEW(ggconv->tv), "typing", NULL, TRUE); - gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(ggconv->tv), "\n", GNT_TEXT_FLAG_NORMAL); - - /* Unnecessary to print the timestamp for delayed message */ - if (!(flags & GAIM_MESSAGE_DELAYED) && - gaim_prefs_get_bool("/gaim/gnt/conversations/timestamps")) - gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(ggconv->tv), - gaim_utf8_strftime("(%H:%M:%S) ", localtime(&mtime)), GNT_TEXT_FLAG_DIM); - - if (flags & GAIM_MESSAGE_AUTO_RESP) - gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(ggconv->tv), - _(" "), GNT_TEXT_FLAG_BOLD); - - if (who && *who && (flags & (GAIM_MESSAGE_SEND | GAIM_MESSAGE_RECV))) - { - char * name = NULL; - - if (gaim_message_meify((char*)message, -1)) - name = g_strdup_printf("*** %s ", who); - else - name = g_strdup_printf("%s: ", who); - - gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(ggconv->tv), - name, GNT_TEXT_FLAG_BOLD); - g_free(name); - } - else - fl = GNT_TEXT_FLAG_DIM; - - if (flags & GAIM_MESSAGE_ERROR) - fl |= GNT_TEXT_FLAG_BOLD; - if (flags & GAIM_MESSAGE_NICK) - fl |= GNT_TEXT_FLAG_UNDERLINE; - - /* XXX: Remove this workaround when textview can parse messages. */ - newline = gaim_strdup_withhtml(message); - strip = gaim_markup_strip_html(newline); - gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(ggconv->tv), - strip, fl); - - g_free(newline); - g_free(strip); - - if (notify) { - strip = g_strdup_printf(_("\n%s is typing..."), gaim_conversation_get_name(conv)); - gnt_text_view_append_text_with_tag(GNT_TEXT_VIEW(ggconv->tv), - strip, GNT_TEXT_FLAG_DIM, "typing"); - g_free(strip); - } - - if (pos <= 1) - gnt_text_view_scroll(GNT_TEXT_VIEW(ggconv->tv), 0); - - if (flags & (GAIM_MESSAGE_RECV | GAIM_MESSAGE_NICK | GAIM_MESSAGE_ERROR)) - gnt_widget_set_urgent(ggconv->tv); -} - -static void -gg_write_chat(GaimConversation *conv, const char *who, const char *message, - GaimMessageFlags flags, time_t mtime) -{ - gaim_conversation_write(conv, who, message, flags, mtime); -} - -static void -gg_write_im(GaimConversation *conv, const char *who, const char *message, - GaimMessageFlags flags, time_t mtime) -{ - GaimAccount *account = gaim_conversation_get_account(conv); - if (flags & GAIM_MESSAGE_SEND) - { - who = gaim_connection_get_display_name(gaim_account_get_connection(account)); - if (!who) - who = gaim_account_get_alias(account); - if (!who) - who = gaim_account_get_username(account); - } - else if (flags & GAIM_MESSAGE_RECV) - { - GaimBuddy *buddy; - who = gaim_conversation_get_name(conv); - buddy = gaim_find_buddy(account, who); - if (buddy) - who = gaim_buddy_get_contact_alias(buddy); - } - - gaim_conversation_write(conv, who, message, flags, mtime); -} - -static void -gg_write_conv(GaimConversation *conv, const char *who, const char *alias, - const char *message, GaimMessageFlags flags, time_t mtime) -{ - const char *name; - if (alias && *alias) - name = alias; - else if (who && *who) - name = who; - else - name = NULL; - - gg_write_common(conv, name, message, flags, mtime); -} - -static void -gg_chat_add_users(GaimConversation *conv, GList *users, gboolean new_arrivals) -{ - GGConv *ggc = conv->ui_data; - GntEntry *entry = GNT_ENTRY(ggc->entry); - - if (!new_arrivals) - { - /* Print the list of users in the room */ - GString *string = g_string_new(_("List of users:\n")); - GList *iter; - - for (iter = users; iter; iter = iter->next) - { - GaimConvChatBuddy *cbuddy = iter->data; - char *str; - - if ((str = cbuddy->alias) == NULL) - str = cbuddy->name; - g_string_append_printf(string, "[ %s ]", str); - } - - gaim_conversation_write(conv, NULL, string->str, - GAIM_MESSAGE_SYSTEM, time(NULL)); - g_string_free(string, TRUE); - } - - for (; users; users = users->next) - { - GaimConvChatBuddy *cbuddy = users->data; - gnt_entry_add_suggest(entry, cbuddy->name); - gnt_entry_add_suggest(entry, cbuddy->alias); - } -} - -static void -gg_chat_rename_user(GaimConversation *conv, const char *old, const char *new_n, const char *new_a) -{ - /* Update the name for string completion */ - GGConv *ggc = conv->ui_data; - GntEntry *entry = GNT_ENTRY(ggc->entry); - gnt_entry_remove_suggest(entry, old); - gnt_entry_add_suggest(entry, new_n); - gnt_entry_add_suggest(entry, new_a); -} - -static void -gg_chat_remove_user(GaimConversation *conv, GList *list) -{ - /* Remove the name from string completion */ - GGConv *ggc = conv->ui_data; - GntEntry *entry = GNT_ENTRY(ggc->entry); - for (; list; list = list->next) - gnt_entry_remove_suggest(entry, list->data); -} - -static void -gg_chat_update_user(GaimConversation *conv, const char *user) -{ -} - -static GaimConversationUiOps conv_ui_ops = -{ - .create_conversation = gg_create_conversation, - .destroy_conversation = gg_destroy_conversation, - .write_chat = gg_write_chat, - .write_im = gg_write_im, - .write_conv = gg_write_conv, - .chat_add_users = gg_chat_add_users, - .chat_rename_user = gg_chat_rename_user, - .chat_remove_users = gg_chat_remove_user, - .chat_update_user = gg_chat_update_user, - .present = NULL, - .has_focus = NULL, - .custom_smiley_add = NULL, - .custom_smiley_write = NULL, - .custom_smiley_close = NULL -}; - -GaimConversationUiOps *gg_conv_get_ui_ops() -{ - return &conv_ui_ops; -} - -/* Xerox */ -static GaimCmdRet -say_command_cb(GaimConversation *conv, - const char *cmd, char **args, char **error, void *data) -{ - if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM) - gaim_conv_im_send(GAIM_CONV_IM(conv), args[0]); - else if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT) - gaim_conv_chat_send(GAIM_CONV_CHAT(conv), args[0]); - - return GAIM_CMD_RET_OK; -} - -/* Xerox */ -static GaimCmdRet -me_command_cb(GaimConversation *conv, - const char *cmd, char **args, char **error, void *data) -{ - char *tmp; - - tmp = g_strdup_printf("/me %s", args[0]); - - if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM) - gaim_conv_im_send(GAIM_CONV_IM(conv), tmp); - else if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT) - gaim_conv_chat_send(GAIM_CONV_CHAT(conv), tmp); - - g_free(tmp); - return GAIM_CMD_RET_OK; -} - -/* Xerox */ -static GaimCmdRet -debug_command_cb(GaimConversation *conv, - const char *cmd, char **args, char **error, void *data) -{ - char *tmp, *markup; - GaimCmdStatus status; - - if (!g_ascii_strcasecmp(args[0], "version")) { - tmp = g_strdup_printf("me is using %s.", VERSION); - markup = g_markup_escape_text(tmp, -1); - - status = gaim_cmd_do_command(conv, tmp, markup, error); - - g_free(tmp); - g_free(markup); - return status; - } else { - gaim_conversation_write(conv, NULL, _("Supported debug options are: version"), - GAIM_MESSAGE_NO_LOG|GAIM_MESSAGE_ERROR, time(NULL)); - return GAIM_CMD_STATUS_OK; - } -} - -/* Xerox */ -static GaimCmdRet -clear_command_cb(GaimConversation *conv, - const char *cmd, char **args, char **error, void *data) -{ - GGConv *ggconv = conv->ui_data; - gnt_text_view_clear(GNT_TEXT_VIEW(ggconv->tv)); - return GAIM_CMD_STATUS_OK; -} - -/* Xerox */ -static GaimCmdRet -help_command_cb(GaimConversation *conv, - const char *cmd, char **args, char **error, void *data) -{ - GList *l, *text; - GString *s; - - if (args[0] != NULL) { - s = g_string_new(""); - text = gaim_cmd_help(conv, args[0]); - - if (text) { - for (l = text; l; l = l->next) - if (l->next) - g_string_append_printf(s, "%s\n", (char *)l->data); - else - g_string_append_printf(s, "%s", (char *)l->data); - } else { - g_string_append(s, _("No such command (in this context).")); - } - } else { - s = g_string_new(_("Use \"/help <command>\" for help on a specific command.\n" - "The following commands are available in this context:\n")); - - text = gaim_cmd_list(conv); - for (l = text; l; l = l->next) - if (l->next) - g_string_append_printf(s, "%s, ", (char *)l->data); - else - g_string_append_printf(s, "%s.", (char *)l->data); - g_list_free(text); - } - - gaim_conversation_write(conv, NULL, s->str, GAIM_MESSAGE_NO_LOG, time(NULL)); - g_string_free(s, TRUE); - - return GAIM_CMD_STATUS_OK; -} - -static GaimCmdRet -cmd_show_window(GaimConversation *conv, const char *cmd, char **args, char **error, gpointer data) -{ - void (*callback)() = data; - callback(); - return GAIM_CMD_STATUS_OK; -} - -void gg_conversation_init() -{ - gaim_prefs_add_none(PREF_ROOT); - gaim_prefs_add_none(PREF_ROOT "/size"); - gaim_prefs_add_int(PREF_ROOT "/size/width", 70); - gaim_prefs_add_int(PREF_ROOT "/size/height", 20); - gaim_prefs_add_none(PREF_ROOT "/position"); - gaim_prefs_add_int(PREF_ROOT "/position/x", 0); - gaim_prefs_add_int(PREF_ROOT "/position/y", 0); - - /* Xerox the commands */ - gaim_cmd_register("say", "S", GAIM_CMD_P_DEFAULT, - GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_IM, NULL, - say_command_cb, _("say <message>: Send a message normally as if you weren't using a command."), NULL); - gaim_cmd_register("me", "S", GAIM_CMD_P_DEFAULT, - GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_IM, NULL, - me_command_cb, _("me <action>: Send an IRC style action to a buddy or chat."), NULL); - gaim_cmd_register("debug", "w", GAIM_CMD_P_DEFAULT, - GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_IM, NULL, - debug_command_cb, _("debug <option>: Send various debug information to the current conversation."), NULL); - gaim_cmd_register("clear", "", GAIM_CMD_P_DEFAULT, - GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_IM, NULL, - clear_command_cb, _("clear: Clears the conversation scrollback."), NULL); - gaim_cmd_register("help", "w", GAIM_CMD_P_DEFAULT, - GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, NULL, - help_command_cb, _("help <command>: Help on a specific command."), NULL); - - /* Now some commands to bring up some other windows */ - gaim_cmd_register("plugins", "", GAIM_CMD_P_DEFAULT, - GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_IM, NULL, - cmd_show_window, _("plugins: Show the plugins window."), gg_plugins_show_all); - gaim_cmd_register("buddylist", "", GAIM_CMD_P_DEFAULT, - GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_IM, NULL, - cmd_show_window, _("buddylist: Show the buddylist."), gg_blist_show); - gaim_cmd_register("accounts", "", GAIM_CMD_P_DEFAULT, - GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_IM, NULL, - cmd_show_window, _("accounts: Show the accounts window."), gg_accounts_show_all); - gaim_cmd_register("debugwin", "", GAIM_CMD_P_DEFAULT, - GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_IM, NULL, - cmd_show_window, _("debugwin: Show the debug window."), gg_debug_window_show); - gaim_cmd_register("prefs", "", GAIM_CMD_P_DEFAULT, - GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_IM, NULL, - cmd_show_window, _("prefs: Show the preference window."), gg_prefs_show_all); - gaim_cmd_register("status", "", GAIM_CMD_P_DEFAULT, - GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_IM, NULL, - cmd_show_window, _("statuses: Show the savedstatuses window."), gg_savedstatus_show_all); -} - -void gg_conversation_uninit() -{ -} - -void gg_conversation_set_active(GaimConversation *conv) -{ - GGConv *ggconv = conv->ui_data; - GaimAccount *account; - char *title; - - g_return_if_fail(ggconv); - g_return_if_fail(g_list_find(ggconv->list, conv)); - - ggconv->active_conv = conv; - account = gaim_conversation_get_account(conv); - title = get_conversation_title(conv, account); - gnt_screen_rename_widget(ggconv->window, title); - g_free(title); -} - diff -r 317e7613e581 -r 0e3a8505ebbe console/gntconv.h --- a/console/gntconv.h Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,94 +0,0 @@ -/** - * @file gntconv.h GNT Conversation API - * @ingroup gntui - * - * gaim - * - * Gaim is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef _GNT_CONV_H -#define _GNT_CONV_H - -#include -#include - -#include "conversation.h" - -/*************************************************************************** - * @name GNT Conversations API - ***************************************************************************/ -/*@{*/ - -typedef struct _GGConv GGConv; -typedef struct _GGConvChat GGConvChat; -typedef struct _GGConvIm GGConvIm; - -struct _GGConv -{ - GList *list; - GaimConversation *active_conv; - - GntWidget *window; /* the container */ - GntWidget *entry; /* entry */ - GntWidget *tv; /* text-view */ - - union - { - GGConvChat *chat; - GGConvIm *im; - } u; -}; - -struct _GGConvChat -{ - GntWidget *userlist; /* the userlist */ -}; - -struct _GGConvIm -{ - void *nothing_for_now; -}; - -/** - * Get the ui-functions. - * - * @return The GaimConversationUiOps populated with the appropriate functions. - */ -GaimConversationUiOps *gg_conv_get_ui_ops(void); - -/** - * Perform the necessary initializations. - */ -void gg_conversation_init(void); - -/** - * Perform the necessary uninitializations. - */ -void gg_conversation_uninit(void); - -/** - * Set a conversation as active in a contactized conversation - * - * @param conv The conversation to make active. - */ -void gg_conversation_set_active(GaimConversation *conv); - -/*@}*/ - -#endif diff -r 317e7613e581 -r 0e3a8505ebbe console/gntdebug.c --- a/console/gntdebug.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,304 +0,0 @@ -/** - * @file gntdebug.c GNT Debug API - * @ingroup gntui - * - * gaim - * - * Gaim is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include -#include -#include -#include -#include -#include - -#include "gntdebug.h" -#include "gntgaim.h" -#include "util.h" - -#include -#include - -#define PREF_ROOT "/gaim/gnt/debug" - -static struct -{ - GntWidget *window; - GntWidget *tview; - gboolean paused; - gboolean timestamps; -} debug; - -static gboolean -debug_window_kpress_cb(GntWidget *wid, const char *key, GntTextView *view) -{ - if (key[0] == 27) - { - if (strcmp(key, GNT_KEY_DOWN) == 0) - gnt_text_view_scroll(view, 1); - else if (strcmp(key, GNT_KEY_UP) == 0) - gnt_text_view_scroll(view, -1); - else if (strcmp(key, GNT_KEY_PGDOWN) == 0) - gnt_text_view_scroll(view, wid->priv.height - 2); - else if (strcmp(key, GNT_KEY_PGUP) == 0) - gnt_text_view_scroll(view, -(wid->priv.height - 2)); - else - return FALSE; - return TRUE; - } - return FALSE; -} - -static void -gg_debug_print(GaimDebugLevel level, const char *category, - const char *args) -{ - if (debug.window && !debug.paused) - { - int pos = gnt_text_view_get_lines_below(GNT_TEXT_VIEW(debug.tview)); - GntTextFormatFlags flag = GNT_TEXT_FLAG_NORMAL; - - if (debug.timestamps) { - const char *mdate; - time_t mtime = time(NULL); - mdate = gaim_utf8_strftime("%H:%M:%S ", localtime(&mtime)); - gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(debug.tview), - mdate, flag); - } - - gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(debug.tview), - category, GNT_TEXT_FLAG_BOLD); - gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(debug.tview), - ": ", GNT_TEXT_FLAG_BOLD); - - switch (level) - { - case GAIM_DEBUG_WARNING: - flag |= GNT_TEXT_FLAG_UNDERLINE; - case GAIM_DEBUG_ERROR: - case GAIM_DEBUG_FATAL: - flag |= GNT_TEXT_FLAG_BOLD; - break; - default: - break; - } - - gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(debug.tview), args, flag); - if (pos <= 1) - gnt_text_view_scroll(GNT_TEXT_VIEW(debug.tview), 0); - } -} - -static GaimDebugUiOps uiops = -{ - gg_debug_print, -}; - -GaimDebugUiOps *gg_debug_get_ui_ops() -{ - return &uiops; -} - -static void -reset_debug_win(GntWidget *w, gpointer null) -{ - debug.window = debug.tview = NULL; -} - -static void -clear_debug_win(GntWidget *w, GntTextView *tv) -{ - gnt_text_view_clear(tv); -} - -static void -print_stderr(const char *string) -{ - g_printerr("%s", string); -} - -static void -suppress_error_messages(const char *message) -{} - -static void -toggle_pause(GntWidget *w, gpointer n) -{ - debug.paused = !debug.paused; -} - -static void -toggle_timestamps(GntWidget *w, gpointer n) -{ - debug.timestamps = !debug.timestamps; - gaim_prefs_set_bool("/core/debug/timestamps", debug.timestamps); -} - -/* Xerox */ -static void -gaim_glib_log_handler(const gchar *domain, GLogLevelFlags flags, - const gchar *msg, gpointer user_data) -{ - GaimDebugLevel level; - char *new_msg = NULL; - char *new_domain = NULL; - - if ((flags & G_LOG_LEVEL_ERROR) == G_LOG_LEVEL_ERROR) - level = GAIM_DEBUG_ERROR; - else if ((flags & G_LOG_LEVEL_CRITICAL) == G_LOG_LEVEL_CRITICAL) - level = GAIM_DEBUG_FATAL; - else if ((flags & G_LOG_LEVEL_WARNING) == G_LOG_LEVEL_WARNING) - level = GAIM_DEBUG_WARNING; - else if ((flags & G_LOG_LEVEL_MESSAGE) == G_LOG_LEVEL_MESSAGE) - level = GAIM_DEBUG_INFO; - else if ((flags & G_LOG_LEVEL_INFO) == G_LOG_LEVEL_INFO) - level = GAIM_DEBUG_INFO; - else if ((flags & G_LOG_LEVEL_DEBUG) == G_LOG_LEVEL_DEBUG) - level = GAIM_DEBUG_MISC; - else - { - gaim_debug_warning("gntdebug", - "Unknown glib logging level in %d\n", flags); - - level = GAIM_DEBUG_MISC; /* This will never happen. */ - } - - if (msg != NULL) - new_msg = gaim_utf8_try_convert(msg); - - if (domain != NULL) - new_domain = gaim_utf8_try_convert(domain); - - if (new_msg != NULL) - { - gaim_debug(level, (new_domain != NULL ? new_domain : "g_log"), - "%s\n", new_msg); - - g_free(new_msg); - } - - g_free(new_domain); -} - -static void -size_changed_cb(GntWidget *widget, int oldw, int oldh) -{ - int w, h; - gnt_widget_get_size(widget, &w, &h); - gaim_prefs_set_int(PREF_ROOT "/size/width", w); - gaim_prefs_set_int(PREF_ROOT "/size/height", h); -} - -void gg_debug_window_show() -{ - debug.paused = FALSE; - debug.timestamps = gaim_prefs_get_bool("/core/debug/timestamps"); - if (debug.window == NULL) - { - GntWidget *wid, *box; - debug.window = gnt_vbox_new(FALSE); - gnt_box_set_toplevel(GNT_BOX(debug.window), TRUE); - gnt_box_set_title(GNT_BOX(debug.window), _("Debug Window")); - gnt_box_set_pad(GNT_BOX(debug.window), 0); - gnt_box_set_alignment(GNT_BOX(debug.window), GNT_ALIGN_MID); - - debug.tview = gnt_text_view_new(); - gnt_box_add_widget(GNT_BOX(debug.window), debug.tview); - gnt_widget_set_size(debug.tview, - gaim_prefs_get_int(PREF_ROOT "/size/width"), - gaim_prefs_get_int(PREF_ROOT "/size/height")); - g_signal_connect(G_OBJECT(debug.tview), "size_changed", G_CALLBACK(size_changed_cb), NULL); - - gnt_box_add_widget(GNT_BOX(debug.window), gnt_line_new(FALSE)); - - box = gnt_hbox_new(FALSE); - gnt_box_set_alignment(GNT_BOX(box), GNT_ALIGN_MID); - gnt_box_set_fill(GNT_BOX(box), FALSE); - - /* XXX: Setting the GROW_Y for the following widgets don't make sense. But right now - * it's necessary to make the width of the debug window resizable ... like I said, - * it doesn't make sense. The bug is likely in the packing in gntbox.c. - */ - wid = gnt_button_new(_("Clear")); - g_signal_connect(G_OBJECT(wid), "activate", G_CALLBACK(clear_debug_win), debug.tview); - GNT_WIDGET_SET_FLAGS(wid, GNT_WIDGET_GROW_Y); - gnt_box_add_widget(GNT_BOX(box), wid); - - wid = gnt_check_box_new(_("Pause")); - g_signal_connect(G_OBJECT(wid), "toggled", G_CALLBACK(toggle_pause), NULL); - GNT_WIDGET_SET_FLAGS(wid, GNT_WIDGET_GROW_Y); - gnt_box_add_widget(GNT_BOX(box), wid); - - wid = gnt_check_box_new(_("Timestamps")); - gnt_check_box_set_checked(GNT_CHECK_BOX(wid), debug.timestamps); - g_signal_connect(G_OBJECT(wid), "toggled", G_CALLBACK(toggle_timestamps), NULL); - GNT_WIDGET_SET_FLAGS(wid, GNT_WIDGET_GROW_Y); - gnt_box_add_widget(GNT_BOX(box), wid); - - gnt_box_add_widget(GNT_BOX(debug.window), box); - GNT_WIDGET_SET_FLAGS(box, GNT_WIDGET_GROW_Y); - - gnt_widget_set_name(debug.window, "debug-window"); - - g_signal_connect(G_OBJECT(debug.window), "destroy", G_CALLBACK(reset_debug_win), NULL); - g_signal_connect(G_OBJECT(debug.window), "key_pressed", G_CALLBACK(debug_window_kpress_cb), debug.tview); - } - - gnt_widget_show(debug.window); -} - -static gboolean -start_with_debugwin(gpointer null) -{ - gg_debug_window_show(); - return FALSE; -} - -void gg_debug_init() -{ -/* Xerox */ -#define REGISTER_G_LOG_HANDLER(name) \ - g_log_set_handler((name), G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL \ - | G_LOG_FLAG_RECURSION, \ - gaim_glib_log_handler, NULL) - - /* Register the glib log handlers. */ - REGISTER_G_LOG_HANDLER(NULL); - REGISTER_G_LOG_HANDLER("GLib"); - REGISTER_G_LOG_HANDLER("GModule"); - REGISTER_G_LOG_HANDLER("GLib-GObject"); - REGISTER_G_LOG_HANDLER("GThread"); - - g_set_print_handler(print_stderr); /* Redirect the debug messages to stderr */ - g_set_printerr_handler(suppress_error_messages); - - gaim_prefs_add_none(PREF_ROOT); - gaim_prefs_add_none(PREF_ROOT "/size"); - gaim_prefs_add_int(PREF_ROOT "/size/width", 60); - gaim_prefs_add_int(PREF_ROOT "/size/height", 15); - - if (gaim_debug_is_enabled()) - g_timeout_add(0, start_with_debugwin, NULL); -} - -void gg_debug_uninit() -{ -} - diff -r 317e7613e581 -r 0e3a8505ebbe console/gntdebug.h --- a/console/gntdebug.h Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/** - * @file gntdebug.h GNT Debug API - * @ingroup gntui - * - * gaim - * - * Gaim is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef _GNT_DEBUG_H -#define _GNT_DEBUG_H - -#include "debug.h" - -/********************************************************************** - * @name GNT Debug API - **********************************************************************/ -/*@{*/ - -/** - * Get the ui-functions. - * - * @return The GaimDebugUiOps structure populated with the appropriate functions. - */ -GaimDebugUiOps *gg_debug_get_ui_ops(void); - -/** - * Perform necessary initializations. - */ -void gg_debug_init(void); - -/** - * Perform necessary uninitializations. - */ -void gg_debug_uninit(void); - -/** - * Show the debug window. - */ -void gg_debug_window_show(void); - -/*@}*/ - -#endif diff -r 317e7613e581 -r 0e3a8505ebbe console/gntft.c --- a/console/gntft.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,532 +0,0 @@ -/** - * @file gntft.c GNT File Transfer UI - * @ingroup gntui - * - * gaim - * - * Gaim is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include -#include -#include -#include -#include -#include -#include "internal.h" - -#include "debug.h" -#include "notify.h" -#include "ft.h" -#include "prpl.h" -#include "util.h" - -#include "gntft.h" -#include "prefs.h" - -#define GAIM_GNTXFER(xfer) \ - (GaimGntXferUiData *)(xfer)->ui_data - -typedef struct -{ - gboolean keep_open; - gboolean auto_clear; - gint num_transfers; - - GntWidget *window; - GntWidget *tree; - - GntWidget *remove_button; - GntWidget *stop_button; - GntWidget *close_button; -} GaimGntXferDialog; - -static GaimGntXferDialog *xfer_dialog = NULL; - -typedef struct -{ - time_t last_updated_time; - gboolean in_list; - - char *name; - -} GaimGntXferUiData; - -enum -{ - COLUMN_PROGRESS = 0, - COLUMN_FILENAME, - COLUMN_SIZE, - COLUMN_SPEED, - COLUMN_REMAINING, - COLUMN_STATUS, - NUM_COLUMNS -}; - - -/************************************************************************** - * Utility Functions - **************************************************************************/ - -static void -update_title_progress() -{ - const GList *list; - int num_active_xfers = 0; - guint64 total_bytes_xferred = 0; - guint64 total_file_size = 0; - - if (xfer_dialog == NULL || xfer_dialog->window == NULL) - return; - - /* Find all active transfers */ - for (list = gnt_tree_get_rows(GNT_TREE(xfer_dialog->tree)); list; list = list->next) { - GaimXfer *xfer = (GaimXfer *)list->data; - - if (gaim_xfer_get_status(xfer) == GAIM_XFER_STATUS_STARTED) { - num_active_xfers++; - total_bytes_xferred += gaim_xfer_get_bytes_sent(xfer); - total_file_size += gaim_xfer_get_size(xfer); - } - } - - /* Update the title */ - if (num_active_xfers > 0) { - gchar *title; - int total_pct = 0; - - if (total_file_size > 0) { - total_pct = 100 * total_bytes_xferred / total_file_size; - } - - title = g_strdup_printf(_("File Transfers - %d%% of %d files"), - total_pct, num_active_xfers); - gnt_screen_rename_widget((xfer_dialog->window), title); - g_free(title); - } else { - gnt_screen_rename_widget((xfer_dialog->window), _("File Transfers")); - } -} - - -/************************************************************************** - * Callbacks - **************************************************************************/ -static void -toggle_keep_open_cb(GntWidget *w) -{ - xfer_dialog->keep_open = !xfer_dialog->keep_open; - gaim_prefs_set_bool("/gaim/gnt/filetransfer/keep_open", - xfer_dialog->keep_open); -} - -static void -toggle_clear_finished_cb(GntWidget *w) -{ - xfer_dialog->auto_clear = !xfer_dialog->auto_clear; - gaim_prefs_set_bool("/gaim/gnt/filetransfer/clear_finished", - xfer_dialog->auto_clear); -} - -static void -remove_button_cb(GntButton *button) -{ - GaimXfer *selected_xfer = gnt_tree_get_selection_data(GNT_TREE(xfer_dialog->tree)); - if (selected_xfer && (selected_xfer->status == GAIM_XFER_STATUS_CANCEL_LOCAL || - selected_xfer->status == GAIM_XFER_STATUS_CANCEL_REMOTE || - selected_xfer->status == GAIM_XFER_STATUS_DONE)) { - gg_xfer_dialog_remove_xfer(selected_xfer); - } -} - -static void -stop_button_cb(GntButton *button) -{ - GaimXfer *selected_xfer = gnt_tree_get_selection_data(GNT_TREE(xfer_dialog->tree)); - if (selected_xfer && selected_xfer->status == GAIM_XFER_STATUS_STARTED) - gaim_xfer_cancel_local(selected_xfer); -} - -#if 0 -static void -tree_selection_changed_cb(GntTree *tree, GntTreeRow *old, GntTreeRow *current, gpointer n) -{ - xfer_dialog->selected_xfer = (GaimXfer *)gnt_tree_get_selection_data(tree); -} -#endif - -/************************************************************************** - * Dialog Building Functions - **************************************************************************/ - - -void -gg_xfer_dialog_new(void) -{ - const GList *iter; - GntWidget *window; - GntWidget *bbox; - GntWidget *button; - GntWidget *checkbox; - GntWidget *tree; - - if (!xfer_dialog) - xfer_dialog = g_new0(GaimGntXferDialog, 1); - - xfer_dialog->keep_open = - gaim_prefs_get_bool("/gaim/gnt/filetransfer/keep_open"); - xfer_dialog->auto_clear = - gaim_prefs_get_bool("/gaim/gnt/filetransfer/clear_finished"); - - /* Create the window. */ - xfer_dialog->window = window = gnt_vbox_new(FALSE); - g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gg_xfer_dialog_destroy), NULL); - gnt_box_set_toplevel(GNT_BOX(window), TRUE); - gnt_box_set_title(GNT_BOX(window), _("File Transfers")); - - xfer_dialog->tree = tree = gnt_tree_new_with_columns(NUM_COLUMNS); - gnt_tree_set_column_titles(GNT_TREE(tree), _("Progress"), _("Filename"), _("Size"), _("Speed"), _("Remaining"), _("Status")); - gnt_tree_set_col_width(GNT_TREE(tree), COLUMN_PROGRESS, 8); - gnt_tree_set_col_width(GNT_TREE(tree), COLUMN_FILENAME, 8); - gnt_tree_set_col_width(GNT_TREE(tree), COLUMN_SIZE, 10); - gnt_tree_set_col_width(GNT_TREE(tree), COLUMN_SPEED, 10); - gnt_tree_set_col_width(GNT_TREE(tree), COLUMN_REMAINING, 10); - gnt_tree_set_col_width(GNT_TREE(tree), COLUMN_STATUS, 10); - gnt_tree_set_show_title(GNT_TREE(tree), TRUE); - gnt_box_add_widget(GNT_BOX(window), tree); - /*g_signal_connect(G_OBJECT(tree), "selection-changed",*/ - /*G_CALLBACK(tree_selection_changed_cb), NULL);*/ - checkbox = gnt_check_box_new( _("Close this window when all transfers finish")); - gnt_check_box_set_checked(GNT_CHECK_BOX(checkbox), - !xfer_dialog->keep_open); - g_signal_connect(G_OBJECT(checkbox), "toggled", - G_CALLBACK(toggle_keep_open_cb), NULL); - gnt_box_add_widget(GNT_BOX(window), checkbox); - - checkbox = gnt_check_box_new(_("Clear finished transfers")); - gnt_check_box_set_checked(GNT_CHECK_BOX(checkbox), - xfer_dialog->auto_clear); - g_signal_connect(G_OBJECT(checkbox), "toggled", - G_CALLBACK(toggle_clear_finished_cb), NULL); - gnt_box_add_widget(GNT_BOX(window), checkbox); - - bbox = gnt_hbox_new(TRUE); - - xfer_dialog->remove_button = button = gnt_button_new(_("Remove")); - g_signal_connect(G_OBJECT(button), "activate", - G_CALLBACK(remove_button_cb), NULL); - gnt_box_add_widget(GNT_BOX(bbox), button); - - xfer_dialog->stop_button = button = gnt_button_new(_("Stop")); - g_signal_connect(G_OBJECT(button), "activate", - G_CALLBACK(stop_button_cb), NULL); - gnt_box_add_widget(GNT_BOX(bbox), button); - - xfer_dialog->close_button = button = gnt_button_new(_("Close")); - g_signal_connect(G_OBJECT(button), "activate", - G_CALLBACK(gg_xfer_dialog_destroy), NULL); - gnt_box_add_widget(GNT_BOX(bbox), button); - - gnt_box_add_widget(GNT_BOX(window), bbox); - - for (iter = gaim_xfers_get_all(); iter; iter = iter->next) { - GaimXfer *xfer = (GaimXfer *)iter->data; - GaimGntXferUiData *data = GAIM_GNTXFER(xfer); - if (data->in_list) { - gg_xfer_dialog_add_xfer(xfer); - gg_xfer_dialog_update_xfer(xfer); - gnt_tree_set_selected(GNT_TREE(tree), xfer); - } - } - gnt_widget_show(xfer_dialog->window); -} - -void -gg_xfer_dialog_destroy() -{ - gnt_widget_destroy(xfer_dialog->window); - g_free(xfer_dialog); - xfer_dialog = NULL; -} - -void -gg_xfer_dialog_show() -{ - if (xfer_dialog == NULL) - gg_xfer_dialog_new(); -} - -void -gg_xfer_dialog_add_xfer(GaimXfer *xfer) -{ - GaimGntXferUiData *data; - GaimXferType type; - char *size_str, *remaining_str; - char *lfilename, *utf8; - - g_return_if_fail(xfer_dialog != NULL); - g_return_if_fail(xfer != NULL); - - gaim_xfer_ref(xfer); - - data = GAIM_GNTXFER(xfer); - data->in_list = TRUE; - - gg_xfer_dialog_show(); - - data->last_updated_time = 0; - - type = gaim_xfer_get_type(xfer); - - size_str = gaim_str_size_to_units(gaim_xfer_get_size(xfer)); - remaining_str = gaim_str_size_to_units(gaim_xfer_get_bytes_remaining(xfer)); - - lfilename = g_path_get_basename(gaim_xfer_get_local_filename(xfer)); - utf8 = g_filename_to_utf8(lfilename, -1, NULL, NULL, NULL); - g_free(lfilename); - lfilename = utf8; - gnt_tree_add_row_last(GNT_TREE(xfer_dialog->tree), xfer, - gnt_tree_create_row(GNT_TREE(xfer_dialog->tree), - "0.0", (type == GAIM_XFER_RECEIVE) ? gaim_xfer_get_filename(xfer) : lfilename, - size_str, "0.0", "",_("Waiting for transfer to begin")), NULL); - g_free(lfilename); - - g_free(size_str); - g_free(remaining_str); - - xfer_dialog->num_transfers++; - - update_title_progress(); -} - -void -gg_xfer_dialog_remove_xfer(GaimXfer *xfer) -{ - GaimGntXferUiData *data; - - g_return_if_fail(xfer_dialog != NULL); - g_return_if_fail(xfer != NULL); - - data = GAIM_GNTXFER(xfer); - - if (data == NULL) - return; - - if (!data->in_list) - return; - - data->in_list = FALSE; - - gnt_tree_remove(GNT_TREE(xfer_dialog->tree), xfer); - - xfer_dialog->num_transfers--; - - if (xfer_dialog->num_transfers == 0 && !xfer_dialog->keep_open) - gg_xfer_dialog_destroy(); - else - update_title_progress(); - gaim_xfer_unref(xfer); -} - -void -gg_xfer_dialog_cancel_xfer(GaimXfer *xfer) -{ - GaimGntXferUiData *data; - const gchar *status; - - g_return_if_fail(xfer_dialog != NULL); - g_return_if_fail(xfer != NULL); - - data = GAIM_GNTXFER(xfer); - - if (data == NULL) - return; - - if (!data->in_list) - return; - - if ((gaim_xfer_get_status(xfer) == GAIM_XFER_STATUS_CANCEL_LOCAL) && (xfer_dialog->auto_clear)) { - gg_xfer_dialog_remove_xfer(xfer); - return; - } - - data = GAIM_GNTXFER(xfer); - - update_title_progress(); - - if (gaim_xfer_is_canceled(xfer)) - status = _("Canceled"); - else - status = _("Failed"); - - gnt_tree_change_text(GNT_TREE(xfer_dialog->tree), xfer, COLUMN_STATUS, status); -} - -void -gg_xfer_dialog_update_xfer(GaimXfer *xfer) -{ - GaimGntXferUiData *data; - char *size_str, *remaining_str; - time_t current_time; - char prog_str[5]; - double kb_sent, kb_rem; - double kbps = 0.0; - time_t elapsed, now; - char *kbsec; - - if (xfer->end_time != 0) - now = xfer->end_time; - else - now = time(NULL); - - kb_sent = gaim_xfer_get_bytes_sent(xfer) / 1024.0; - kb_rem = gaim_xfer_get_bytes_remaining(xfer) / 1024.0; - elapsed = (xfer->start_time > 0 ? now - xfer->start_time : 0); - kbps = (elapsed > 0 ? (kb_sent / elapsed) : 0); - - kbsec = g_strdup_printf(_("%.2f KB/s"), kbps); - - g_return_if_fail(xfer_dialog != NULL); - g_return_if_fail(xfer != NULL); - - if ((data = GAIM_GNTXFER(xfer)) == NULL) - return; - - if (data->in_list == FALSE) - return; - - current_time = time(NULL); - if (((current_time - data->last_updated_time) == 0) && - (!gaim_xfer_is_completed(xfer))) { - /* Don't update the window more than once per second */ - return; - } - data->last_updated_time = current_time; - - size_str = gaim_str_size_to_units(gaim_xfer_get_size(xfer)); - remaining_str = gaim_str_size_to_units(gaim_xfer_get_bytes_remaining(xfer)); - - gnt_tree_change_text(GNT_TREE(xfer_dialog->tree), xfer, COLUMN_PROGRESS, - g_ascii_dtostr(prog_str, sizeof(prog_str), gaim_xfer_get_progress(xfer) * 100.)); - gnt_tree_change_text(GNT_TREE(xfer_dialog->tree), xfer, COLUMN_SIZE, size_str); - gnt_tree_change_text(GNT_TREE(xfer_dialog->tree), xfer, COLUMN_REMAINING, remaining_str); - gnt_tree_change_text(GNT_TREE(xfer_dialog->tree), xfer, COLUMN_SPEED, kbsec); - g_free(size_str); - g_free(remaining_str); - if (gaim_xfer_is_completed(xfer)) { - gnt_tree_change_text(GNT_TREE(xfer_dialog->tree), xfer, COLUMN_STATUS, _("Finished")); - } else { - gnt_tree_change_text(GNT_TREE(xfer_dialog->tree), xfer, COLUMN_STATUS, _("Transferring")); - } - - update_title_progress(); - - if (gaim_xfer_is_completed(xfer) && xfer_dialog->auto_clear) - gg_xfer_dialog_remove_xfer(xfer); -} - -/************************************************************************** - * File Transfer UI Ops - **************************************************************************/ -static void -gg_xfer_new_xfer(GaimXfer *xfer) -{ - GaimGntXferUiData *data; - - /* This is where we're setting xfer->ui_data for the first time. */ - data = g_new0(GaimGntXferUiData, 1); - xfer->ui_data = data; -} - -static void -gg_xfer_destroy(GaimXfer *xfer) -{ - GaimGntXferUiData *data; - - data = GAIM_GNTXFER(xfer); - if (data) { - g_free(data->name); - g_free(data); - xfer->ui_data = NULL; - } -} - -static void -gg_xfer_add_xfer(GaimXfer *xfer) -{ - if (!xfer_dialog) - gg_xfer_dialog_new(); - - gg_xfer_dialog_add_xfer(xfer); - gnt_tree_set_selected(GNT_TREE(xfer_dialog->tree), xfer); -} - -static void -gg_xfer_update_progress(GaimXfer *xfer, double percent) -{ - if (xfer_dialog) - gg_xfer_dialog_update_xfer(xfer); -} - -static void -gg_xfer_cancel_local(GaimXfer *xfer) -{ - if (xfer_dialog) - gg_xfer_dialog_cancel_xfer(xfer); -} - -static void -gg_xfer_cancel_remote(GaimXfer *xfer) -{ - if (xfer_dialog) - gg_xfer_dialog_cancel_xfer(xfer); -} - -static GaimXferUiOps ops = -{ - gg_xfer_new_xfer, - gg_xfer_destroy, - gg_xfer_add_xfer, - gg_xfer_update_progress, - gg_xfer_cancel_local, - gg_xfer_cancel_remote -}; - -/************************************************************************** - * GNT File Transfer API - **************************************************************************/ -void -gg_xfers_init(void) -{ - gaim_prefs_add_none("/gaim/gnt/filetransfer"); - gaim_prefs_add_bool("/gaim/gnt/filetransfer/clear_finished", TRUE); - gaim_prefs_add_bool("/gaim/gnt/filetransfer/keep_open", FALSE); -} - -void -gg_xfers_uninit(void) -{ - if (xfer_dialog != NULL) - gg_xfer_dialog_destroy(); -} - -GaimXferUiOps * -gg_xfers_get_ui_ops(void) -{ - return &ops; -} diff -r 317e7613e581 -r 0e3a8505ebbe console/gntft.h --- a/console/gntft.h Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,123 +0,0 @@ -/** - * @file gntft.h GNT File Transfer UI - * @ingroup gntui - * - * gaim - * - * Gaim is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef _GAIM_GNTFT_H_ -#define _GAIM_GNTFT_H_ - -#include "ft.h" - - -/**************************************************************************/ -/** @name GNT File Transfer Dialog API */ -/**************************************************************************/ -/*@{*/ - -/** - * Creates a new file transfer dialog. - * - * @return The new dialog. - */ -void gg_xfer_dialog_new(void); - -/** - * Destroys a file transfer dialog. - * - * @param dialog The file transfer dialog. - */ -void gg_xfer_dialog_destroy(void); - -/** - * Displays the file transfer dialog given. - * If dialog is @c NULL, displays the default dialog, creating one if necessary - * - * @param dialog The file transfer dialog to show. - */ -void gg_xfer_dialog_show(void); - -/** - * Hides the file transfer dialog. - * - * @param dialog The file transfer dialog to hide. - */ -void gg_xfer_dialog_hide(); - -/** - * Adds a file transfer to the dialog. - * - * @param dialog The file transfer dialog. - * @param xfer The file transfer. - */ -void gg_xfer_dialog_add_xfer(GaimXfer *xfer); - -/** - * Removes a file transfer from the dialog. - * - * @param dialog The file transfer dialog. - * @param xfer The file transfer. - */ -void gg_xfer_dialog_remove_xfer(GaimXfer *xfer); - -/** - * Indicate in a file transfer dialog that a transfer was canceled. - * - * @param dialog The file transfer dialog. - * @param xfer The file transfer that was canceled. - */ -void gg_xfer_dialog_cancel_xfer(GaimXfer *xfer); - -/** - * Updates the information for a transfer in the dialog. - * - * @param dialog The file transfer dialog. - * @param xfer The file transfer. - */ -void gg_xfer_dialog_update_xfer(GaimXfer *xfer); - -/*@}*/ - -/**************************************************************************/ -/** @name GNT File Transfer API */ -/**************************************************************************/ -/*@{*/ - -/** - * Initializes the GNT file transfer system. - */ -void gg_xfers_init(void); - -/** - * Uninitializes the GNT file transfer system. - */ -void gg_xfers_uninit(void); - -/** - * Returns the UI operations structure for the GNT file transfer UI. - * - * @return The GNT file transfer UI operations structure. - */ -GaimXferUiOps *gg_xfers_get_ui_ops(void); - -/*@}*/ - -#endif /* _GAIM_GNTFT_H_ */ diff -r 317e7613e581 -r 0e3a8505ebbe console/gntgaim.c --- a/console/gntgaim.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,417 +0,0 @@ -/** - * gaim - * - * Gaim is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include "account.h" -#include "conversation.h" -#include "core.h" -#include "debug.h" -#include "eventloop.h" -#include "ft.h" -#include "log.h" -#include "notify.h" -#include "prefix.h" -#include "prefs.h" -#include "prpl.h" -#include "pounce.h" -#include "savedstatuses.h" -#include "sound.h" -#include "status.h" -#include "util.h" -#include "whiteboard.h" - -#include "gntdebug.h" -#include "gntgaim.h" -#include "gntprefs.h" -#include "gntui.h" -#include "gntidle.h" - -#define _GNU_SOURCE -#include - -#include "config.h" - -static void -debug_init() -{ - gg_debug_init(); - gaim_debug_set_ui_ops(gg_debug_get_ui_ops()); -} - -static GaimCoreUiOps core_ops = -{ - gg_prefs_init, - debug_init, - gnt_ui_init, - gnt_ui_uninit -}; - -static GaimCoreUiOps * -gnt_core_get_ui_ops() -{ - return &core_ops; -} - -/* Anything IO-related is directly copied from gtkgaim's source tree */ - -#define GAIM_GNT_READ_COND (G_IO_IN | G_IO_HUP | G_IO_ERR) -#define GAIM_GNT_WRITE_COND (G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL) - -typedef struct _GaimGntIOClosure { - GaimInputFunction function; - guint result; - gpointer data; - -} GaimGntIOClosure; - -static void gaim_gnt_io_destroy(gpointer data) -{ - g_free(data); -} - -static gboolean gaim_gnt_io_invoke(GIOChannel *source, GIOCondition condition, gpointer data) -{ - GaimGntIOClosure *closure = data; - GaimInputCondition gaim_cond = 0; - - if (condition & GAIM_GNT_READ_COND) - gaim_cond |= GAIM_INPUT_READ; - if (condition & GAIM_GNT_WRITE_COND) - gaim_cond |= GAIM_INPUT_WRITE; - -#if 0 - gaim_debug(GAIM_DEBUG_MISC, "gtk_eventloop", - "CLOSURE: callback for %d, fd is %d\n", - closure->result, g_io_channel_unix_get_fd(source)); -#endif - -#ifdef _WIN32 - if(! gaim_cond) { -#if DEBUG - gaim_debug_misc("gnt_eventloop", - "CLOSURE received GIOCondition of 0x%x, which does not" - " match 0x%x (READ) or 0x%x (WRITE)\n", - condition, GAIM_GNT_READ_COND, GAIM_GNT_WRITE_COND); -#endif /* DEBUG */ - - return TRUE; - } -#endif /* _WIN32 */ - - closure->function(closure->data, g_io_channel_unix_get_fd(source), - gaim_cond); - - return TRUE; -} - -static guint gnt_input_add(gint fd, GaimInputCondition condition, GaimInputFunction function, - gpointer data) -{ - GaimGntIOClosure *closure = g_new0(GaimGntIOClosure, 1); - GIOChannel *channel; - GIOCondition cond = 0; - - closure->function = function; - closure->data = data; - - if (condition & GAIM_INPUT_READ) - cond |= GAIM_GNT_READ_COND; - if (condition & GAIM_INPUT_WRITE) - cond |= GAIM_GNT_WRITE_COND; - - channel = g_io_channel_unix_new(fd); - closure->result = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, cond, - gaim_gnt_io_invoke, closure, gaim_gnt_io_destroy); - - g_io_channel_unref(channel); - return closure->result; -} - -static GaimEventLoopUiOps eventloop_ops = -{ - g_timeout_add, - g_source_remove, - gnt_input_add, - g_source_remove, - NULL /* input_get_error */ -}; - -static GaimEventLoopUiOps * -gnt_eventloop_get_ui_ops(void) -{ - return &eventloop_ops; -} - -/* This is copied from gtkgaim */ -static char * -gnt_find_binary_location(void *symbol, void *data) -{ - static char *fullname = NULL; - static gboolean first = TRUE; - - char *argv0 = data; - struct stat st; - char *basebuf, *linkbuf, *fullbuf; - - if (!first) - /* We've already been through this. */ - return strdup(fullname); - - first = FALSE; - - if (!argv0) - return NULL; - - - basebuf = g_find_program_in_path(argv0); - - /* But we still need to deal with symbolic links */ - g_lstat(basebuf, &st); - while ((st.st_mode & S_IFLNK) == S_IFLNK) { - int written; - linkbuf = g_malloc(1024); - written = readlink(basebuf, linkbuf, 1024 - 1); - if (written == -1) - { - /* This really shouldn't happen, but do we - * need something better here? */ - g_free(linkbuf); - continue; - } - linkbuf[written] = '\0'; - if (linkbuf[0] == G_DIR_SEPARATOR) { - /* an absolute path */ - fullbuf = g_strdup(linkbuf); - } else { - char *dirbuf = g_path_get_dirname(basebuf); - /* a relative path */ - fullbuf = g_strdup_printf("%s%s%s", - dirbuf, G_DIR_SEPARATOR_S, - linkbuf); - g_free(dirbuf); - } - /* There's no memory leak here. Really! */ - g_free(linkbuf); - g_free(basebuf); - basebuf = fullbuf; - g_lstat(basebuf, &st); - } - - fullname = basebuf; - return strdup(fullname); -} - - -/* This is mostly copied from gtkgaim's source tree */ -static void -show_usage(const char *name, gboolean terse) -{ - char *text; - - if (terse) { - text = g_strdup_printf(_("%s. Try `%s -h' for more information.\n"), VERSION, name); - } else { - text = g_strdup_printf(_("%s\n" - "Usage: %s [OPTION]...\n\n" - " -c, --config=DIR use DIR for config files\n" - " -d, --debug print debugging messages to stdout\n" - " -h, --help display this help and exit\n" - " -n, --nologin don't automatically login\n" - " -v, --version display the current version and exit\n"), VERSION, name); - } - - gaim_print_utf8_to_console(stdout, text); - g_free(text); -} - -static int -init_libgaim(int argc, char **argv) -{ - char *path; - int opt; - gboolean opt_help = FALSE; - gboolean opt_nologin = FALSE; - gboolean opt_version = FALSE; - char *opt_config_dir_arg = NULL; - char *opt_session_arg = NULL; - gboolean debug_enabled = FALSE; - - struct option long_options[] = { - {"config", required_argument, NULL, 'c'}, - {"debug", no_argument, NULL, 'd'}, - {"help", no_argument, NULL, 'h'}, - {"nologin", no_argument, NULL, 'n'}, - {"session", required_argument, NULL, 's'}, - {"version", no_argument, NULL, 'v'}, - {0, 0, 0, 0} - }; - - gaim_br_set_locate_fallback_func(gnt_find_binary_location, argv[0]); - -#ifdef ENABLE_NLS - bindtextdomain(PACKAGE, LOCALEDIR); - bind_textdomain_codeset(PACKAGE, "UTF-8"); - textdomain(PACKAGE); -#endif - -#ifdef HAVE_SETLOCALE - setlocale(LC_ALL, ""); -#endif - - /* scan command-line options */ - opterr = 1; - while ((opt = getopt_long(argc, argv, -#ifndef _WIN32 - "c:dhn::s:v", -#else - "c:dhn::v", -#endif - long_options, NULL)) != -1) { - switch (opt) { - case 'c': /* config dir */ - g_free(opt_config_dir_arg); - opt_config_dir_arg = g_strdup(optarg); - break; - case 'd': /* debug */ - debug_enabled = TRUE; - break; - case 'h': /* help */ - opt_help = TRUE; - break; - case 'n': /* no autologin */ - opt_nologin = TRUE; - break; - case 's': /* use existing session ID */ - g_free(opt_session_arg); - opt_session_arg = g_strdup(optarg); - break; - case 'v': /* version */ - opt_version = TRUE; - break; - case '?': /* show terse help */ - default: - show_usage(argv[0], TRUE); - return 0; - break; - } - } - - /* show help message */ - if (opt_help) { - show_usage(argv[0], FALSE); - return 0; - } - /* show version message */ - if (opt_version) { - printf("gaim-text %s\n", VERSION); - return 0; - } - - /* set a user-specified config directory */ - if (opt_config_dir_arg != NULL) { - gaim_util_set_user_dir(opt_config_dir_arg); - g_free(opt_config_dir_arg); - } - - /* - * We're done piddling around with command line arguments. - * Fire up this baby. - */ - - /* Because we don't want debug-messages to show up and corrup the display */ - gaim_debug_set_enabled(debug_enabled); - - gaim_core_set_ui_ops(gnt_core_get_ui_ops()); - gaim_eventloop_set_ui_ops(gnt_eventloop_get_ui_ops()); - gaim_idle_set_ui_ops(gg_idle_get_ui_ops()); - - path = g_build_filename(gaim_user_dir(), "plugins", NULL); - gaim_plugins_add_search_path(path); - g_free(path); - - gaim_plugins_add_search_path(LIBDIR); - - if (!gaim_core_init(GAIM_GNT_UI)) - { - fprintf(stderr, - "Initialization of the Gaim core failed. Dumping core.\n" - "Please report this!\n"); - abort(); - } - - /* TODO: Move blist loading into gaim_blist_init() */ - gaim_set_blist(gaim_blist_new()); - gaim_blist_load(); - - /* TODO: Move prefs loading into gaim_prefs_init() */ - gaim_prefs_load(); - gaim_prefs_update_old(); - - /* load plugins we had when we quit */ - gaim_plugins_load_saved("/gaim/gnt/plugins/loaded"); - - /* TODO: Move pounces loading into gaim_pounces_init() */ - gaim_pounces_load(); - - if (opt_nologin) - { - /* Set all accounts to "offline" */ - GaimSavedStatus *saved_status; - - /* If we've used this type+message before, lookup the transient status */ - saved_status = gaim_savedstatus_find_transient_by_type_and_message( - GAIM_STATUS_OFFLINE, NULL); - - /* If this type+message is unique then create a new transient saved status */ - if (saved_status == NULL) - saved_status = gaim_savedstatus_new(NULL, GAIM_STATUS_OFFLINE); - - /* Set the status for each account */ - gaim_savedstatus_activate(saved_status); - } - else - { - /* Everything is good to go--sign on already */ - if (!gaim_prefs_get_bool("/core/savedstatus/startup_current_status")) - gaim_savedstatus_activate(gaim_savedstatus_get_startup()); - gaim_accounts_restore_current_statuses(); - } - - return 1; -} - -int main(int argc, char **argv) -{ - signal(SIGPIPE, SIG_IGN); - - /* Initialize the libgaim stuff */ - if (!init_libgaim(argc, argv)) - return 0; - - gaim_blist_show(); - gnt_main(); - -#ifdef STANDALONE - gaim_core_quit(); -#endif - - return 0; -} - diff -r 317e7613e581 -r 0e3a8505ebbe console/gntgaim.h --- a/console/gntgaim.h Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -/** - * gaim - * - * Gaim is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include - -#include "libpurple/internal.h" - -#define GAIM_GNT_UI "gnt-gaim" - diff -r 317e7613e581 -r 0e3a8505ebbe console/gntidle.c --- a/console/gntidle.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -/* - * gaim - * - * Gaim is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include "internal.h" -#include "gntidle.h" -#include "gntwm.h" - -#include "idle.h" - -static time_t -gg_get_idle_time() -{ - return gnt_wm_get_idle_time(); -} - -static GaimIdleUiOps ui_ops = -{ - gg_get_idle_time -}; - -GaimIdleUiOps * -gg_idle_get_ui_ops() -{ - return &ui_ops; -} diff -r 317e7613e581 -r 0e3a8505ebbe console/gntidle.h --- a/console/gntidle.h Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,44 +0,0 @@ -/** - * @file gntidle.h GNT Idle API - * @ingroup gntui - * - * gaim - * - * Pidgin is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef _GNT_IDLE_H_ -#define _GNT_IDLE_H_ - -#include "idle.h" - -/**************************************************************************/ -/** @name GNT Idle API */ -/**************************************************************************/ -/*@{*/ - -/** - * Returns the GNT idle UI ops. - * - * @return The UI operations structure. - */ -GaimIdleUiOps *gg_idle_get_ui_ops(void); - -/*@}*/ - -#endif /* _GG_IDLE_H_ */ diff -r 317e7613e581 -r 0e3a8505ebbe console/gntnotify.c --- a/console/gntnotify.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,374 +0,0 @@ -/** - * @file gntnotify.c GNT Notify API - * @ingroup gntui - * - * gaim - * - * Gaim is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include -#include -#include -#include -#include - -#include - -#include "gntnotify.h" -#include "gntgaim.h" - -static struct -{ - GntWidget *window; - GntWidget *tree; -} emaildialog; - -static void -notify_msg_window_destroy_cb(GntWidget *window, GaimNotifyMsgType type) -{ - gaim_notify_close(type, window); -} - -static void * -gg_notify_message(GaimNotifyMsgType type, const char *title, - const char *primary, const char *secondary) -{ - GntWidget *window, *button; - GntTextFormatFlags pf = 0, sf = 0; - - switch (type) - { - case GAIM_NOTIFY_MSG_ERROR: - sf |= GNT_TEXT_FLAG_BOLD; - case GAIM_NOTIFY_MSG_WARNING: - pf |= GNT_TEXT_FLAG_UNDERLINE; - case GAIM_NOTIFY_MSG_INFO: - pf |= GNT_TEXT_FLAG_BOLD; - break; - } - - window = gnt_box_new(FALSE, TRUE); - gnt_box_set_toplevel(GNT_BOX(window), TRUE); - gnt_box_set_title(GNT_BOX(window), title); - gnt_box_set_fill(GNT_BOX(window), FALSE); - gnt_box_set_alignment(GNT_BOX(window), GNT_ALIGN_MID); - - if (primary) - gnt_box_add_widget(GNT_BOX(window), - gnt_label_new_with_format(primary, pf)); - if (secondary) - gnt_box_add_widget(GNT_BOX(window), - gnt_label_new_with_format(secondary, sf)); - - button = gnt_button_new(_("OK")); - gnt_box_add_widget(GNT_BOX(window), button); - g_signal_connect_swapped(G_OBJECT(button), "activate", - G_CALLBACK(gnt_widget_destroy), window); - g_signal_connect(G_OBJECT(window), "destroy", - G_CALLBACK(notify_msg_window_destroy_cb), GINT_TO_POINTER(type)); - - gnt_widget_show(window); - return window; -} - -/* handle is, in all/most occasions, a GntWidget * */ -static void gg_close_notify(GaimNotifyType type, void *handle) -{ - GntWidget *widget = handle; - - if (!widget) - return; - - while (widget->parent) - widget = widget->parent; - - if (type == GAIM_NOTIFY_SEARCHRESULTS) - gaim_notify_searchresults_free(g_object_get_data(handle, "notify-results")); -#if 1 - /* This did not seem to be necessary */ - g_signal_handlers_disconnect_by_func(G_OBJECT(widget), - G_CALLBACK(notify_msg_window_destroy_cb), GINT_TO_POINTER(type)); -#endif - gnt_widget_destroy(widget); -} - -static void *gg_notify_formatted(const char *title, const char *primary, - const char *secondary, const char *text) -{ - /* XXX: For now, simply strip the html and use _notify_message. For future use, - * there should be some way of parsing the makrups from GntTextView */ - char *unformat = gaim_markup_strip_html(text); - char *t = g_strdup_printf("%s%s%s", - secondary ? secondary : "", - secondary ? "\n" : "", - unformat ? unformat : ""); - - void *ret = gg_notify_message(GAIM_NOTIFY_FORMATTED, title, primary, t); - - g_free(t); - g_free(unformat); - - return ret; -} - -static void -reset_email_dialog() -{ - emaildialog.window = NULL; - emaildialog.tree = NULL; -} - -static void -setup_email_dialog() -{ - GntWidget *box, *tree, *button; - if (emaildialog.window) - return; - - emaildialog.window = box = gnt_vbox_new(FALSE); - gnt_box_set_toplevel(GNT_BOX(box), TRUE); - gnt_box_set_title(GNT_BOX(box), _("Emails")); - gnt_box_set_fill(GNT_BOX(box), FALSE); - gnt_box_set_alignment(GNT_BOX(box), GNT_ALIGN_MID); - gnt_box_set_pad(GNT_BOX(box), 0); - - gnt_box_add_widget(GNT_BOX(box), - gnt_label_new_with_format(_("You have mail!"), GNT_TEXT_FLAG_BOLD)); - - emaildialog.tree = tree = gnt_tree_new_with_columns(3); - gnt_tree_set_column_titles(GNT_TREE(tree), _("Account"), _("From"), _("Subject")); - gnt_tree_set_show_title(GNT_TREE(tree), TRUE); - gnt_tree_set_col_width(GNT_TREE(tree), 0, 15); - gnt_tree_set_col_width(GNT_TREE(tree), 1, 25); - gnt_tree_set_col_width(GNT_TREE(tree), 2, 25); - - gnt_box_add_widget(GNT_BOX(box), tree); - - button = gnt_button_new(_("Close")); - gnt_box_add_widget(GNT_BOX(box), button); - - g_signal_connect_swapped(G_OBJECT(button), "activate", G_CALLBACK(gnt_widget_destroy), box); - g_signal_connect(G_OBJECT(box), "destroy", G_CALLBACK(reset_email_dialog), NULL); -} - -static void * -gg_notify_emails(GaimConnection *gc, size_t count, gboolean detailed, - const char **subjects, const char **froms, const char **tos, - const char **urls) -{ - GaimAccount *account = gaim_connection_get_account(gc); - GString *message = g_string_new(NULL); - void *ret; - - if (!detailed) - { - g_string_append_printf(message, - ngettext("%s (%s) has %d new message.", - "%s (%s) has %d new messages.", - (int)count), - tos ? *tos : gaim_account_get_username(account), - gaim_account_get_protocol_name(account), (int)count); - } - else - { - char *to; - - setup_email_dialog(); - - to = g_strdup_printf("%s (%s)", tos ? *tos : gaim_account_get_username(account), - gaim_account_get_protocol_name(account)); - gnt_tree_add_row_after(GNT_TREE(emaildialog.tree), GINT_TO_POINTER(time(NULL)), - gnt_tree_create_row(GNT_TREE(emaildialog.tree), to, - froms ? *froms : "[Unknown sender]", - *subjects), - NULL, NULL); - g_free(to); - gnt_widget_show(emaildialog.window); - return NULL; - } - - ret = gg_notify_message(GAIM_NOTIFY_EMAIL, _("New Mail"), _("You have mail!"), message->str); - g_string_free(message, TRUE); - return ret; -} - -static void * -gg_notify_email(GaimConnection *gc, const char *subject, const char *from, - const char *to, const char *url) -{ - return gg_notify_emails(gc, 1, subject != NULL, - subject ? &subject : NULL, - from ? &from : NULL, - to ? &to : NULL, - url ? &url : NULL); -} - -static void * -gg_notify_userinfo(GaimConnection *gc, const char *who, GaimNotifyUserInfo *user_info) -{ - /* Xeroxed from gtknotify.c */ - char *primary; - char *info; - void *ui_handle; - - primary = g_strdup_printf(_("Info for %s"), who); - info = gaim_notify_user_info_get_text_with_newline(user_info, "
"); - ui_handle = gg_notify_formatted(_("Buddy Information"), primary, NULL, info); - g_free(info); - g_free(primary); - return ui_handle; -} - -static void -notify_button_activated(GntWidget *widget, GaimNotifySearchButton *b) -{ - GList *list = NULL; - GaimAccount *account = g_object_get_data(G_OBJECT(widget), "notify-account"); - gpointer data = g_object_get_data(G_OBJECT(widget), "notify-data"); - - list = gnt_tree_get_selection_text_list(GNT_TREE(widget)); - - b->callback(gaim_account_get_connection(account), list, data); - g_list_foreach(list, (GFunc)g_free, NULL); - g_list_free(list); -} - -static void -gg_notify_sr_new_rows(GaimConnection *gc, - GaimNotifySearchResults *results, void *data) -{ - GntTree *tree = GNT_TREE(data); - GList *o; - - /* XXX: Do I need to empty the tree here? */ - - for (o = results->rows; o; o = o->next) - { - gnt_tree_add_row_after(GNT_TREE(tree), o->data, - gnt_tree_create_row_from_list(GNT_TREE(tree), o->data), - NULL, NULL); - } -} - -static void * -gg_notify_searchresults(GaimConnection *gc, const char *title, - const char *primary, const char *secondary, - GaimNotifySearchResults *results, gpointer data) -{ - GntWidget *window, *tree, *box, *button; - GList *iter; - - window = gnt_vbox_new(FALSE); - gnt_box_set_toplevel(GNT_BOX(window), TRUE); - gnt_box_set_title(GNT_BOX(window), title); - gnt_box_set_fill(GNT_BOX(window), FALSE); - gnt_box_set_pad(GNT_BOX(window), 0); - gnt_box_set_alignment(GNT_BOX(window), GNT_ALIGN_MID); - - gnt_box_add_widget(GNT_BOX(window), - gnt_label_new_with_format(primary, GNT_TEXT_FLAG_BOLD)); - gnt_box_add_widget(GNT_BOX(window), - gnt_label_new_with_format(secondary, GNT_TEXT_FLAG_NORMAL)); - - tree = gnt_tree_new_with_columns(g_list_length(results->columns)); - gnt_tree_set_show_title(GNT_TREE(tree), TRUE); - gnt_box_add_widget(GNT_BOX(window), tree); - - box = gnt_hbox_new(TRUE); - - for (iter = results->buttons; iter; iter = iter->next) - { - GaimNotifySearchButton *b = iter->data; - const char *text; - - switch (b->type) - { - case GAIM_NOTIFY_BUTTON_LABELED: - text = b->label; - break; - case GAIM_NOTIFY_BUTTON_CONTINUE: - text = _("Continue"); - break; - case GAIM_NOTIFY_BUTTON_ADD: - text = _("Add"); - break; - case GAIM_NOTIFY_BUTTON_INFO: - text = _("Info"); - break; - case GAIM_NOTIFY_BUTTON_IM: - text = _("IM"); - break; - case GAIM_NOTIFY_BUTTON_JOIN: - text = _("Join"); - break; - case GAIM_NOTIFY_BUTTON_INVITE: - text = _("Invite"); - break; - default: - text = _("(none)"); - } - - button = gnt_button_new(text); - g_object_set_data(G_OBJECT(button), "notify-account", gaim_connection_get_account(gc)); - g_object_set_data(G_OBJECT(button), "notify-data", data); - g_signal_connect_swapped(G_OBJECT(button), "activate", - G_CALLBACK(notify_button_activated), b); - - gnt_box_add_widget(GNT_BOX(box), button); - } - - gnt_box_add_widget(GNT_BOX(window), box); - - gg_notify_sr_new_rows(gc, results, tree); - - gnt_widget_show(window); - g_object_set_data(G_OBJECT(window), "notify-results", results); - - return tree; -} - -static GaimNotifyUiOps ops = -{ - .notify_message = gg_notify_message, - .close_notify = gg_close_notify, /* The rest of the notify-uiops return a GntWidget. - These widgets should be destroyed from here. */ - .notify_formatted = gg_notify_formatted, - .notify_email = gg_notify_email, - .notify_emails = gg_notify_emails, - .notify_userinfo = gg_notify_userinfo, - - .notify_searchresults = gg_notify_searchresults, - .notify_searchresults_new_rows = gg_notify_sr_new_rows, - .notify_uri = NULL /* This is of low-priority to me */ -}; - -GaimNotifyUiOps *gg_notify_get_ui_ops() -{ - return &ops; -} - -void gg_notify_init() -{ -} - -void gg_notify_uninit() -{ -} - - diff -r 317e7613e581 -r 0e3a8505ebbe console/gntnotify.h --- a/console/gntnotify.h Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -/** - * @file gntnotify.h GNT Notify API - * @ingroup gntui - * - * gaim - * - * Gaim is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef _GNT_NOTIFY_H -#define _GNT_NOTIFY_H - -#include "notify.h" - -/********************************************************************** - * @name GNT Notify API - **********************************************************************/ -/*@{*/ - -/** - * Get the ui-functions. - * - * @return The GaimNotifyUiOps structure populated with the appropriate functions. - */ -GaimNotifyUiOps *gg_notify_get_ui_ops(void); - -/** - * Perform necessary initializations. - */ -void gg_notify_init(void); - -/** - * Perform necessary uninitializations. - */ -void gg_notify_uninit(void); - -/*@}*/ - -#endif - diff -r 317e7613e581 -r 0e3a8505ebbe console/gntplugin.c --- a/console/gntplugin.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,274 +0,0 @@ -/** - * @file gntplugin.c GNT Plugins API - * @ingroup gntui - * - * gaim - * - * Gaim is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include -#include -#include -#include -#include -#include - -#include "notify.h" - -#include "gntgaim.h" -#include "gntplugin.h" - -static struct -{ - GntWidget *tree; - GntWidget *window; - GntWidget *aboot; - GntWidget *conf; -} plugins; - -static GHashTable *confwins; - -static void -decide_conf_button(GaimPlugin *plugin) -{ - if (gaim_plugin_is_loaded(plugin) && - ((GAIM_IS_GNT_PLUGIN(plugin) && - GAIM_GNT_PLUGIN_UI_INFO(plugin) != NULL) || - (plugin->info->prefs_info && - plugin->info->prefs_info->get_plugin_pref_frame))) - gnt_widget_set_visible(plugins.conf, TRUE); - else - gnt_widget_set_visible(plugins.conf, FALSE); - - gnt_box_readjust(GNT_BOX(plugins.window)); - gnt_widget_draw(plugins.window); -} - -static void -plugin_toggled_cb(GntWidget *tree, GaimPlugin *plugin, gpointer null) -{ - if (gnt_tree_get_choice(GNT_TREE(tree), plugin)) - { - if(!gaim_plugin_load(plugin)) - gaim_notify_error(NULL, "ERROR", "loading plugin failed", NULL); - } - else - { - GntWidget *win; - - if (!gaim_plugin_unload(plugin)) - gaim_notify_error(NULL, "ERROR", "unloading plugin failed", NULL); - - if ((win = g_hash_table_lookup(confwins, plugin)) != NULL) - { - gnt_widget_destroy(win); - } - } - decide_conf_button(plugin); - gg_plugins_save_loaded(); -} - -/* Xerox */ -void -gg_plugins_save_loaded(void) -{ - gaim_plugins_save_loaded("/gaim/gnt/plugins/loaded"); -} - -static void -selection_changed(GntWidget *widget, gpointer old, gpointer current, gpointer null) -{ - GaimPlugin *plugin = current; - char *text; - - /* XXX: Use formatting and stuff */ - gnt_text_view_clear(GNT_TEXT_VIEW(plugins.aboot)); - text = g_strdup_printf(_("Name: %s\nVersion: %s\nDescription: %s\nAuthor: %s\nWebsite: %s\nFilename: %s\n"), - SAFE(plugin->info->name), SAFE(plugin->info->version), SAFE(plugin->info->description), - SAFE(plugin->info->author), SAFE(plugin->info->homepage), SAFE(plugin->path)); - gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(plugins.aboot), - text, GNT_TEXT_FLAG_NORMAL); - gnt_text_view_scroll(GNT_TEXT_VIEW(plugins.aboot), 0); - g_free(text); - decide_conf_button(plugin); -} - -static void -reset_plugin_window(GntWidget *window, gpointer null) -{ - plugins.window = NULL; - plugins.tree = NULL; - plugins.aboot = NULL; -} - -static int -plugin_compare(GaimPlugin *p1, GaimPlugin *p2) -{ - char *s1 = g_utf8_strup(p1->info->name, -1); - char *s2 = g_utf8_strup(p2->info->name, -1); - int ret = g_utf8_collate(s1, s2); - g_free(s1); - g_free(s2); - return ret; -} - -static void -confwin_init() -{ - confwins = g_hash_table_new(g_direct_hash, g_direct_equal); -} - -static void -remove_confwin(GntWidget *window, gpointer plugin) -{ - g_hash_table_remove(confwins, plugin); -} - -static void -configure_plugin_cb(GntWidget *button, gpointer null) -{ - GaimPlugin *plugin; - GGPluginFrame callback; - - g_return_if_fail(plugins.tree != NULL); - - plugin = gnt_tree_get_selection_data(GNT_TREE(plugins.tree)); - if (!gaim_plugin_is_loaded(plugin)) - { - gaim_notify_error(plugin, _("Error"), - _("Plugin need to be loaded before you can configure it."), NULL); - return; - } - - if (confwins && g_hash_table_lookup(confwins, plugin)) - return; - - if (GAIM_IS_GNT_PLUGIN(plugin) && - (callback = GAIM_GNT_PLUGIN_UI_INFO(plugin)) != NULL) - { - GntWidget *window = gnt_vbox_new(FALSE); - GntWidget *box, *button; - - gnt_box_set_toplevel(GNT_BOX(window), TRUE); - gnt_box_set_title(GNT_BOX(window), plugin->info->name); - gnt_box_set_alignment(GNT_BOX(window), GNT_ALIGN_MID); - - box = callback(); - gnt_box_add_widget(GNT_BOX(window), box); - - box = gnt_hbox_new(FALSE); - gnt_box_add_widget(GNT_BOX(window), box); - - button = gnt_button_new(_("Close")); - gnt_box_add_widget(GNT_BOX(box), button); - g_signal_connect_swapped(G_OBJECT(button), "activate", - G_CALLBACK(gnt_widget_destroy), window); - g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(remove_confwin), plugin); - - gnt_widget_show(window); - - if (confwins == NULL) - confwin_init(); - g_hash_table_insert(confwins, plugin, window); - } - else if (plugin->info->prefs_info && - plugin->info->prefs_info->get_plugin_pref_frame) - { - gaim_notify_info(plugin, _("..."), - _("Still need to do something about this."), NULL); - return; - } - else - { - gaim_notify_info(plugin, _("Error"), - _("No configuration options for this plugin."), NULL); - return; - } -} - -void gg_plugins_show_all() -{ - GntWidget *window, *tree, *box, *aboot, *button; - GList *iter; - if (plugins.window) - return; - - gaim_plugins_probe(G_MODULE_SUFFIX); - - plugins.window = window = gnt_vbox_new(FALSE); - gnt_box_set_toplevel(GNT_BOX(window), TRUE); - gnt_box_set_title(GNT_BOX(window), _("Plugins")); - gnt_box_set_pad(GNT_BOX(window), 0); - gnt_box_set_alignment(GNT_BOX(window), GNT_ALIGN_MID); - - gnt_box_add_widget(GNT_BOX(window), - gnt_label_new(_("You can (un)load plugins from the following list."))); - gnt_box_add_widget(GNT_BOX(window), gnt_hline_new()); - - box = gnt_hbox_new(FALSE); - gnt_box_add_widget(GNT_BOX(window), box); - gnt_box_add_widget(GNT_BOX(window), gnt_hline_new()); - - gnt_box_set_pad(GNT_BOX(box), 0); - plugins.tree = tree = gnt_tree_new(); - gnt_tree_set_compare_func(GNT_TREE(tree), (GCompareFunc)plugin_compare); - GNT_WIDGET_SET_FLAGS(tree, GNT_WIDGET_NO_BORDER); - gnt_box_add_widget(GNT_BOX(box), tree); - gnt_box_add_widget(GNT_BOX(box), gnt_vline_new()); - - plugins.aboot = aboot = gnt_text_view_new(); - gnt_widget_set_size(aboot, 40, 20); - gnt_box_add_widget(GNT_BOX(box), aboot); - - for (iter = gaim_plugins_get_all(); iter; iter = iter->next) - { - GaimPlugin *plug = iter->data; - - if (plug->info->type != GAIM_PLUGIN_STANDARD || - (plug->info->flags & GAIM_PLUGIN_FLAG_INVISIBLE) || - plug->error) - continue; - - gnt_tree_add_choice(GNT_TREE(tree), plug, - gnt_tree_create_row(GNT_TREE(tree), plug->info->name), NULL, NULL); - gnt_tree_set_choice(GNT_TREE(tree), plug, gaim_plugin_is_loaded(plug)); - } - gnt_tree_set_col_width(GNT_TREE(tree), 0, 30); - g_signal_connect(G_OBJECT(tree), "toggled", G_CALLBACK(plugin_toggled_cb), NULL); - g_signal_connect(G_OBJECT(tree), "selection_changed", G_CALLBACK(selection_changed), NULL); - - box = gnt_hbox_new(FALSE); - gnt_box_add_widget(GNT_BOX(window), box); - - button = gnt_button_new(_("Close")); - gnt_box_add_widget(GNT_BOX(box), button); - g_signal_connect_swapped(G_OBJECT(button), "activate", - G_CALLBACK(gnt_widget_destroy), window); - - plugins.conf = button = gnt_button_new(_("Configure Plugin")); - gnt_box_add_widget(GNT_BOX(box), button); - g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(configure_plugin_cb), NULL); - - g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(reset_plugin_window), NULL); - - gnt_widget_show(window); - - decide_conf_button(gnt_tree_get_selection_data(GNT_TREE(tree))); -} - diff -r 317e7613e581 -r 0e3a8505ebbe console/gntplugin.h --- a/console/gntplugin.h Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -/** - * @file gntplugin.h GNT Plugins API - * @ingroup gntui - * - * gaim - * - * Gaim is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef _GNT_PLUGIN_H -#define _GNT_PLUGIN_H - -#include - -#include - -#include - -#include "gntgaim.h" - -/********************************************************************** - * @name GNT Plugins API - **********************************************************************/ -/*@{*/ - -typedef GntWidget* (*GGPluginFrame) (); - -/* Guess where these came from */ -#define GAIM_GNT_PLUGIN_TYPE GAIM_GNT_UI - -/** - * Decide whether a plugin is a GNT-plugin. - */ -#define GAIM_IS_GNT_PLUGIN(plugin) \ - ((plugin)->info != NULL && (plugin)->info->ui_info != NULL && \ - !strcmp((plugin)->info->ui_requirement, GAIM_GNT_PLUGIN_TYPE)) - -/** - * Get the ui-info from GNT-plugins. - */ -#define GAIM_GNT_PLUGIN_UI_INFO(plugin) \ - (GGPluginFrame)((plugin)->info->ui_info) - -/** - * Show a list of plugins. - */ -void gg_plugins_show_all(void); - -/** - * Save the list of loaded plugins. - */ -void gg_plugins_save_loaded(void); - -/*@}*/ - -#endif diff -r 317e7613e581 -r 0e3a8505ebbe console/gntpounce.c --- a/console/gntpounce.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,956 +0,0 @@ -/** - * @file gntpounce.c GNT Buddy Pounce API - * @ingroup gntui - * - * gaim - * - * Gaim is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "internal.h" -#include "gntgaim.h" - -#include "account.h" -#include "conversation.h" -#include "debug.h" -#include "notify.h" -#include "prpl.h" -#include "request.h" -#include "server.h" -#include "util.h" - -#include "gntpounce.h" - - -typedef struct -{ - /* Pounce data */ - GaimPounce *pounce; - GaimAccount *account; - - /* The window */ - GntWidget *window; - - /* Pounce on Whom */ - GntWidget *account_menu; - GntWidget *buddy_entry; - - /* Pounce options */ - GntWidget *on_away; - - /* Pounce When Buddy... */ - GntWidget *signon; - GntWidget *signoff; - GntWidget *away; - GntWidget *away_return; - GntWidget *idle; - GntWidget *idle_return; - GntWidget *typing; - GntWidget *typed; - GntWidget *stop_typing; - GntWidget *message_recv; - - /* Action */ - GntWidget *open_win; - GntWidget *popup; - GntWidget *popup_entry; - GntWidget *send_msg; - GntWidget *send_msg_entry; - GntWidget *exec_cmd; - GntWidget *exec_cmd_entry; - GntWidget *play_sound; - - GntWidget *save_pounce; - - /* Buttons */ - GntWidget *save_button; - -} GaimGntPounceDialog; - -typedef struct -{ - GntWidget *window; - GntWidget *tree; - GntWidget *modify_button; - GntWidget *delete_button; -} PouncesManager; - -static PouncesManager *pounces_manager = NULL; - -/************************************************************************** - * Callbacks - **************************************************************************/ -static gint -delete_win_cb(GntWidget *w, GaimGntPounceDialog *dialog) -{ - gnt_widget_destroy(dialog->window); - g_free(dialog); - - return TRUE; -} - -static void -cancel_cb(GntWidget *w, GaimGntPounceDialog *dialog) -{ - gnt_widget_destroy(dialog->window); -} - -static void -add_pounce_to_treeview(GntTree *tree, GaimPounce *pounce) -{ - GaimAccount *account; - const char *pouncer; - const char *pouncee; - - account = gaim_pounce_get_pouncer(pounce); - pouncer = gaim_account_get_username(account); - pouncee = gaim_pounce_get_pouncee(pounce); - gnt_tree_add_row_last(tree, pounce, - gnt_tree_create_row(tree, pouncer, pouncee), NULL); -} - -static void -populate_pounces_list(PouncesManager *dialog) -{ - const GList *pounces; - - gnt_tree_remove_all(GNT_TREE(dialog->tree)); - - for (pounces = gaim_pounces_get_all(); pounces != NULL; - pounces = g_list_next(pounces)) - { - add_pounce_to_treeview(GNT_TREE(dialog->tree), pounces->data); - } -} - -static void -update_pounces(void) -{ - /* Rebuild the pounces list if the pounces manager is open */ - if (pounces_manager != NULL) - { - populate_pounces_list(pounces_manager); - } -} - -static void -signed_on_off_cb(GaimConnection *gc, gpointer user_data) -{ - update_pounces(); -} - -static void -save_pounce_cb(GntWidget *w, GaimGntPounceDialog *dialog) -{ - const char *name; - const char *message, *command, *reason; - GaimPounceEvent events = GAIM_POUNCE_NONE; - GaimPounceOption options = GAIM_POUNCE_OPTION_NONE; - - name = gnt_entry_get_text(GNT_ENTRY(dialog->buddy_entry)); - - if (*name == '\0') - { - gaim_notify_error(NULL, NULL, - _("Please enter a buddy to pounce."), NULL); - return; - } - - /* Options */ - if (gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->on_away))) - options |= GAIM_POUNCE_OPTION_AWAY; - - /* Events */ - if (gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->signon))) - events |= GAIM_POUNCE_SIGNON; - - if (gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->signoff))) - events |= GAIM_POUNCE_SIGNOFF; - - if (gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->away))) - events |= GAIM_POUNCE_AWAY; - - if (gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->away_return))) - events |= GAIM_POUNCE_AWAY_RETURN; - - if (gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->idle))) - events |= GAIM_POUNCE_IDLE; - - if (gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->idle_return))) - events |= GAIM_POUNCE_IDLE_RETURN; - - if (gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->typing))) - events |= GAIM_POUNCE_TYPING; - - if (gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->typed))) - events |= GAIM_POUNCE_TYPED; - - if (gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->stop_typing))) - events |= GAIM_POUNCE_TYPING_STOPPED; - - if (gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->message_recv))) - events |= GAIM_POUNCE_MESSAGE_RECEIVED; - - /* Data fields */ - message = gnt_entry_get_text(GNT_ENTRY(dialog->send_msg_entry)); - command = gnt_entry_get_text(GNT_ENTRY(dialog->exec_cmd_entry)); - reason = gnt_entry_get_text(GNT_ENTRY(dialog->popup_entry)); - - if (*reason == '\0') reason = NULL; - if (*message == '\0') message = NULL; - if (*command == '\0') command = NULL; - - if (dialog->pounce == NULL) { - dialog->pounce = gaim_pounce_new(GAIM_GNT_UI, dialog->account, - name, events, options); - } else { - gaim_pounce_set_events(dialog->pounce, events); - gaim_pounce_set_options(dialog->pounce, options); - gaim_pounce_set_pouncer(dialog->pounce, dialog->account); - gaim_pounce_set_pouncee(dialog->pounce, name); - } - - /* Actions */ - gaim_pounce_action_set_enabled(dialog->pounce, "open-window", - gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->open_win))); - gaim_pounce_action_set_enabled(dialog->pounce, "popup-notify", - gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->popup))); - gaim_pounce_action_set_enabled(dialog->pounce, "send-message", - gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->send_msg))); - gaim_pounce_action_set_enabled(dialog->pounce, "execute-command", - gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->exec_cmd))); - gaim_pounce_action_set_enabled(dialog->pounce, "play-beep", - gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->play_sound))); - - gaim_pounce_action_set_attribute(dialog->pounce, "send-message", - "message", message); - gaim_pounce_action_set_attribute(dialog->pounce, "execute-command", - "command", command); - gaim_pounce_action_set_attribute(dialog->pounce, "popup-notify", - "reason", reason); - - /* Set the defaults for next time. */ - gaim_prefs_set_bool("/gaim/gnt/pounces/default_actions/open-window", - gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->open_win))); - gaim_prefs_set_bool("/gaim/gnt/pounces/default_actions/popup-notify", - gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->popup))); - gaim_prefs_set_bool("/gaim/gnt/pounces/default_actions/send-message", - gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->send_msg))); - gaim_prefs_set_bool("/gaim/gnt/pounces/default_actions/execute-command", - gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->exec_cmd))); - gaim_prefs_set_bool("/gaim/gnt/pounces/default_actions/play-beep", - gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->play_sound))); - - gaim_pounce_set_save(dialog->pounce, - gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->save_pounce))); - - gaim_pounce_set_pouncer(dialog->pounce, - (GaimAccount *)gnt_combo_box_get_selected_data(GNT_COMBO_BOX(dialog->account_menu))); - - update_pounces(); - - gnt_widget_destroy(dialog->window); -} - - -void -gg_pounce_editor_show(GaimAccount *account, const char *name, - GaimPounce *cur_pounce) -{ - GaimGntPounceDialog *dialog; - GntWidget *window; - GntWidget *bbox; - GntWidget *hbox; - GntWidget *button; - GntWidget *combo; - GList *list; - - g_return_if_fail((cur_pounce != NULL) || - (account != NULL) || - (gaim_accounts_get_all() != NULL)); - - dialog = g_new0(GaimGntPounceDialog, 1); - - if (cur_pounce != NULL) { - dialog->pounce = cur_pounce; - dialog->account = gaim_pounce_get_pouncer(cur_pounce); - } else if (account != NULL) { - dialog->pounce = NULL; - dialog->account = account; - } else { - GList *connections = gaim_connections_get_all(); - GaimConnection *gc; - - if (connections != NULL) { - gc = (GaimConnection *)connections->data; - dialog->account = gaim_connection_get_account(gc); - } else - dialog->account = gaim_accounts_get_all()->data; - - dialog->pounce = NULL; - } - - /* Create the window. */ - dialog->window = window = gnt_vbox_new(FALSE); - gnt_box_set_pad(GNT_BOX(window), 0); - gnt_box_set_toplevel(GNT_BOX(window), TRUE); - gnt_box_set_alignment(GNT_BOX(window), GNT_ALIGN_LEFT); - gnt_box_set_title(GNT_BOX(window), - (cur_pounce == NULL - ? _("New Buddy Pounce") : _("Edit Buddy Pounce"))); - - g_signal_connect(G_OBJECT(window), "destroy", - G_CALLBACK(delete_win_cb), dialog); - - gnt_box_add_widget(GNT_BOX(window), gnt_label_new_with_format(_("Pounce Who"), GNT_TEXT_FLAG_BOLD)); - - /* Account: */ - gnt_box_add_widget(GNT_BOX(window), gnt_label_new(_("Account:"))); - dialog->account_menu = combo = gnt_combo_box_new(); - list = gaim_accounts_get_all(); - for (; list; list = list->next) - { - GaimAccount *account; - char *text; - - account = list->data; - text = g_strdup_printf("%s (%s)", - gaim_account_get_username(account), - gaim_account_get_protocol_name(account)); - gnt_combo_box_add_data(GNT_COMBO_BOX(combo), account, text); - g_free(text); - } - if (dialog->account) - gnt_combo_box_set_selected(GNT_COMBO_BOX(combo), dialog->account); - - gnt_box_add_widget(GNT_BOX(window), combo); - - /* Buddy: */ - hbox = gnt_hbox_new(FALSE); - gnt_box_add_widget(GNT_BOX(hbox), gnt_label_new(_("Buddy name:"))); - - dialog->buddy_entry = gnt_entry_new(NULL); - gnt_box_add_widget(GNT_BOX(hbox), dialog->buddy_entry); - - gnt_box_add_widget(GNT_BOX(window), hbox); - - if (cur_pounce != NULL) { - gnt_entry_set_text(GNT_ENTRY(dialog->buddy_entry), - gaim_pounce_get_pouncee(cur_pounce)); - } else if (name != NULL) { - gnt_entry_set_text(GNT_ENTRY(dialog->buddy_entry), name); - } - - gnt_box_add_widget(GNT_BOX(window), gnt_line_new(FALSE)); - gnt_box_add_widget(GNT_BOX(window), gnt_label_new_with_format(_("Pounce When Buddy..."), GNT_TEXT_FLAG_BOLD)); - - dialog->signon = gnt_check_box_new(_("Signs on")); - dialog->signoff = gnt_check_box_new(_("Signs off")); - dialog->away = gnt_check_box_new(_("Goes away")); - dialog->away_return = gnt_check_box_new(_("Returns from away")); - dialog->idle = gnt_check_box_new(_("Becomes idle")); - dialog->idle_return = gnt_check_box_new(_("Is no longer idle")); - dialog->typing = gnt_check_box_new(_("Starts typing")); - dialog->typed = gnt_check_box_new(_("Pauses while typing")); - dialog->stop_typing = gnt_check_box_new(_("Stops typing")); - dialog->message_recv = gnt_check_box_new(_("Sends a message")); - - hbox = gnt_hbox_new(FALSE); - gnt_box_set_pad(GNT_BOX(hbox), 2); - gnt_box_add_widget(GNT_BOX(hbox), dialog->signon); - gnt_box_add_widget(GNT_BOX(hbox), dialog->signoff); - gnt_box_add_widget(GNT_BOX(window), hbox); - hbox = gnt_hbox_new(FALSE); - gnt_box_set_pad(GNT_BOX(hbox), 2); - gnt_box_add_widget(GNT_BOX(hbox), dialog->away); - gnt_box_add_widget(GNT_BOX(hbox), dialog->away_return); - gnt_box_add_widget(GNT_BOX(window), hbox); - hbox = gnt_hbox_new(FALSE); - gnt_box_set_pad(GNT_BOX(hbox), 2); - gnt_box_add_widget(GNT_BOX(hbox), dialog->idle); - gnt_box_add_widget(GNT_BOX(hbox), dialog->idle_return); - gnt_box_add_widget(GNT_BOX(window), hbox); - hbox = gnt_hbox_new(FALSE); - gnt_box_set_pad(GNT_BOX(hbox), 2); - gnt_box_add_widget(GNT_BOX(hbox), dialog->typing); - gnt_box_add_widget(GNT_BOX(hbox), dialog->typed); - gnt_box_add_widget(GNT_BOX(window), hbox); - hbox = gnt_hbox_new(FALSE); - gnt_box_set_pad(GNT_BOX(hbox), 2); - gnt_box_add_widget(GNT_BOX(hbox), dialog->stop_typing); - gnt_box_add_widget(GNT_BOX(hbox), dialog->message_recv); - gnt_box_add_widget(GNT_BOX(window), hbox); - - /* Create the "Action" frame. */ - gnt_box_add_widget(GNT_BOX(window), gnt_line_new(FALSE)); - gnt_box_add_widget(GNT_BOX(window), gnt_label_new_with_format(_("Action"), GNT_TEXT_FLAG_BOLD)); - - dialog->open_win = gnt_check_box_new(_("Open an IM window")); - dialog->popup = gnt_check_box_new(_("Pop up a notification")); - dialog->send_msg = gnt_check_box_new(_("Send a message")); - dialog->exec_cmd = gnt_check_box_new(_("Execute a command")); - dialog->play_sound = gnt_check_box_new(_("Play a sound")); - - dialog->send_msg_entry = gnt_entry_new(NULL); - dialog->exec_cmd_entry = gnt_entry_new(NULL); - dialog->popup_entry = gnt_entry_new(NULL); - dialog->exec_cmd_entry = gnt_entry_new(NULL); - - hbox = gnt_hbox_new(FALSE); - gnt_box_add_widget(GNT_BOX(hbox), dialog->open_win); - gnt_box_add_widget(GNT_BOX(window), hbox); - hbox = gnt_hbox_new(FALSE); - gnt_box_add_widget(GNT_BOX(hbox), dialog->popup); - gnt_box_add_widget(GNT_BOX(hbox), dialog->popup_entry); - gnt_box_add_widget(GNT_BOX(window), hbox); - hbox = gnt_hbox_new(FALSE); - gnt_box_add_widget(GNT_BOX(hbox), dialog->send_msg); - gnt_box_add_widget(GNT_BOX(hbox), dialog->send_msg_entry); - gnt_box_add_widget(GNT_BOX(window), hbox); - hbox = gnt_hbox_new(FALSE); - gnt_box_add_widget(GNT_BOX(hbox), dialog->exec_cmd); - gnt_box_add_widget(GNT_BOX(hbox), dialog->exec_cmd_entry); - gnt_box_add_widget(GNT_BOX(window), hbox); - hbox = gnt_hbox_new(FALSE); - gnt_box_add_widget(GNT_BOX(hbox), dialog->play_sound); - gnt_box_add_widget(GNT_BOX(window), hbox); - - gnt_box_add_widget(GNT_BOX(window), gnt_line_new(FALSE)); - gnt_box_add_widget(GNT_BOX(window), gnt_label_new_with_format(_("Options"), GNT_TEXT_FLAG_BOLD)); - dialog->on_away = gnt_check_box_new(_("Pounce only when my status is not available")); - gnt_box_add_widget(GNT_BOX(window), dialog->on_away); - dialog->save_pounce = gnt_check_box_new(_("Recurring")); - gnt_box_add_widget(GNT_BOX(window), dialog->save_pounce); - - - gnt_box_add_widget(GNT_BOX(window), gnt_line_new(FALSE)); - /* Now the button box! */ - bbox = gnt_hbox_new(TRUE); - - /* Cancel button */ - button = gnt_button_new(_("Cancel")); - gnt_box_add_widget(GNT_BOX(bbox), button); - g_signal_connect(G_OBJECT(button), "activate", - G_CALLBACK(cancel_cb), dialog); - - /* Save button */ - dialog->save_button = button = gnt_button_new(_("Save")); - gnt_box_add_widget(GNT_BOX(bbox), button); - g_signal_connect(G_OBJECT(button), "activate", - G_CALLBACK(save_pounce_cb), dialog); - - gnt_box_add_widget(GNT_BOX(window), bbox); - - - /* Set the values of stuff. */ - if (cur_pounce != NULL) - { - GaimPounceEvent events = gaim_pounce_get_events(cur_pounce); - GaimPounceOption options = gaim_pounce_get_options(cur_pounce); - const char *value; - - /* Options */ - gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->on_away), - (options & GAIM_POUNCE_OPTION_AWAY)); - - /* Events */ - gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->signon), - (events & GAIM_POUNCE_SIGNON)); - gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->signoff), - (events & GAIM_POUNCE_SIGNOFF)); - gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->away), - (events & GAIM_POUNCE_AWAY)); - gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->away_return), - (events & GAIM_POUNCE_AWAY_RETURN)); - gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->idle), - (events & GAIM_POUNCE_IDLE)); - gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->idle_return), - (events & GAIM_POUNCE_IDLE_RETURN)); - gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->typing), - (events & GAIM_POUNCE_TYPING)); - gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->typed), - (events & GAIM_POUNCE_TYPED)); - gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->stop_typing), - (events & GAIM_POUNCE_TYPING_STOPPED)); - gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->message_recv), - (events & GAIM_POUNCE_MESSAGE_RECEIVED)); - - /* Actions */ - gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->open_win), - gaim_pounce_action_is_enabled(cur_pounce, "open-window")); - gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->popup), - gaim_pounce_action_is_enabled(cur_pounce, "popup-notify")); - gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->send_msg), - gaim_pounce_action_is_enabled(cur_pounce, "send-message")); - gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->exec_cmd), - gaim_pounce_action_is_enabled(cur_pounce, "execute-command")); - gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->play_sound), - gaim_pounce_action_is_enabled(cur_pounce, "play-beep")); - - gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->save_pounce), - gaim_pounce_get_save(cur_pounce)); - - if ((value = gaim_pounce_action_get_attribute(cur_pounce, - "send-message", - "message")) != NULL) - { - gnt_entry_set_text(GNT_ENTRY(dialog->send_msg_entry), value); - } - - if ((value = gaim_pounce_action_get_attribute(cur_pounce, - "popup-notify", - "reason")) != NULL) - { - gnt_entry_set_text(GNT_ENTRY(dialog->popup_entry), value); - } - - if ((value = gaim_pounce_action_get_attribute(cur_pounce, - "execute-command", - "command")) != NULL) - { - gnt_entry_set_text(GNT_ENTRY(dialog->exec_cmd_entry), value); - } - } - else - { - GaimBuddy *buddy = NULL; - - if (name != NULL) - buddy = gaim_find_buddy(account, name); - - /* Set some defaults */ - if (buddy == NULL) { - gnt_check_box_set_checked( - GNT_CHECK_BOX(dialog->signon), TRUE); - } else { - if (!GAIM_BUDDY_IS_ONLINE(buddy)) { - gnt_check_box_set_checked( - GNT_CHECK_BOX(dialog->signon), TRUE); - } else { - gboolean default_set = FALSE; - GaimPresence *presence = gaim_buddy_get_presence(buddy); - - if (gaim_presence_is_idle(presence)) - { - gnt_check_box_set_checked( - GNT_CHECK_BOX(dialog->idle_return), TRUE); - - default_set = TRUE; - } - - if (!gaim_presence_is_available(presence)) - { - gnt_check_box_set_checked( - GNT_CHECK_BOX(dialog->away_return), TRUE); - - default_set = TRUE; - } - - if (!default_set) - { - gnt_check_box_set_checked( - GNT_CHECK_BOX(dialog->signon), TRUE); - } - } - } - - gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->open_win), - gaim_prefs_get_bool("/gaim/gnt/pounces/default_actions/open-window")); - gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->popup), - gaim_prefs_get_bool("/gaim/gnt/pounces/default_actions/popup-notify")); - gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->send_msg), - gaim_prefs_get_bool("/gaim/gnt/pounces/default_actions/send-message")); - gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->exec_cmd), - gaim_prefs_get_bool("/gaim/gnt/pounces/default_actions/execute-command")); - gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->play_sound), - gaim_prefs_get_bool("/gaim/gnt/pounces/default_actions/play-beep")); - } - - gnt_widget_show(window); -} - - - -static gboolean -pounces_manager_destroy_cb(GntWidget *widget, gpointer user_data) -{ - PouncesManager *dialog = user_data; - - dialog->window = NULL; - gg_pounces_manager_hide(); - - return FALSE; -} - - -static void -pounces_manager_add_cb(GntButton *button, gpointer user_data) -{ - gg_pounce_editor_show(NULL, NULL, NULL); -} - - -static void -pounces_manager_modify_cb(GntButton *button, gpointer user_data) -{ - PouncesManager *dialog = user_data; - GaimPounce *pounce = gnt_tree_get_selection_data(GNT_TREE(dialog->tree)); - gg_pounce_editor_show(NULL, NULL, pounce); -} - -static void -pounces_manager_delete_confirm_cb(GaimPounce *pounce) -{ - gnt_tree_remove(GNT_TREE(pounces_manager->tree), pounce); - - gaim_request_close_with_handle(pounce); - gaim_pounce_destroy(pounce); -} - - -static void -pounces_manager_delete_cb(GntButton *button, gpointer user_data) -{ - PouncesManager *dialog = user_data; - GaimPounce *pounce; - GaimAccount *account; - const char *pouncer, *pouncee; - char *buf; - - pounce = (GaimPounce *)gnt_tree_get_selection_data(GNT_TREE(dialog->tree)); - account = gaim_pounce_get_pouncer(pounce); - pouncer = gaim_account_get_username(account); - pouncee = gaim_pounce_get_pouncee(pounce); - buf = g_strdup_printf(_("Are you sure you want to delete the pounce on %s for %s?"), pouncee, pouncer); - gaim_request_action(pounce, NULL, buf, NULL, 0, pounce, 2, - _("Delete"), pounces_manager_delete_confirm_cb, - _("Cancel"), NULL); - g_free(buf); -} - -static void -pounces_manager_close_cb(GntButton *button, gpointer user_data) -{ - gg_pounces_manager_hide(); -} - - -void -gg_pounces_manager_show(void) -{ - PouncesManager *dialog; - GntWidget *bbox; - GntWidget *button; - GntWidget *tree; - GntWidget *win; - - if (pounces_manager != NULL) { - return; - } - - pounces_manager = dialog = g_new0(PouncesManager, 1); - - dialog->window = win = gnt_vbox_new(FALSE); - gnt_box_set_toplevel(GNT_BOX(win), TRUE); - gnt_box_set_title(GNT_BOX(win), _("Buddy Pounces")); - gnt_box_set_pad(GNT_BOX(win), 0); - - g_signal_connect(G_OBJECT(win), "destroy", - G_CALLBACK(pounces_manager_destroy_cb), dialog); - - /* List of saved buddy pounces */ - dialog->tree = tree = GNT_WIDGET(gnt_tree_new_with_columns(2)); - gnt_tree_set_column_titles(GNT_TREE(tree), "Account", "Pouncee", NULL); - gnt_tree_set_show_title(GNT_TREE(tree), TRUE); - - gnt_box_add_widget(GNT_BOX(win), tree); - - /* Button box. */ - bbox = gnt_hbox_new(TRUE); - - /* Add button */ - button = gnt_button_new(_("Add")); - gnt_box_add_widget(GNT_BOX(bbox), button); - - g_signal_connect(G_OBJECT(button), "activate", - G_CALLBACK(pounces_manager_add_cb), dialog); - - /* Modify button */ - button = gnt_button_new(_("Modify")); - dialog->modify_button = button; - gnt_box_add_widget(GNT_BOX(bbox), button); - - g_signal_connect(G_OBJECT(button), "activate", - G_CALLBACK(pounces_manager_modify_cb), dialog); - - /* Delete button */ - button = gnt_button_new(_("Delete")); - dialog->delete_button = button; - gnt_box_add_widget(GNT_BOX(bbox), button); - - g_signal_connect(G_OBJECT(button), "activate", - G_CALLBACK(pounces_manager_delete_cb), dialog); - - /* Close button */ - button = gnt_button_new(_("Close")); - gnt_box_add_widget(GNT_BOX(bbox), button); - gnt_widget_show(button); - - g_signal_connect(G_OBJECT(button), "activate", - G_CALLBACK(pounces_manager_close_cb), dialog); - - gnt_box_add_widget(GNT_BOX(win), bbox); - - gnt_widget_show(win); - populate_pounces_list(pounces_manager); -} - -void -gg_pounces_manager_hide(void) -{ - if (pounces_manager == NULL) - return; - - if (pounces_manager->window != NULL) - gnt_widget_destroy(pounces_manager->window); - - gaim_signals_disconnect_by_handle(pounces_manager); - - g_free(pounces_manager); - pounces_manager = NULL; -} - -static void -pounce_cb(GaimPounce *pounce, GaimPounceEvent events, void *data) -{ - GaimConversation *conv; - GaimAccount *account; - GaimBuddy *buddy; - const char *pouncee; - const char *alias; - - pouncee = gaim_pounce_get_pouncee(pounce); - account = gaim_pounce_get_pouncer(pounce); - - buddy = gaim_find_buddy(account, pouncee); - if (buddy != NULL) - { - alias = gaim_buddy_get_alias(buddy); - if (alias == NULL) - alias = pouncee; - } - else - alias = pouncee; - - if (gaim_pounce_action_is_enabled(pounce, "open-window")) - { - conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, pouncee, account); - - if (conv == NULL) - conv = gaim_conversation_new(GAIM_CONV_TYPE_IM, account, pouncee); - } - - if (gaim_pounce_action_is_enabled(pounce, "popup-notify")) - { - char *tmp; - const char *name_shown; - const char *reason; - reason = gaim_pounce_action_get_attribute(pounce, "popup-notify", - "reason"); - - /* - * Here we place the protocol name in the pounce dialog to lessen - * confusion about what protocol a pounce is for. - */ - tmp = g_strdup_printf( - (events & GAIM_POUNCE_TYPING) ? - _("%s has started typing to you (%s)") : - (events & GAIM_POUNCE_TYPED) ? - _("%s has paused while typing to you (%s)") : - (events & GAIM_POUNCE_SIGNON) ? - _("%s has signed on (%s)") : - (events & GAIM_POUNCE_IDLE_RETURN) ? - _("%s has returned from being idle (%s)") : - (events & GAIM_POUNCE_AWAY_RETURN) ? - _("%s has returned from being away (%s)") : - (events & GAIM_POUNCE_TYPING_STOPPED) ? - _("%s has stopped typing to you (%s)") : - (events & GAIM_POUNCE_SIGNOFF) ? - _("%s has signed off (%s)") : - (events & GAIM_POUNCE_IDLE) ? - _("%s has become idle (%s)") : - (events & GAIM_POUNCE_AWAY) ? - _("%s has gone away. (%s)") : - (events & GAIM_POUNCE_MESSAGE_RECEIVED) ? - _("%s has sent you a message. (%s)") : - _("Unknown pounce event. Please report this!"), - alias, gaim_account_get_protocol_name(account)); - - /* - * Ok here is where I change the second argument, title, from - * NULL to the account alias if we have it or the account - * name if that's all we have - */ - if ((name_shown = gaim_account_get_alias(account)) == NULL) - name_shown = gaim_account_get_username(account); - - if (reason == NULL) - { - gaim_notify_info(NULL, name_shown, tmp, gaim_date_format_full(NULL)); - } - else - { - char *tmp2 = g_strdup_printf("%s\n\n%s", reason, gaim_date_format_full(NULL)); - gaim_notify_info(NULL, name_shown, tmp, tmp2); - g_free(tmp2); - } - g_free(tmp); - } - - if (gaim_pounce_action_is_enabled(pounce, "send-message")) - { - const char *message; - - message = gaim_pounce_action_get_attribute(pounce, "send-message", - "message"); - - if (message != NULL) - { - conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, pouncee, account); - - if (conv == NULL) - conv = gaim_conversation_new(GAIM_CONV_TYPE_IM, account, pouncee); - - gaim_conversation_write(conv, NULL, message, - GAIM_MESSAGE_SEND, time(NULL)); - - serv_send_im(account->gc, (char *)pouncee, (char *)message, 0); - } - } - - if (gaim_pounce_action_is_enabled(pounce, "execute-command")) - { - const char *command; - - command = gaim_pounce_action_get_attribute(pounce, - "execute-command", "command"); - - if (command != NULL) - { - char *localecmd = g_locale_from_utf8(command, -1, NULL, - NULL, NULL); - - if (localecmd != NULL) - { - int pid = fork(); - - if (pid == 0) { - char *args[4]; - - args[0] = "sh"; - args[1] = "-c"; - args[2] = (char *)localecmd; - args[3] = NULL; - - execvp(args[0], args); - - _exit(0); - } - g_free(localecmd); - } - } - } - - if (gaim_pounce_action_is_enabled(pounce, "play-beep")) - { - beep(); - } -} - -static void -free_pounce(GaimPounce *pounce) -{ - update_pounces(); -} - -static void -new_pounce(GaimPounce *pounce) -{ - gaim_pounce_action_register(pounce, "open-window"); - gaim_pounce_action_register(pounce, "popup-notify"); - gaim_pounce_action_register(pounce, "send-message"); - gaim_pounce_action_register(pounce, "execute-command"); - gaim_pounce_action_register(pounce, "play-beep"); - - update_pounces(); -} - -void * -gg_pounces_get_handle() -{ - static int handle; - - return &handle; -} - -void -gg_pounces_init(void) -{ - gaim_pounces_register_handler(GAIM_GNT_UI, pounce_cb, new_pounce, - free_pounce); - - gaim_prefs_add_none("/gaim/gnt/pounces"); - gaim_prefs_add_none("/gaim/gnt/pounces/default_actions"); - gaim_prefs_add_bool("/gaim/gnt/pounces/default_actions/open-window", - FALSE); - gaim_prefs_add_bool("/gaim/gnt/pounces/default_actions/popup-notify", - TRUE); - gaim_prefs_add_bool("/gaim/gnt/pounces/default_actions/send-message", - FALSE); - gaim_prefs_add_bool("/gaim/gnt/pounces/default_actions/execute-command", - FALSE); - gaim_prefs_add_bool("/gaim/gnt/pounces/default_actions/play-beep", - FALSE); - gaim_prefs_add_none("/gaim/gnt/pounces/dialog"); - - gaim_signal_connect(gaim_connections_get_handle(), "signed-on", - gg_pounces_get_handle(), - GAIM_CALLBACK(signed_on_off_cb), NULL); - gaim_signal_connect(gaim_connections_get_handle(), "signed-off", - gg_pounces_get_handle(), - GAIM_CALLBACK(signed_on_off_cb), NULL); -} - -/* XXX: There's no such thing in pidgin. Perhaps there should be? */ -void gg_pounces_uninit() -{ - gaim_pounces_register_handler(GAIM_GNT_UI, NULL, NULL, NULL); - - gaim_signals_disconnect_by_handle(gg_pounces_get_handle()); -} - diff -r 317e7613e581 -r 0e3a8505ebbe console/gntpounce.h --- a/console/gntpounce.h Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -/** - * @file gntpounce.h GNT Buddy Pounce API - * @ingroup gntui - * - * gaim - * - * Gaim is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef _GAIM_GNTPOUNCE_H_ -#define _GAIM_GNTPOUNCE_H_ - -#include "pounce.h" - -/** - * Displays a New Buddy Pounce or Edit Buddy Pounce dialog. - * - * @param account The optional account to use. - * @param name The optional name to pounce on. - * @param cur_pounce The current buddy pounce, if editing an existing one. - */ -void gg_pounce_editor_show(GaimAccount *account, const char *name, - GaimPounce *cur_pounce); - -/** - * Shows the pounces manager window. - */ -void gg_pounces_manager_show(void); - -/** - * Hides the pounces manager window. - */ -void gg_pounces_manager_hide(void); - -/** - * Returns the gtkpounces handle - * - * @return The handle to the GTK+ pounces system - */ -void *gg_pounces_get_handle(void); - -/** - * Initializes the GNT pounces subsystem. - */ -void gg_pounces_init(void); - -/** - * Uninitializes the GNT pounces subsystem. - */ -void gg_pounces_uninit(void); - -#endif /* _GAIM_GTKPOUNCE_H_ */ diff -r 317e7613e581 -r 0e3a8505ebbe console/gntprefs.c --- a/console/gntprefs.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,286 +0,0 @@ -/** - * @file gntprefs.c GNT Preferences API - * @ingroup gntui - * - * gaim - * - * Gaim is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include -#include - -#include "gntgaim.h" -#include "gntprefs.h" -#include "gntrequest.h" - -#include - -static GList *freestrings; /* strings to be freed when the pref-window is closed */ - -void gg_prefs_init() -{ - gaim_prefs_add_none("/gaim"); - gaim_prefs_add_none("/gaim/gnt"); - - gaim_prefs_add_none("/gaim/gnt/plugins"); - gaim_prefs_add_path_list("/gaim/gnt/plugins/loaded", NULL); - - gaim_prefs_add_none("/gaim/gnt/conversations"); - gaim_prefs_add_bool("/gaim/gnt/conversations/timestamps", TRUE); - gaim_prefs_add_bool("/gaim/gnt/conversations/notify_typing", FALSE); /* XXX: Not functional yet */ -} - -typedef struct -{ - GaimPrefType type; - const char *pref; - const char *label; - GList *(*lv)(); /* If the value is to be selected from a number of choices */ -} Prefs; - -static GList * -get_log_options() -{ - return gaim_log_logger_get_options(); -} - -static GList * -get_idle_options() -{ - GList *list = NULL; - list = g_list_append(list, "Based on keyboard use"); /* XXX: string freeze */ - list = g_list_append(list, "system"); - list = g_list_append(list, (char*)_("From last sent message")); - list = g_list_append(list, "gaim"); - list = g_list_append(list, (char*)_("Never")); - list = g_list_append(list, "never"); - return list; -} - -static GList * -get_status_titles() -{ - GList *list = NULL; - const GList *iter; - for (iter = gaim_savedstatuses_get_all(); iter; iter = iter->next) { - char *str; - if (gaim_savedstatus_is_transient(iter->data)) - continue; - str = g_strdup_printf("%ld", gaim_savedstatus_get_creation_time(iter->data)); - list = g_list_append(list, (char*)gaim_savedstatus_get_title(iter->data)); - list = g_list_append(list, str); - freestrings = g_list_prepend(freestrings, str); - } - return list; -} - -static GaimRequestField * -get_pref_field(Prefs *prefs) -{ - GaimRequestField *field = NULL; - - if (prefs->lv == NULL) - { - switch (prefs->type) - { - case GAIM_PREF_BOOLEAN: - field = gaim_request_field_bool_new(prefs->pref, _(prefs->label), - gaim_prefs_get_bool(prefs->pref)); - break; - case GAIM_PREF_INT: - field = gaim_request_field_int_new(prefs->pref, _(prefs->label), - gaim_prefs_get_int(prefs->pref)); - break; - case GAIM_PREF_STRING: - field = gaim_request_field_string_new(prefs->pref, _(prefs->label), - gaim_prefs_get_string(prefs->pref), FALSE); - break; - default: - break; - } - } - else - { - GList *list = prefs->lv(), *iter; - if (list) - field = gaim_request_field_list_new(prefs->pref, _(prefs->label)); - for (iter = list; iter; iter = iter->next) - { - gboolean select = FALSE; - const char *data = iter->data; - int idata; - iter = iter->next; - switch (prefs->type) - { - case GAIM_PREF_BOOLEAN: - sscanf(iter->data, "%d", &idata); - if (gaim_prefs_get_bool(prefs->pref) == idata) - select = TRUE; - break; - case GAIM_PREF_INT: - sscanf(iter->data, "%d", &idata); - if (gaim_prefs_get_int(prefs->pref) == idata) - select = TRUE; - break; - case GAIM_PREF_STRING: - if (strcmp(gaim_prefs_get_string(prefs->pref), iter->data) == 0) - select = TRUE; - break; - default: - break; - } - gaim_request_field_list_add(field, data, iter->data); - if (select) - gaim_request_field_list_add_selected(field, data); - } - g_list_free(list); - } - return field; -} - -static Prefs blist[] = -{ - {GAIM_PREF_BOOLEAN, "/gaim/gnt/blist/idletime", N_("Show Idle Time"), NULL}, - {GAIM_PREF_BOOLEAN, "/gaim/gnt/blist/showoffline", N_("Show Offline Buddies"), NULL}, - {GAIM_PREF_NONE, NULL, NULL, NULL} -}; - -static Prefs convs[] = -{ - {GAIM_PREF_BOOLEAN, "/gaim/gnt/conversations/timestamps", N_("Show Timestamps"), NULL}, - {GAIM_PREF_BOOLEAN, "/gaim/gnt/conversations/notify_typing", N_("Notify buddies when you are typing"), NULL}, - {GAIM_PREF_NONE, NULL, NULL, NULL} -}; - -static Prefs logging[] = -{ - {GAIM_PREF_STRING, "/core/logging/format", N_("Log format"), get_log_options}, - {GAIM_PREF_BOOLEAN, "/core/logging/log_ims", N_("Log IMs"), NULL}, - {GAIM_PREF_BOOLEAN, "/core/logging/log_chats", N_("Log chats"), NULL}, - {GAIM_PREF_BOOLEAN, "/core/logging/log_system", N_("Log status change events"), NULL}, - {GAIM_PREF_NONE, NULL, NULL, NULL}, -}; - -/* XXX: Translate after the freeze */ -static Prefs idle[] = -{ - {GAIM_PREF_STRING, "/core/away/idle_reporting", "Report Idle time", get_idle_options}, - {GAIM_PREF_BOOLEAN, "/core/away/away_when_idle", "Change status when idle", NULL}, - {GAIM_PREF_INT, "/core/away/mins_before_away", "Minutes before changing status", NULL}, - {GAIM_PREF_INT, "/core/savedstatus/idleaway", "Change status to", get_status_titles}, - {GAIM_PREF_NONE, NULL, NULL, NULL}, -}; - -static void -free_strings() -{ - g_list_foreach(freestrings, (GFunc)g_free, NULL); - g_list_free(freestrings); - freestrings = NULL; -} - -static void -save_cb(void *data, GaimRequestFields *allfields) -{ - GList *list; - for (list = gaim_request_fields_get_groups(allfields); list; list = list->next) - { - GaimRequestFieldGroup *group = list->data; - GList *fields = gaim_request_field_group_get_fields(group); - - for (; fields ; fields = fields->next) - { - GaimRequestField *field = fields->data; - GaimRequestFieldType type = gaim_request_field_get_type(field); - GaimPrefType pt; - gpointer val = NULL; - const char *id = gaim_request_field_get_id(field); - - switch (type) - { - case GAIM_REQUEST_FIELD_LIST: - val = gaim_request_field_list_get_selected(field)->data; - break; - case GAIM_REQUEST_FIELD_BOOLEAN: - val = GINT_TO_POINTER(gaim_request_field_bool_get_value(field)); - break; - case GAIM_REQUEST_FIELD_INTEGER: - val = GINT_TO_POINTER(gaim_request_field_int_get_value(field)); - break; - case GAIM_REQUEST_FIELD_STRING: - val = (gpointer)gaim_request_field_string_get_value(field); - break; - default: - break; - } - - pt = gaim_prefs_get_type(id); - switch (pt) - { - case GAIM_PREF_INT: - if (type == GAIM_REQUEST_FIELD_LIST) /* Lists always return string */ - sscanf(val, "%ld", (long int *)&val); - gaim_prefs_set_int(id, GPOINTER_TO_INT(val)); - break; - case GAIM_PREF_BOOLEAN: - gaim_prefs_set_bool(id, GPOINTER_TO_INT(val)); - break; - case GAIM_PREF_STRING: - gaim_prefs_set_string(id, val); - break; - default: - break; - } - } - } - free_strings(); -} - -static void -add_pref_group(GaimRequestFields *fields, const char *title, Prefs *prefs) -{ - GaimRequestField *field; - GaimRequestFieldGroup *group; - int i; - - group = gaim_request_field_group_new(title); - gaim_request_fields_add_group(fields, group); - for (i = 0; prefs[i].pref; i++) - { - field = get_pref_field(prefs + i); - if (field) - gaim_request_field_group_add_field(group, field); - } -} - -void gg_prefs_show_all() -{ - GaimRequestFields *fields; - - fields = gaim_request_fields_new(); - - add_pref_group(fields, _("Buddy List"), blist); - add_pref_group(fields, _("Conversations"), convs); - add_pref_group(fields, _("Logging"), logging); - add_pref_group(fields, _("Idle"), idle); - - gaim_request_fields(NULL, _("Preferences"), NULL, NULL, fields, - _("Save"), G_CALLBACK(save_cb), _("Cancel"), free_strings, NULL); -} - diff -r 317e7613e581 -r 0e3a8505ebbe console/gntprefs.h --- a/console/gntprefs.h Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -/** - * @file gntprefs.h GNT Preferences API - * @ingroup gntui - * - * gaim - * - * Gaim is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef _GNT_PREFS_H -#define _GNT_PREFS_H - -/********************************************************************** - * @name GNT Preferences API - **********************************************************************/ -/*@{*/ - -/** - * Perform necessary initializations. - */ -void gg_prefs_init(void); - -/** - * Show the preferences dialog. - */ -void gg_prefs_show_all(void); - -/*@}*/ - -#endif diff -r 317e7613e581 -r 0e3a8505ebbe console/gntrequest.c --- a/console/gntrequest.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,619 +0,0 @@ -/** - * @file gntrequest.c GNT Request API - * @ingroup gntui - * - * gaim - * - * Gaim is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "gntgaim.h" -#include "gntrequest.h" -#include "util.c" - -typedef struct -{ - void *user_data; - GntWidget *entry, *dialog; - GCallback *cbs; -} GaimGntFileRequest; - -static GntWidget * -setup_request_window(const char *title, const char *primary, - const char *secondary, GaimRequestType type) -{ - GntWidget *window; - - window = gnt_vbox_new(FALSE); - gnt_box_set_toplevel(GNT_BOX(window), TRUE); - gnt_box_set_title(GNT_BOX(window), title); - gnt_box_set_alignment(GNT_BOX(window), GNT_ALIGN_MID); - - if (primary) - gnt_box_add_widget(GNT_BOX(window), - gnt_label_new_with_format(primary, GNT_TEXT_FLAG_BOLD)); - if (secondary) - gnt_box_add_widget(GNT_BOX(window), gnt_label_new(secondary)); - - g_signal_connect_swapped(G_OBJECT(window), "destroy", G_CALLBACK(gaim_request_close), - GINT_TO_POINTER(type)); - - return window; -} - -static GntWidget * -setup_button_box(gpointer userdata, gpointer cb, gpointer data, ...) -{ - GntWidget *box, *button; - va_list list; - const char *text; - gpointer callback; - - box = gnt_hbox_new(FALSE); - - va_start(list, data); - - while ((text = va_arg(list, const char *))) - { - callback = va_arg(list, gpointer); - button = gnt_button_new(text); - gnt_box_add_widget(GNT_BOX(box), button); - g_object_set_data(G_OBJECT(button), "activate-callback", callback); - g_object_set_data(G_OBJECT(button), "activate-userdata", userdata); - g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(cb), data); - } - - va_end(list); - return box; -} - -static void -notify_input_cb(GntWidget *button, GntWidget *entry) -{ - GaimRequestInputCb callback = g_object_get_data(G_OBJECT(button), "activate-callback"); - gpointer data = g_object_get_data(G_OBJECT(button), "activate-userdata"); - const char *text = gnt_entry_get_text(GNT_ENTRY(entry)); - - if (callback) - callback(data, text); - - while (button->parent) - button = button->parent; - - gaim_request_close(GAIM_REQUEST_INPUT, button); -} - -static void * -gg_request_input(const char *title, const char *primary, - const char *secondary, const char *default_value, - gboolean multiline, gboolean masked, gchar *hint, - const char *ok_text, GCallback ok_cb, - const char *cancel_text, GCallback cancel_cb, - void *user_data) -{ - GntWidget *window, *box, *entry; - - window = setup_request_window(title, primary, secondary, GAIM_REQUEST_INPUT); - - entry = gnt_entry_new(default_value); - if (masked) - gnt_entry_set_masked(GNT_ENTRY(entry), TRUE); - gnt_box_add_widget(GNT_BOX(window), entry); - - box = setup_button_box(user_data, notify_input_cb, entry, - ok_text, ok_cb, cancel_text, cancel_cb, NULL); - gnt_box_add_widget(GNT_BOX(window), box); - - gnt_widget_show(window); - - return window; -} - -static void -gg_close_request(GaimRequestType type, gpointer ui_handle) -{ - GntWidget *widget = GNT_WIDGET(ui_handle); - while (widget->parent) - widget = widget->parent; - gnt_widget_destroy(widget); -} - -static void -request_choice_cb(GntWidget *button, GntComboBox *combo) -{ - GaimRequestChoiceCb callback = g_object_get_data(G_OBJECT(button), "activate-callback"); - gpointer data = g_object_get_data(G_OBJECT(button), "activate-userdata"); - int choice = GPOINTER_TO_INT(gnt_combo_box_get_selected_data(GNT_COMBO_BOX(combo))) - 1; - - if (callback) - callback(data, choice); - - while (button->parent) - button = button->parent; - - gaim_request_close(GAIM_REQUEST_INPUT, button); -} - -static void * -gg_request_choice(const char *title, const char *primary, - const char *secondary, unsigned int default_value, - const char *ok_text, GCallback ok_cb, - const char *cancel_text, GCallback cancel_cb, - void *user_data, va_list choices) -{ - GntWidget *window, *combo, *box; - const char *text; - int val; - - window = setup_request_window(title, primary, secondary, GAIM_REQUEST_CHOICE); - - combo = gnt_combo_box_new(); - gnt_box_add_widget(GNT_BOX(window), combo); - while ((text = va_arg(choices, const char *))) - { - val = va_arg(choices, int); - gnt_combo_box_add_data(GNT_COMBO_BOX(combo), GINT_TO_POINTER(val + 1), text); - } - gnt_combo_box_set_selected(GNT_COMBO_BOX(combo), GINT_TO_POINTER(default_value + 1)); - - box = setup_button_box(user_data, request_choice_cb, combo, - ok_text, ok_cb, cancel_text, cancel_cb, NULL); - gnt_box_add_widget(GNT_BOX(window), box); - - gnt_widget_show(window); - - return window; -} - -static void -request_action_cb(GntWidget *button, GntWidget *window) -{ - GaimRequestActionCb callback = g_object_get_data(G_OBJECT(button), "activate-callback"); - gpointer data = g_object_get_data(G_OBJECT(button), "activate-userdata"); - int id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(button), "activate-id")); - - if (callback) - callback(data, id); - - gaim_request_close(GAIM_REQUEST_ACTION, window); -} - -static void* -gg_request_action(const char *title, const char *primary, - const char *secondary, unsigned int default_value, - void *user_data, size_t actioncount, - va_list actions) -{ - GntWidget *window, *box, *button; - int i; - - window = setup_request_window(title, primary, secondary, GAIM_REQUEST_ACTION); - - box = gnt_hbox_new(FALSE); - gnt_box_add_widget(GNT_BOX(window), box); - for (i = 0; i < actioncount; i++) - { - const char *text = va_arg(actions, const char *); - GaimRequestActionCb callback = va_arg(actions, GaimRequestActionCb); - - button = gnt_button_new(text); - gnt_box_add_widget(GNT_BOX(box), button); - - g_object_set_data(G_OBJECT(button), "activate-callback", callback); - g_object_set_data(G_OBJECT(button), "activate-userdata", user_data); - g_object_set_data(G_OBJECT(button), "activate-id", GINT_TO_POINTER(i)); - g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(request_action_cb), window); - } - - gnt_widget_show(window); - - return window; -} - -static void -request_fields_cb(GntWidget *button, GaimRequestFields *fields) -{ - GaimRequestFieldsCb callback = g_object_get_data(G_OBJECT(button), "activate-callback"); - gpointer data = g_object_get_data(G_OBJECT(button), "activate-userdata"); - GList *list; - - /* Update the data of the fields. GtkGaim does this differently. Instead of - * updating the fields at the end like here, it updates the appropriate field - * instantly whenever a change is made. That allows it to make sure the - * 'required' fields are entered before the user can hit OK. It's not the case - * here, althought it can be done. I am not honouring the 'required' fields - * for the moment. */ - for (list = gaim_request_fields_get_groups(fields); list; list = list->next) - { - GaimRequestFieldGroup *group = list->data; - GList *fields = gaim_request_field_group_get_fields(group); - - for (; fields ; fields = fields->next) - { - GaimRequestField *field = fields->data; - GaimRequestFieldType type = gaim_request_field_get_type(field); - if (type == GAIM_REQUEST_FIELD_BOOLEAN) - { - GntWidget *check = field->ui_data; - gboolean value = gnt_check_box_get_checked(GNT_CHECK_BOX(check)); - gaim_request_field_bool_set_value(field, value); - } - else if (type == GAIM_REQUEST_FIELD_STRING) - { - GntWidget *entry = field->ui_data; - const char *text = gnt_entry_get_text(GNT_ENTRY(entry)); - gaim_request_field_string_set_value(field, (text && *text) ? text : NULL); - } - else if (type == GAIM_REQUEST_FIELD_INTEGER) - { - GntWidget *entry = field->ui_data; - const char *text = gnt_entry_get_text(GNT_ENTRY(entry)); - int value = (text && *text) ? atoi(text) : 0; - gaim_request_field_int_set_value(field, value); - } - else if (type == GAIM_REQUEST_FIELD_CHOICE) - { - GntWidget *combo = field->ui_data; - int id; - id = GPOINTER_TO_INT(gnt_combo_box_get_selected_data(GNT_COMBO_BOX(combo))); - gaim_request_field_choice_set_value(field, id); - } - else if (type == GAIM_REQUEST_FIELD_LIST) - { - GList *list = NULL; - if (gaim_request_field_list_get_multi_select(field)) - { - const GList *iter; - GntWidget *tree = field->ui_data; - - iter = gaim_request_field_list_get_items(field); - for (; iter; iter = iter->next) - { - const char *text = iter->data; - gpointer key = gaim_request_field_list_get_data(field, text); - if (gnt_tree_get_choice(GNT_TREE(tree), key)) - list = g_list_prepend(list, key); - } - } - else - { - GntWidget *combo = field->ui_data; - gpointer data = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(combo)); - list = g_list_append(list, data); - } - - gaim_request_field_list_set_selected(field, list); - g_list_free(list); - } - else if (type == GAIM_REQUEST_FIELD_ACCOUNT) - { - GntWidget *combo = field->ui_data; - GaimAccount *acc = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(combo)); - gaim_request_field_account_set_value(field, acc); - } - } - } - - if (callback) - callback(data, fields); - - while (button->parent) - button = button->parent; - - gaim_request_close(GAIM_REQUEST_FIELDS, button); -} - -static void * -gg_request_fields(const char *title, const char *primary, - const char *secondary, GaimRequestFields *allfields, - const char *ok, GCallback ok_cb, - const char *cancel, GCallback cancel_cb, - void *userdata) -{ - GntWidget *window, *box; - GList *grlist; - - window = setup_request_window(title, primary, secondary, GAIM_REQUEST_FIELDS); - - /* This is how it's going to work: the request-groups are going to be - * stacked vertically one after the other. A GntLine will be separating - * the groups. */ - box = gnt_vbox_new(FALSE); - gnt_box_set_pad(GNT_BOX(box), 0); - gnt_box_set_fill(GNT_BOX(box), TRUE); - for (grlist = gaim_request_fields_get_groups(allfields); grlist; grlist = grlist->next) - { - GaimRequestFieldGroup *group = grlist->data; - GList *fields = gaim_request_field_group_get_fields(group); - GntWidget *hbox; - const char *title = gaim_request_field_group_get_title(group); - - if (title) - gnt_box_add_widget(GNT_BOX(box), - gnt_label_new_with_format(title, GNT_TEXT_FLAG_BOLD)); - - for (; fields ; fields = fields->next) - { - /* XXX: Break each of the fields into a separate function? */ - GaimRequestField *field = fields->data; - GaimRequestFieldType type = gaim_request_field_get_type(field); - const char *label = gaim_request_field_get_label(field); - - hbox = gnt_hbox_new(TRUE); /* hrm */ - gnt_box_add_widget(GNT_BOX(box), hbox); - - if (type != GAIM_REQUEST_FIELD_BOOLEAN && label) - { - GntWidget *l = gnt_label_new(label); - gnt_widget_set_size(l, 0, 1); - gnt_box_add_widget(GNT_BOX(hbox), l); - } - - if (type == GAIM_REQUEST_FIELD_BOOLEAN) - { - GntWidget *check = gnt_check_box_new(label); - gnt_check_box_set_checked(GNT_CHECK_BOX(check), - gaim_request_field_bool_get_default_value(field)); - gnt_box_add_widget(GNT_BOX(hbox), check); - field->ui_data = check; - } - else if (type == GAIM_REQUEST_FIELD_STRING) - { - GntWidget *entry = gnt_entry_new( - gaim_request_field_string_get_default_value(field)); - gnt_entry_set_masked(GNT_ENTRY(entry), - gaim_request_field_string_is_masked(field)); - gnt_box_add_widget(GNT_BOX(hbox), entry); - field->ui_data = entry; - } - else if (type == GAIM_REQUEST_FIELD_INTEGER) - { - char str[256]; - int val = gaim_request_field_int_get_default_value(field); - GntWidget *entry; - - snprintf(str, sizeof(str), "%d", val); - entry = gnt_entry_new(str); - gnt_entry_set_flag(GNT_ENTRY(entry), GNT_ENTRY_FLAG_INT); - gnt_box_add_widget(GNT_BOX(hbox), entry); - field->ui_data = entry; - } - else if (type == GAIM_REQUEST_FIELD_CHOICE) - { - int id; - const GList *list; - GntWidget *combo = gnt_combo_box_new(); - gnt_box_add_widget(GNT_BOX(hbox), combo); - field->ui_data = combo; - - list = gaim_request_field_choice_get_labels(field); - for (id = 1; list; list = list->next, id++) - { - gnt_combo_box_add_data(GNT_COMBO_BOX(combo), - GINT_TO_POINTER(id), list->data); - } - gnt_combo_box_set_selected(GNT_COMBO_BOX(combo), - GINT_TO_POINTER(gaim_request_field_choice_get_default_value(field))); - } - else if (type == GAIM_REQUEST_FIELD_LIST) - { - const GList *list; - gboolean multi = gaim_request_field_list_get_multi_select(field); - if (multi) - { - GntWidget *tree = gnt_tree_new(); - gnt_box_add_widget(GNT_BOX(hbox), tree); - field->ui_data = tree; - - list = gaim_request_field_list_get_items(field); - for (; list; list = list->next) - { - const char *text = list->data; - gpointer key = gaim_request_field_list_get_data(field, text); - gnt_tree_add_choice(GNT_TREE(tree), key, - gnt_tree_create_row(GNT_TREE(tree), text), NULL, NULL); - if (gaim_request_field_list_is_selected(field, text)) - gnt_tree_set_choice(GNT_TREE(tree), key, TRUE); - } - } - else - { - GntWidget *combo = gnt_combo_box_new(); - gnt_box_set_alignment(GNT_BOX(hbox), GNT_ALIGN_MID); - gnt_box_add_widget(GNT_BOX(hbox), combo); - field->ui_data = combo; - - list = gaim_request_field_list_get_items(field); - for (; list; list = list->next) - { - const char *text = list->data; - gpointer key = gaim_request_field_list_get_data(field, text); - gnt_combo_box_add_data(GNT_COMBO_BOX(combo), key, text); - if (gaim_request_field_list_is_selected(field, text)) - gnt_combo_box_set_selected(GNT_COMBO_BOX(combo), key); - } - } - } - else if (type == GAIM_REQUEST_FIELD_ACCOUNT) - { - gboolean all; - GaimAccount *def; - GList *list; - GntWidget *combo = gnt_combo_box_new(); - gnt_box_set_alignment(GNT_BOX(hbox), GNT_ALIGN_MID); - gnt_box_add_widget(GNT_BOX(hbox), combo); - field->ui_data = combo; - - all = gaim_request_field_account_get_show_all(field); - def = gaim_request_field_account_get_default_value(field); - - if (all) - list = gaim_accounts_get_all(); - else - list = gaim_connections_get_all(); - - for (; list; list = list->next) - { - GaimAccount *account; - char *text; - - if (all) - account = list->data; - else - account = gaim_connection_get_account(list->data); - - text = g_strdup_printf("%s (%s)", - gaim_account_get_username(account), - gaim_account_get_protocol_name(account)); - gnt_combo_box_add_data(GNT_COMBO_BOX(combo), account, text); - g_free(text); - if (account == def) - gnt_combo_box_set_selected(GNT_COMBO_BOX(combo), account); - } - gnt_widget_set_size(combo, 20, 3); /* ew */ - } - else - { - gnt_box_add_widget(GNT_BOX(hbox), - gnt_label_new_with_format(_("Not implemented yet."), - GNT_TEXT_FLAG_BOLD)); - } - } - if (grlist->next) - gnt_box_add_widget(GNT_BOX(box), gnt_hline_new()); - } - gnt_box_add_widget(GNT_BOX(window), box); - - box = setup_button_box(userdata, request_fields_cb, allfields, - ok, ok_cb, cancel, cancel_cb, NULL); - gnt_box_add_widget(GNT_BOX(window), box); - - gnt_widget_show(window); - - return window; -} - -static void -file_cancel_cb(GntWidget *wid, gpointer fq) -{ - GaimGntFileRequest *data = fq; - if (data->cbs[1] != NULL) - ((GaimRequestFileCb)data->cbs[1])(data->user_data, NULL); - - gaim_request_close(GAIM_REQUEST_FILE, data->dialog); -} - -static void -file_ok_cb(GntWidget *wid, gpointer fq) -{ - GaimGntFileRequest *data = fq; - if (data->cbs[0] != NULL) - ((GaimRequestFileCb)data->cbs[0])(data->user_data, gnt_entry_get_text(GNT_ENTRY(data->entry))); - - gaim_request_close(GAIM_REQUEST_FILE, data->dialog); -} - -static void -file_request_destroy(GaimGntFileRequest *data) -{ - g_free(data->cbs); - g_free(data); -} - -static void * -gg_request_file(const char *title, const char *filename, - gboolean savedialog, - GCallback ok_cb, GCallback cancel_cb, - void *user_data) -{ - GntWidget *window = gnt_vbox_new(FALSE); - GntWidget *entry, *hbox, *button; - GaimGntFileRequest *data = g_new0(GaimGntFileRequest, 1); - - data->user_data = user_data; - data->cbs = g_new0(GCallback, 2); - data->cbs[0] = ok_cb; - data->cbs[1] = cancel_cb; - data->dialog = window; - data->entry = entry = gnt_entry_new(g_strconcat(gaim_home_dir(), G_DIR_SEPARATOR_S, filename, NULL)); - gnt_widget_set_size(entry, 30, 1); - gnt_box_set_toplevel(GNT_BOX(window), TRUE); - gnt_box_set_title(GNT_BOX(window), title ? title : (savedialog ? _("Save File...") : _("Open File..."))); -#if 0 - /* After the string freeze */ - gnt_box_add_widget(GNT_BOX(window), gnt_label_new(_("Please enter a full path for a file"))); -#endif - gnt_box_add_widget(GNT_BOX(window), entry); - - hbox = gnt_hbox_new(TRUE); - gnt_box_set_alignment(GNT_BOX(hbox), GNT_ALIGN_MID); - - button = gnt_button_new(_("Cancel")); - g_signal_connect(G_OBJECT(button), "activate", - G_CALLBACK(file_cancel_cb), data); - gnt_box_add_widget(GNT_BOX(hbox), button); - - button = gnt_button_new(_("OK")); - g_signal_connect(G_OBJECT(button), "activate", - G_CALLBACK(file_ok_cb), data); - gnt_box_add_widget(GNT_BOX(hbox), button); - - gnt_box_add_widget(GNT_BOX(window), hbox); - - g_signal_connect_swapped(G_OBJECT(window), "destroy", - G_CALLBACK(file_request_destroy), data); - - gnt_widget_show(window); - - return window; -} - -static GaimRequestUiOps uiops = -{ - .request_input = gg_request_input, - .close_request = gg_close_request, - .request_choice = gg_request_choice, - .request_action = gg_request_action, - .request_fields = gg_request_fields, - .request_file = gg_request_file, - .request_folder = NULL /* No plans for this */ -}; - -GaimRequestUiOps *gg_request_get_ui_ops() -{ - return &uiops; -} - -void gg_request_init() -{ -} - -void gg_request_uninit() -{ -} - diff -r 317e7613e581 -r 0e3a8505ebbe console/gntrequest.h --- a/console/gntrequest.h Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -/** - * @file gntrequest.h GNT Request API - * @ingroup gntui - * - * gaim - * - * Gaim is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef _GNT_REQUEST_H -#define _GNT_REQUEST_H - -#include "request.h" - -/********************************************************************** - * @name GNT Request API - **********************************************************************/ -/*@{*/ - -/** - * Get the ui-functions. - * - * @return The GaimRequestUiOps structure populated with the appropriate functions. - */ -GaimRequestUiOps *gg_request_get_ui_ops(void); - -/** - * Perform necessary initializations. - */ -void gg_request_init(void); - -/** - * Perform necessary uninitializations. - */ -void gg_request_uninit(void); - -/*@}*/ - -#endif diff -r 317e7613e581 -r 0e3a8505ebbe console/gntstatus.c --- a/console/gntstatus.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,606 +0,0 @@ -/** - * @file gntstatus.c GNT Status API - * @ingroup gntui - * - * gaim - * - * Gaim is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "gntgaim.h" -#include "gntstatus.h" - -static struct -{ - GntWidget *window; - GntWidget *tree; -} statuses; - -typedef struct -{ - GaimSavedStatus *saved; - GntWidget *window; - GntWidget *title; - GntWidget *type; - GntWidget *message; - GntWidget *tree; - GHashTable *hash; /* list of windows for substatuses */ -} EditStatus; - -typedef struct -{ - GaimAccount *account; - const GaimStatusType *type; - char *message; -} RowInfo; - -typedef struct -{ - GntWidget *window; - GntWidget *type; - GntWidget *message; - - EditStatus *parent; - RowInfo *key; -} EditSubStatus; - -static GList *edits; /* List of opened edit-status dialogs */ - -static void -reset_status_window(GntWidget *widget, gpointer null) -{ - statuses.window = NULL; - statuses.tree = NULL; -} - -static void -populate_statuses(GntTree *tree) -{ - const GList *list; - - for (list = gaim_savedstatuses_get_all(); list; list = list->next) - { - GaimSavedStatus *saved = list->data; - const char *title, *type, *message; - - if (gaim_savedstatus_is_transient(saved)) - continue; - - title = gaim_savedstatus_get_title(saved); - type = gaim_primitive_get_name_from_type(gaim_savedstatus_get_type(saved)); - message = gaim_savedstatus_get_message(saved); /* XXX: Strip possible markups */ - - gnt_tree_add_row_last(tree, saved, - gnt_tree_create_row(tree, title, type, message), NULL); - } -} - -static void -really_delete_status(GaimSavedStatus *saved) -{ - GList *iter; - - for (iter = edits; iter; iter = iter->next) - { - EditStatus *edit = iter->data; - if (edit->saved == saved) - { - gnt_widget_destroy(edit->window); - break; - } - } - - if (statuses.tree) - gnt_tree_remove(GNT_TREE(statuses.tree), saved); - - gaim_savedstatus_delete(gaim_savedstatus_get_title(saved)); -} - -static void -ask_before_delete(GntWidget *button, gpointer null) -{ - char *ask; - GaimSavedStatus *saved; - - g_return_if_fail(statuses.tree != NULL); - - saved = gnt_tree_get_selection_data(GNT_TREE(statuses.tree)); - ask = g_strdup_printf(_("Are you sure you want to delete \"%s\""), - gaim_savedstatus_get_title(saved)); - - gaim_request_action(saved, _("Delete Status"), ask, NULL, 0, saved, 2, - _("Delete"), really_delete_status, _("Cancel"), NULL); - g_free(ask); -} - -static void -use_savedstatus_cb(GntWidget *widget, gpointer null) -{ - g_return_if_fail(statuses.tree != NULL); - - gaim_savedstatus_activate(gnt_tree_get_selection_data(GNT_TREE(statuses.tree))); -} - -static void -edit_savedstatus_cb(GntWidget *widget, gpointer null) -{ - g_return_if_fail(statuses.tree != NULL); - - gg_savedstatus_edit(gnt_tree_get_selection_data(GNT_TREE(statuses.tree))); -} - -void gg_savedstatus_show_all() -{ - GntWidget *window, *tree, *box, *button; - if (statuses.window) - return; - - statuses.window = window = gnt_vbox_new(FALSE); - gnt_box_set_toplevel(GNT_BOX(window), TRUE); - gnt_box_set_title(GNT_BOX(window), _("Saved Statuses")); - gnt_box_set_fill(GNT_BOX(window), FALSE); - gnt_box_set_alignment(GNT_BOX(window), GNT_ALIGN_MID); - gnt_box_set_pad(GNT_BOX(window), 0); - - /* XXX: Add some sorting function to sort alphabetically, perhaps */ - statuses.tree = tree = gnt_tree_new_with_columns(3); - gnt_tree_set_column_titles(GNT_TREE(tree), _("Title"), _("Type"), _("Message")); - gnt_tree_set_show_title(GNT_TREE(tree), TRUE); - gnt_tree_set_col_width(GNT_TREE(tree), 0, 25); - gnt_tree_set_col_width(GNT_TREE(tree), 1, 12); - gnt_tree_set_col_width(GNT_TREE(tree), 2, 35); - gnt_box_add_widget(GNT_BOX(window), tree); - - populate_statuses(GNT_TREE(tree)); - - box = gnt_hbox_new(FALSE); - gnt_box_add_widget(GNT_BOX(window), box); - - button = gnt_button_new(_("Use")); - gnt_box_add_widget(GNT_BOX(box), button); - g_signal_connect(G_OBJECT(button), "activate", - G_CALLBACK(use_savedstatus_cb), NULL); - - button = gnt_button_new(_("Add")); - gnt_box_add_widget(GNT_BOX(box), button); - g_signal_connect_swapped(G_OBJECT(button), "activate", - G_CALLBACK(gg_savedstatus_edit), NULL); - - button = gnt_button_new(_("Edit")); - gnt_box_add_widget(GNT_BOX(box), button); - g_signal_connect(G_OBJECT(button), "activate", - G_CALLBACK(edit_savedstatus_cb), NULL); - - button = gnt_button_new(_("Delete")); - gnt_box_add_widget(GNT_BOX(box), button); - g_signal_connect(G_OBJECT(button), "activate", - G_CALLBACK(ask_before_delete), NULL); - - button = gnt_button_new(_("Close")); - gnt_box_add_widget(GNT_BOX(box), button); - g_signal_connect_swapped(G_OBJECT(button), "activate", - G_CALLBACK(gnt_widget_destroy), window); - - g_signal_connect(G_OBJECT(window), "destroy", - G_CALLBACK(reset_status_window), NULL); - gnt_widget_show(window); -} - -static void -destroy_substatus_win(GaimAccount *account, EditSubStatus *sub, gpointer null) -{ - gnt_widget_destroy(sub->window); /* the "destroy" callback will remove entry from the hashtable */ -} - -static void -free_key(gpointer key, gpointer n) -{ - RowInfo *row = key; - g_free(row->message); - g_free(key); -} - - -static void -update_edit_list(GntWidget *widget, EditStatus *edit) -{ - edits = g_list_remove(edits, edit); - gaim_notify_close_with_handle(edit); - g_hash_table_foreach(edit->hash, (GHFunc)destroy_substatus_win, NULL); - g_list_foreach((GList*)gnt_tree_get_rows(GNT_TREE(edit->tree)), free_key, NULL); - g_free(edit); -} - -static void -set_substatuses(EditStatus *edit) -{ - const GList *iter; - for (iter = gnt_tree_get_rows(GNT_TREE(edit->tree)); iter; iter = iter->next) { - RowInfo *key = iter->data; - if (gnt_tree_get_choice(GNT_TREE(edit->tree), key)) { - gaim_savedstatus_set_substatus(edit->saved, key->account, key->type, key->message); - } - } -} - - -static void -use_trans_status_cb(GntWidget *button, EditStatus *edit) -{ - const char *message; - GaimStatusPrimitive prim; - GaimSavedStatus *saved; - - message = gnt_entry_get_text(GNT_ENTRY(edit->message)); - prim = GPOINTER_TO_INT(gnt_combo_box_get_selected_data(GNT_COMBO_BOX(edit->type))); - - saved = gaim_savedstatus_find_transient_by_type_and_message(prim, message); - if (saved == NULL) { - saved = gaim_savedstatus_new(NULL, prim); - edit->saved = saved; - set_substatuses(edit); - } - gaim_savedstatus_set_message(saved, message); - gaim_savedstatus_activate(saved); - gnt_widget_destroy(edit->window); -} - -static void -save_savedstatus_cb(GntWidget *button, EditStatus *edit) -{ - const char *title, *message; - GaimStatusPrimitive prim; - GaimSavedStatus *find; - - title = gnt_entry_get_text(GNT_ENTRY(edit->title)); - message = gnt_entry_get_text(GNT_ENTRY(edit->message)); - if (!message || !*message) - message = NULL; - - prim = GPOINTER_TO_INT(gnt_combo_box_get_selected_data(GNT_COMBO_BOX(edit->type))); - - if (!title || !*title) - { - gaim_notify_error(edit, _("Error"), _("Invalid title"), - _("Please enter a non-empty title for the status.")); - return; - } - - find = gaim_savedstatus_find(title); - if (find && find != edit->saved) - { - gaim_notify_error(edit, _("Error"), _("Duplicate title"), - _("Please enter a different title for the status.")); - return; - } - - if (edit->saved == NULL) - { - edit->saved = gaim_savedstatus_new(title, prim); - gaim_savedstatus_set_message(edit->saved, message); - set_substatuses(edit); - if (statuses.tree) - gnt_tree_add_row_last(GNT_TREE(statuses.tree), edit->saved, - gnt_tree_create_row(GNT_TREE(statuses.tree), title, - gaim_primitive_get_name_from_type(prim), message), NULL); - } - else - { - gaim_savedstatus_set_title(edit->saved, title); - gaim_savedstatus_set_type(edit->saved, prim); - gaim_savedstatus_set_message(edit->saved, message); - if (statuses.tree) - { - gnt_tree_change_text(GNT_TREE(statuses.tree), edit->saved, 0, title); - gnt_tree_change_text(GNT_TREE(statuses.tree), edit->saved, 1, - gaim_primitive_get_name_from_type(prim)); - gnt_tree_change_text(GNT_TREE(statuses.tree), edit->saved, 2, message); - } - } - - if (g_object_get_data(G_OBJECT(button), "use")) - gaim_savedstatus_activate(edit->saved); - - gnt_widget_destroy(edit->window); -} - -static void -add_substatus(EditStatus *edit, GaimAccount *account) -{ - char *name; - const char *type = NULL, *message = NULL; - GaimSavedStatusSub *sub = NULL; - RowInfo *key; - - if (!edit || !edit->tree) - return; - - if (edit->saved) - sub = gaim_savedstatus_get_substatus(edit->saved, account); - - key = g_new0(RowInfo, 1); - key->account = account; - - if (sub) - { - key->type = gaim_savedstatus_substatus_get_type(sub); - type = gaim_status_type_get_name(key->type); - message = gaim_savedstatus_substatus_get_message(sub); - key->message = g_strdup(message); - } - - name = g_strdup_printf("%s (%s)", gaim_account_get_username(account), - gaim_account_get_protocol_name(account)); - gnt_tree_add_choice(GNT_TREE(edit->tree), key, - gnt_tree_create_row(GNT_TREE(edit->tree), - name, type ? type : "", message ? message : ""), NULL, NULL); - - if (sub) - gnt_tree_set_choice(GNT_TREE(edit->tree), key, TRUE); - g_free(name); -} - -static void -substatus_window_destroy_cb(GntWidget *window, EditSubStatus *sub) -{ - g_hash_table_remove(sub->parent->hash, sub->key->account); - g_free(sub); -} - -static void -save_substatus_cb(GntWidget *widget, EditSubStatus *sub) -{ - GaimSavedStatus *saved = sub->parent->saved; - RowInfo *row = sub->key; - const char *message; - GaimStatusType *type; - - type = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(sub->type)); - message = gnt_entry_get_text(GNT_ENTRY(sub->message)); - - row->type = type; - row->message = g_strdup(message); - - if (saved) /* Save the substatus if the savedstatus actually exists. */ - gaim_savedstatus_set_substatus(saved, row->account, type, message); - - gnt_tree_set_choice(GNT_TREE(sub->parent->tree), row, TRUE); - gnt_tree_change_text(GNT_TREE(sub->parent->tree), row, 1, - gaim_status_type_get_name(type)); - gnt_tree_change_text(GNT_TREE(sub->parent->tree), row, 2, message); - - gnt_widget_destroy(sub->window); -} - -static gboolean -popup_substatus(GntTree *tree, const char *key, EditStatus *edit) -{ - if (key[0] == ' ' && key[1] == 0) - { - EditSubStatus *sub; - GntWidget *window, *combo, *entry, *box, *button, *l; - GaimSavedStatusSub *substatus = NULL; - const GList *iter; - char *name; - RowInfo *selected = gnt_tree_get_selection_data(tree); - GaimAccount *account = selected->account; - - if (gnt_tree_get_choice(tree, selected)) - { - /* There was a savedstatus for this account. Now remove it. */ - g_free(selected->message); - selected->type = NULL; - selected->message = NULL; - /* XXX: should we really be saving it right now? */ - gaim_savedstatus_unset_substatus(edit->saved, account); - gnt_tree_change_text(tree, account, 1, NULL); - gnt_tree_change_text(tree, account, 2, NULL); - return FALSE; - } - - if (g_hash_table_lookup(edit->hash, account)) - return TRUE; - - if (edit->saved) - substatus = gaim_savedstatus_get_substatus(edit->saved, account); - - sub = g_new0(EditSubStatus, 1); - sub->parent = edit; - sub->key = selected; - - sub->window = window = gnt_vbox_new(FALSE); - gnt_box_set_toplevel(GNT_BOX(window), TRUE); - gnt_box_set_title(GNT_BOX(window), _("Substatus")); /* XXX: a better title */ - - box = gnt_hbox_new(FALSE); - gnt_box_add_widget(GNT_BOX(box), gnt_label_new(_("Account:"))); - name = g_strdup_printf("%s (%s)", gaim_account_get_username(account), - gaim_account_get_protocol_name(account)); - gnt_box_add_widget(GNT_BOX(box), gnt_label_new(name)); - g_free(name); - gnt_box_add_widget(GNT_BOX(window), box); - - box = gnt_hbox_new(FALSE); - gnt_box_add_widget(GNT_BOX(box), (l = gnt_label_new(_("Status:")))); - gnt_widget_set_size(l, 0, 1); /* I don't like having to do this */ - sub->type = combo = gnt_combo_box_new(); - gnt_box_add_widget(GNT_BOX(box), combo); - gnt_box_add_widget(GNT_BOX(window), box); - - for (iter = gaim_account_get_status_types(account); iter; iter = iter->next) - { - GaimStatusType *type = iter->data; - if (!gaim_status_type_is_user_settable(type)) - continue; - gnt_combo_box_add_data(GNT_COMBO_BOX(combo), type, gaim_status_type_get_name(type)); - } - - box = gnt_hbox_new(FALSE); - gnt_box_add_widget(GNT_BOX(box), gnt_label_new(_("Message:"))); - sub->message = entry = gnt_entry_new(substatus ? gaim_savedstatus_substatus_get_message(substatus) : NULL); - gnt_box_add_widget(GNT_BOX(box), entry); - gnt_box_add_widget(GNT_BOX(window), box); - - box = gnt_hbox_new(FALSE); - button = gnt_button_new(_("Cancel")); - g_signal_connect_swapped(G_OBJECT(button), "activate", G_CALLBACK(gnt_widget_destroy), window); - gnt_box_add_widget(GNT_BOX(box), button); - button = gnt_button_new(_("Save")); - g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(save_substatus_cb), sub); - gnt_box_add_widget(GNT_BOX(box), button); - gnt_box_add_widget(GNT_BOX(window), box); - - gnt_widget_show(window); - - g_hash_table_insert(edit->hash, account, sub); - - g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(substatus_window_destroy_cb), sub); - - return TRUE; - } - return FALSE; -} - -void gg_savedstatus_edit(GaimSavedStatus *saved) -{ - EditStatus *edit; - GntWidget *window, *box, *button, *entry, *combo, *label, *tree; - GaimStatusPrimitive prims[] = {GAIM_STATUS_AVAILABLE, GAIM_STATUS_AWAY, - GAIM_STATUS_INVISIBLE, GAIM_STATUS_OFFLINE, GAIM_STATUS_UNSET}, current; - GList *iter; - int i; - - if (saved) - { - GList *iter; - for (iter = edits; iter; iter = iter->next) - { - edit = iter->data; - if (edit->saved == saved) - return; - } - } - - edit = g_new0(EditStatus, 1); - edit->saved = saved; - edit->window = window = gnt_vbox_new(FALSE); - gnt_box_set_toplevel(GNT_BOX(window), TRUE); - gnt_box_set_title(GNT_BOX(window), _("Edit Status")); - gnt_box_set_fill(GNT_BOX(window), TRUE); - gnt_box_set_alignment(GNT_BOX(window), GNT_ALIGN_LEFT); - gnt_box_set_pad(GNT_BOX(window), 0); - - edits = g_list_append(edits, edit); - - /* Title */ - box = gnt_hbox_new(FALSE); - gnt_box_set_alignment(GNT_BOX(box), GNT_ALIGN_LEFT); - gnt_box_add_widget(GNT_BOX(window), box); - gnt_box_add_widget(GNT_BOX(box), gnt_label_new(_("Title"))); - - edit->title = entry = gnt_entry_new(saved ? gaim_savedstatus_get_title(saved) : NULL); - gnt_box_add_widget(GNT_BOX(box), entry); - - /* Type */ - box = gnt_hbox_new(FALSE); - gnt_box_add_widget(GNT_BOX(window), box); - gnt_box_add_widget(GNT_BOX(box), label = gnt_label_new(_("Status"))); - gnt_widget_set_size(label, 0, 1); - - edit->type = combo = gnt_combo_box_new(); - gnt_box_add_widget(GNT_BOX(box), combo); - current = saved ? gaim_savedstatus_get_type(saved) : GAIM_STATUS_UNSET; - for (i = 0; prims[i] != GAIM_STATUS_UNSET; i++) - { - gnt_combo_box_add_data(GNT_COMBO_BOX(combo), GINT_TO_POINTER(prims[i]), - gaim_primitive_get_name_from_type(prims[i])); - if (prims[i] == current) - gnt_combo_box_set_selected(GNT_COMBO_BOX(combo), GINT_TO_POINTER(current)); - } - - /* Message */ - box = gnt_hbox_new(FALSE); - gnt_box_add_widget(GNT_BOX(window), box); - gnt_box_add_widget(GNT_BOX(box), gnt_label_new(_("Message"))); - - edit->message = entry = gnt_entry_new(saved ? gaim_savedstatus_get_message(saved) : NULL); - gnt_box_add_widget(GNT_BOX(window), entry); - - gnt_box_add_widget(GNT_BOX(window), gnt_hline_new()); - gnt_box_add_widget(GNT_BOX(window), gnt_label_new(_("Use different status for following accounts"))); - - edit->hash = g_hash_table_new(g_direct_hash, g_direct_equal); - edit->tree = tree = gnt_tree_new_with_columns(3); - gnt_box_add_widget(GNT_BOX(window), tree); - gnt_tree_set_show_title(GNT_TREE(tree), TRUE); - gnt_tree_set_column_titles(GNT_TREE(tree), _("Account"), _("Status"), _("Message")); - gnt_tree_set_col_width(GNT_TREE(tree), 0, 30); - gnt_tree_set_col_width(GNT_TREE(tree), 1, 10); - gnt_tree_set_col_width(GNT_TREE(tree), 2, 30); - - for (iter = gaim_accounts_get_all(); iter; iter = iter->next) - { - add_substatus(edit, iter->data); - } - - g_signal_connect(G_OBJECT(tree), "key_pressed", G_CALLBACK(popup_substatus), edit); - - /* The buttons */ - box = gnt_hbox_new(FALSE); - gnt_box_add_widget(GNT_BOX(window), box); - - /* Use */ - button = gnt_button_new(_("Use")); - gnt_box_add_widget(GNT_BOX(box), button); - g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(use_trans_status_cb), edit); - - /* Save */ - button = gnt_button_new(_("Save")); - gnt_box_add_widget(GNT_BOX(box), button); - g_object_set_data(G_OBJECT(button), "use", NULL); - g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(save_savedstatus_cb), edit); - - /* Save & Use */ - button = gnt_button_new(_("Save & Use")); - gnt_box_add_widget(GNT_BOX(box), button); - g_object_set_data(G_OBJECT(button), "use", GINT_TO_POINTER(TRUE)); - g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(save_savedstatus_cb), edit); - - /* Cancel */ - button = gnt_button_new(_("Cancel")); - gnt_box_add_widget(GNT_BOX(box), button); - g_signal_connect_swapped(G_OBJECT(button), "activate", - G_CALLBACK(gnt_widget_destroy), window); - - g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(update_edit_list), edit); - - gnt_widget_show(window); -} - diff -r 317e7613e581 -r 0e3a8505ebbe console/gntstatus.h --- a/console/gntstatus.h Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -/** - * @file gntstatus.h GNT Status API - * @ingroup gntui - * - * gaim - * - * Gaim is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef _GNT_STATUS_H -#define _GNT_STATUS_H - -#include -#include - -/********************************************************************** - * @name GNT BuddyList API - **********************************************************************/ -/*@{*/ - -/** - * Show a dialog with all the saved statuses. - */ -void gg_savedstatus_show_all(void); - -/** - * Show a dialog to edit a status. - * - * @param saved The saved status to edit. Set it to @c NULL to create a new status. - */ -void gg_savedstatus_edit(GaimSavedStatus *saved); - -/*@}*/ - -#endif diff -r 317e7613e581 -r 0e3a8505ebbe console/gntui.c --- a/console/gntui.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,118 +0,0 @@ -/** - * gaim - * - * Gaim is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include "gntui.h" - -#include "gntaccount.h" -#include "gntblist.h" -#include "gntconn.h" -#include "gntconv.h" -#include "gntdebug.h" -#include "gntft.h" -#include "gntnotify.h" -#include "gntplugin.h" -#include "gntpounce.h" -#include "gntprefs.h" -#include "gntrequest.h" -#include "gntstatus.h" -#include "internal.h" - -#include - -void gnt_ui_init() -{ -#ifdef STANDALONE - gnt_init(); -#endif - - gaim_prefs_add_none("/gaim/gnt"); - - /* Accounts */ - gg_accounts_init(); - gaim_accounts_set_ui_ops(gg_accounts_get_ui_ops()); - - /* Connections */ - gg_connections_init(); - gaim_connections_set_ui_ops(gg_connections_get_ui_ops()); - - /* Initialize the buddy list */ - gg_blist_init(); - gaim_blist_set_ui_ops(gg_blist_get_ui_ops()); - - /* Now the conversations */ - gg_conversation_init(); - gaim_conversations_set_ui_ops(gg_conv_get_ui_ops()); - - /* Notify */ - gg_notify_init(); - gaim_notify_set_ui_ops(gg_notify_get_ui_ops()); - - gg_request_init(); - gaim_request_set_ui_ops(gg_request_get_ui_ops()); - - gg_pounces_init(); - - gg_xfers_init(); - gaim_xfers_set_ui_ops(gg_xfers_get_ui_ops()); - - gnt_register_action(_("Accounts"), gg_accounts_show_all); - gnt_register_action(_("Buddy List"), gg_blist_show); - gnt_register_action(_("Buddy Pounces"), gg_pounces_manager_show); - gnt_register_action(_("Debug Window"), gg_debug_window_show); - gnt_register_action(_("File Transfers"), gg_xfer_dialog_show); - gnt_register_action(_("Plugins"), gg_plugins_show_all); - gnt_register_action(_("Preferences"), gg_prefs_show_all); - gnt_register_action(_("Statuses"), gg_savedstatus_show_all); - -#ifdef STANDALONE - - gg_plugins_save_loaded(); -} - -void gnt_ui_uninit() -{ - gaim_accounts_set_ui_ops(NULL); - gg_accounts_uninit(); - - gaim_connections_set_ui_ops(NULL); - gg_connections_uninit(); - - gaim_blist_set_ui_ops(NULL); - gg_blist_uninit(); - - gaim_conversations_set_ui_ops(NULL); - gg_conversation_uninit(); - - gaim_notify_set_ui_ops(NULL); - gg_notify_uninit(); - - gaim_request_set_ui_ops(NULL); - gg_request_uninit(); - - gg_pounces_uninit(); - - gg_xfers_uninit(); - gaim_xfers_set_ui_ops(NULL); - - gnt_quit(); -#endif -} - diff -r 317e7613e581 -r 0e3a8505ebbe console/gntui.h --- a/console/gntui.h Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -/** - * gaim - * - * Gaim is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef _GNT_UI_H -#define _GNT_UI_H - -#include "gnt.h" - -void gnt_ui_init(void); -void gnt_ui_uninit(void); - -#endif diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/AUTHORS diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/COPYING --- a/console/libgnt/COPYING Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,340 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/ChangeLog diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/INSTALL --- a/console/libgnt/INSTALL Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,229 +0,0 @@ -Copyright 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software -Foundation, Inc. - - This file is free documentation; the Free Software Foundation gives -unlimited permission to copy, distribute and modify it. - -Basic Installation -================== - - These are generic installation instructions. - - The `configure' shell script attempts to guess correct values for -various system-dependent variables used during compilation. It uses -those values to create a `Makefile' in each directory of the package. -It may also create one or more `.h' files containing system-dependent -definitions. Finally, it creates a shell script `config.status' that -you can run in the future to recreate the current configuration, and a -file `config.log' containing compiler output (useful mainly for -debugging `configure'). - - It can also use an optional file (typically called `config.cache' -and enabled with `--cache-file=config.cache' or simply `-C') that saves -the results of its tests to speed up reconfiguring. (Caching is -disabled by default to prevent problems with accidental use of stale -cache files.) - - If you need to do unusual things to compile the package, please try -to figure out how `configure' could check whether to do them, and mail -diffs or instructions to the address given in the `README' so they can -be considered for the next release. If you are using the cache, and at -some point `config.cache' contains results you don't want to keep, you -may remove or edit it. - - The file `configure.ac' (or `configure.in') is used to create -`configure' by a program called `autoconf'. You only need -`configure.ac' if you want to change it or regenerate `configure' using -a newer version of `autoconf'. - -The simplest way to compile this package is: - - 1. `cd' to the directory containing the package's source code and type - `./configure' to configure the package for your system. If you're - using `csh' on an old version of System V, you might need to type - `sh ./configure' instead to prevent `csh' from trying to execute - `configure' itself. - - Running `configure' takes awhile. While running, it prints some - messages telling which features it is checking for. - - 2. Type `make' to compile the package. - - 3. Optionally, type `make check' to run any self-tests that come with - the package. - - 4. Type `make install' to install the programs and any data files and - documentation. - - 5. You can remove the program binaries and object files from the - source code directory by typing `make clean'. To also remove the - files that `configure' created (so you can compile the package for - a different kind of computer), type `make distclean'. There is - also a `make maintainer-clean' target, but that is intended mainly - for the package's developers. If you use it, you may have to get - all sorts of other programs in order to regenerate files that came - with the distribution. - -Compilers and Options -===================== - - Some systems require unusual options for compilation or linking that -the `configure' script does not know about. Run `./configure --help' -for details on some of the pertinent environment variables. - - You can give `configure' initial values for configuration parameters -by setting variables in the command line or in the environment. Here -is an example: - - ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix - - *Note Defining Variables::, for more details. - -Compiling For Multiple Architectures -==================================== - - You can compile the package for more than one kind of computer at the -same time, by placing the object files for each architecture in their -own directory. To do this, you must use a version of `make' that -supports the `VPATH' variable, such as GNU `make'. `cd' to the -directory where you want the object files and executables to go and run -the `configure' script. `configure' automatically checks for the -source code in the directory that `configure' is in and in `..'. - - If you have to use a `make' that does not support the `VPATH' -variable, you have to compile the package for one architecture at a -time in the source code directory. After you have installed the -package for one architecture, use `make distclean' before reconfiguring -for another architecture. - -Installation Names -================== - - By default, `make install' will install the package's files in -`/usr/local/bin', `/usr/local/man', etc. You can specify an -installation prefix other than `/usr/local' by giving `configure' the -option `--prefix=PATH'. - - You can specify separate installation prefixes for -architecture-specific files and architecture-independent files. If you -give `configure' the option `--exec-prefix=PATH', the package will use -PATH as the prefix for installing programs and libraries. -Documentation and other data files will still use the regular prefix. - - In addition, if you use an unusual directory layout you can give -options like `--bindir=PATH' to specify different values for particular -kinds of files. Run `configure --help' for a list of the directories -you can set and what kinds of files go in them. - - If the package supports it, you can cause programs to be installed -with an extra prefix or suffix on their names by giving `configure' the -option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. - -Optional Features -================= - - Some packages pay attention to `--enable-FEATURE' options to -`configure', where FEATURE indicates an optional part of the package. -They may also pay attention to `--with-PACKAGE' options, where PACKAGE -is something like `gnu-as' or `x' (for the X Window System). The -`README' should mention any `--enable-' and `--with-' options that the -package recognizes. - - For packages that use the X Window System, `configure' can usually -find the X include and library files automatically, but if it doesn't, -you can use the `configure' options `--x-includes=DIR' and -`--x-libraries=DIR' to specify their locations. - -Specifying the System Type -========================== - - There may be some features `configure' cannot figure out -automatically, but needs to determine by the type of machine the package -will run on. Usually, assuming the package is built to be run on the -_same_ architectures, `configure' can figure that out, but if it prints -a message saying it cannot guess the machine type, give it the -`--build=TYPE' option. TYPE can either be a short name for the system -type, such as `sun4', or a canonical name which has the form: - - CPU-COMPANY-SYSTEM - -where SYSTEM can have one of these forms: - - OS KERNEL-OS - - See the file `config.sub' for the possible values of each field. If -`config.sub' isn't included in this package, then this package doesn't -need to know the machine type. - - If you are _building_ compiler tools for cross-compiling, you should -use the `--target=TYPE' option to select the type of system they will -produce code for. - - If you want to _use_ a cross compiler, that generates code for a -platform different from the build platform, you should specify the -"host" platform (i.e., that on which the generated programs will -eventually be run) with `--host=TYPE'. - -Sharing Defaults -================ - - If you want to set default values for `configure' scripts to share, -you can create a site shell script called `config.site' that gives -default values for variables like `CC', `cache_file', and `prefix'. -`configure' looks for `PREFIX/share/config.site' if it exists, then -`PREFIX/etc/config.site' if it exists. Or, you can set the -`CONFIG_SITE' environment variable to the location of the site script. -A warning: not all `configure' scripts look for a site script. - -Defining Variables -================== - - Variables not defined in a site shell script can be set in the -environment passed to `configure'. However, some packages may run -configure again during the build, and the customized values of these -variables may be lost. In order to avoid this problem, you should set -them in the `configure' command line, using `VAR=value'. For example: - - ./configure CC=/usr/local2/bin/gcc - -will cause the specified gcc to be used as the C compiler (unless it is -overridden in the site shell script). - -`configure' Invocation -====================== - - `configure' recognizes the following options to control how it -operates. - -`--help' -`-h' - Print a summary of the options to `configure', and exit. - -`--version' -`-V' - Print the version of Autoconf used to generate the `configure' - script, and exit. - -`--cache-file=FILE' - Enable the cache: use and save the results of the tests in FILE, - traditionally `config.cache'. FILE defaults to `/dev/null' to - disable caching. - -`--config-cache' -`-C' - Alias for `--cache-file=config.cache'. - -`--quiet' -`--silent' -`-q' - Do not print messages saying which checks are being made. To - suppress all normal output, redirect it to `/dev/null' (any error - messages will still be shown). - -`--srcdir=DIR' - Look for the package's source code in directory DIR. Usually - `configure' can determine that directory automatically. - -`configure' also accepts some other, not widely useful, options. Run -`configure --help' for more details. - diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/Makefile.am --- a/console/libgnt/Makefile.am Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,83 +0,0 @@ -EXTRA_DIST=genmarshal - -SUBDIRS = . wms -pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = gnt.pc - -lib_LTLIBRARIES = libgnt.la - -libgnt_la_SOURCES = \ - gntmarshal.c \ - gntwidget.c \ - gntbindable.c \ - gntbox.c \ - gntbutton.c \ - gntcheckbox.c \ - gntclipboard.c \ - gntcolors.c \ - gntcombobox.c \ - gntentry.c \ - gntkeys.c \ - gntlabel.c \ - gntline.c \ - gntmenu.c \ - gntmenuitem.c \ - gntmenuitemcheck.c \ - gntstyle.c \ - gnttextview.c \ - gnttree.c \ - gntutils.c \ - gntwindow.c \ - gntwm.c \ - gntmain.c - -libgnt_la_headers = \ - gntwidget.h \ - gntbindable.h \ - gntbox.h \ - gntbutton.h \ - gntcheckbox.h \ - gntclipboard.h \ - gntcolors.h \ - gntcombobox.h \ - gntentry.h \ - gntkeys.h \ - gntlabel.h \ - gntline.h \ - gntmarshal.h \ - gntmenu.h \ - gntmenuitem.h \ - gntmenuitemcheck.h \ - gntstyle.h \ - gnttextview.h \ - gnttree.h \ - gntutils.h \ - gntwindow.h \ - gntwm.h \ - gnt.h - -CLEANFILES = \ - gntmarshal.h \ - gntmarshal.c - -gntmarshal.c: genmarshal gntmarshal.h - echo "#include \"gntmarshal.h\"" > $@ - cat genmarshal | glib-genmarshal --prefix=gnt_closure_marshal --body >> $@ - -gntmarshal.h: genmarshal - cat genmarshal | glib-genmarshal --prefix=gnt_closure_marshal --header > $@ - -libgnt_laincludedir=$(includedir)/gnt -libgnt_lainclude_HEADERS = \ - $(libgnt_la_headers) - -libgnt_la_DEPENDENCIES = -libgnt_la_LDFLAGS = -export-dynamic -libgnt_la_LIBADD = \ - $(GLIB_LIBS) \ - $(GNT_LIBS) - -AM_CPPFLAGS = \ - $(GLIB_CFLAGS) \ - $(GNT_CFLAGS) \ - $(DEBUG_CFLAGS) diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/NEWS diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/README diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/autogen.sh --- a/console/libgnt/autogen.sh Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ -#!/bin/sh - -(libtoolize --version) < /dev/null > /dev/null 2>&1 || { - echo; - echo "You must have libtool installed to compile LibGNT"; - echo; - exit; -} - -(automake --version) < /dev/null > /dev/null 2>&1 || { - echo; - echo "You must have automake installed to compile LibGNT"; - echo; - exit; -} - -(autoconf --version) < /dev/null > /dev/null 2>&1 || { - echo; - echo "You must have autoconf installed to compile LibGNT"; - echo; - exit; -} - -echo "Generating configuration files for LibGNT, please wait...." -echo; - -echo "Running libtoolize, please ignore non-fatal messages...." -echo n | libtoolize --copy --force || exit; - -# Add other directories to this list if people continue to experience -# brokennesses ... Obviously the real answer is for them to fix it -# themselves, but for Luke's sake we have this. -for dir in "/usr/local/share/aclocal" \ - "/opt/gnome-1.4/share/aclocal" -do - if test -d $dir ; then - ACLOCAL_FLAGS="$ACLOCAL_FLAGS -I $dir" - fi -done - -libtoolize -c -f --automake -aclocal $ACLOCAL_FLAGS || exit; -autoheader || exit; -automake --add-missing --copy; -autoconf || exit; -automake || exit; -./configure $@ - diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/configure.ac --- a/console/libgnt/configure.ac Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,257 +0,0 @@ -dnl Process this file with autoconf to produce a configure script. -AC_INIT([libgnt], [0.0.0dev], [gaim-devel@lists.sourceforge.net]) -AC_CANONICAL_SYSTEM -AM_CONFIG_HEADER(config.h) -AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION) - -AC_PREREQ([2.50]) - -AC_PATH_PROG(sedpath, sed) - -dnl Storing configure arguments -AC_DEFINE_UNQUOTED(CONFIG_ARGS, "$ac_configure_args", [configure arguments]) - -dnl Checks for programs. -AC_PROG_CC -AC_DISABLE_STATIC -AM_PROG_LIBTOOL -LIBTOOL="$LIBTOOL --silent" -AC_PROG_INSTALL - -dnl we don't use autobreak on cygwin!! -dnl AC_CYGWIN - -dnl Checks for header files. -AC_HEADER_STDC -AC_HEADER_SYS_WAIT -AC_CHECK_HEADERS(arpa/nameser_compat.h fcntl.h sys/time.h unistd.h locale.h signal.h stdint.h regex.h) - -dnl Checks for typedefs, structures, and compiler characteristics. -AC_C_CONST -AC_STRUCT_TM - -AC_C_BIGENDIAN - -dnl Checks for library functions. -AC_TYPE_SIGNAL -AC_FUNC_STRFTIME -AC_CHECK_FUNCS(strdup strstr atexit setlocale) - -dnl to prevent the g_stat()/g_unlink() crash, -dnl (09:50:07) Robot101: LSchiere2: it's easy. +LC_SYS_LARGEFILE somewhere in configure.ac -AC_SYS_LARGEFILE - -dnl FreeBSD doesn't have libdl, dlopen is provided by libc -AC_CHECK_FUNC(dlopen, LIBDL="", [AC_CHECK_LIB(dl, dlopen, LIBDL="-ldl")]) - -AC_MSG_CHECKING(for the %z format string in strftime()) -AC_TRY_RUN([ -#ifdef HAVE_SYS_TIME_H -#include -#endif -#include -#include - -int main() -{ - char buf[6]; - time_t t = time(NULL); - - if (strftime(buf, sizeof(buf), "%z", localtime(&t)) != 5) - return 1; - - fprintf(stderr, "strftime(\"%%z\") yields: \"%s\"\n", buf); - - return !((buf[0] == '-' || buf[0] == '+') && - (buf[1] >= '0' && buf[1] <= '9') && - (buf[2] >= '0' && buf[2] <= '9') && - (buf[3] >= '0' && buf[3] <= '9') && - (buf[4] >= '0' && buf[4] <= '9') - ); -} -], -[ - AC_MSG_RESULT(yes) - AC_DEFINE([HAVE_STRFTIME_Z_FORMAT], [1], - [Define to 1 if you have a strftime() that supports the %z format string.]) -], -[ - AC_MSG_RESULT(no) -], -[ - # Fallback for Cross Compiling... - # This will enable the compatibility code. - AC_MSG_RESULT(no) -] -) - - -AC_CHECK_HEADER(sys/utsname.h) -AC_CHECK_FUNC(uname) - -if test "x$enable_debug" = "xyes" ; then - AC_DEFINE(DEBUG, 1, [Define if debugging is enabled.]) - enable_fatal_asserts="yes" -fi - -if test "x$enable_fatal_asserts" = "xyes" ; then - AC_DEFINE(GAIM_FATAL_ASSERTS, 1, [Define to make assertions fatal (useful for debugging).]) -fi - -if test "x$enable_deprecated" = "xno"; then - DEBUG_CFLAGS="$DEBUG_CFLAGS -DG_DISABLE_DEPRECATED -DGDK_DISABLE_DEPRECATED -DGDK_PIXBUF_DISABLE_DEPRECATED -DGTK_DISABLE_DEPRECATED" -fi - -if test "x$GCC" = "xyes"; then - dnl We enable -Wall later. - dnl If it's set after the warning CFLAGS in the compiler invocation, it counteracts the -Wno... flags. - dnl This leads to warnings we don't want. - CFLAGS=`echo $CFLAGS |$sedpath 's/-Wall//'` - - dnl ENABLE WARNINGS SUPPORTED BY THE VERSION OF GCC IN USE - dnl - dnl Future Possibilities - dnl - dnl Consider adding -Wbad-function-cast. - dnl This leads to spurious warnings using GPOINTER_TO_INT(), et al. directly on a function call. - dnl We'd need an intermediate variable. - dnl - dnl Consider adding -Wfloat-equal. - dnl This leads to warnings with Perl. - dnl Perhaps we could write ugly configure magic and pass -Wno-float-equal down to that subdirectory. - dnl On the other hand, it's probably actually broken, so maybe the Perl folks should fix that? - dnl - dnl Consider removing -Wno-sign-compare (from the -Wextra set) and fixing all those cases. - dnl This is likely non-trivial. - dnl - for newflag in \ - "-Waggregate-return" \ - "-Wcast-align" \ - "-Wdeclaration-after-statement" \ - "-Werror-implicit-function-declaration" \ - "-Wextra -Wno-sign-compare -Wno-unused-parameter" \ - "-Winit-self" \ - "-Wmissing-declarations" \ - "-Wmissing-prototypes" \ - "-Wnested-externs" \ - "-Wpointer-arith" \ - "-Wundef" \ - ; do - orig_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS $newflag" - AC_MSG_CHECKING(for $newflag option to gcc) - AC_TRY_COMPILE([], [ - int main() {return 0;} - ], [ - AC_MSG_RESULT(yes) - CFLAGS="$orig_CFLAGS" - DEBUG_CFLAGS="$DEBUG_CFLAGS $newflag" - ], [ - AC_MSG_RESULT(no) - CFLAGS="$orig_CFLAGS" - ]) - done - - if test "x$enable_fortify" = "xyes"; then - AC_MSG_CHECKING(for FORTIFY_SOURCE support) - AC_TRY_COMPILE([#include ], [ - int main() { - #if !(__GNUC_PREREQ (4, 1) \ - || (defined __GNUC_RH_RELEASE__ && __GNUC_PREREQ (4, 0)) \ - || (defined __GNUC_RH_RELEASE__ && __GNUC_PREREQ (3, 4) \ - && __GNUC_MINOR__ == 4 \ - && (__GNUC_PATCHLEVEL__ > 2 \ - || (__GNUC_PATCHLEVEL__ == 2 && __GNUC_RH_RELEASE__ >= 8)))) - #error No FORTIFY_SOURCE support - #endif - return 0; - } - ], [ - AC_MSG_RESULT(yes) - DEBUG_CFLAGS="$DEBUG_CFLAGS -D_FORTIFY_SOURCE=2" - ], [ - AC_MSG_RESULT(no) - ]) - fi - - DEBUG_CFLAGS="-Wall $DEBUG_CFLAGS" - CFLAGS="-g $CFLAGS" -fi -AC_SUBST(CFLAGS) - -PKG_CHECK_MODULES(GLIB, [glib-2.0 >= 2.0.0 gobject-2.0 gmodule-2.0],, - [ - AC_MSG_ERROR([ -*** GLib 2.0 is required to build LibGNT; please make sure you have the GLib -*** development headers installed. The latest version of GLib is -*** always available at http://www.gtk.org/.]) - ]) -AC_SUBST(GLIB_CFLAGS) -AC_SUBST(GLIB_LIBS) - - -AC_MSG_CHECKING(for me pot o' gold) -AC_MSG_RESULT(no) -AC_CHECK_FUNCS(gethostid lrand48) -AC_CHECK_FUNCS(memcpy memmove random strchr strerror vprintf) -AC_CHECK_HEADERS(malloc.h paths.h sgtty.h stdarg.h sys/cdefs.h) -AC_CHECK_HEADERS(sys/file.h sys/filio.h sys/ioctl.h sys/msgbuf.h) -AC_CHECK_HEADERS(sys/select.h sys/uio.h sys/utsname.h sys/wait.h) -AC_CHECK_HEADERS(termios.h) -#AC_CHECK_FUNC(wcwidth, [AC_DEFINE([HAVE_WCWIDTH], [1], [Define to 1 if you have wcwidth function.])]) -#AC_VAR_TIMEZONE_EXTERNALS - -GNT_CFLAGS= -GNT_LIBS= -AC_CHECK_LIB(ncursesw, initscr, [GNT_LIBS="-lncursesw"], [enable_gnt=no]) -AC_CHECK_LIB(panelw, update_panels, [GNT_LIBS="$GNT_LIBS -lpanelw"], [enable_gnt=no]) - -# If ncursesw is not found, look for plain old ncurses -if test "x$enable_gnt" = "xno"; then - AC_CHECK_LIB(ncurses, initscr, [[GNT_LIBS="-lncurses"] [enable_gnt=yes]], [enable_gnt=no]) - AC_CHECK_LIB(panel, update_panels, [[GNT_LIBS="$GNT_LIBS -lpanel"] [enable_gnt=yes]], [enable_gnt=no]) - AC_DEFINE(NO_WIDECHAR, [1], [Define to 1 if you do not have ncursesw.]) -else - dnl # Some distros put the headers in ncursesw/, some don't - found_ncurses_h=no - for f in /usr/include/ncursesw/ncurses.h /usr/include/ncurses.h - do - AC_CHECK_HEADER($f,[ - AC_MSG_CHECKING([if $f supports wide characters]) - AC_TRY_COMPILE([ - #define _XOPEN_SOURCE_EXTENDED - #include <$f> - ], [ - #ifndef get_wch - # error get_wch not found! - #endif - ], [ - dir=`dirname $f` - if test x"$dir" != x"." ; then - GNT_CFLAGS="-I$dir/" - else - GNT_CFLAGS="" - fi - - found_ncurses_h=yes - AC_MSG_RESULT([yes]) - break - ], [ - AC_MSG_RESULT([no]) - ]) - ]) - done -fi -AC_SUBST(GNT_CFLAGS) -AC_SUBST(GNT_LIBS) - -if test "x$enable_gnt" = "xno"; then - AC_MSG_ERROR([ -*** You need ncursesw or ncurses.]) -fi - -AC_OUTPUT([Makefile - gnt.pc - wms/Makefile - ]) - diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/genmarshal --- a/console/libgnt/genmarshal Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -BOOLEAN:VOID -BOOLEAN:STRING -VOID:INT,INT,INT,INT -VOID:INT,INT -VOID:POINTER,POINTER -BOOLEAN:INT,INT -BOOLEAN:INT,INT,INT -BOOLEAN:POINTER,POINTER,POINTER -BOOLEAN:INT,INT,INT,POINTER -VOID:STRING,STRING diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gnt-skel.c --- a/console/libgnt/gnt-skel.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,106 +0,0 @@ -#include "gnt-skel.h" - -enum -{ - SIGS = 1, -}; - -static GntWidgetClass *parent_class = NULL; -static guint signals[SIGS] = { 0 }; - -static void -gnt_skel_draw(GntWidget *widget) -{ - GNTDEBUG; -} - -static void -gnt_skel_size_request(GntWidget *widget) -{ -} - -static void -gnt_skel_map(GntWidget *widget) -{ - if (widget->priv.width == 0 || widget->priv.height == 0) - gnt_widget_size_request(widget); - GNTDEBUG; -} - -static gboolean -gnt_skel_key_pressed(GntWidget *widget, const char *text) -{ - return FALSE; -} - -static void -gnt_skel_destroy(GntWidget *widget) -{ -} - -static void -gnt_skel_class_init(GntSkelClass *klass) -{ - GObjectClass *obj_class = G_OBJECT_CLASS(klass); - - parent_class = GNT_WIDGET_CLASS(klass); - parent_class->destroy = gnt_skel_destroy; - parent_class->draw = gnt_skel_draw; - parent_class->map = gnt_skel_map; - parent_class->size_request = gnt_skel_size_request; - parent_class->key_pressed = gnt_skel_key_pressed; - - parent_class->actions = g_hash_table_duplicate(parent_class->actions, g_str_hash, - g_str_equal, NULL, (GDestroyNotify)gnt_widget_action_free); - parent_class->bindings = g_hash_table_duplicate(parent_class->bindings, g_str_hash, - g_str_equal, NULL, (GDestroyNotify)gnt_widget_action_param_free); - - gnt_widget_actions_read(G_OBJECT_CLASS_TYPE(klass), klass); - - GNTDEBUG; -} - -static void -gnt_skel_init(GTypeInstance *instance, gpointer class) -{ - GNTDEBUG; -} - -/****************************************************************************** - * GntSkel API - *****************************************************************************/ -GType -gnt_skel_get_gtype(void) -{ - static GType type = 0; - - if(type == 0) - { - static const GTypeInfo info = { - sizeof(GntSkelClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc)gnt_skel_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof(GntSkel), - 0, /* n_preallocs */ - gnt_skel_init, /* instance_init */ - }; - - type = g_type_register_static(GNT_TYPE_WIDGET, - "GntSkel", - &info, 0); - } - - return type; -} - -GntWidget *gnt_skel_new() -{ - GntWidget *widget = g_object_new(GNT_TYPE_SKEL, NULL); - GntSkel *skel = GNT_SKEL(widget); - - return widget; -} - diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gnt-skel.h --- a/console/libgnt/gnt-skel.h Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -#ifndef GNT_SKEL_H -#define GNT_SKEL_H - -#include "gntwidget.h" -#include "gnt.h" -#include "gntcolors.h" -#include "gntkeys.h" - -#define GNT_TYPE_SKEL (gnt_skel_get_gtype()) -#define GNT_SKEL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNT_TYPE_SKEL, GntSkel)) -#define GNT_SKEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GNT_TYPE_SKEL, GntSkelClass)) -#define GNT_IS_SKEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GNT_TYPE_SKEL)) -#define GNT_IS_SKEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GNT_TYPE_SKEL)) -#define GNT_SKEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GNT_TYPE_SKEL, GntSkelClass)) - -#define GNT_SKEL_FLAGS(obj) (GNT_SKEL(obj)->priv.flags) -#define GNT_SKEL_SET_FLAGS(obj, flags) (GNT_SKEL_FLAGS(obj) |= flags) -#define GNT_SKEL_UNSET_FLAGS(obj, flags) (GNT_SKEL_FLAGS(obj) &= ~(flags)) - -typedef struct _GnSkel GntSkel; -typedef struct _GnSkelPriv GntSkelPriv; -typedef struct _GnSkelClass GntSkelClass; - -struct _GnSkel -{ - GntWidget parent; -}; - -struct _GnSkelClass -{ - GntWidgetClass parent; - - void (*gnt_reserved1)(void); - void (*gnt_reserved2)(void); - void (*gnt_reserved3)(void); - void (*gnt_reserved4)(void); -}; - -G_BEGIN_DECLS - -GType gnt_skel_get_gtype(void); - -GntWidget *gnt_skel_new(); - -G_END_DECLS - -#endif /* GNT_SKEL_H */ diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gnt.h --- a/console/libgnt/gnt.h Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -#include -#include "gntwidget.h" -#include "gntclipboard.h" -#include "gntcolors.h" -#include "gntkeys.h" - -void gnt_init(void); - -void gnt_main(void); - -gboolean gnt_ascii_only(void); - -void gnt_screen_occupy(GntWidget *widget); - -void gnt_screen_release(GntWidget *widget); - -void gnt_screen_update(GntWidget *widget); - -void gnt_screen_take_focus(GntWidget *widget); - -void gnt_screen_resize_widget(GntWidget *widget, int width, int height); - -void gnt_screen_move_widget(GntWidget *widget, int x, int y); - -void gnt_screen_rename_widget(GntWidget *widget, const char *text); - -gboolean gnt_widget_has_focus(GntWidget *widget); - -void gnt_widget_set_urgent(GntWidget *widget); - -void gnt_register_action(const char *label, void (*callback)()); - -gboolean gnt_screen_menu_show(gpointer menu); - -void gnt_quit(void); - -GntClipboard *gnt_get_clipboard(void); - -gchar *gnt_get_clipboard_string(void); - -void gnt_set_clipboard_string(gchar *); diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gnt.pc.in --- a/console/libgnt/gnt.pc.in Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ -datarootdir=@datarootdir@ -datadir=@datadir@ -sysconfdir=@sysconfdir@ - -Name: LibGNT -Description: Glib Ncurses Toolkit is a collection of curses-widgets. -Version: @VERSION@ -Requires: glib-2.0 -Cflags: -I${includedir}/gnt -Libs: -L${libdir} -lgnt diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gntbindable.c --- a/console/libgnt/gntbindable.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,232 +0,0 @@ -#include "gntbindable.h" -#include "gntstyle.h" -#include "gnt.h" -#include "gntutils.h" - -static GObjectClass *parent_class = NULL; - -static void -gnt_bindable_class_init(GntBindableClass *klass) -{ - parent_class = g_type_class_peek_parent(klass); - - klass->actions = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, - (GDestroyNotify)gnt_bindable_action_free); - klass->bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, - (GDestroyNotify)gnt_bindable_action_param_free); - - gnt_style_read_actions(G_OBJECT_CLASS_TYPE(klass), GNT_BINDABLE_CLASS(klass)); - GNTDEBUG; -} - -static gpointer -bindable_clone(GntBindableAction *action) -{ - GntBindableAction *ret = g_new0(GntBindableAction, 1); - ret->name = g_strdup(action->name); - ret->u = action->u; - return ret; -} - -static gpointer -binding_clone(GntBindableActionParam *param) -{ - GntBindableActionParam *p = g_new0(GntBindableActionParam, 1); - p->list = g_list_copy(param->list); - p->action = param->action; - return p; -} - -static void -duplicate_hashes(GntBindableClass *klass) -{ - /* Duplicate the bindings from parent class */ - if (klass->actions) { - klass->actions = g_hash_table_duplicate(klass->actions, g_str_hash, - g_str_equal, g_free, (GDestroyNotify)gnt_bindable_action_free, - (GDupFunc)g_strdup, (GDupFunc)bindable_clone); - klass->bindings = g_hash_table_duplicate(klass->bindings, g_str_hash, - g_str_equal, g_free, (GDestroyNotify)gnt_bindable_action_param_free, - (GDupFunc)g_strdup, (GDupFunc)binding_clone); - } else { - klass->actions = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, - (GDestroyNotify)gnt_bindable_action_free); - klass->bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, - (GDestroyNotify)gnt_bindable_action_param_free); - } - - GNTDEBUG; -} - -/****************************************************************************** - * GntBindable API - *****************************************************************************/ -GType -gnt_bindable_get_gtype(void) -{ - static GType type = 0; - - if(type == 0) { - static const GTypeInfo info = { - sizeof(GntBindableClass), - (GBaseInitFunc)duplicate_hashes, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc)gnt_bindable_class_init, - NULL, - NULL, /* class_data */ - sizeof(GntBindable), - 0, /* n_preallocs */ - NULL, /* instance_init */ - NULL /* value_table */ - }; - - type = g_type_register_static(G_TYPE_OBJECT, - "GntBindable", - &info, G_TYPE_FLAG_ABSTRACT); - } - - return type; -} - -/** - * Key Remaps - */ -const char * -gnt_bindable_remap_keys(GntBindable *bindable, const char *text) -{ - const char *remap = NULL; - GType type = G_OBJECT_TYPE(bindable); - GntBindableClass *klass = GNT_BINDABLE_CLASS(GNT_BINDABLE_GET_CLASS(bindable)); - - if (klass->remaps == NULL) - { - klass->remaps = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); - gnt_styles_get_keyremaps(type, klass->remaps); - } - - remap = g_hash_table_lookup(klass->remaps, text); - - return (remap ? remap : text); -} - -/** - * Actions and Bindings - */ -gboolean -gnt_bindable_perform_action_named(GntBindable *bindable, const char *name, ...) -{ - GntBindableClass *klass = GNT_BINDABLE_CLASS(GNT_BINDABLE_GET_CLASS(bindable)); - GList *list = NULL; - va_list args; - GntBindableAction *action; - void *p; - - va_start(args, name); - while ((p = va_arg(args, void *)) != NULL) - list = g_list_append(list, p); - va_end(args); - - action = g_hash_table_lookup(klass->actions, name); - if (action && action->u.action) { - return action->u.action(bindable, list); - } - return FALSE; -} - -gboolean -gnt_bindable_perform_action_key(GntBindable *bindable, const char *keys) -{ - GntBindableClass *klass = GNT_BINDABLE_CLASS(GNT_BINDABLE_GET_CLASS(bindable)); - GntBindableActionParam *param = g_hash_table_lookup(klass->bindings, keys); - - if (param && param->action) { - if (param->list) - return param->action->u.action(bindable, param->list); - else - return param->action->u.action_noparam(bindable); - } - return FALSE; -} - -static void -register_binding(GntBindableClass *klass, const char *name, const char *trigger, GList *list) -{ - GntBindableActionParam *param; - GntBindableAction *action; - - if (name == NULL || *name == '\0') { - g_hash_table_remove(klass->bindings, (char*)trigger); - gnt_keys_del_combination(trigger); - return; - } - - action = g_hash_table_lookup(klass->actions, name); - if (!action) { - g_printerr("GntWidget: Invalid action name %s for %s\n", - name, g_type_name(G_OBJECT_CLASS_TYPE(klass))); - if (list) - g_list_free(list); - return; - } - - param = g_new0(GntBindableActionParam, 1); - param->action = action; - param->list = list; - g_hash_table_replace(klass->bindings, g_strdup(trigger), param); - gnt_keys_add_combination(trigger); -} - -void gnt_bindable_register_binding(GntBindableClass *klass, const char *name, - const char *trigger, ...) -{ - GList *list = NULL; - va_list args; - void *data; - - va_start(args, trigger); - while ((data = va_arg(args, void *))) { - list = g_list_append(list, data); - } - va_end(args); - - register_binding(klass, name, trigger, list); -} - -void gnt_bindable_class_register_action(GntBindableClass *klass, const char *name, - GntBindableActionCallback callback, const char *trigger, ...) -{ - void *data; - va_list args; - GntBindableAction *action = g_new0(GntBindableAction, 1); - GList *list; - - action->name = g_strdup(name); - action->u.action = callback; - - g_hash_table_replace(klass->actions, g_strdup(name), action); - - if (trigger && *trigger) { - list = NULL; - va_start(args, trigger); - while ((data = va_arg(args, void *))) { - list = g_list_append(list, data); - } - va_end(args); - - register_binding(klass, name, trigger, list); - } -} - -void gnt_bindable_action_free(GntBindableAction *action) -{ - g_free(action->name); - g_free(action); -} - -void gnt_bindable_action_param_free(GntBindableActionParam *param) -{ - g_list_free(param->list); /* XXX: There may be a leak here for string parameters */ - g_free(param); -} - - diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gntbindable.h --- a/console/libgnt/gntbindable.h Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,90 +0,0 @@ -#ifndef GNT_BINDABLE_H -#define GNT_BINDABLE_H - -#include -#include -#include -#include - -#define GNT_TYPE_BINDABLE (gnt_bindable_get_gtype()) -#define GNT_BINDABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNT_TYPE_BINDABLE, GntBindable)) -#define GNT_BINDABLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GNT_TYPE_BINDABLE, GntBindableClass)) -#define GNT_IS_BINDABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GNT_TYPE_BINDABLE)) -#define GNT_IS_BINDABLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GNT_TYPE_BINDABLE)) -#define GNT_BINDABLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GNT_TYPE_BINDABLE, GntBindableClass)) - -#define GNTDEBUG g_printerr("%s\n", __FUNCTION__) - -typedef struct _GnBindable GntBindable; -typedef struct _GnBindableClass GntBindableClass; - -struct _GnBindable -{ - GObject inherit; -}; - -struct _GnBindableClass -{ - GObjectClass parent; - - GHashTable *remaps; /* Key remaps */ - GHashTable *actions; /* name -> Action */ - GHashTable *bindings; /* key -> ActionParam */ - - void (*gnt_reserved1)(void); - void (*gnt_reserved2)(void); - void (*gnt_reserved3)(void); - void (*gnt_reserved4)(void); -}; - -G_BEGIN_DECLS - -GType gnt_bindable_get_gtype(void); - -/******************/ -/* Key Remaps */ -/******************/ -const char * gnt_bindable_remap_keys(GntBindable *bindable, const char *text); - -/******************/ -/* Bindable Actions */ -/******************/ -typedef gboolean (*GntBindableActionCallback) (GntBindable *bindable, GList *params); -typedef gboolean (*GntBindableActionCallbackNoParam)(GntBindable *bindable); - -typedef struct _GnBindableAction GntBindableAction; -typedef struct _GnBindableActionParam GntBindableActionParam; - -struct _GnBindableAction -{ - char *name; /* The name of the action */ - union { - gboolean (*action)(GntBindable *bindable, GList *params); - gboolean (*action_noparam)(GntBindable *bindable); - } u; -}; - -struct _GnBindableActionParam -{ - GntBindableAction *action; - GList *list; -}; - - -/*GntBindableAction *gnt_bindable_action_parse(const char *name);*/ - -void gnt_bindable_action_free(GntBindableAction *action); -void gnt_bindable_action_param_free(GntBindableActionParam *param); - -void gnt_bindable_class_register_action(GntBindableClass *klass, const char *name, - GntBindableActionCallback callback, const char *trigger, ...); -void gnt_bindable_register_binding(GntBindableClass *klass, const char *name, - const char *trigger, ...); - -gboolean gnt_bindable_perform_action_key(GntBindable *bindable, const char *keys); -gboolean gnt_bindable_perform_action_named(GntBindable *bindable, const char *name, ...); - -G_END_DECLS - -#endif /* GNT_BINDABLE_H */ - diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gntbox.c --- a/console/libgnt/gntbox.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,788 +0,0 @@ -#include "gntbox.h" -#include "gntutils.h" - -#include - -enum -{ - SIGS = 1, -}; - -static GntWidgetClass *parent_class = NULL; - -static GntWidget * find_focusable_widget(GntBox *box); - -static void -add_to_focus(gpointer value, gpointer data) -{ - GntBox *box = GNT_BOX(data); - GntWidget *w = GNT_WIDGET(value); - - if (GNT_IS_BOX(w)) - g_list_foreach(GNT_BOX(w)->list, add_to_focus, box); - else if (GNT_WIDGET_IS_FLAG_SET(w, GNT_WIDGET_CAN_TAKE_FOCUS)) - box->focus = g_list_append(box->focus, w); -} - -static void -get_title_thingies(GntBox *box, char *title, int *p, int *r) -{ - GntWidget *widget = GNT_WIDGET(box); - int len; - char *end = (char*)gnt_util_onscreen_width_to_pointer(title, widget->priv.width - 4, &len); - - if (p) - *p = (widget->priv.width - len) / 2; - if (r) - *r = (widget->priv.width + len) / 2; - *end = '\0'; -} - -static void -gnt_box_draw(GntWidget *widget) -{ - GntBox *box = GNT_BOX(widget); - - if (box->focus == NULL && widget->parent == NULL) - g_list_foreach(box->list, add_to_focus, box); - - g_list_foreach(box->list, (GFunc)gnt_widget_draw, NULL); - - gnt_box_sync_children(box); - - if (box->title && !GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER)) - { - int pos, right; - char *title = g_strdup(box->title); - - get_title_thingies(box, title, &pos, &right); - - if (gnt_widget_has_focus(widget)) - wbkgdset(widget->window, '\0' | COLOR_PAIR(GNT_COLOR_TITLE)); - else - wbkgdset(widget->window, '\0' | COLOR_PAIR(GNT_COLOR_TITLE_D)); - mvwaddch(widget->window, 0, pos-1, ACS_RTEE | COLOR_PAIR(GNT_COLOR_NORMAL)); - mvwaddstr(widget->window, 0, pos, title); - mvwaddch(widget->window, 0, right, ACS_LTEE | COLOR_PAIR(GNT_COLOR_NORMAL)); - g_free(title); - } - - GNTDEBUG; -} - -static void -reposition_children(GntWidget *widget) -{ - GList *iter; - GntBox *box = GNT_BOX(widget); - int w, h, curx, cury, max; - gboolean has_border = FALSE; - - w = h = 0; - max = 0; - curx = widget->priv.x; - cury = widget->priv.y; - if (!(GNT_WIDGET_FLAGS(widget) & GNT_WIDGET_NO_BORDER)) - { - has_border = TRUE; - curx += 1; - cury += 1; - } - - for (iter = box->list; iter; iter = iter->next) - { - if (GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(iter->data), GNT_WIDGET_INVISIBLE)) - continue; - gnt_widget_set_position(GNT_WIDGET(iter->data), curx, cury); - gnt_widget_get_size(GNT_WIDGET(iter->data), &w, &h); - if (box->vertical) - { - if (h) - { - cury += h + box->pad; - if (max < w) - max = w; - } - } - else - { - if (w) - { - curx += w + box->pad; - if (max < h) - max = h; - } - } - } - - if (has_border) - { - curx += 1; - cury += 1; - max += 2; - } - - if (box->list) - { - if (box->vertical) - cury -= box->pad; - else - curx -= box->pad; - } - - if (box->vertical) - { - widget->priv.width = max; - widget->priv.height = cury - widget->priv.y; - } - else - { - widget->priv.width = curx - widget->priv.x; - widget->priv.height = max; - } -} - -static void -gnt_box_set_position(GntWidget *widget, int x, int y) -{ - GList *iter; - int changex, changey; - - changex = widget->priv.x - x; - changey = widget->priv.y - y; - - for (iter = GNT_BOX(widget)->list; iter; iter = iter->next) - { - GntWidget *w = GNT_WIDGET(iter->data); - gnt_widget_set_position(w, w->priv.x - changex, - w->priv.y - changey); - } -} - -static void -gnt_box_size_request(GntWidget *widget) -{ - GntBox *box = GNT_BOX(widget); - GList *iter; - int maxw = 0, maxh = 0; - - g_list_foreach(box->list, (GFunc)gnt_widget_size_request, NULL); - - for (iter = box->list; iter; iter = iter->next) - { - int w, h; - gnt_widget_get_size(GNT_WIDGET(iter->data), &w, &h); - if (maxh < h) - maxh = h; - if (maxw < w) - maxw = w; - } - - for (iter = box->list; iter; iter = iter->next) - { - int w, h; - GntWidget *wid = GNT_WIDGET(iter->data); - - gnt_widget_get_size(wid, &w, &h); - - if (box->homogeneous) - { - if (box->vertical) - h = maxh; - else - w = maxw; - } - if (box->fill) - { - if (box->vertical) - w = maxw; - else - h = maxh; - } - - gnt_widget_set_size(wid, w, h); - } - - reposition_children(widget); -} - -static void -gnt_box_map(GntWidget *widget) -{ - if (widget->priv.width == 0 || widget->priv.height == 0) - { - gnt_widget_size_request(widget); - find_focusable_widget(GNT_BOX(widget)); - } - GNTDEBUG; -} - -/* Ensures that the current widget can take focus */ -static GntWidget * -find_focusable_widget(GntBox *box) -{ - /* XXX: Make sure the widget is visible? */ - if (box->focus == NULL && GNT_WIDGET(box)->parent == NULL) - g_list_foreach(box->list, add_to_focus, box); - - if (box->active == NULL && box->focus) - box->active = box->focus->data; - - return box->active; -} - -static void -find_next_focus(GntBox *box) -{ - gpointer last = box->active; - do - { - GList *iter = g_list_find(box->focus, box->active); - if (iter && iter->next) - box->active = iter->next->data; - else if (box->focus) - box->active = box->focus->data; - if (!GNT_WIDGET_IS_FLAG_SET(box->active, GNT_WIDGET_INVISIBLE)) - break; - } while (box->active != last); -} - -static void -find_prev_focus(GntBox *box) -{ - gpointer last = box->active; - - if (!box->focus) - return; - - do - { - GList *iter = g_list_find(box->focus, box->active); - if (!iter) - box->active = box->focus->data; - else if (!iter->prev) - box->active = g_list_last(box->focus)->data; - else - box->active = iter->prev->data; - if (!GNT_WIDGET_IS_FLAG_SET(box->active, GNT_WIDGET_INVISIBLE)) - break; - } while (box->active != last); -} - -static gboolean -gnt_box_key_pressed(GntWidget *widget, const char *text) -{ - GntBox *box = GNT_BOX(widget); - GntWidget *now; - - if (box->active == NULL && !find_focusable_widget(box)) - return FALSE; - - if (gnt_widget_key_pressed(box->active, text)) - return TRUE; - - now = box->active; - - if (text[0] == 27) - { - if (strcmp(text, GNT_KEY_LEFT) == 0) - { - find_prev_focus(box); - } - else if (strcmp(text, GNT_KEY_RIGHT) == 0) - { - find_next_focus(box); - } - } - else if (text[0] == '\t') - { - find_next_focus(box); - } - - if (now && now != box->active) - { - gnt_widget_set_focus(now, FALSE); - gnt_widget_set_focus(box->active, TRUE); - return TRUE; - } - - return FALSE; -} - -static void -gnt_box_lost_focus(GntWidget *widget) -{ - GntWidget *w = GNT_BOX(widget)->active; - if (w) - gnt_widget_set_focus(w, FALSE); - gnt_widget_draw(widget); -} - -static void -gnt_box_gained_focus(GntWidget *widget) -{ - GntWidget *w = GNT_BOX(widget)->active; - if (w) - gnt_widget_set_focus(w, TRUE); - gnt_widget_draw(widget); -} - -static void -gnt_box_destroy(GntWidget *w) -{ - GntBox *box = GNT_BOX(w); - - gnt_box_remove_all(box); - gnt_screen_release(w); -} - -static void -gnt_box_expose(GntWidget *widget, int x, int y, int width, int height) -{ - WINDOW *win = newwin(height, width, widget->priv.y + y, widget->priv.x + x); - copywin(widget->window, win, y, x, 0, 0, height - 1, width - 1, FALSE); - wrefresh(win); - delwin(win); -} - -static gboolean -gnt_box_confirm_size(GntWidget *widget, int width, int height) -{ - GList *iter; - GntBox *box = GNT_BOX(widget); - int wchange, hchange; - - if (widget->priv.width != width && !GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_GROW_X)) - return FALSE; - if (widget->priv.height != height && !GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_GROW_Y)) - return FALSE; - - if (!box->list) - return TRUE; - - wchange = widget->priv.width - width; - hchange = widget->priv.height - height; - - if (wchange == 0 && hchange == 0) - return TRUE; /* Quit playing games */ - - /* XXX: Right now, I am trying to just apply all the changes to - * just one widget. It should be possible to distribute the - * changes to all the widgets in the box. */ - for (iter = box->list; iter; iter = iter->next) - { - GntWidget *wid = iter->data; - int w, h; - - gnt_widget_get_size(wid, &w, &h); - - if (gnt_widget_confirm_size(wid, w - wchange, h - hchange)) - { - GList *i; - - for (i = box->list; i; i = i->next) - { - int tw, th; - if (i == iter) continue; - gnt_widget_get_size(GNT_WIDGET(i->data), &tw, &th); - if (box->vertical) - { - if (!gnt_widget_confirm_size(i->data, tw - wchange, th)) - return FALSE; - } - else - { - if (!gnt_widget_confirm_size(i->data, tw, th - hchange)) - return FALSE; - } - } -#if 0 - gnt_widget_set_size(wid, w - wchange, h - hchange); - if (box->vertical) - hchange = 0; - else - wchange = 0; - - for (i = box->list; i; i = i->next) - { - int tw, th; - if (i == iter) continue; - gnt_widget_get_size(GNT_WIDGET(i->data), &tw, &th); - gnt_widget_set_size(i->data, tw - wchange, th - hchange); - } -#endif - g_object_set_data(G_OBJECT(box), "size-queued", wid); - return TRUE; - } - } - - return FALSE; -} - -static void -gnt_box_size_changed(GntWidget *widget, int oldw, int oldh) -{ - int wchange, hchange; - GList *i; - GntBox *box = GNT_BOX(widget); - GntWidget *wid; - int tw, th; - - wchange = widget->priv.width - oldw; - hchange = widget->priv.height - oldh; - - wid = g_object_get_data(G_OBJECT(box), "size-queued"); - if (wid) - { - gnt_widget_get_size(wid, &tw, &th); - gnt_widget_set_size(wid, tw + wchange, th + hchange); - g_object_set_data(G_OBJECT(box), "size-queued", NULL); - } - - if (box->vertical) - hchange = 0; - else - wchange = 0; - - for (i = box->list; i; i = i->next) - { - if (wid != i->data) - { - gnt_widget_get_size(GNT_WIDGET(i->data), &tw, &th); - gnt_widget_set_size(i->data, tw + wchange, th + hchange); - } - } - - reposition_children(widget); -} - -static gboolean -gnt_box_clicked(GntWidget *widget, GntMouseEvent event, int cx, int cy) -{ - GList *iter; - for (iter = GNT_BOX(widget)->list; iter; iter = iter->next) { - int x, y, w, h; - GntWidget *wid = iter->data; - - gnt_widget_get_position(wid, &x, &y); - gnt_widget_get_size(wid, &w, &h); - - if (cx >= x && cx < x + w && cy >= y && cy < y + h) { - if (event <= GNT_MIDDLE_MOUSE_DOWN && - GNT_WIDGET_IS_FLAG_SET(wid, GNT_WIDGET_CAN_TAKE_FOCUS)) { - while (widget->parent) - widget = widget->parent; - gnt_box_give_focus_to_child(GNT_BOX(widget), wid); - } - return gnt_widget_clicked(wid, event, cx, cy); - } - } - return FALSE; -} - -static void -gnt_box_class_init(GntBoxClass *klass) -{ - parent_class = GNT_WIDGET_CLASS(klass); - parent_class->destroy = gnt_box_destroy; - parent_class->draw = gnt_box_draw; - parent_class->expose = gnt_box_expose; - parent_class->map = gnt_box_map; - parent_class->size_request = gnt_box_size_request; - parent_class->set_position = gnt_box_set_position; - parent_class->key_pressed = gnt_box_key_pressed; - parent_class->clicked = gnt_box_clicked; - parent_class->lost_focus = gnt_box_lost_focus; - parent_class->gained_focus = gnt_box_gained_focus; - parent_class->confirm_size = gnt_box_confirm_size; - parent_class->size_changed = gnt_box_size_changed; - - GNTDEBUG; -} - -static void -gnt_box_init(GTypeInstance *instance, gpointer class) -{ - GntWidget *widget = GNT_WIDGET(instance); - GntBox *box = GNT_BOX(widget); - /* Initially make both the height and width resizable. - * Update the flags as necessary when widgets are added to it. */ - GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_GROW_X | GNT_WIDGET_GROW_Y); - GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_CAN_TAKE_FOCUS); - GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW); - box->pad = 1; - box->fill = TRUE; - GNTDEBUG; -} - -/****************************************************************************** - * GntBox API - *****************************************************************************/ -GType -gnt_box_get_gtype(void) -{ - static GType type = 0; - - if(type == 0) - { - static const GTypeInfo info = { - sizeof(GntBoxClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc)gnt_box_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof(GntBox), - 0, /* n_preallocs */ - gnt_box_init, /* instance_init */ - NULL /* value_table */ - }; - - type = g_type_register_static(GNT_TYPE_WIDGET, - "GntBox", - &info, 0); - } - - return type; -} - -GntWidget *gnt_box_new(gboolean homo, gboolean vert) -{ - GntWidget *widget = g_object_new(GNT_TYPE_BOX, NULL); - GntBox *box = GNT_BOX(widget); - - box->homogeneous = homo; - box->vertical = vert; - box->alignment = vert ? GNT_ALIGN_LEFT : GNT_ALIGN_MID; - - return widget; -} - -void gnt_box_add_widget(GntBox *b, GntWidget *widget) -{ - b->list = g_list_append(b->list, widget); - widget->parent = GNT_WIDGET(b); - - if (b->vertical) - { - if (!GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_GROW_X)) - GNT_WIDGET_UNSET_FLAGS(GNT_WIDGET(b), GNT_WIDGET_GROW_X); - } - else - { - if (!GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_GROW_Y)) - GNT_WIDGET_UNSET_FLAGS(GNT_WIDGET(b), GNT_WIDGET_GROW_Y); - } -} - -void gnt_box_set_title(GntBox *b, const char *title) -{ - char *prev = b->title; - GntWidget *w = GNT_WIDGET(b); - b->title = g_strdup(title); - if (w->window && !GNT_WIDGET_IS_FLAG_SET(w, GNT_WIDGET_NO_BORDER)) { - /* Erase the old title */ - int pos, right; - get_title_thingies(b, prev, &pos, &right); - mvwhline(w->window, 0, pos - 1, ACS_HLINE | COLOR_PAIR(GNT_COLOR_NORMAL), - right - pos + 2); - g_free(prev); - } -} - -void gnt_box_set_pad(GntBox *box, int pad) -{ - box->pad = pad; - /* XXX: Perhaps redraw if already showing? */ -} - -void gnt_box_set_toplevel(GntBox *box, gboolean set) -{ - GntWidget *widget = GNT_WIDGET(box); - if (set) - { - GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW); - GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_CAN_TAKE_FOCUS); - } - else - { - GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW); - GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_CAN_TAKE_FOCUS); - } -} - -void gnt_box_sync_children(GntBox *box) -{ - GList *iter; - GntWidget *widget = GNT_WIDGET(box); - int pos = 1; - - if (GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER)) - pos = 0; - - for (iter = box->list; iter; iter = iter->next) - { - GntWidget *w = GNT_WIDGET(iter->data); - int height, width; - int x, y; - - if (GNT_WIDGET_IS_FLAG_SET(w, GNT_WIDGET_INVISIBLE)) - continue; - - if (GNT_IS_BOX(w)) - gnt_box_sync_children(GNT_BOX(w)); - - gnt_widget_get_size(w, &width, &height); - - x = w->priv.x - widget->priv.x; - y = w->priv.y - widget->priv.y; - - if (box->vertical) - { - x = pos; - if (box->alignment == GNT_ALIGN_RIGHT) - x += widget->priv.width - width; - else if (box->alignment == GNT_ALIGN_MID) - x += (widget->priv.width - width)/2; - if (x + width > widget->priv.width - pos) - x -= x + width - (widget->priv.width - pos); - } - else - { - y = pos; - if (box->alignment == GNT_ALIGN_BOTTOM) - y += widget->priv.height - height; - else if (box->alignment == GNT_ALIGN_MID) - y += (widget->priv.height - height)/2; - if (y + height >= widget->priv.height - pos) - y = widget->priv.height - height - pos; - } - - copywin(w->window, widget->window, 0, 0, - y, x, y + height - 1, x + width - 1, FALSE); - gnt_widget_set_position(w, x + widget->priv.x, y + widget->priv.y); - } -} - -void gnt_box_set_alignment(GntBox *box, GntAlignment alignment) -{ - box->alignment = alignment; -} - -void gnt_box_remove(GntBox *box, GntWidget *widget) -{ - box->list = g_list_remove(box->list, widget); - if (GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_CAN_TAKE_FOCUS) - && GNT_WIDGET(box)->parent == NULL && box->focus) - { - if (widget == box->active) - { - find_next_focus(box); - if (box->active == widget) /* There's only one widget */ - box->active = NULL; - } - box->focus = g_list_remove(box->focus, widget); - } - - if (GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(box), GNT_WIDGET_MAPPED)) - gnt_widget_draw(GNT_WIDGET(box)); -} - -void gnt_box_remove_all(GntBox *box) -{ - g_list_foreach(box->list, (GFunc)gnt_widget_destroy, NULL); - g_list_free(box->list); - g_list_free(box->focus); - box->list = NULL; - box->focus = NULL; - GNT_WIDGET(box)->priv.width = 0; - GNT_WIDGET(box)->priv.height = 0; -} - -void gnt_box_readjust(GntBox *box) -{ - GList *iter; - GntWidget *wid; - int width, height; - - if (GNT_WIDGET(box)->parent != NULL) - return; - - for (iter = box->list; iter; iter = iter->next) - { - GntWidget *w = iter->data; - if (GNT_IS_BOX(w)) - gnt_box_readjust(GNT_BOX(w)); - else - { - GNT_WIDGET_UNSET_FLAGS(w, GNT_WIDGET_MAPPED); - w->priv.width = 0; - w->priv.height = 0; - } - } - - wid = GNT_WIDGET(box); - GNT_WIDGET_UNSET_FLAGS(wid, GNT_WIDGET_MAPPED); - wid->priv.width = 0; - wid->priv.height = 0; - - if (wid->parent == NULL) - { - g_list_free(box->focus); - box->focus = NULL; - box->active = NULL; - gnt_widget_size_request(wid); - gnt_widget_get_size(wid, &width, &height); - gnt_screen_resize_widget(wid, width, height); - find_focusable_widget(box); - } -} - -void gnt_box_set_fill(GntBox *box, gboolean fill) -{ - box->fill = fill; -} - -void gnt_box_move_focus(GntBox *box, int dir) -{ - GntWidget *now; - - if (box->active == NULL) - { - find_focusable_widget(box); - return; - } - - now = box->active; - - if (dir == 1) - find_next_focus(box); - else if (dir == -1) - find_prev_focus(box); - - if (now && now != box->active) - { - gnt_widget_set_focus(now, FALSE); - gnt_widget_set_focus(box->active, TRUE); - } - - if (GNT_WIDGET(box)->window) - gnt_widget_draw(GNT_WIDGET(box)); -} - -void gnt_box_give_focus_to_child(GntBox *box, GntWidget *widget) -{ - GList *find = g_list_find(box->focus, widget); - gpointer now = box->active; - if (find) - box->active = widget; - if (now && now != box->active) - { - gnt_widget_set_focus(now, FALSE); - gnt_widget_set_focus(box->active, TRUE); - } - - if (GNT_WIDGET(box)->window) - gnt_widget_draw(GNT_WIDGET(box)); -} - diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gntbox.h --- a/console/libgnt/gntbox.h Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,98 +0,0 @@ -#ifndef GNT_BOX_H -#define GNT_BOX_H - -#include "gnt.h" -#include "gntwidget.h" - -#define GNT_TYPE_BOX (gnt_box_get_gtype()) -#define GNT_BOX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNT_TYPE_BOX, GntBox)) -#define GNT_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GNT_TYPE_BOX, GntBoxClass)) -#define GNT_IS_BOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GNT_TYPE_BOX)) -#define GNT_IS_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GNT_TYPE_BOX)) -#define GNT_BOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GNT_TYPE_BOX, GntBoxClass)) - -typedef struct _GnBox GntBox; -typedef struct _GnBoxClass GntBoxClass; - -typedef enum -{ - /* These for vertical boxes */ - GNT_ALIGN_LEFT, - GNT_ALIGN_RIGHT, - - GNT_ALIGN_MID, - - /* These for horizontal boxes */ - GNT_ALIGN_TOP, - GNT_ALIGN_BOTTOM -} GntAlignment; - -struct _GnBox -{ - GntWidget parent; - - gboolean vertical; - gboolean homogeneous; - gboolean fill; - GList *list; /* List of widgets */ - - GntWidget *active; - int pad; /* Number of spaces to use between widgets */ - GntAlignment alignment; /* How are the widgets going to be aligned? */ - - char *title; - GList *focus; /* List of widgets to cycle focus (only valid for parent boxes) */ - - void (*gnt_reserved1)(void); - void (*gnt_reserved2)(void); - void (*gnt_reserved3)(void); - void (*gnt_reserved4)(void); -}; - -struct _GnBoxClass -{ - GntWidgetClass parent; - - void (*gnt_reserved1)(void); - void (*gnt_reserved2)(void); - void (*gnt_reserved3)(void); - void (*gnt_reserved4)(void); -}; - -G_BEGIN_DECLS - -GType gnt_box_get_gtype(void); - -#define gnt_vbox_new(homo) gnt_box_new(homo, TRUE) -#define gnt_hbox_new(homo) gnt_box_new(homo, FALSE) - -GntWidget *gnt_box_new(gboolean homo, gboolean vert); - -void gnt_box_add_widget(GntBox *box, GntWidget *widget); - -void gnt_box_set_title(GntBox *box, const char *title); - -void gnt_box_set_pad(GntBox *box, int pad); - -void gnt_box_set_toplevel(GntBox *box, gboolean set); - -void gnt_box_sync_children(GntBox *box); - -void gnt_box_set_alignment(GntBox *box, GntAlignment alignment); - -void gnt_box_remove(GntBox *box, GntWidget *widget); /* XXX: does NOT destroy widget */ - -void gnt_box_remove_all(GntBox *box); /* Removes AND destroys all the widgets in it */ - -void gnt_box_readjust(GntBox *box); - -void gnt_box_set_fill(GntBox *box, gboolean fill); - -void gnt_box_move_focus(GntBox *box, int dir); /* +1 to move forward, -1 for backward */ - -void gnt_box_give_focus_to_child(GntBox *box, GntWidget *widget); - -G_END_DECLS - -#endif /* GNT_BOX_H */ - diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gntbutton.c --- a/console/libgnt/gntbutton.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,136 +0,0 @@ -#include - -#include "gntbutton.h" -#include "gntutils.h" - -enum -{ - SIGS = 1, -}; - -static GntWidgetClass *parent_class = NULL; - -static void -gnt_button_draw(GntWidget *widget) -{ - GntButton *button = GNT_BUTTON(widget); - GntColorType type; - - if (gnt_widget_has_focus(widget)) - type = GNT_COLOR_HIGHLIGHT; - else - type = GNT_COLOR_NORMAL; - - wbkgdset(widget->window, '\0' | COLOR_PAIR(type)); - mvwaddstr(widget->window, 1, 2, button->priv->text); - - GNTDEBUG; -} - -static void -gnt_button_size_request(GntWidget *widget) -{ - GntButton *button = GNT_BUTTON(widget); - gnt_util_get_text_bound(button->priv->text, - &widget->priv.width, &widget->priv.height); - widget->priv.width += 4; - if (!GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER)) - widget->priv.height += 2; -} - -static void -gnt_button_map(GntWidget *widget) -{ - if (widget->priv.width == 0 || widget->priv.height == 0) - gnt_widget_size_request(widget); - GNTDEBUG; -} - -static gboolean -gnt_button_key_pressed(GntWidget *widget, const char *key) -{ - if (strcmp(key, GNT_KEY_ENTER) == 0) - { - gnt_widget_activate(widget); - return TRUE; - } - return FALSE; -} - -static gboolean -gnt_button_clicked(GntWidget *widget, GntMouseEvent event, int x, int y) -{ - if (event == GNT_LEFT_MOUSE_DOWN) { - gnt_widget_activate(widget); - return TRUE; - } - return FALSE; -} - -static void -gnt_button_class_init(GntWidgetClass *klass) -{ - parent_class = GNT_WIDGET_CLASS(klass); - parent_class->draw = gnt_button_draw; - parent_class->map = gnt_button_map; - parent_class->size_request = gnt_button_size_request; - parent_class->key_pressed = gnt_button_key_pressed; - parent_class->clicked = gnt_button_clicked; - - GNTDEBUG; -} - -static void -gnt_button_init(GTypeInstance *instance, gpointer class) -{ - GntWidget *widget = GNT_WIDGET(instance); - GntButton *button = GNT_BUTTON(instance); - button->priv = g_new0(GntButtonPriv, 1); - - GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_GROW_X); - - widget->priv.minw = 4; - widget->priv.minh = 3; - GNTDEBUG; -} - -/****************************************************************************** - * GntButton API - *****************************************************************************/ -GType -gnt_button_get_gtype(void) { - static GType type = 0; - - if(type == 0) { - static const GTypeInfo info = { - sizeof(GntButtonClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc)gnt_button_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof(GntButton), - 0, /* n_preallocs */ - gnt_button_init, /* instance_init */ - NULL /* value_table */ - }; - - type = g_type_register_static(GNT_TYPE_WIDGET, - "GntButton", - &info, 0); - } - - return type; -} - -GntWidget *gnt_button_new(const char *text) -{ - GntWidget *widget = g_object_new(GNT_TYPE_BUTTON, NULL); - GntButton *button = GNT_BUTTON(widget); - - button->priv->text = gnt_util_onscreen_fit_string(text, -1); - gnt_widget_set_take_focus(widget, TRUE); - - return widget; -} - diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gntbutton.h --- a/console/libgnt/gntbutton.h Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -#ifndef GNT_BUTTON_H -#define GNT_BUTTON_H - -#include -#include -#include "gnt.h" -#include "gntwidget.h" - -#define GNT_TYPE_BUTTON (gnt_button_get_gtype()) -#define GNT_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNT_TYPE_BUTTON, GntButton)) -#define GNT_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GNT_TYPE_BUTTON, GntButtonClass)) -#define GNT_IS_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GNT_TYPE_BUTTON)) -#define GNT_IS_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GNT_TYPE_BUTTON)) -#define GNT_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GNT_TYPE_BUTTON, GntButtonClass)) - -typedef struct _GnButton GntButton; -typedef struct _GnButtonPriv GntButtonPriv; -typedef struct _GnButtonClass GntButtonClass; - -struct _GnButtonPriv -{ - char *text; -}; - -struct _GnButton -{ - GntWidget parent; - - GntButtonPriv *priv; - - void (*gnt_reserved1)(void); - void (*gnt_reserved2)(void); - void (*gnt_reserved3)(void); - void (*gnt_reserved4)(void); -}; - -struct _GnButtonClass -{ - GntWidgetClass parent; - - void (*gnt_reserved1)(void); - void (*gnt_reserved2)(void); - void (*gnt_reserved3)(void); - void (*gnt_reserved4)(void); -}; - -G_BEGIN_DECLS - -GType gnt_button_get_gtype(void); - -GntWidget *gnt_button_new(const char *text); - -G_END_DECLS - -#endif /* GNT_BUTTON_H */ diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gntcheckbox.c --- a/console/libgnt/gntcheckbox.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,156 +0,0 @@ -#include "gntcheckbox.h" - -enum -{ - SIG_TOGGLED = 1, - SIGS, -}; - -static GntButtonClass *parent_class = NULL; -static guint signals[SIGS] = { 0 }; - -static void -gnt_check_box_draw(GntWidget *widget) -{ - GntCheckBox *cb = GNT_CHECK_BOX(widget); - GntColorType type; - char *text; - - if (gnt_widget_has_focus(widget)) - type = GNT_COLOR_HIGHLIGHT; - else - type = GNT_COLOR_NORMAL; - - wbkgdset(widget->window, '\0' | COLOR_PAIR(type)); - - text = g_strdup_printf("[%c]", cb->checked ? 'X' : ' '); - mvwaddstr(widget->window, 0, 0, text); - g_free(text); - - wbkgdset(widget->window, '\0' | COLOR_PAIR(GNT_COLOR_NORMAL)); - mvwaddstr(widget->window, 0, 4, GNT_BUTTON(cb)->priv->text); - - GNTDEBUG; -} - -static void -toggle_selection(GntWidget *widget) -{ - GNT_CHECK_BOX(widget)->checked = !GNT_CHECK_BOX(widget)->checked; - g_signal_emit(widget, signals[SIG_TOGGLED], 0); - gnt_widget_draw(widget); -} - -static gboolean -gnt_check_box_key_pressed(GntWidget *widget, const char *text) -{ - if (text[0] == ' ' && text[1] == '\0') - { - toggle_selection(widget); - return TRUE; - } - - return FALSE; -} - -static gboolean -gnt_check_box_clicked(GntWidget *widget, GntMouseEvent event, int x, int y) -{ - if (event == GNT_LEFT_MOUSE_DOWN) { - toggle_selection(widget); - return TRUE; - } - return FALSE; -} - -static void -gnt_check_box_class_init(GntCheckBoxClass *klass) -{ - GntWidgetClass *wclass = GNT_WIDGET_CLASS(klass); - - parent_class = GNT_BUTTON_CLASS(klass); - /*parent_class->destroy = gnt_check_box_destroy;*/ - wclass->draw = gnt_check_box_draw; - /*parent_class->map = gnt_check_box_map;*/ - /*parent_class->size_request = gnt_check_box_size_request;*/ - wclass->key_pressed = gnt_check_box_key_pressed; - wclass->clicked = gnt_check_box_clicked; - - signals[SIG_TOGGLED] = - g_signal_new("toggled", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GntCheckBoxClass, toggled), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - GNTDEBUG; -} - -static void -gnt_check_box_init(GTypeInstance *instance, gpointer class) -{ - GntWidget *widget = GNT_WIDGET(instance); - widget->priv.minh = 1; - widget->priv.minw = 4; - GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW); - GNTDEBUG; -} - -/****************************************************************************** - * GntCheckBox API - *****************************************************************************/ -GType -gnt_check_box_get_gtype(void) -{ - static GType type = 0; - - if(type == 0) - { - static const GTypeInfo info = { - sizeof(GntCheckBoxClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc)gnt_check_box_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof(GntCheckBox), - 0, /* n_preallocs */ - gnt_check_box_init, /* instance_init */ - NULL /* value_table */ - }; - - type = g_type_register_static(GNT_TYPE_BUTTON, - "GntCheckBox", - &info, 0); - } - - return type; -} - -GntWidget *gnt_check_box_new(const char *text) -{ - GntWidget *widget = g_object_new(GNT_TYPE_CHECK_BOX, NULL); - - GNT_BUTTON(widget)->priv->text = g_strdup(text); - gnt_widget_set_take_focus(widget, TRUE); - - return widget; -} - -void gnt_check_box_set_checked(GntCheckBox *box, gboolean set) -{ - if (set != box->checked) - { - box->checked = set; - g_signal_emit(box, signals[SIG_TOGGLED], 0); - } -} - -gboolean gnt_check_box_get_checked(GntCheckBox *box) -{ - return box->checked; -} - - - diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gntcheckbox.h --- a/console/libgnt/gntcheckbox.h Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -#ifndef GNT_CHECK_BOX_H -#define GNT_CHECK_BOX_H - -#include "gntbutton.h" -#include "gnt.h" -#include "gntcolors.h" -#include "gntkeys.h" - -#define GNT_TYPE_CHECK_BOX (gnt_check_box_get_gtype()) -#define GNT_CHECK_BOX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNT_TYPE_CHECK_BOX, GntCheckBox)) -#define GNT_CHECK_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GNT_TYPE_CHECK_BOX, GntCheckBoxClass)) -#define GNT_IS_CHECK_BOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GNT_TYPE_CHECK_BOX)) -#define GNT_IS_CHECK_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GNT_TYPE_CHECK_BOX)) -#define GNT_CHECK_BOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GNT_TYPE_CHECK_BOX, GntCheckBoxClass)) - -#define GNT_CHECK_BOX_FLAGS(obj) (GNT_CHECK_BOX(obj)->priv.flags) -#define GNT_CHECK_BOX_SET_FLAGS(obj, flags) (GNT_CHECK_BOX_FLAGS(obj) |= flags) -#define GNT_CHECK_BOX_UNSET_FLAGS(obj, flags) (GNT_CHECK_BOX_FLAGS(obj) &= ~(flags)) - -typedef struct _GnCheckBox GntCheckBox; -typedef struct _GnCheckBoxPriv GntCheckBoxPriv; -typedef struct _GnCheckBoxClass GntCheckBoxClass; - -struct _GnCheckBox -{ - GntButton parent; - gboolean checked; -}; - -struct _GnCheckBoxClass -{ - GntButtonClass parent; - - void (*toggled)(void); - - void (*gnt_reserved1)(void); - void (*gnt_reserved2)(void); - void (*gnt_reserved3)(void); - void (*gnt_reserved4)(void); -}; - -G_BEGIN_DECLS - -GType gnt_check_box_get_gtype(void); - -GntWidget *gnt_check_box_new(const char *text); - -void gnt_check_box_set_checked(GntCheckBox *box, gboolean set); - -gboolean gnt_check_box_get_checked(GntCheckBox *box); - -G_END_DECLS - -#endif /* GNT_CHECK_BOX_H */ diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gntclipboard.c --- a/console/libgnt/gntclipboard.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,74 +0,0 @@ -#include "gntclipboard.h" - -gchar *string; - -enum { - SIG_CLIPBOARD = 0, - SIGS -}; - -static guint signals[SIGS] = { 0 }; - -static void -gnt_clipboard_class_init(GntClipboardClass *klass) -{ - signals[SIG_CLIPBOARD] = - g_signal_new("clipboard_changed", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, G_TYPE_POINTER); - -} - -/****************************************************************************** - * GntClipboard API - *****************************************************************************/ - -void -gnt_clipboard_set_string(GntClipboard *clipboard, gchar *string) -{ - g_free(clipboard->string); - clipboard->string = g_strdup(string); - g_signal_emit(clipboard, signals[SIG_CLIPBOARD], 0, clipboard->string); -} - -gchar * -gnt_clipboard_get_string(GntClipboard *clipboard) -{ - return g_strdup(clipboard->string); -} - -static void gnt_clipboard_init(GTypeInstance *instance, gpointer class) { - GntClipboard *clipboard = GNT_CLIPBOARD(instance); - clipboard->string = g_strdup(""); -} - -GType -gnt_clipboard_get_gtype(void) -{ - static GType type = 0; - - if (type == 0) { - static const GTypeInfo info = { - sizeof(GntClipboardClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc)gnt_clipboard_class_init, - NULL, - NULL, /* class_data */ - sizeof(GntClipboard), - 0, /* n_preallocs */ - gnt_clipboard_init, /* instance_init */ - NULL /* value_table */ - }; - - type = g_type_register_static(G_TYPE_OBJECT, - "GntClipboard", - &info, 0); - } - - return type; -} diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gntclipboard.h --- a/console/libgnt/gntclipboard.h Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -#ifndef GNT_CLIPBOARD_H -#define GNT_CLIPBOARD_H - -#include -#include -#include - -#define GNT_TYPE_CLIPBOARD (gnt_clipboard_get_gtype()) -#define GNT_CLIPBOARD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNT_TYPE_CLIPBOARD, GntClipboard)) -#define GNT_CLIPBOARD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GNT_TYPE_CLIPBOARD, GntClipboardClass)) -#define GNT_IS_CLIPBOARD(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GNT_TYPE_CLIPBOARD)) -#define GNT_IS_CLIPBOARD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GNT_TYPE_CLIPBOARD)) -#define GNT_CLIPBOARD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GNT_TYPE_CLIPBOARD, GntClipboardClass)) - -#define GNTDEBUG g_printerr("%s\n", __FUNCTION__) - -typedef struct _GnClipboard GntClipboard; -typedef struct _GnClipboardClass GntClipboardClass; - -struct _GnClipboard -{ - GObject inherit; - gchar *string; -}; - -struct _GnClipboardClass -{ - GObjectClass parent; - - void (*gnt_reserved1)(void); - void (*gnt_reserved2)(void); - void (*gnt_reserved3)(void); - void (*gnt_reserved4)(void); -}; - -G_BEGIN_DECLS - -GType gnt_clipboard_get_gtype(void); - -gchar *gnt_clipboard_get_string(GntClipboard *); - -void gnt_clipboard_set_string(GntClipboard *, gchar *); - -G_END_DECLS - -#endif diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gntcolors.c --- a/console/libgnt/gntcolors.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,256 +0,0 @@ -#include "config.h" - -#include - -#include "gntcolors.h" -#include "gntstyle.h" - -#include - -#include -#include - -static struct -{ - short r, g, b; -} colors[GNT_TOTAL_COLORS]; - -static void -backup_colors() -{ - short i; - for (i = 0; i < GNT_TOTAL_COLORS; i++) - { - color_content(i, &colors[i].r, - &colors[i].g, &colors[i].b); - } -} - -static gboolean -can_use_custom_color() -{ - return (gnt_style_get_bool(GNT_STYLE_COLOR, FALSE) && can_change_color()); -} - -static void -restore_colors() -{ - short i; - for (i = 0; i < GNT_TOTAL_COLORS; i++) - { - init_color(i, colors[i].r, - colors[i].g, colors[i].b); - } -} - -void gnt_init_colors() -{ - static gboolean init = FALSE; - int defaults; - - if (init) - return; - init = TRUE; - - start_color(); - defaults = use_default_colors(); - - if (can_use_custom_color()) - { - backup_colors(); - - /* Do some init_color()s */ - init_color(GNT_COLOR_BLACK, 0, 0, 0); - init_color(GNT_COLOR_RED, 1000, 0, 0); - init_color(GNT_COLOR_GREEN, 0, 1000, 0); - init_color(GNT_COLOR_BLUE, 250, 250, 700); - init_color(GNT_COLOR_WHITE, 1000, 1000, 1000); - init_color(GNT_COLOR_GRAY, 699, 699, 699); - init_color(GNT_COLOR_DARK_GRAY, 256, 256, 256); - - /* Now some init_pair()s */ - init_pair(GNT_COLOR_NORMAL, GNT_COLOR_BLACK, GNT_COLOR_WHITE); - init_pair(GNT_COLOR_HIGHLIGHT, GNT_COLOR_WHITE, GNT_COLOR_BLUE); - init_pair(GNT_COLOR_SHADOW, GNT_COLOR_BLACK, GNT_COLOR_DARK_GRAY); - - init_pair(GNT_COLOR_TITLE, GNT_COLOR_WHITE, GNT_COLOR_BLUE); - init_pair(GNT_COLOR_TITLE_D, GNT_COLOR_WHITE, GNT_COLOR_GRAY); - - init_pair(GNT_COLOR_TEXT_NORMAL, GNT_COLOR_WHITE, GNT_COLOR_BLUE); - init_pair(GNT_COLOR_HIGHLIGHT_D, GNT_COLOR_BLACK, GNT_COLOR_GRAY); - init_pair(GNT_COLOR_DISABLED, GNT_COLOR_GRAY, GNT_COLOR_WHITE); - init_pair(GNT_COLOR_URGENT, GNT_COLOR_WHITE, GNT_COLOR_RED); - } - else - { - int bg; - - if (defaults == OK) { - init_pair(GNT_COLOR_NORMAL, -1, -1); - bg = -1; - } else { - init_pair(GNT_COLOR_NORMAL, COLOR_BLACK, COLOR_WHITE); - bg = COLOR_WHITE; - } - init_pair(GNT_COLOR_DISABLED, COLOR_YELLOW, bg); - init_pair(GNT_COLOR_URGENT, COLOR_GREEN, bg); - - init_pair(GNT_COLOR_HIGHLIGHT, COLOR_WHITE, COLOR_BLUE); - init_pair(GNT_COLOR_SHADOW, COLOR_BLACK, COLOR_BLACK); - init_pair(GNT_COLOR_TITLE, COLOR_WHITE, COLOR_BLUE); - init_pair(GNT_COLOR_TITLE_D, COLOR_WHITE, COLOR_BLACK); - init_pair(GNT_COLOR_TEXT_NORMAL, COLOR_WHITE, COLOR_BLUE); - init_pair(GNT_COLOR_HIGHLIGHT_D, COLOR_CYAN, COLOR_BLACK); - } -} - -void -gnt_uninit_colors() -{ - if (can_use_custom_color()) - restore_colors(); -} - -static int -get_color(char *key) -{ - int color; - gboolean custom = can_use_custom_color(); - - key = g_strstrip(key); - - if (strcmp(key, "black") == 0) - color = custom ? GNT_COLOR_BLACK : COLOR_BLACK; - else if (strcmp(key, "red") == 0) - color = custom ? GNT_COLOR_RED : COLOR_RED; - else if (strcmp(key, "green") == 0) - color = custom ? GNT_COLOR_GREEN : COLOR_GREEN; - else if (strcmp(key, "blue") == 0) - color = custom ? GNT_COLOR_BLUE : COLOR_BLUE; - else if (strcmp(key, "white") == 0) - color = custom ? GNT_COLOR_WHITE : COLOR_WHITE; - else if (strcmp(key, "gray") == 0) - color = custom ? GNT_COLOR_GRAY : COLOR_YELLOW; /* eh? */ - else if (strcmp(key, "darkgray") == 0) - color = custom ? GNT_COLOR_DARK_GRAY : COLOR_BLACK; - else if (strcmp(key, "magenta") == 0) - color = COLOR_MAGENTA; - else if (strcmp(key, "cyan") == 0) - color = COLOR_CYAN; - else - color = -1; - return color; -} - -#if GLIB_CHECK_VERSION(2,6,0) -void gnt_colors_parse(GKeyFile *kfile) -{ - GError *error = NULL; - gsize nkeys; - char **keys = g_key_file_get_keys(kfile, "colors", &nkeys, &error); - - if (error) - { - g_printerr("GntColors: %s\n", error->message); - g_error_free(error); - error = NULL; - } - else if (nkeys) - { - gnt_init_colors(); - while (nkeys--) - { - gsize len; - gchar *key = keys[nkeys]; - char **list = g_key_file_get_string_list(kfile, "colors", key, &len, NULL); - if (len == 3) - { - int r = atoi(list[0]); - int g = atoi(list[1]); - int b = atoi(list[2]); - int color = -1; - - key = g_ascii_strdown(key, -1); - color = get_color(key); - g_free(key); - if (color == -1) - continue; - - init_color(color, r, g, b); - } - g_strfreev(list); - } - - g_strfreev(keys); - } - - gnt_color_pairs_parse(kfile); -} - -void gnt_color_pairs_parse(GKeyFile *kfile) -{ - GError *error = NULL; - gsize nkeys; - char **keys = g_key_file_get_keys(kfile, "colorpairs", &nkeys, &error); - - if (error) - { - g_printerr("GntColors: %s\n", error->message); - g_error_free(error); - return; - } - else if (nkeys) - gnt_init_colors(); - - while (nkeys--) - { - gsize len; - gchar *key = keys[nkeys]; - char **list = g_key_file_get_string_list(kfile, "colorpairs", key, &len, NULL); - if (len == 2) - { - GntColorType type = 0; - gchar *fgc = g_ascii_strdown(list[0], -1); - gchar *bgc = g_ascii_strdown(list[1], -1); - int fg = get_color(fgc); - int bg = get_color(bgc); - g_free(fgc); - g_free(bgc); - if (fg == -1 || bg == -1) - continue; - - key = g_ascii_strdown(key, -1); - - if (strcmp(key, "normal") == 0) - type = GNT_COLOR_NORMAL; - else if (strcmp(key, "highlight") == 0) - type = GNT_COLOR_HIGHLIGHT; - else if (strcmp(key, "highlightd") == 0) - type = GNT_COLOR_HIGHLIGHT_D; - else if (strcmp(key, "shadow") == 0) - type = GNT_COLOR_SHADOW; - else if (strcmp(key, "title") == 0) - type = GNT_COLOR_TITLE; - else if (strcmp(key, "titled") == 0) - type = GNT_COLOR_TITLE_D; - else if (strcmp(key, "text") == 0) - type = GNT_COLOR_TEXT_NORMAL; - else if (strcmp(key, "disabled") == 0) - type = GNT_COLOR_DISABLED; - else if (strcmp(key, "urgent") == 0) - type = GNT_COLOR_URGENT; - else { - g_free(key); - continue; - } - g_free(key); - - init_pair(type, fg, bg); - } - g_strfreev(list); - } - - g_strfreev(keys); -} - -#endif /* GKeyFile */ diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gntcolors.h --- a/console/libgnt/gntcolors.h Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -#ifndef GNT_COLORS_H -#define GNT_COLORS_H - -#include - -typedef enum -{ - GNT_COLOR_NORMAL = 1, - GNT_COLOR_HIGHLIGHT, /* eg. when a button is selected */ - GNT_COLOR_DISABLED, /* eg. when a button is disabled */ - GNT_COLOR_HIGHLIGHT_D, /* eg. when a button is selected, but some other window is in focus */ - GNT_COLOR_TEXT_NORMAL, - GNT_COLOR_TEXT_INACTIVE, /* when the entry is out of focus */ - GNT_COLOR_MNEMONIC, - GNT_COLOR_MNEMONIC_D, - GNT_COLOR_SHADOW, - GNT_COLOR_TITLE, - GNT_COLOR_TITLE_D, - GNT_COLOR_URGENT, /* this is for the 'urgent' windows */ - GNT_COLORS -} GntColorType; - -enum -{ - GNT_COLOR_BLACK = 0, - GNT_COLOR_RED, - GNT_COLOR_GREEN, - GNT_COLOR_BLUE, - GNT_COLOR_WHITE, - GNT_COLOR_GRAY, - GNT_COLOR_DARK_GRAY, - GNT_TOTAL_COLORS -}; - -/* populate some default colors */ -void gnt_init_colors(void); - -void gnt_uninit_colors(void); - -#if GLIB_CHECK_VERSION(2,6,0) -void gnt_colors_parse(GKeyFile *kfile); - -void gnt_color_pairs_parse(GKeyFile *kfile); -#endif - -#endif diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gntcombobox.c --- a/console/libgnt/gntcombobox.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,324 +0,0 @@ -#include "gntbox.h" -#include "gntcombobox.h" -#include "gnttree.h" -#include "gntmarshal.h" -#include "gntutils.h" - -#include - -enum -{ - SIG_SELECTION_CHANGED, - SIGS, -}; - -static GntWidgetClass *parent_class = NULL; -static guint signals[SIGS] = { 0 }; -static void (*widget_lost_focus)(GntWidget *widget); - -static void -set_selection(GntComboBox *box, gpointer key) -{ - if (box->selected != key) - { - /* XXX: make sure the key actually does exist */ - gpointer old = box->selected; - box->selected = key; - if (GNT_WIDGET(box)->window) - gnt_widget_draw(GNT_WIDGET(box)); - if (box->dropdown) - gnt_tree_set_selected(GNT_TREE(box->dropdown), key); - g_signal_emit(box, signals[SIG_SELECTION_CHANGED], 0, old, key); - } -} - -static void -hide_popup(GntComboBox *box, gboolean set) -{ - gnt_widget_set_size(box->dropdown, - box->dropdown->priv.width - 1, box->dropdown->priv.height); - if (set) - set_selection(box, gnt_tree_get_selection_data(GNT_TREE(box->dropdown))); - else - gnt_tree_set_selected(GNT_TREE(box->dropdown), box->selected); - gnt_widget_hide(box->dropdown->parent); -} - -static void -gnt_combo_box_draw(GntWidget *widget) -{ - GntComboBox *box = GNT_COMBO_BOX(widget); - char *text = NULL, *s; - GntColorType type; - int len; - - if (box->dropdown && box->selected) - text = gnt_tree_get_selection_text(GNT_TREE(box->dropdown)); - - if (text == NULL) - text = g_strdup(""); - - if (gnt_widget_has_focus(widget)) - type = GNT_COLOR_HIGHLIGHT; - else - type = GNT_COLOR_NORMAL; - - wbkgdset(widget->window, '\0' | COLOR_PAIR(type)); - - s = (char*)gnt_util_onscreen_width_to_pointer(text, widget->priv.width - 4, &len); - *s = '\0'; - - mvwaddstr(widget->window, 1, 1, text); - whline(widget->window, ' ' | COLOR_PAIR(type), widget->priv.width - 4 - len); - mvwaddch(widget->window, 1, widget->priv.width - 3, ACS_VLINE | COLOR_PAIR(GNT_COLOR_NORMAL)); - mvwaddch(widget->window, 1, widget->priv.width - 2, ACS_DARROW | COLOR_PAIR(GNT_COLOR_NORMAL)); - - g_free(text); - GNTDEBUG; -} - -static void -gnt_combo_box_size_request(GntWidget *widget) -{ - if (!GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_MAPPED)) - { - GntWidget *dd = GNT_COMBO_BOX(widget)->dropdown; - gnt_widget_size_request(dd); - widget->priv.height = 3; /* For now, a combobox will have border */ - widget->priv.width = MAX(10, dd->priv.width + 4); - } -} - -static void -gnt_combo_box_map(GntWidget *widget) -{ - if (widget->priv.width == 0 || widget->priv.height == 0) - gnt_widget_size_request(widget); - GNTDEBUG; -} - -static void -popup_dropdown(GntComboBox *box) -{ - GntWidget *widget = GNT_WIDGET(box); - GntWidget *parent = box->dropdown->parent; - int height = g_list_length(GNT_TREE(box->dropdown)->list); - int y = widget->priv.y + widget->priv.height - 1; - gnt_widget_set_size(box->dropdown, widget->priv.width, height + 2); - - if (y + height + 2 >= getmaxy(stdscr)) - y = widget->priv.y - height - 1; - gnt_widget_set_position(parent, widget->priv.x, y); - if (parent->window) - { - mvwin(parent->window, y, widget->priv.x); - wresize(parent->window, height+2, widget->priv.width); - } - parent->priv.width = widget->priv.width; - parent->priv.height = height + 2; - - GNT_WIDGET_UNSET_FLAGS(parent, GNT_WIDGET_INVISIBLE); - gnt_widget_draw(parent); -} - -static gboolean -gnt_combo_box_key_pressed(GntWidget *widget, const char *text) -{ - GntComboBox *box = GNT_COMBO_BOX(widget); - if (GNT_WIDGET_IS_FLAG_SET(box->dropdown->parent, GNT_WIDGET_MAPPED)) - { - if (text[1] == 0) - { - switch (text[0]) - { - case '\r': - case '\t': - hide_popup(box, TRUE); - return TRUE; - case 27: - hide_popup(box, FALSE); - return TRUE; - } - } - if (gnt_widget_key_pressed(box->dropdown, text)) - return TRUE; - } - else - { - if (text[0] == 27) - { - if (strcmp(text, GNT_KEY_UP) == 0 || - strcmp(text, GNT_KEY_DOWN) == 0) - { - popup_dropdown(box); - return TRUE; - } - } - } - - return FALSE; -} - -static void -gnt_combo_box_destroy(GntWidget *widget) -{ - gnt_widget_destroy(GNT_COMBO_BOX(widget)->dropdown->parent); -} - -static void -gnt_combo_box_lost_focus(GntWidget *widget) -{ - GntComboBox *combo = GNT_COMBO_BOX(widget); - if (GNT_WIDGET_IS_FLAG_SET(combo->dropdown->parent, GNT_WIDGET_MAPPED)) - hide_popup(combo, FALSE); - widget_lost_focus(widget); -} - -static gboolean -gnt_combo_box_clicked(GntWidget *widget, GntMouseEvent event, int x, int y) -{ - GntComboBox *box = GNT_COMBO_BOX(widget); - gboolean dshowing = GNT_WIDGET_IS_FLAG_SET(box->dropdown->parent, GNT_WIDGET_MAPPED); - - if (event == GNT_MOUSE_SCROLL_UP) { - if (dshowing) - gnt_widget_key_pressed(box->dropdown, GNT_KEY_UP); - } else if (event == GNT_MOUSE_SCROLL_DOWN) { - if (dshowing) - gnt_widget_key_pressed(box->dropdown, GNT_KEY_DOWN); - } else if (event == GNT_LEFT_MOUSE_DOWN) { - if (dshowing) { - hide_popup(box, TRUE); - } else { - popup_dropdown(GNT_COMBO_BOX(widget)); - } - } else - return FALSE; - return TRUE; -} - -static void -gnt_combo_box_size_changed(GntWidget *widget, int oldw, int oldh) -{ - GntComboBox *box = GNT_COMBO_BOX(widget); - gnt_widget_set_size(box->dropdown, widget->priv.width - 1, box->dropdown->priv.height); -} - -static void -gnt_combo_box_class_init(GntComboBoxClass *klass) -{ - parent_class = GNT_WIDGET_CLASS(klass); - - parent_class->destroy = gnt_combo_box_destroy; - parent_class->draw = gnt_combo_box_draw; - parent_class->map = gnt_combo_box_map; - parent_class->size_request = gnt_combo_box_size_request; - parent_class->key_pressed = gnt_combo_box_key_pressed; - parent_class->clicked = gnt_combo_box_clicked; - parent_class->size_changed = gnt_combo_box_size_changed; - - widget_lost_focus = parent_class->lost_focus; - parent_class->lost_focus = gnt_combo_box_lost_focus; - - signals[SIG_SELECTION_CHANGED] = - g_signal_new("selection-changed", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - gnt_closure_marshal_VOID__POINTER_POINTER, - G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER); - - GNTDEBUG; -} - -static void -gnt_combo_box_init(GTypeInstance *instance, gpointer class) -{ - GntWidget *box; - GntWidget *widget = GNT_WIDGET(instance); - GntComboBox *combo = GNT_COMBO_BOX(instance); - - GNT_WIDGET_SET_FLAGS(GNT_WIDGET(instance), - GNT_WIDGET_GROW_X | GNT_WIDGET_CAN_TAKE_FOCUS | GNT_WIDGET_NO_SHADOW); - combo->dropdown = gnt_tree_new(); - - box = gnt_box_new(FALSE, FALSE); - GNT_WIDGET_SET_FLAGS(box, GNT_WIDGET_NO_SHADOW | GNT_WIDGET_NO_BORDER | GNT_WIDGET_TRANSIENT); - gnt_box_set_pad(GNT_BOX(box), 0); - gnt_box_add_widget(GNT_BOX(box), combo->dropdown); - - widget->priv.minw = 4; - widget->priv.minh = 3; - GNTDEBUG; -} - -/****************************************************************************** - * GntComboBox API - *****************************************************************************/ -GType -gnt_combo_box_get_gtype(void) -{ - static GType type = 0; - - if(type == 0) - { - static const GTypeInfo info = { - sizeof(GntComboBoxClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc)gnt_combo_box_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof(GntComboBox), - 0, /* n_preallocs */ - gnt_combo_box_init, /* instance_init */ - NULL /* value_table */ - }; - - type = g_type_register_static(GNT_TYPE_WIDGET, - "GntComboBox", - &info, 0); - } - - return type; -} - -GntWidget *gnt_combo_box_new() -{ - GntWidget *widget = g_object_new(GNT_TYPE_COMBO_BOX, NULL); - - return widget; -} - -void gnt_combo_box_add_data(GntComboBox *box, gpointer key, const char *text) -{ - gnt_tree_add_row_last(GNT_TREE(box->dropdown), key, - gnt_tree_create_row(GNT_TREE(box->dropdown), text), NULL); - if (box->selected == NULL) - set_selection(box, key); -} - -gpointer gnt_combo_box_get_selected_data(GntComboBox *box) -{ - return box->selected; -} - -void gnt_combo_box_set_selected(GntComboBox *box, gpointer key) -{ - set_selection(box, key); -} - -void gnt_combo_box_remove(GntComboBox *box, gpointer key) -{ - gnt_tree_remove(GNT_TREE(box->dropdown), key); - if (box->selected == key) - set_selection(box, NULL); -} - -void gnt_combo_box_remove_all(GntComboBox *box) -{ - gnt_tree_remove_all(GNT_TREE(box->dropdown)); - set_selection(box, NULL); -} - diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gntcombobox.h --- a/console/libgnt/gntcombobox.h Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -#ifndef GNT_COMBO_BOX_H -#define GNT_COMBO_BOX_H - -#include "gnt.h" -#include "gntcolors.h" -#include "gntkeys.h" -#include "gntwidget.h" - -#define GNT_TYPE_COMBO_BOX (gnt_combo_box_get_gtype()) -#define GNT_COMBO_BOX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNT_TYPE_COMBO_BOX, GntComboBox)) -#define GNT_COMBO_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GNT_TYPE_COMBO_BOX, GntComboBoxClass)) -#define GNT_IS_COMBO_BOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GNT_TYPE_COMBO_BOX)) -#define GNT_IS_COMBO_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GNT_TYPE_COMBO_BOX)) -#define GNT_COMBO_BOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GNT_TYPE_COMBO_BOX, GntComboBoxClass)) - -#define GNT_COMBO_BOX_FLAGS(obj) (GNT_COMBO_BOX(obj)->priv.flags) -#define GNT_COMBO_BOX_SET_FLAGS(obj, flags) (GNT_COMBO_BOX_FLAGS(obj) |= flags) -#define GNT_COMBO_BOX_UNSET_FLAGS(obj, flags) (GNT_COMBO_BOX_FLAGS(obj) &= ~(flags)) - -typedef struct _GnComboBox GntComboBox; -typedef struct _GnComboBoxPriv GntComboBoxPriv; -typedef struct _GnComboBoxClass GntComboBoxClass; - -struct _GnComboBox -{ - GntWidget parent; - - GntWidget *dropdown; /* This is a GntTree */ - - void *selected; /* Currently selected key */ -}; - -struct _GnComboBoxClass -{ - GntWidgetClass parent; - - void (*gnt_reserved1)(void); - void (*gnt_reserved2)(void); - void (*gnt_reserved3)(void); - void (*gnt_reserved4)(void); -}; - -G_BEGIN_DECLS - -GType gnt_combo_box_get_gtype(void); - -GntWidget *gnt_combo_box_new(void); - -void gnt_combo_box_add_data(GntComboBox *box, gpointer key, const char *text); - -void gnt_combo_box_remove(GntComboBox *box, gpointer key); - -void gnt_combo_box_remove_all(GntComboBox *box); - -gpointer gnt_combo_box_get_selected_data(GntComboBox *box); - -void gnt_combo_box_set_selected(GntComboBox *box, gpointer key); - -G_END_DECLS - -#endif /* GNT_COMBO_BOX_H */ diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gntentry.c --- a/console/libgnt/gntentry.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,932 +0,0 @@ -#include -#include - -#include "gntbox.h" -#include "gntentry.h" -#include "gntstyle.h" -#include "gnttree.h" -#include "gntutils.h" - -enum -{ - SIG_TEXT_CHANGED, - SIGS, -}; -static guint signals[SIGS] = { 0 }; - -static GntWidgetClass *parent_class = NULL; - -static void gnt_entry_set_text_internal(GntEntry *entry, const char *text); - -static void -destroy_suggest(GntEntry *entry) -{ - if (entry->ddown) - { - gnt_widget_destroy(entry->ddown->parent); - entry->ddown = NULL; - } -} - -static char * -get_beginning_of_word(GntEntry *entry) -{ - char *s = entry->cursor; - while (s > entry->start) - { - char *t = g_utf8_find_prev_char(entry->start, s); - if (isspace(*t)) - break; - s = t; - } - return s; -} - -static gboolean -show_suggest_dropdown(GntEntry *entry) -{ - char *suggest = NULL; - int len; - int offset = 0, x, y; - int count = 0; - GList *iter; - - if (entry->word) - { - char *s = get_beginning_of_word(entry); - suggest = g_strndup(s, entry->cursor - s); - if (entry->scroll < s) - offset = gnt_util_onscreen_width(entry->scroll, s); - } - else - suggest = g_strdup(entry->start); - len = strlen(suggest); /* Don't need to use the utf8-function here */ - - if (entry->ddown == NULL) - { - GntWidget *box = gnt_vbox_new(FALSE); - entry->ddown = gnt_tree_new(); - gnt_tree_set_compare_func(GNT_TREE(entry->ddown), (GCompareFunc)g_utf8_collate); - gnt_box_add_widget(GNT_BOX(box), entry->ddown); - /* XXX: Connect to the "activate" signal for the dropdown tree */ - - GNT_WIDGET_SET_FLAGS(box, GNT_WIDGET_TRANSIENT); - - gnt_widget_get_position(GNT_WIDGET(entry), &x, &y); - x += offset; - y++; - if (y + 10 >= getmaxy(stdscr)) - y -= 11; - gnt_widget_set_position(box, x, y); - } - else - gnt_tree_remove_all(GNT_TREE(entry->ddown)); - - for (count = 0, iter = entry->suggests; iter; iter = iter->next) - { - const char *text = iter->data; - if (g_ascii_strncasecmp(suggest, text, len) == 0 && strlen(text) >= len) - { - gnt_tree_add_row_after(GNT_TREE(entry->ddown), (gpointer)text, - gnt_tree_create_row(GNT_TREE(entry->ddown), text), - NULL, NULL); - count++; - } - } - g_free(suggest); - - if (count == 0) - { - destroy_suggest(entry); - return FALSE; - } - - gnt_widget_draw(entry->ddown->parent); - return TRUE; -} - -static void -gnt_entry_draw(GntWidget *widget) -{ - GntEntry *entry = GNT_ENTRY(widget); - int stop; - gboolean focus; - - if ((focus = gnt_widget_has_focus(widget))) - wbkgdset(widget->window, '\0' | COLOR_PAIR(GNT_COLOR_TEXT_NORMAL)); - else - wbkgdset(widget->window, '\0' | COLOR_PAIR(GNT_COLOR_HIGHLIGHT_D)); - - if (entry->masked) - { - mvwhline(widget->window, 0, 0, gnt_ascii_only() ? '*' : ACS_BULLET, - g_utf8_pointer_to_offset(entry->scroll, entry->end)); - } - else - mvwprintw(widget->window, 0, 0, "%s", entry->scroll); - - stop = gnt_util_onscreen_width(entry->scroll, entry->end); - if (stop < widget->priv.width) - whline(widget->window, ENTRY_CHAR, widget->priv.width - stop); - - if (focus) - mvwchgat(widget->window, 0, gnt_util_onscreen_width(entry->scroll, entry->cursor), - 1, A_REVERSE, GNT_COLOR_TEXT_NORMAL, NULL); - - GNTDEBUG; -} - -static void -gnt_entry_size_request(GntWidget *widget) -{ - if (!GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_MAPPED)) - { - widget->priv.height = 1; - widget->priv.width = 20; - } -} - -static void -gnt_entry_map(GntWidget *widget) -{ - if (widget->priv.width == 0 || widget->priv.height == 0) - gnt_widget_size_request(widget); - GNTDEBUG; -} - -static void -entry_redraw(GntWidget *widget) -{ - gnt_entry_draw(widget); - gnt_widget_queue_update(widget); -} - -static void -entry_text_changed(GntEntry *entry) -{ - g_signal_emit(entry, signals[SIG_TEXT_CHANGED], 0); -} - -static gboolean -move_back(GntBindable *bind, GList *null) -{ - GntEntry *entry = GNT_ENTRY(bind); - if (entry->cursor <= entry->start) - return FALSE; - entry->cursor = g_utf8_find_prev_char(entry->start, entry->cursor); - if (entry->cursor < entry->scroll) - entry->scroll = entry->cursor; - entry_redraw(GNT_WIDGET(entry)); - return TRUE; -} - -static gboolean -move_forward(GntBindable *bind, GList *list) -{ - GntEntry *entry = GNT_ENTRY(bind); - if (entry->cursor >= entry->end) - return FALSE; - entry->cursor = g_utf8_find_next_char(entry->cursor, NULL); - while (gnt_util_onscreen_width(entry->scroll, entry->cursor) >= GNT_WIDGET(entry)->priv.width) - entry->scroll = g_utf8_find_next_char(entry->scroll, NULL); - entry_redraw(GNT_WIDGET(entry)); - return TRUE; -} - -static gboolean -backspace(GntBindable *bind, GList *null) -{ - int len; - GntEntry *entry = GNT_ENTRY(bind); - - if (entry->cursor <= entry->start) - return TRUE; - - len = entry->cursor - g_utf8_find_prev_char(entry->start, entry->cursor); - entry->cursor -= len; - memmove(entry->cursor, entry->cursor + len, entry->end - entry->cursor); - entry->end -= len; - - if (entry->scroll > entry->start) - entry->scroll = g_utf8_find_prev_char(entry->start, entry->scroll); - - entry_redraw(GNT_WIDGET(entry)); - if (entry->ddown) - show_suggest_dropdown(entry); - entry_text_changed(entry); - return TRUE; -} - -static gboolean -delkey(GntBindable *bind, GList *null) -{ - int len; - GntEntry *entry = GNT_ENTRY(bind); - - if (entry->cursor >= entry->end) - return FALSE; - - len = g_utf8_find_next_char(entry->cursor, NULL) - entry->cursor; - memmove(entry->cursor, entry->cursor + len, entry->end - entry->cursor - len + 1); - entry->end -= len; - entry_redraw(GNT_WIDGET(entry)); - - if (entry->ddown) - show_suggest_dropdown(entry); - entry_text_changed(entry); - return TRUE; -} - -static gboolean -move_start(GntBindable *bind, GList *null) -{ - GntEntry *entry = GNT_ENTRY(bind); - entry->scroll = entry->cursor = entry->start; - entry_redraw(GNT_WIDGET(entry)); - return TRUE; -} - -static gboolean -move_end(GntBindable *bind, GList *null) -{ - GntEntry *entry = GNT_ENTRY(bind); - entry->cursor = entry->end; - /* This should be better than this */ - while (gnt_util_onscreen_width(entry->scroll, entry->cursor) >= GNT_WIDGET(entry)->priv.width) - entry->scroll = g_utf8_find_next_char(entry->scroll, NULL); - entry_redraw(GNT_WIDGET(entry)); - return TRUE; -} - -static gboolean -history_prev(GntBindable *bind, GList *null) -{ - GntEntry *entry = GNT_ENTRY(bind); - if (entry->histlength && entry->history->prev) - { - entry->history = entry->history->prev; - gnt_entry_set_text_internal(entry, entry->history->data); - destroy_suggest(entry); - entry_text_changed(entry); - - return TRUE; - } - return FALSE; -} - -static gboolean -history_next(GntBindable *bind, GList *null) -{ - GntEntry *entry = GNT_ENTRY(bind); - if (entry->histlength && entry->history->next) - { - if (entry->history->prev == NULL) - { - /* Save the current contents */ - char *text = g_strdup(gnt_entry_get_text(entry)); - g_free(entry->history->data); - entry->history->data = text; - } - - entry->history = entry->history->next; - gnt_entry_set_text_internal(entry, entry->history->data); - destroy_suggest(entry); - entry_text_changed(entry); - - return TRUE; - } - return FALSE; -} - -static gboolean -clipboard_paste(GntBindable *bind, GList *n) -{ - GntEntry *entry = GNT_ENTRY(bind); - gchar *i, *text, *a, *all; - text = i = gnt_get_clipboard_string(); - while (*i != '\0') { - i = g_utf8_next_char(i); - if (*i == '\r' || *i == '\n') - *i = ' '; - } - a = g_strndup(entry->start, entry->cursor - entry->start); - all = g_strconcat(a, text, entry->cursor, NULL); - gnt_entry_set_text_internal(entry, all); - g_free(a); - g_free(text); - g_free(all); - return TRUE; -} - -static gboolean -suggest_show(GntBindable *bind, GList *null) -{ - return show_suggest_dropdown(GNT_ENTRY(bind)); -} - -static gboolean -suggest_next(GntBindable *bind, GList *null) -{ - GntEntry *entry = GNT_ENTRY(bind); - if (entry->ddown) { - gnt_bindable_perform_action_named(GNT_BINDABLE(entry->ddown), "move-down", NULL); - return TRUE; - } - return FALSE; -} - -static gboolean -suggest_prev(GntBindable *bind, GList *null) -{ - GntEntry *entry = GNT_ENTRY(bind); - if (entry->ddown) { - gnt_bindable_perform_action_named(GNT_BINDABLE(entry->ddown), "move-up", NULL); - return TRUE; - } - return FALSE; -} - -static gboolean -del_to_home(GntBindable *bind, GList *null) -{ - GntEntry *entry = GNT_ENTRY(bind); - if (entry->cursor <= entry->start) - return TRUE; - memmove(entry->start, entry->cursor, entry->end - entry->cursor); - entry->end -= (entry->cursor - entry->start); - entry->cursor = entry->scroll = entry->start; - memset(entry->end, '\0', entry->buffer - (entry->end - entry->start)); - entry_redraw(GNT_WIDGET(bind)); - entry_text_changed(entry); - return TRUE; -} - -static gboolean -del_to_end(GntBindable *bind, GList *null) -{ - GntEntry *entry = GNT_ENTRY(bind); - if (entry->end <= entry->cursor) - return TRUE; - entry->end = entry->cursor; - memset(entry->end, '\0', entry->buffer - (entry->end - entry->start)); - entry_redraw(GNT_WIDGET(bind)); - entry_text_changed(entry); - return TRUE; -} - -#define SAME(a,b) ((g_unichar_isalpha(a) && g_unichar_isalpha(b)) || \ - (g_unichar_isdigit(a) && g_unichar_isdigit(b)) || \ - (g_unichar_isspace(a) && g_unichar_isspace(b)) || \ - (g_unichar_iswide(a) && g_unichar_iswide(b))) - -static const char * -begin_word(const char *text, const char *begin) -{ - gunichar ch = 0; - while (text > begin && (!*text || g_unichar_isspace(g_utf8_get_char(text)))) - text = g_utf8_find_prev_char(begin, text); - ch = g_utf8_get_char(text); - while ((text = g_utf8_find_prev_char(begin, text)) >= begin) { - gunichar cur = g_utf8_get_char(text); - if (!SAME(ch, cur)) - break; - } - - return (text ? g_utf8_find_next_char(text, NULL) : begin); -} - -static const char * -next_begin_word(const char *text, const char *end) -{ - gunichar ch = 0; - ch = g_utf8_get_char(text); - while ((text = g_utf8_find_next_char(text, end)) != NULL && text <= end) { - gunichar cur = g_utf8_get_char(text); - if (!SAME(ch, cur)) - break; - } - - while (text && text < end && g_unichar_isspace(g_utf8_get_char(text))) - text = g_utf8_find_next_char(text, end); - return (text ? text : end); -} - -#undef SAME -static gboolean -move_back_word(GntBindable *bind, GList *null) -{ - GntEntry *entry = GNT_ENTRY(bind); - const char *iter = g_utf8_find_prev_char(entry->start, entry->cursor); - - if (iter < entry->start) - return TRUE; - iter = begin_word(iter, entry->start); - entry->cursor = (char*)iter; - if (entry->cursor < entry->scroll) - entry->scroll = entry->cursor; - entry_redraw(GNT_WIDGET(bind)); - return TRUE; -} - -static gboolean -del_prev_word(GntBindable *bind, GList *null) -{ - GntWidget *widget = GNT_WIDGET(bind); - GntEntry *entry = GNT_ENTRY(bind); - char *iter = g_utf8_find_prev_char(entry->start, entry->cursor); - int count; - - if (iter < entry->start) - return TRUE; - iter = (char*)begin_word(iter, entry->start); - count = entry->cursor - iter; - memmove(iter, entry->cursor, entry->end - entry->cursor); - entry->end -= count; - entry->cursor = iter; - if (entry->cursor <= entry->scroll) { - entry->scroll = entry->cursor - widget->priv.width + 2; - if (entry->scroll < entry->start) - entry->scroll = entry->start; - } - memset(entry->end, '\0', entry->buffer - (entry->end - entry->start)); - entry_redraw(widget); - entry_text_changed(entry); - - return TRUE; -} - -static gboolean -move_forward_word(GntBindable *bind, GList *list) -{ - GntEntry *entry = GNT_ENTRY(bind); - GntWidget *widget = GNT_WIDGET(bind); - entry->cursor = (char *)next_begin_word(entry->cursor, entry->end); - while (gnt_util_onscreen_width(entry->scroll, entry->cursor) >= widget->priv.width) { - entry->scroll = g_utf8_find_next_char(entry->scroll, NULL); - } - entry_redraw(widget); - return TRUE; -} - -static gboolean -delete_forward_word(GntBindable *bind, GList *list) -{ - GntEntry *entry = GNT_ENTRY(bind); - GntWidget *widget = GNT_WIDGET(bind); - char *iter = (char *)next_begin_word(entry->cursor, entry->end); - int len = entry->end - iter + 1; - if (len <= 0) - return TRUE; - memmove(entry->cursor, iter, len); - len = iter - entry->cursor; - entry->end -= len; - memset(entry->end, '\0', len); - entry_redraw(widget); - entry_text_changed(entry); - return TRUE; -} - -static gboolean -gnt_entry_key_pressed(GntWidget *widget, const char *text) -{ - GntEntry *entry = GNT_ENTRY(widget); - - if (text[0] == 27) - { - if (text[1] == 0) - { - destroy_suggest(entry); - return TRUE; - } - - return FALSE; - } - else - { - if (text[0] == '\t') - { - if (entry->ddown) - destroy_suggest(entry); - else if (entry->suggests) - return show_suggest_dropdown(entry); - - return FALSE; - } - else if (text[0] == '\r' && entry->ddown) - { - char *text = g_strdup(gnt_tree_get_selection_data(GNT_TREE(entry->ddown))); - destroy_suggest(entry); - if (entry->word) - { - char *s = get_beginning_of_word(entry); - char *iter = text; - while (*iter && toupper(*s) == toupper(*iter)) - { - *s++ = *iter++; - } - gnt_entry_key_pressed(widget, iter); - } - else - { - gnt_entry_set_text_internal(entry, text); - } - g_free(text); - entry_text_changed(entry); - return TRUE; - } - - if (!iscntrl(text[0])) - { - const char *str, *next; - - for (str = text; *str; str = next) - { - int len; - next = g_utf8_find_next_char(str, NULL); - len = next - str; - - /* Valid input? */ - /* XXX: Is it necessary to use _unichar_ variants here? */ - if (ispunct(*str) && (entry->flag & GNT_ENTRY_FLAG_NO_PUNCT)) - continue; - if (isspace(*str) && (entry->flag & GNT_ENTRY_FLAG_NO_SPACE)) - continue; - if (isalpha(*str) && !(entry->flag & GNT_ENTRY_FLAG_ALPHA)) - continue; - if (isdigit(*str) && !(entry->flag & GNT_ENTRY_FLAG_INT)) - continue; - - /* Reached the max? */ - if (entry->max && g_utf8_pointer_to_offset(entry->start, entry->end) >= entry->max) - continue; - - if (entry->end + len - entry->start >= entry->buffer) - { - /* This will cause the buffer to grow */ - char *tmp = g_strdup(entry->start); - gnt_entry_set_text_internal(entry, tmp); - g_free(tmp); - } - - memmove(entry->cursor + len, entry->cursor, entry->end - entry->cursor + 1); - entry->end += len; - - while (str < next) - { - if (*str == '\r' || *str == '\n') - *entry->cursor = ' '; - else - *entry->cursor = *str; - entry->cursor++; - str++; - } - - while (gnt_util_onscreen_width(entry->scroll, entry->cursor) >= widget->priv.width) - entry->scroll = g_utf8_find_next_char(entry->scroll, NULL); - - if (entry->ddown) - show_suggest_dropdown(entry); - } - entry_redraw(widget); - entry_text_changed(entry); - return TRUE; - } - } - - return FALSE; -} - -static void -gnt_entry_destroy(GntWidget *widget) -{ - GntEntry *entry = GNT_ENTRY(widget); - g_free(entry->start); - - if (entry->history) - { - entry->history = g_list_first(entry->history); - g_list_foreach(entry->history, (GFunc)g_free, NULL); - g_list_free(entry->history); - } - - if (entry->suggests) - { - g_list_foreach(entry->suggests, (GFunc)g_free, NULL); - g_list_free(entry->suggests); - } - - if (entry->ddown) - { - gnt_widget_destroy(entry->ddown->parent); - } -} - -static void -gnt_entry_lost_focus(GntWidget *widget) -{ - GntEntry *entry = GNT_ENTRY(widget); - destroy_suggest(entry); - entry_redraw(widget); -} - -static void -gnt_entry_class_init(GntEntryClass *klass) -{ - GntBindableClass *bindable = GNT_BINDABLE_CLASS(klass); - char s[2] = {erasechar(), 0}; - - parent_class = GNT_WIDGET_CLASS(klass); - parent_class->destroy = gnt_entry_destroy; - parent_class->draw = gnt_entry_draw; - parent_class->map = gnt_entry_map; - parent_class->size_request = gnt_entry_size_request; - parent_class->key_pressed = gnt_entry_key_pressed; - parent_class->lost_focus = gnt_entry_lost_focus; - - signals[SIG_TEXT_CHANGED] = - g_signal_new("text_changed", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GntEntryClass, text_changed), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gnt_bindable_class_register_action(bindable, "cursor-home", move_start, - GNT_KEY_CTRL_A, NULL); - gnt_bindable_register_binding(bindable, "cursor-home", GNT_KEY_HOME, NULL); - gnt_bindable_class_register_action(bindable, "cursor-end", move_end, - GNT_KEY_CTRL_E, NULL); - gnt_bindable_register_binding(bindable, "cursor-end", GNT_KEY_END, NULL); - gnt_bindable_class_register_action(bindable, "delete-prev", backspace, - GNT_KEY_BACKSPACE, NULL); - gnt_bindable_register_binding(bindable, "delete-prev", s, NULL); - gnt_bindable_register_binding(bindable, "delete-prev", GNT_KEY_CTRL_H, NULL); - gnt_bindable_class_register_action(bindable, "delete-next", delkey, - GNT_KEY_DEL, NULL); - gnt_bindable_register_binding(bindable, "delete-next", GNT_KEY_CTRL_D, NULL); - gnt_bindable_class_register_action(bindable, "delete-start", del_to_home, - GNT_KEY_CTRL_U, NULL); - gnt_bindable_class_register_action(bindable, "delete-end", del_to_end, - GNT_KEY_CTRL_K, NULL); - gnt_bindable_class_register_action(bindable, "delete-prev-word", del_prev_word, - GNT_KEY_CTRL_W, NULL); - gnt_bindable_class_register_action(bindable, "cursor-prev-word", move_back_word, - "\033" "b", NULL); - gnt_bindable_class_register_action(bindable, "cursor-prev", move_back, - GNT_KEY_LEFT, NULL); - gnt_bindable_register_binding(bindable, "cursor-prev", GNT_KEY_CTRL_B, NULL); - gnt_bindable_class_register_action(bindable, "cursor-next", move_forward, - GNT_KEY_RIGHT, NULL); - gnt_bindable_register_binding(bindable, "cursor-next", GNT_KEY_CTRL_F, NULL); - gnt_bindable_class_register_action(bindable, "cursor-next-word", move_forward_word, - "\033" "f", NULL); - gnt_bindable_class_register_action(bindable, "delete-next-word", delete_forward_word, - "\033" "d", NULL); - gnt_bindable_class_register_action(bindable, "suggest-show", suggest_show, - "\t", NULL); - gnt_bindable_class_register_action(bindable, "suggest-next", suggest_next, - GNT_KEY_DOWN, NULL); - gnt_bindable_class_register_action(bindable, "suggest-prev", suggest_prev, - GNT_KEY_UP, NULL); - gnt_bindable_class_register_action(bindable, "history-prev", history_prev, - GNT_KEY_CTRL_DOWN, NULL); - gnt_bindable_class_register_action(bindable, "history-next", history_next, - GNT_KEY_CTRL_UP, NULL); - gnt_bindable_class_register_action(bindable, "clipboard-paste", clipboard_paste, - GNT_KEY_CTRL_V, NULL); - - gnt_style_read_actions(G_OBJECT_CLASS_TYPE(klass), GNT_BINDABLE_CLASS(klass)); - GNTDEBUG; -} - -static void -gnt_entry_init(GTypeInstance *instance, gpointer class) -{ - GntWidget *widget = GNT_WIDGET(instance); - GntEntry *entry = GNT_ENTRY(instance); - - entry->flag = GNT_ENTRY_FLAG_ALL; - entry->max = 0; - - entry->histlength = 0; - entry->history = NULL; - - entry->word = TRUE; - entry->always = FALSE; - entry->suggests = NULL; - - GNT_WIDGET_SET_FLAGS(GNT_WIDGET(entry), - GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW | GNT_WIDGET_CAN_TAKE_FOCUS); - GNT_WIDGET_SET_FLAGS(GNT_WIDGET(entry), GNT_WIDGET_GROW_X); - - widget->priv.minw = 3; - widget->priv.minh = 1; - - GNTDEBUG; -} - -/****************************************************************************** - * GntEntry API - *****************************************************************************/ -GType -gnt_entry_get_gtype(void) -{ - static GType type = 0; - - if(type == 0) - { - static const GTypeInfo info = { - sizeof(GntEntryClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc)gnt_entry_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof(GntEntry), - 0, /* n_preallocs */ - gnt_entry_init, /* instance_init */ - NULL /* value_table */ - }; - - type = g_type_register_static(GNT_TYPE_WIDGET, - "GntEntry", - &info, 0); - } - - return type; -} - -GntWidget *gnt_entry_new(const char *text) -{ - GntWidget *widget = g_object_new(GNT_TYPE_ENTRY, NULL); - GntEntry *entry = GNT_ENTRY(widget); - - gnt_entry_set_text_internal(entry, text); - - return widget; -} - -static void -gnt_entry_set_text_internal(GntEntry *entry, const char *text) -{ - int len; - int scroll, cursor; - - g_free(entry->start); - - if (text && text[0]) - { - len = strlen(text); - } - else - { - len = 0; - } - - entry->buffer = len + 128; - - scroll = entry->scroll - entry->start; - cursor = entry->end - entry->cursor; - - entry->start = g_new0(char, entry->buffer); - if (text) - snprintf(entry->start, len + 1, "%s", text); - entry->end = entry->start + len; - - entry->scroll = entry->start + scroll; - entry->cursor = entry->end - cursor; - - if (GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(entry), GNT_WIDGET_MAPPED)) - entry_redraw(GNT_WIDGET(entry)); -} - -void gnt_entry_set_text(GntEntry *entry, const char *text) -{ - gboolean changed = TRUE; - if (text == NULL && entry->start == NULL) - changed = FALSE; - if (text && entry->start && g_utf8_collate(text, entry->start) == 0) - changed = FALSE; - gnt_entry_set_text_internal(entry, text); - if (changed) - entry_text_changed(entry); -} - -void gnt_entry_set_max(GntEntry *entry, int max) -{ - entry->max = max; -} - -void gnt_entry_set_flag(GntEntry *entry, GntEntryFlag flag) -{ - entry->flag = flag; - /* XXX: Check the existing string to make sure the flags are respected? */ -} - -const char *gnt_entry_get_text(GntEntry *entry) -{ - return entry->start; -} - -void gnt_entry_clear(GntEntry *entry) -{ - gnt_entry_set_text_internal(entry, NULL); - entry->scroll = entry->cursor = entry->end = entry->start; - entry_redraw(GNT_WIDGET(entry)); - destroy_suggest(entry); - entry_text_changed(entry); -} - -void gnt_entry_set_masked(GntEntry *entry, gboolean set) -{ - entry->masked = set; -} - -void gnt_entry_add_to_history(GntEntry *entry, const char *text) -{ - g_return_if_fail(entry->history != NULL); /* Need to set_history_length first */ - - if (g_list_length(entry->history) >= entry->histlength) - return; - - entry->history = g_list_first(entry->history); - g_free(entry->history->data); - entry->history->data = g_strdup(text); - entry->history = g_list_prepend(entry->history, NULL); -} - -void gnt_entry_set_history_length(GntEntry *entry, int num) -{ - if (num == 0) - { - entry->histlength = num; - if (entry->history) - { - entry->history = g_list_first(entry->history); - g_list_foreach(entry->history, (GFunc)g_free, NULL); - g_list_free(entry->history); - entry->history = NULL; - } - return; - } - - if (entry->histlength == 0) - { - entry->histlength = num; - entry->history = g_list_append(NULL, NULL); - return; - } - - if (num > 0 && num < entry->histlength) - { - GList *first, *iter; - int index = 0; - for (first = entry->history, index = 0; first->prev; first = first->prev, index++); - while ((iter = g_list_nth(first, num)) != NULL) - { - g_free(iter->data); - first = g_list_delete_link(first, iter); - } - entry->histlength = num; - if (index >= num) - entry->history = g_list_last(first); - return; - } - - entry->histlength = num; -} - -void gnt_entry_set_word_suggest(GntEntry *entry, gboolean word) -{ - entry->word = word; -} - -void gnt_entry_set_always_suggest(GntEntry *entry, gboolean always) -{ - entry->always = always; -} - -void gnt_entry_add_suggest(GntEntry *entry, const char *text) -{ - GList *find; - - if (!text || !*text) - return; - - find = g_list_find_custom(entry->suggests, text, (GCompareFunc)g_utf8_collate); - if (find) - return; - entry->suggests = g_list_append(entry->suggests, g_strdup(text)); -} - -void gnt_entry_remove_suggest(GntEntry *entry, const char *text) -{ - GList *find = g_list_find_custom(entry->suggests, text, (GCompareFunc)g_utf8_collate); - if (find) - { - g_free(find->data); - entry->suggests = g_list_delete_link(entry->suggests, find); - } -} - diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gntentry.h --- a/console/libgnt/gntentry.h Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,106 +0,0 @@ -#ifndef GNT_ENTRY_H -#define GNT_ENTRY_H - -#include "gntwidget.h" -#include "gnt.h" -#include "gntcolors.h" -#include "gntkeys.h" - -#define GNT_TYPE_ENTRY (gnt_entry_get_gtype()) -#define GNT_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNT_TYPE_ENTRY, GntEntry)) -#define GNT_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GNT_TYPE_ENTRY, GntEntryClass)) -#define GNT_IS_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GNT_TYPE_ENTRY)) -#define GNT_IS_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GNT_TYPE_ENTRY)) -#define GNT_ENTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GNT_TYPE_ENTRY, GntEntryClass)) - -#define GNT_ENTRY_FLAGS(obj) (GNT_ENTRY(obj)->priv.flags) -#define GNT_ENTRY_SET_FLAGS(obj, flags) (GNT_ENTRY_FLAGS(obj) |= flags) -#define GNT_ENTRY_UNSET_FLAGS(obj, flags) (GNT_ENTRY_FLAGS(obj) &= ~(flags)) - -#define ENTRY_CHAR '_' /* The character to use to fill in the blank places */ - -typedef struct _GnEntry GntEntry; -typedef struct _GnEntryPriv GntEntryPriv; -typedef struct _GnEntryClass GntEntryClass; - -typedef enum -{ - GNT_ENTRY_FLAG_ALPHA = 1 << 0, /* Only alpha */ - GNT_ENTRY_FLAG_INT = 1 << 1, /* Only integer */ - GNT_ENTRY_FLAG_NO_SPACE = 1 << 2, /* No blank space is allowed */ - GNT_ENTRY_FLAG_NO_PUNCT = 1 << 3, /* No punctuations */ - GNT_ENTRY_FLAG_MASK = 1 << 4, /* Mask the inputs */ -} GntEntryFlag; - -#define GNT_ENTRY_FLAG_ALL (GNT_ENTRY_FLAG_ALPHA | GNT_ENTRY_FLAG_INT) - -struct _GnEntry -{ - GntWidget parent; - - GntEntryFlag flag; - - char *start; - char *end; - char *scroll; /* Current scrolling position */ - char *cursor; /* Cursor location */ - /* 0 <= cursor - scroll < widget-width */ - - size_t buffer; /* Size of the buffer */ - - int max; /* 0 means infinite */ - gboolean masked; - - GList *history; /* History of the strings. User can use this by pressing ctrl+up/down */ - int histlength; /* How long can the history be? */ - - GList *suggests; /* List of suggestions */ - gboolean word; /* Are the suggestions for only a word, or for the whole thing? */ - gboolean always; /* Should the list of suggestions show at all times, or only on tab-press? */ - GntWidget *ddown; /* The dropdown with the suggested list */ -}; - -struct _GnEntryClass -{ - GntWidgetClass parent; - - void (*text_changed)(GntEntry *entry); - void (*gnt_reserved1)(void); - void (*gnt_reserved2)(void); - void (*gnt_reserved3)(void); - void (*gnt_reserved4)(void); -}; - -G_BEGIN_DECLS - -GType gnt_entry_get_gtype(void); - -GntWidget *gnt_entry_new(const char *text); - -void gnt_entry_set_max(GntEntry *entry, int max); - -void gnt_entry_set_text(GntEntry *entry, const char *text); - -void gnt_entry_set_flag(GntEntry *entry, GntEntryFlag flag); - -const char *gnt_entry_get_text(GntEntry *entry); - -void gnt_entry_clear(GntEntry *entry); - -void gnt_entry_set_masked(GntEntry *entry, gboolean set); - -void gnt_entry_add_to_history(GntEntry *entry, const char *text); - -void gnt_entry_set_history_length(GntEntry *entry, int num); - -void gnt_entry_set_word_suggest(GntEntry *entry, gboolean word); - -void gnt_entry_set_always_suggest(GntEntry *entry, gboolean always); - -void gnt_entry_add_suggest(GntEntry *entry, const char *text); - -void gnt_entry_remove_suggest(GntEntry *entry, const char *text); - -G_END_DECLS - -#endif /* GNT_ENTRY_H */ diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gntkeys.c --- a/console/libgnt/gntkeys.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,243 +0,0 @@ -#include "gntkeys.h" - -#include -#include -#include - -char *gnt_key_cup; -char *gnt_key_cdown; -char *gnt_key_cleft; -char *gnt_key_cright; - -static const char *term; -static GHashTable *specials; - -void gnt_init_keys() -{ - const char *controls[] = {"", "c-", "ctrl-", "ctr-", "ctl-", NULL}; - const char *alts[] = {"", "alt-", "a-", "m-", "meta-", NULL}; - int c, a, ch; - char key[32]; - - if (term == NULL) { - term = getenv("TERM"); - if (!term) - term = ""; /* Just in case */ - } - - if (strcmp(term, "xterm") == 0 || strcmp(term, "rxvt") == 0) { - gnt_key_cup = "\033" "[1;5A"; - gnt_key_cdown = "\033" "[1;5B"; - gnt_key_cright = "\033" "[1;5C"; - gnt_key_cleft = "\033" "[1;5D"; - } else if (strcmp(term, "screen") == 0 || strcmp(term, "rxvt-unicode") == 0) { - gnt_key_cup = "\033" "Oa"; - gnt_key_cdown = "\033" "Ob"; - gnt_key_cright = "\033" "Oc"; - gnt_key_cleft = "\033" "Od"; - } - - specials = g_hash_table_new(g_str_hash, g_str_equal); - -#define INSERT_KEY(k, code) do { \ - g_hash_table_insert(specials, g_strdup(k), g_strdup(code)); \ - gnt_keys_add_combination(code); \ - } while (0) - - INSERT_KEY("home", GNT_KEY_HOME); - INSERT_KEY("end", GNT_KEY_END); - INSERT_KEY("pageup", GNT_KEY_PGUP); - INSERT_KEY("pagedown", GNT_KEY_PGDOWN); - INSERT_KEY("insert", GNT_KEY_INS); - INSERT_KEY("delete", GNT_KEY_DEL); - - INSERT_KEY("left", GNT_KEY_LEFT); - INSERT_KEY("right", GNT_KEY_RIGHT); - INSERT_KEY("up", GNT_KEY_UP); - INSERT_KEY("down", GNT_KEY_DOWN); - - INSERT_KEY("tab", "\t"); - INSERT_KEY("menu", GNT_KEY_POPUP); - - INSERT_KEY("f1", GNT_KEY_F1); - INSERT_KEY("f2", GNT_KEY_F2); - INSERT_KEY("f3", GNT_KEY_F3); - INSERT_KEY("f4", GNT_KEY_F4); - INSERT_KEY("f5", GNT_KEY_F5); - INSERT_KEY("f6", GNT_KEY_F6); - INSERT_KEY("f7", GNT_KEY_F7); - INSERT_KEY("f8", GNT_KEY_F8); - INSERT_KEY("f9", GNT_KEY_F9); - INSERT_KEY("f10", GNT_KEY_F10); - INSERT_KEY("f11", GNT_KEY_F11); - INSERT_KEY("f12", GNT_KEY_F12); - -#define REM_LENGTH (sizeof(key) - (cur - key)) -#define INSERT_COMB(k, code) do { \ - snprintf(key, sizeof(key), "%s%s%s", controls[c], alts[a], k); \ - INSERT_KEY(key, code); \ - } while (0); - - /* Lower-case alphabets */ - for (a = 0, c = 0; controls[c]; c++, a = 0) { - if (c) { - INSERT_COMB("up", gnt_key_cup); - INSERT_COMB("down", gnt_key_cdown); - INSERT_COMB("left", gnt_key_cleft); - INSERT_COMB("right", gnt_key_cright); - } - - for (a = 0; alts[a]; a++) { - for (ch = 0; ch < 26; ch++) { - char str[2] = {'a' + ch, 0}, code[4] = "\0\0\0\0"; - int ind = 0; - if (a) - code[ind++] = '\033'; - code[ind] = (c ? 1 : 'a') + ch; - INSERT_COMB(str, code); - } - } - } - c = 0; - for (a = 0; alts[a]; a++) { - /* Upper-case alphabets */ - for (ch = 0; ch < 26; ch++) { - char str[2] = {'A' + ch, 0}, code[] = {'\033', 'A' + ch, 0}; - INSERT_COMB(str, code); - } - /* Digits */ - for (ch = 0; ch < 10; ch++) { - char str[2] = {'0' + ch, 0}, code[] = {'\033', '0' + ch, 0}; - INSERT_COMB(str, code); - } - } -} - -void gnt_keys_refine(char *text) -{ - if (*text == 27 && *(text + 1) == '[' && - (*(text + 2) >= 'A' && *(text + 2) <= 'D')) { - /* Apparently this is necessary for urxvt and screen and xterm */ - if (strcmp(term, "screen") == 0 || strcmp(term, "rxvt-unicode") == 0 || - strcmp(term, "xterm") == 0) - *(text + 1) = 'O'; - } else if (*(unsigned char*)text == 195) { - if (*(text + 2) == 0 && strcmp(term, "xterm") == 0) { - *(text) = 27; - *(text + 1) -= 64; /* Say wha? */ - } - } -} - -const char *gnt_key_translate(const char *name) -{ - return g_hash_table_lookup(specials, name); -} - -/** - * The key-bindings will be saved in a tree. When a keystroke happens, GNT will - * find the sequence that matches a binding and return the length. - * A sequence should not be a prefix of another sequence. If it is, then only - * the shortest one will be processed. If we want to change that, we will need - * to allow getting the k-th prefix that matches the input, and pay attention - * to the return value of gnt_wm_process_input in gntmain.c. - */ -#define SIZE 256 - -#define IS_END 1 << 0 -struct _node -{ - struct _node *next[SIZE]; - int ref; - int flags; -}; - -static struct _node root = {.ref = 1, .flags = 0}; - -static void add_path(struct _node *node, const char *path) -{ - struct _node *n = NULL; - if (!path || !*path) { - node->flags |= IS_END; - return; - } - while (*path && node->next[*path]) { - node = node->next[*path]; - node->ref++; - path++; - } - if (!*path) - return; - n = g_new0(struct _node, 1); - n->ref = 1; - node->next[*path++] = n; - add_path(n, path); -} - -void gnt_keys_add_combination(const char *path) -{ - add_path(&root, path); -} - -static void del_path(struct _node *node, const char *path) -{ - struct _node *next = NULL; - - if (!*path) - return; - next = node->next[*path]; - if (!next) - return; - del_path(next, path + 1); - next->ref--; - if (next->ref == 0) { - node->next[*path] = NULL; - g_free(next); - } -} - -void gnt_keys_del_combination(const char *path) -{ - del_path(&root, path); -} - -int gnt_keys_find_combination(const char *path) -{ - int depth = 0; - struct _node *n = &root; - - root.flags &= ~IS_END; - while (*path && n->next[*path] && !(n->flags & IS_END)) { - if (g_utf8_find_next_char(path, NULL) - path > 1) - return 0; - n = n->next[*path++]; - depth++; - } - - if (!(n->flags & IS_END)) - depth = 0; - return depth; -} - -static void -print_path(struct _node *node, int depth) -{ - int i; - for (i = 0; i < SIZE; i++) { - if (node->next[i]) { - g_printerr("%*c (%d:%d)\n", depth * 4, i, node->next[i]->ref, - node->next[i]->flags); - print_path(node->next[i], depth + 1); - } - } -} - -/* this is purely for debugging purposes. */ -void gnt_keys_print_combinations(void); -void gnt_keys_print_combinations() -{ - g_printerr("--------\n"); - print_path(&root, 1); - g_printerr("--------\n"); -} - diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gntkeys.h --- a/console/libgnt/gntkeys.h Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,99 +0,0 @@ -#ifndef GNT_KEYS_H -#define GNT_KEYS_H - -#include -#include - -/** - * terminfo/termcap doesn't provide all the information that I want to use, eg. - * ctrl-up, ctrl-down etc. So I am going to hard-code some of the information - * for some popular $TERMs - */ -extern char *gnt_key_cup; -extern char *gnt_key_cdown; -extern char *gnt_key_cleft; -extern char *gnt_key_cright; - -#define SAFE(x) ((x) ? (x) : "") - -#define GNT_KEY_POPUP SAFE(key_f16) /* Apparently */ - -/* Arrow keys */ -#define GNT_KEY_LEFT SAFE(key_left) -#define GNT_KEY_RIGHT SAFE(key_right) -#define GNT_KEY_UP SAFE(key_up) -#define GNT_KEY_DOWN SAFE(key_down) - -#define GNT_KEY_CTRL_UP SAFE(gnt_key_cup) -#define GNT_KEY_CTRL_DOWN SAFE(gnt_key_cdown) -#define GNT_KEY_CTRL_RIGHT SAFE(gnt_key_cright) -#define GNT_KEY_CTRL_LEFT SAFE(gnt_key_cleft) - -#define GNT_KEY_PGUP SAFE(key_ppage) -#define GNT_KEY_PGDOWN SAFE(key_npage) -#define GNT_KEY_HOME SAFE(key_home) -#define GNT_KEY_END SAFE(key_end) - -#define GNT_KEY_ENTER carriage_return - -#define GNT_KEY_BACKSPACE SAFE(key_backspace) -#define GNT_KEY_DEL SAFE(key_dc) -#define GNT_KEY_INS SAFE(key_ic) - -#define GNT_KEY_CTRL_A "\001" -#define GNT_KEY_CTRL_B "\002" -#define GNT_KEY_CTRL_D "\004" -#define GNT_KEY_CTRL_E "\005" -#define GNT_KEY_CTRL_F "\006" -#define GNT_KEY_CTRL_G "\007" -#define GNT_KEY_CTRL_H "\010" -#define GNT_KEY_CTRL_I "\011" -#define GNT_KEY_CTRL_J "\012" -#define GNT_KEY_CTRL_K "\013" -#define GNT_KEY_CTRL_L "\014" -#define GNT_KEY_CTRL_M "\012" -#define GNT_KEY_CTRL_N "\016" -#define GNT_KEY_CTRL_O "\017" -#define GNT_KEY_CTRL_P "\020" -#define GNT_KEY_CTRL_R "\022" -#define GNT_KEY_CTRL_T "\024" -#define GNT_KEY_CTRL_U "\025" -#define GNT_KEY_CTRL_V "\026" -#define GNT_KEY_CTRL_W "\027" -#define GNT_KEY_CTRL_X "\030" -#define GNT_KEY_CTRL_Y "\031" - -#define GNT_KEY_F1 SAFE(key_f1) -#define GNT_KEY_F2 SAFE(key_f2) -#define GNT_KEY_F3 SAFE(key_f3) -#define GNT_KEY_F4 SAFE(key_f4) -#define GNT_KEY_F5 SAFE(key_f5) -#define GNT_KEY_F6 SAFE(key_f6) -#define GNT_KEY_F7 SAFE(key_f7) -#define GNT_KEY_F8 SAFE(key_f8) -#define GNT_KEY_F9 SAFE(key_f9) -#define GNT_KEY_F10 SAFE(key_f10) -#define GNT_KEY_F11 SAFE(key_f11) -#define GNT_KEY_F12 SAFE(key_f12) - -/** - * This will do stuff with the terminal settings and stuff. - */ -void gnt_init_keys(void); -void gnt_keys_refine(char *text); -const char *gnt_key_translate(const char *name); - -void gnt_keys_add_combination(const char *path); -void gnt_keys_del_combination(const char *path); -int gnt_keys_find_combination(const char *path); - - -/* A lot of commonly used variable names are defined in . - * #undef them to make life easier for everyone. */ - -#undef columns -#undef lines -#undef buttons -#undef newline - -#endif diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gntlabel.c --- a/console/libgnt/gntlabel.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,124 +0,0 @@ -#include "gntlabel.h" -#include "gntutils.h" - -#include - -enum -{ - SIGS = 1, -}; - -static GntWidgetClass *parent_class = NULL; - -static void -gnt_label_destroy(GntWidget *widget) -{ - GntLabel *label = GNT_LABEL(widget); - g_free(label->text); -} - -static void -gnt_label_draw(GntWidget *widget) -{ - GntLabel *label = GNT_LABEL(widget); - chtype flag = gnt_text_format_flag_to_chtype(label->flags); - - wbkgdset(widget->window, '\0' | flag); - mvwaddstr(widget->window, 0, 0, label->text); - - GNTDEBUG; -} - -static void -gnt_label_size_request(GntWidget *widget) -{ - GntLabel *label = GNT_LABEL(widget); - - gnt_util_get_text_bound(label->text, - &widget->priv.width, &widget->priv.height); -} - -static void -gnt_label_class_init(GntLabelClass *klass) -{ - parent_class = GNT_WIDGET_CLASS(klass); - parent_class->destroy = gnt_label_destroy; - parent_class->draw = gnt_label_draw; - parent_class->map = NULL; - parent_class->size_request = gnt_label_size_request; - - GNTDEBUG; -} - -static void -gnt_label_init(GTypeInstance *instance, gpointer class) -{ - GntWidget *widget = GNT_WIDGET(instance); - GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_GROW_X); - widget->priv.minw = 3; - widget->priv.minh = 1; - GNTDEBUG; -} - -/****************************************************************************** - * GntLabel API - *****************************************************************************/ -GType -gnt_label_get_gtype(void) -{ - static GType type = 0; - - if(type == 0) - { - static const GTypeInfo info = { - sizeof(GntLabelClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc)gnt_label_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof(GntLabel), - 0, /* n_preallocs */ - gnt_label_init, /* instance_init */ - NULL /* value_table */ - }; - - type = g_type_register_static(GNT_TYPE_WIDGET, - "GntLabel", - &info, 0); - } - - return type; -} - -GntWidget *gnt_label_new(const char *text) -{ - return gnt_label_new_with_format(text, 0); -} - -GntWidget *gnt_label_new_with_format(const char *text, GntTextFormatFlags flags) -{ - GntWidget *widget = g_object_new(GNT_TYPE_LABEL, NULL); - GntLabel *label = GNT_LABEL(widget); - - label->text = gnt_util_onscreen_fit_string(text, -1); - label->flags = flags; - gnt_widget_set_take_focus(widget, FALSE); - GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW); - - return widget; -} - -void gnt_label_set_text(GntLabel *label, const char *text) -{ - g_free(label->text); - label->text = gnt_util_onscreen_fit_string(text, -1); - - if (GNT_WIDGET(label)->window) - { - gnt_widget_hide(GNT_WIDGET(label)); - gnt_label_size_request(GNT_WIDGET(label)); - gnt_widget_draw(GNT_WIDGET(label)); - } -} - diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gntlabel.h --- a/console/libgnt/gntlabel.h Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -#ifndef GNT_LABEL_H -#define GNT_LABEL_H - -#include "gnt.h" -#include "gntwidget.h" -#include "gnttextview.h" - -#define GNT_TYPE_LABEL (gnt_label_get_gtype()) -#define GNT_LABEL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNT_TYPE_LABEL, GntLabel)) -#define GNT_LABEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GNT_TYPE_LABEL, GntLabelClass)) -#define GNT_IS_LABEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GNT_TYPE_LABEL)) -#define GNT_IS_LABEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GNT_TYPE_LABEL)) -#define GNT_LABEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GNT_TYPE_LABEL, GntLabelClass)) - -typedef struct _GnLabel GntLabel; -typedef struct _GnLabelClass GntLabelClass; - -struct _GnLabel -{ - GntWidget parent; - - char *text; - GntTextFormatFlags flags; - - void (*gnt_reserved1)(void); - void (*gnt_reserved2)(void); - void (*gnt_reserved3)(void); - void (*gnt_reserved4)(void); -}; - -struct _GnLabelClass -{ - GntWidgetClass parent; - - void (*gnt_reserved1)(void); - void (*gnt_reserved2)(void); - void (*gnt_reserved3)(void); - void (*gnt_reserved4)(void); -}; - -G_BEGIN_DECLS - -GType gnt_label_get_gtype(void); - -GntWidget *gnt_label_new(const char *text); - -GntWidget *gnt_label_new_with_format(const char *text, GntTextFormatFlags flags); - -void gnt_label_set_text(GntLabel *label, const char *text); - -G_END_DECLS - -#endif /* GNT_LABEL_H */ - diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gntline.c --- a/console/libgnt/gntline.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,115 +0,0 @@ -#include "gntline.h" - -enum -{ - SIGS = 1, -}; - -static GntWidgetClass *parent_class = NULL; - -static void -gnt_line_draw(GntWidget *widget) -{ - GntLine *line = GNT_LINE(widget); - if (line->vertical) - mvwvline(widget->window, 1, 0, ACS_VLINE | COLOR_PAIR(GNT_COLOR_NORMAL), - widget->priv.height - 2); - else - mvwhline(widget->window, 0, 1, ACS_HLINE | COLOR_PAIR(GNT_COLOR_NORMAL), - widget->priv.width - 2); -} - -static void -gnt_line_size_request(GntWidget *widget) -{ - if (GNT_LINE(widget)->vertical) - { - widget->priv.width = 1; - widget->priv.height = 5; - } - else - { - widget->priv.width = 5; - widget->priv.height = 1; - } -} - -static void -gnt_line_map(GntWidget *widget) -{ - if (widget->priv.width == 0 || widget->priv.height == 0) - gnt_widget_size_request(widget); - GNTDEBUG; -} - -static void -gnt_line_class_init(GntLineClass *klass) -{ - parent_class = GNT_WIDGET_CLASS(klass); - parent_class->draw = gnt_line_draw; - parent_class->map = gnt_line_map; - parent_class->size_request = gnt_line_size_request; - - GNTDEBUG; -} - -static void -gnt_line_init(GTypeInstance *instance, gpointer class) -{ - GntWidget *widget = GNT_WIDGET(instance); - GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_NO_SHADOW | GNT_WIDGET_NO_BORDER); - widget->priv.minw = 1; - widget->priv.minh = 1; - GNTDEBUG; -} - -/****************************************************************************** - * GntLine API - *****************************************************************************/ -GType -gnt_line_get_gtype(void) -{ - static GType type = 0; - - if(type == 0) - { - static const GTypeInfo info = { - sizeof(GntLineClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc)gnt_line_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof(GntLine), - 0, /* n_preallocs */ - gnt_line_init, /* instance_init */ - NULL /* value_table */ - }; - - type = g_type_register_static(GNT_TYPE_WIDGET, - "GntLine", - &info, 0); - } - - return type; -} - -GntWidget *gnt_line_new(gboolean vertical) -{ - GntWidget *widget = g_object_new(GNT_TYPE_LINE, NULL); - GntLine *line = GNT_LINE(widget); - - line->vertical = vertical; - - if (vertical) - { - GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_GROW_Y); - } - else - { - GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_GROW_X); - } - - return widget; -} - diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gntline.h --- a/console/libgnt/gntline.h Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -#ifndef GNT_LINE_H -#define GNT_LINE_H - -#include "gntwidget.h" -#include "gnt.h" -#include "gntcolors.h" -#include "gntkeys.h" - -#define GNT_TYPE_LINE (gnt_line_get_gtype()) -#define GNT_LINE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNT_TYPE_LINE, GntLine)) -#define GNT_LINE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GNT_TYPE_LINE, GntLineClass)) -#define GNT_IS_LINE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GNT_TYPE_LINE)) -#define GNT_IS_LINE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GNT_TYPE_LINE)) -#define GNT_LINE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GNT_TYPE_LINE, GntLineClass)) - -#define GNT_LINE_FLAGS(obj) (GNT_LINE(obj)->priv.flags) -#define GNT_LINE_SET_FLAGS(obj, flags) (GNT_LINE_FLAGS(obj) |= flags) -#define GNT_LINE_UNSET_FLAGS(obj, flags) (GNT_LINE_FLAGS(obj) &= ~(flags)) - -typedef struct _GnLine GntLine; -typedef struct _GnLinePriv GntLinePriv; -typedef struct _GnLineClass GntLineClass; - -struct _GnLine -{ - GntWidget parent; - - gboolean vertical; -}; - -struct _GnLineClass -{ - GntWidgetClass parent; - - void (*gnt_reserved1)(void); - void (*gnt_reserved2)(void); - void (*gnt_reserved3)(void); - void (*gnt_reserved4)(void); -}; - -G_BEGIN_DECLS - -GType gnt_line_get_gtype(void); - -#define gnt_hline_new() gnt_line_new(FALSE) -#define gnt_vline_new() gnt_line_new(TRUE) - -GntWidget *gnt_line_new(gboolean vertical); - -G_END_DECLS - -#endif /* GNT_LINE_H */ diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gntmain.c --- a/console/libgnt/gntmain.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,535 +0,0 @@ -#define _GNU_SOURCE -#if defined(__APPLE__) -#define _XOPEN_SOURCE_EXTENDED -#endif - -#include "config.h" - -#include - -#include -#include - -#include "gnt.h" -#include "gntbox.h" -#include "gntcolors.h" -#include "gntclipboard.h" -#include "gntkeys.h" -#include "gntmenu.h" -#include "gntstyle.h" -#include "gnttree.h" -#include "gntutils.h" -#include "gntwm.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -/** - * Notes: Interesting functions to look at: - * scr_dump, scr_init, scr_restore: for workspaces - * - * Need to wattrset for colors to use with PDCurses. - */ - -static GIOChannel *channel = NULL; - -static gboolean ascii_only; -static gboolean mouse_enabled; - -static void setup_io(void); - -static gboolean refresh_screen(); - -GntWM *wm; -static GntClipboard *clipboard; - -#define HOLDING_ESCAPE (escape_stuff.timer != 0) - -static struct { - int timer; -} escape_stuff; - -static gboolean -escape_timeout(gpointer data) -{ - gnt_wm_process_input(wm, "\033"); - escape_stuff.timer = 0; - return FALSE; -} - -/** - * Mouse support: - * - bring a window on top if you click on its taskbar - * - click on the top-bar of the active window and drag+drop to move a window - * - click on a window to bring it to focus - * - allow scrolling in tree/textview on wheel-scroll event - * - click to activate button or select a row in tree - * wishlist: - * - have a little [X] on the windows, and clicking it will close that window. - */ -static gboolean -detect_mouse_action(const char *buffer) -{ - int x, y; - static enum { - MOUSE_NONE, - MOUSE_LEFT, - MOUSE_RIGHT, - MOUSE_MIDDLE - } button = MOUSE_NONE; - static GntWidget *remember = NULL; - static int offset = 0; - GntMouseEvent event; - GntWidget *widget = NULL; - PANEL *p = NULL; - - if (!wm->ordered || buffer[0] != 27) - return FALSE; - - buffer++; - if (strlen(buffer) < 5) - return FALSE; - - x = buffer[3]; - y = buffer[4]; - if (x < 0) x += 256; - if (y < 0) y += 256; - x -= 33; - y -= 33; - - while ((p = panel_below(p)) != NULL) { - const GntNode *node = panel_userptr(p); - GntWidget *wid; - if (!node) - continue; - wid = node->me; - if (x >= wid->priv.x && x < wid->priv.x + wid->priv.width) { - if (y >= wid->priv.y && y < wid->priv.y + wid->priv.height) { - widget = wid; - break; - } - } - } - - if (strncmp(buffer, "[M ", 3) == 0) { - /* left button down */ - /* Bring the window you clicked on to front */ - /* If you click on the topbar, then you can drag to move the window */ - event = GNT_LEFT_MOUSE_DOWN; - } else if (strncmp(buffer, "[M\"", 3) == 0) { - /* right button down */ - event = GNT_RIGHT_MOUSE_DOWN; - } else if (strncmp(buffer, "[M!", 3) == 0) { - /* middle button down */ - event = GNT_MIDDLE_MOUSE_DOWN; - } else if (strncmp(buffer, "[M`", 3) == 0) { - /* wheel up*/ - event = GNT_MOUSE_SCROLL_UP; - } else if (strncmp(buffer, "[Ma", 3) == 0) { - /* wheel down */ - event = GNT_MOUSE_SCROLL_DOWN; - } else if (strncmp(buffer, "[M#", 3) == 0) { - /* button up */ - event = GNT_MOUSE_UP; - } else - return FALSE; - - if (gnt_wm_process_click(wm, event, x, y, widget)) - return TRUE; - - if (event == GNT_LEFT_MOUSE_DOWN && widget && widget != wm->_list.window && - !GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_TRANSIENT)) { - if (widget != wm->ordered->data) { - gnt_wm_raise_window(wm, widget); - } - if (y == widget->priv.y) { - offset = x - widget->priv.x; - remember = widget; - button = MOUSE_LEFT; - } - } else if (event == GNT_MOUSE_UP) { - if (button == MOUSE_NONE && y == getmaxy(stdscr) - 1) { - /* Clicked on the taskbar */ - int n = g_list_length(wm->list); - if (n) { - int width = getmaxx(stdscr) / n; - gnt_bindable_perform_action_named(GNT_BINDABLE(wm), "switch-window-n", x/width, NULL); - } - } else if (button == MOUSE_LEFT && remember) { - x -= offset; - if (x < 0) x = 0; - if (y < 0) y = 0; - gnt_screen_move_widget(remember, x, y); - } - button = MOUSE_NONE; - remember = NULL; - offset = 0; - } - - gnt_widget_clicked(widget, event, x, y); - return TRUE; -} - -static gboolean -io_invoke_error(GIOChannel *source, GIOCondition cond, gpointer data) -{ - int id = GPOINTER_TO_INT(data); - g_source_remove(id); - g_io_channel_unref(source); - - channel = NULL; - setup_io(); - return TRUE; -} - -static gboolean -io_invoke(GIOChannel *source, GIOCondition cond, gpointer null) -{ - char keys[256]; - int rd = read(STDIN_FILENO, keys + HOLDING_ESCAPE, sizeof(keys) - 1 - HOLDING_ESCAPE); - char *k; - if (rd < 0) - { - int ch = getch(); /* This should return ERR, but let's see what it really returns */ - endwin(); - printf("ERROR: %s\n", strerror(errno)); - printf("File descriptor is: %d\n\nGIOChannel is: %p\ngetch() = %d\n", STDIN_FILENO, source, ch); - raise(SIGABRT); - } - else if (rd == 0) - { - endwin(); - printf("EOF\n"); - raise(SIGABRT); - } - - rd += HOLDING_ESCAPE; - keys[rd] = 0; - if (mouse_enabled && detect_mouse_action(keys)) - return TRUE; - - if (HOLDING_ESCAPE) - keys[0] = '\033'; - k = keys; - while (rd) { - char back; - int p; - - if (k[0] == '\033' && rd == 1) { - if (escape_stuff.timer) { - gnt_wm_process_input(wm, "\033\033"); - g_source_remove(escape_stuff.timer); - escape_stuff.timer = 0; - break; - } - escape_stuff.timer = g_timeout_add(250, escape_timeout, NULL); - break; - } - - gnt_keys_refine(k); - p = MAX(1, gnt_keys_find_combination(k)); - back = k[p]; - k[p] = '\0'; - gnt_wm_process_input(wm, k); /* XXX: */ - k[p] = back; - rd -= p; - k += p; - } - - return TRUE; -} - -static void -setup_io() -{ - int result; - channel = g_io_channel_unix_new(STDIN_FILENO); - g_io_channel_set_close_on_unref(channel, TRUE); - -#if 0 - g_io_channel_set_encoding(channel, NULL, NULL); - g_io_channel_set_buffered(channel, FALSE); - g_io_channel_set_flags(channel, G_IO_FLAG_NONBLOCK, NULL ); -#endif - - result = g_io_add_watch_full(channel, G_PRIORITY_HIGH, - (G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI), - io_invoke, NULL, NULL); - - g_io_add_watch_full(channel, G_PRIORITY_HIGH, - (G_IO_NVAL), - io_invoke_error, GINT_TO_POINTER(result), NULL); - - g_io_channel_unref(channel); /* Apparently this caused crashes for some people. - But irssi does this, so I am going to assume the - crashes were caused by some other stuff. */ - - g_printerr("gntmain: setting up IO\n"); -} - -static gboolean -refresh_screen() -{ - gnt_bindable_perform_action_named(GNT_BINDABLE(wm), "refresh-screen", NULL); - return FALSE; -} - -/* Xerox */ -static void -clean_pid(void) -{ - int status; - pid_t pid; - - do { - pid = waitpid(-1, &status, WNOHANG); - } while (pid != 0 && pid != (pid_t)-1); - - if ((pid == (pid_t) - 1) && (errno != ECHILD)) { - char errmsg[BUFSIZ]; - g_snprintf(errmsg, BUFSIZ, "Warning: waitpid() returned %d", pid); - perror(errmsg); - } -} - -static void -sighandler(int sig) -{ - switch (sig) { -#ifdef SIGWINCH - case SIGWINCH: - werase(stdscr); - wrefresh(stdscr); - g_idle_add(refresh_screen, NULL); - signal(SIGWINCH, sighandler); - break; -#endif - case SIGCHLD: - clean_pid(); - signal(SIGCHLD, sighandler); - break; - } -} - -static void -init_wm() -{ - const char *name = gnt_style_get(GNT_STYLE_WM); - gpointer handle; - - if (name && *name) { - handle = g_module_open(name, G_MODULE_BIND_LAZY); - if (handle) { - gboolean (*init)(GntWM **); - if (g_module_symbol(handle, "gntwm_init", (gpointer)&init)) { - init(&wm); - } - } - } - if (wm == NULL) - wm = g_object_new(GNT_TYPE_WM, NULL); -} - -void gnt_init() -{ - char *filename; - const char *locale; - - if (channel) - return; - - locale = setlocale(LC_ALL, ""); - - setup_io(); - - if (locale && (strstr(locale, "UTF") || strstr(locale, "utf"))) - ascii_only = FALSE; - else - ascii_only = TRUE; - - initscr(); - typeahead(-1); - noecho(); - curs_set(0); - - gnt_init_keys(); - gnt_init_styles(); - - filename = g_build_filename(g_get_home_dir(), ".gntrc", NULL); - gnt_style_read_configure_file(filename); - g_free(filename); - - gnt_init_colors(); - - wbkgdset(stdscr, '\0' | COLOR_PAIR(GNT_COLOR_NORMAL)); - refresh(); - -#ifdef ALL_MOUSE_EVENTS - if ((mouse_enabled = gnt_style_get_bool(GNT_STYLE_MOUSE, FALSE))) - mousemask(ALL_MOUSE_EVENTS | REPORT_MOUSE_POSITION, NULL); -#endif - - wbkgdset(stdscr, '\0' | COLOR_PAIR(GNT_COLOR_NORMAL)); - werase(stdscr); - wrefresh(stdscr); - -#ifdef SIGWINCH - signal(SIGWINCH, sighandler); -#endif - signal(SIGCHLD, sighandler); - signal(SIGPIPE, SIG_IGN); - - g_type_init(); - - init_wm(); - - clipboard = g_object_new(GNT_TYPE_CLIPBOARD, NULL); -} - -void gnt_main() -{ - wm->loop = g_main_loop_new(NULL, FALSE); - g_main_loop_run(wm->loop); -} - -/********************************* - * Stuff for 'window management' * - *********************************/ - -void gnt_screen_occupy(GntWidget *widget) -{ - gnt_wm_new_window(wm, widget); -} - -void gnt_screen_release(GntWidget *widget) -{ - gnt_wm_window_close(wm, widget); -} - -void gnt_screen_update(GntWidget *widget) -{ - gnt_wm_update_window(wm, widget); -} - -gboolean gnt_widget_has_focus(GntWidget *widget) -{ - GntWidget *w; - if (!widget) - return FALSE; - - if (GNT_IS_MENU(widget)) - return TRUE; - - w = widget; - - while (widget->parent) - widget = widget->parent; - - if (widget == wm->_list.window) - return TRUE; - if (wm->ordered && wm->ordered->data == widget) { - if (GNT_IS_BOX(widget) && - (GNT_BOX(widget)->active == w || widget == w)) - return TRUE; - } - return FALSE; -} - -void gnt_widget_set_urgent(GntWidget *widget) -{ - while (widget->parent) - widget = widget->parent; - - if (wm->ordered && wm->ordered->data == widget) - return; - - GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_URGENT); - - gnt_wm_update_window(wm, widget); -} - -void gnt_quit() -{ - g_hash_table_destroy(wm->nodes); /* XXX: */ - update_panels(); - doupdate(); - gnt_uninit_colors(); - gnt_uninit_styles(); - endwin(); -} - -gboolean gnt_ascii_only() -{ - return ascii_only; -} - -void gnt_screen_resize_widget(GntWidget *widget, int width, int height) -{ - gnt_wm_resize_window(wm, widget, width, height); -} - -void gnt_screen_move_widget(GntWidget *widget, int x, int y) -{ - gnt_wm_move_window(wm, widget, x, y); -} - -void gnt_screen_rename_widget(GntWidget *widget, const char *text) -{ - gnt_box_set_title(GNT_BOX(widget), text); - gnt_widget_draw(widget); - gnt_wm_update_window(wm, widget); -} - -void gnt_register_action(const char *label, void (*callback)()) -{ - GntAction *action = g_new0(GntAction, 1); - action->label = g_strdup(label); - action->callback = callback; - - wm->acts = g_list_append(wm->acts, action); -} - -static void -reset_menu(GntWidget *widget, gpointer null) -{ - wm->menu = NULL; -} - -gboolean gnt_screen_menu_show(gpointer newmenu) -{ - if (wm->menu) { - /* For now, if a menu is being displayed, then another menu - * can NOT take over. */ - return FALSE; - } - - wm->menu = newmenu; - GNT_WIDGET_UNSET_FLAGS(GNT_WIDGET(wm->menu), GNT_WIDGET_INVISIBLE); - gnt_widget_draw(GNT_WIDGET(wm->menu)); - - g_signal_connect(G_OBJECT(wm->menu), "hide", G_CALLBACK(reset_menu), NULL); - - return TRUE; -} - -void gnt_set_clipboard_string(gchar *string) -{ - gnt_clipboard_set_string(clipboard, string); -} - -GntClipboard *gnt_get_clipboard() -{ - return clipboard; -} -gchar *gnt_get_clipboard_string() -{ - return gnt_clipboard_get_string(clipboard); -} diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gntmenu.c --- a/console/libgnt/gntmenu.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,317 +0,0 @@ -#include "gntmenu.h" -#include "gntmenuitemcheck.h" - -#include - -enum -{ - SIGS = 1, -}; - -static GntTreeClass *parent_class = NULL; - -static void (*org_draw)(GntWidget *wid); -static void (*org_destroy)(GntWidget *wid); -static void (*org_map)(GntWidget *wid); -static gboolean (*org_key_pressed)(GntWidget *w, const char *t); - -static void -gnt_menu_draw(GntWidget *widget) -{ - GntMenu *menu = GNT_MENU(widget); - GList *iter; - chtype type; - int i; - - if (menu->type == GNT_MENU_TOPLEVEL) { - wbkgdset(widget->window, '\0' | COLOR_PAIR(GNT_COLOR_HIGHLIGHT)); - werase(widget->window); - - for (i = 0, iter = menu->list; iter; iter = iter->next, i++) { - GntMenuItem *item = GNT_MENUITEM(iter->data); - type = ' ' | COLOR_PAIR(GNT_COLOR_HIGHLIGHT); - if (i == menu->selected) - type |= A_REVERSE; - item->priv.x = getcurx(widget->window) + widget->priv.x; - item->priv.y = getcury(widget->window) + widget->priv.y + 1; - wbkgdset(widget->window, type); - wprintw(widget->window, " %s ", item->text); - } - } else { - org_draw(widget); - } - - GNTDEBUG; -} - -static void -gnt_menu_size_request(GntWidget *widget) -{ - GntMenu *menu = GNT_MENU(widget); - - if (menu->type == GNT_MENU_TOPLEVEL) { - widget->priv.height = 1; - widget->priv.width = getmaxx(stdscr); - } else { - widget->priv.height = g_list_length(menu->list) + 2; - widget->priv.width = 25; /* XXX: */ - } -} - -static void -menu_tree_add(GntMenu *menu, GntMenuItem *item, GntMenuItem *parent) -{ - if (GNT_IS_MENUITEM_CHECK(item)) { - gnt_tree_add_choice(GNT_TREE(menu), item, - gnt_tree_create_row(GNT_TREE(menu), item->text, " "), parent, NULL); - gnt_tree_set_choice(GNT_TREE(menu), item, gnt_menuitem_check_get_checked(GNT_MENUITEM_CHECK(item))); - } else - gnt_tree_add_row_last(GNT_TREE(menu), item, - gnt_tree_create_row(GNT_TREE(menu), item->text, item->submenu ? ">" : " "), parent); - - if (0 && item->submenu) { - GntMenu *sub = GNT_MENU(item->submenu); - GList *iter; - for (iter = sub->list; iter; iter = iter->next) { - GntMenuItem *it = GNT_MENUITEM(iter->data); - menu_tree_add(menu, it, item); - } - } -} - -static void -gnt_menu_map(GntWidget *widget) -{ - GntMenu *menu = GNT_MENU(widget); - - if (menu->type == GNT_MENU_TOPLEVEL) { - gnt_widget_size_request(widget); - } else { - /* Populate the tree */ - GList *iter; - gnt_tree_remove_all(GNT_TREE(widget)); - for (iter = menu->list; iter; iter = iter->next) { - GntMenuItem *item = GNT_MENUITEM(iter->data); - menu_tree_add(menu, item, NULL); - } - org_map(widget); - gnt_tree_adjust_columns(GNT_TREE(widget)); - } - GNTDEBUG; -} - -static void -menuitem_activate(GntMenu *menu, GntMenuItem *item) -{ - if (item) { - if (item->submenu) { - GntMenu *sub = GNT_MENU(item->submenu); - menu->submenu = sub; - sub->type = GNT_MENU_POPUP; /* Submenus are *never* toplevel */ - sub->parentmenu = menu; - if (menu->type != GNT_MENU_TOPLEVEL) { - GntWidget *widget = GNT_WIDGET(menu); - item->priv.x = widget->priv.x + widget->priv.width - 1; - item->priv.y = widget->priv.y + gnt_tree_get_selection_visible_line(GNT_TREE(menu)); - } - gnt_widget_set_position(GNT_WIDGET(sub), item->priv.x, item->priv.y); - GNT_WIDGET_UNSET_FLAGS(GNT_WIDGET(sub), GNT_WIDGET_INVISIBLE); - gnt_widget_draw(GNT_WIDGET(sub)); - } else if (item->callback) { - item->callback(item, item->callbackdata); - while (menu) { - gnt_widget_hide(GNT_WIDGET(menu)); - menu = menu->parentmenu; - } - } - } -} - -static gboolean -gnt_menu_key_pressed(GntWidget *widget, const char *text) -{ - GntMenu *menu = GNT_MENU(widget); - int current = menu->selected; - - if (menu->submenu) { - do menu = menu->submenu; while (menu->submenu); - return (gnt_widget_key_pressed(GNT_WIDGET(menu), text)); - } - - if (text[0] == 27 && text[1] == 0) { - /* Escape closes menu */ - GntMenu *par = menu->parentmenu; - if (par != NULL) { - par->submenu = NULL; - gnt_widget_hide(widget); - } else - gnt_widget_hide(widget); - return TRUE; - } - - if (menu->type == GNT_MENU_TOPLEVEL) { - if (strcmp(text, GNT_KEY_LEFT) == 0) { - menu->selected--; - if (menu->selected < 0) - menu->selected = g_list_length(menu->list) - 1; - } else if (strcmp(text, GNT_KEY_RIGHT) == 0) { - menu->selected++; - if (menu->selected >= g_list_length(menu->list)) - menu->selected = 0; - } else if (strcmp(text, GNT_KEY_ENTER) == 0) { - gnt_widget_activate(widget); - } - - if (current != menu->selected) { - gnt_widget_draw(widget); - return TRUE; - } - } else { - return org_key_pressed(widget, text); - } - - return FALSE; -} - -static void -gnt_menu_destroy(GntWidget *widget) -{ - GntMenu *menu = GNT_MENU(widget); - g_list_foreach(menu->list, (GFunc)g_object_unref, NULL); - g_list_free(menu->list); - org_destroy(widget); -} - -static void -gnt_menu_toggled(GntTree *tree, gpointer key) -{ - GntMenuItem *item = GNT_MENUITEM(key); - GntMenu *menu = GNT_MENU(tree); - gboolean check = gnt_menuitem_check_get_checked(GNT_MENUITEM_CHECK(item)); - gnt_menuitem_check_set_checked(GNT_MENUITEM_CHECK(item), !check); - if (item->callback) - item->callback(item, item->callbackdata); - while (menu) { - gnt_widget_hide(GNT_WIDGET(menu)); - menu = menu->parentmenu; - } -} - -static void -gnt_menu_activate(GntWidget *widget) -{ - GntMenu *menu = GNT_MENU(widget); - GntMenuItem *item; - - if (menu->type == GNT_MENU_TOPLEVEL) { - item = g_list_nth_data(menu->list, menu->selected); - } else { - item = gnt_tree_get_selection_data(GNT_TREE(menu)); - } - - if (item) { - if (GNT_IS_MENUITEM_CHECK(item)) - gnt_menu_toggled(GNT_TREE(widget), item); - else - menuitem_activate(menu, item); - } -} - -static void -gnt_menu_hide(GntWidget *widget) -{ - GntMenu *menu = GNT_MENU(widget); - if (menu->parentmenu) - menu->parentmenu->submenu = NULL; -} - -static void -gnt_menu_class_init(GntMenuClass *klass) -{ - GntWidgetClass *wid_class = GNT_WIDGET_CLASS(klass); - parent_class = GNT_TREE_CLASS(klass); - - org_destroy = wid_class->destroy; - org_map = wid_class->map; - org_draw = wid_class->draw; - org_key_pressed = wid_class->key_pressed; - - wid_class->destroy = gnt_menu_destroy; - wid_class->draw = gnt_menu_draw; - wid_class->map = gnt_menu_map; - wid_class->size_request = gnt_menu_size_request; - wid_class->key_pressed = gnt_menu_key_pressed; - wid_class->activate = gnt_menu_activate; - wid_class->hide = gnt_menu_hide; - - parent_class->toggled = gnt_menu_toggled; - - GNTDEBUG; -} - -static void -gnt_menu_init(GTypeInstance *instance, gpointer class) -{ - GntWidget *widget = GNT_WIDGET(instance); - GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_NO_SHADOW | GNT_WIDGET_NO_BORDER | - GNT_WIDGET_CAN_TAKE_FOCUS | GNT_WIDGET_TRANSIENT); - GNTDEBUG; -} - -/****************************************************************************** - * GntMenu API - *****************************************************************************/ -GType -gnt_menu_get_gtype(void) -{ - static GType type = 0; - - if(type == 0) - { - static const GTypeInfo info = { - sizeof(GntMenuClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc)gnt_menu_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof(GntMenu), - 0, /* n_preallocs */ - gnt_menu_init, /* instance_init */ - NULL /* value_table */ - }; - - type = g_type_register_static(GNT_TYPE_TREE, - "GntMenu", - &info, 0); - } - - return type; -} - -GntWidget *gnt_menu_new(GntMenuType type) -{ - GntWidget *widget = g_object_new(GNT_TYPE_MENU, NULL); - GntMenu *menu = GNT_MENU(widget); - menu->list = NULL; - menu->selected = 0; - menu->type = type; - - if (type == GNT_MENU_TOPLEVEL) { - widget->priv.x = 0; - widget->priv.y = 0; - } else { - GNT_TREE(widget)->show_separator = FALSE; - _gnt_tree_init_internals(GNT_TREE(widget), 2); - gnt_tree_set_col_width(GNT_TREE(widget), 1, 1); /* The second column is to indicate that it has a submenu */ - GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_NO_BORDER); - } - - return widget; -} - -void gnt_menu_add_item(GntMenu *menu, GntMenuItem *item) -{ - menu->list = g_list_append(menu->list, item); -} - diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gntmenu.h --- a/console/libgnt/gntmenu.h Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -#ifndef GNT_MENU_H -#define GNT_MENU_H - -#include "gnttree.h" -#include "gntcolors.h" -#include "gntkeys.h" - -#define GNT_TYPE_MENU (gnt_menu_get_gtype()) -#define GNT_MENU(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNT_TYPE_MENU, GntMenu)) -#define GNT_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GNT_TYPE_MENU, GntMenuClass)) -#define GNT_IS_MENU(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GNT_TYPE_MENU)) -#define GNT_IS_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GNT_TYPE_MENU)) -#define GNT_MENU_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GNT_TYPE_MENU, GntMenuClass)) - -#define GNT_MENU_FLAGS(obj) (GNT_MENU(obj)->priv.flags) -#define GNT_MENU_SET_FLAGS(obj, flags) (GNT_MENU_FLAGS(obj) |= flags) -#define GNT_MENU_UNSET_FLAGS(obj, flags) (GNT_MENU_FLAGS(obj) &= ~(flags)) - -typedef struct _GnMenu GntMenu; -typedef struct _GnMenuPriv GntMenuPriv; -typedef struct _GnMenuClass GntMenuClass; - -#include "gntmenuitem.h" - -/** - * A toplevel-menu is displayed at the top of the screen, and it spans accross - * the entire width of the screen. - * A popup-menu could be displayed, for example, as a context menu for widgets. - */ -typedef enum -{ - GNT_MENU_TOPLEVEL = 1, /* Menu for a toplevel window */ - GNT_MENU_POPUP, /* A popup menu */ -} GntMenuType; - -struct _GnMenu -{ - GntTree parent; - GntMenuType type; - - GList *list; - int selected; - - /* This will keep track of its immediate submenu which is visible so that - * keystrokes can be passed to it. */ - GntMenu *submenu; - GntMenu *parentmenu; -}; - -struct _GnMenuClass -{ - GntTreeClass parent; - - void (*gnt_reserved1)(void); - void (*gnt_reserved2)(void); - void (*gnt_reserved3)(void); - void (*gnt_reserved4)(void); -}; - -G_BEGIN_DECLS - -GType gnt_menu_get_gtype(void); - -GntWidget *gnt_menu_new(GntMenuType type); - -void gnt_menu_add_item(GntMenu *menu, GntMenuItem *item); - -G_END_DECLS - -#endif /* GNT_MENU_H */ diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gntmenuitem.c --- a/console/libgnt/gntmenuitem.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,84 +0,0 @@ -#include "gntmenu.h" -#include "gntmenuitem.h" - -static GObjectClass *parent_class = NULL; - -static void -gnt_menuitem_destroy(GObject *obj) -{ - GntMenuItem *item = GNT_MENUITEM(obj); - g_free(item->text); - item->text = NULL; - if (item->submenu) - gnt_widget_destroy(GNT_WIDGET(item->submenu)); - parent_class->dispose(obj); -} - -static void -gnt_menuitem_class_init(GntMenuItemClass *klass) -{ - GObjectClass *obj_class = G_OBJECT_CLASS(klass); - parent_class = g_type_class_peek_parent(klass); - - obj_class->dispose = gnt_menuitem_destroy; -} - -static void -gnt_menuitem_init(GTypeInstance *instance, gpointer class) -{ -} - -/****************************************************************************** - * GntMenuItem API - *****************************************************************************/ -GType -gnt_menuitem_get_gtype(void) -{ - static GType type = 0; - - if(type == 0) - { - static const GTypeInfo info = { - sizeof(GntMenuItemClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc)gnt_menuitem_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof(GntMenuItem), - 0, /* n_preallocs */ - gnt_menuitem_init, /* instance_init */ - NULL /* value_table */ - }; - - type = g_type_register_static(G_TYPE_OBJECT, - "GntMenuItem", - &info, 0); - } - - return type; -} - -GntMenuItem *gnt_menuitem_new(const char *text) -{ - GObject *item = g_object_new(GNT_TYPE_MENUITEM, NULL); - GntMenuItem *menuitem = GNT_MENUITEM(item); - - menuitem->text = g_strdup(text); - - return menuitem; -} - -void gnt_menuitem_set_callback(GntMenuItem *item, GntMenuItemCallback callback, gpointer data) -{ - item->callback = callback; - item->callbackdata = data; -} - -void gnt_menuitem_set_submenu(GntMenuItem *item, GntMenu *menu) -{ - if (item->submenu) - gnt_widget_destroy(GNT_WIDGET(item->submenu)); - item->submenu = menu; -} - diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gntmenuitem.h --- a/console/libgnt/gntmenuitem.h Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -#ifndef GNT_MENUITEM_H -#define GNT_MENUITEM_H - -#include -#include - -#define GNT_TYPE_MENUITEM (gnt_menuitem_get_gtype()) -#define GNT_MENUITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNT_TYPE_MENUITEM, GntMenuItem)) -#define GNT_MENUITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GNT_TYPE_MENUITEM, GntMenuItemClass)) -#define GNT_IS_MENUITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GNT_TYPE_MENUITEM)) -#define GNT_IS_MENUITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GNT_TYPE_MENUITEM)) -#define GNT_MENUITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GNT_TYPE_MENUITEM, GntMenuItemClass)) - -#define GNT_MENUITEM_FLAGS(obj) (GNT_MENUITEM(obj)->priv.flags) -#define GNT_MENUITEM_SET_FLAGS(obj, flags) (GNT_MENUITEM_FLAGS(obj) |= flags) -#define GNT_MENUITEM_UNSET_FLAGS(obj, flags) (GNT_MENUITEM_FLAGS(obj) &= ~(flags)) - -typedef struct _GnMenuItem GntMenuItem; -typedef struct _GnMenuItemPriv GntMenuItemPriv; -typedef struct _GnMenuItemClass GntMenuItemClass; - -#include "gntmenu.h" - -struct _GnMenuItemPriv -{ - /* These will be used to determine the position of the submenu */ - int x; - int y; -}; - -typedef void (*GntMenuItemCallback)(GntMenuItem *item, gpointer data); - -struct _GnMenuItem -{ - GObject parent; - GntMenuItemPriv priv; - - char *text; - - /* A GntMenuItem can have a callback associated with it. - * The callback will be activated whenever the suer selects it and presses enter (or clicks). - * However, if the GntMenuItem has some child, then the callback and callbackdata will be ignored. */ - gpointer callbackdata; - GntMenuItemCallback callback; - - GntMenu *submenu; -}; - -struct _GnMenuItemClass -{ - GObjectClass parent; - - void (*gnt_reserved1)(void); - void (*gnt_reserved2)(void); - void (*gnt_reserved3)(void); - void (*gnt_reserved4)(void); -}; - -G_BEGIN_DECLS - -GType gnt_menuitem_get_gtype(void); - -GntMenuItem *gnt_menuitem_new(const char *text); - -void gnt_menuitem_set_callback(GntMenuItem *item, GntMenuItemCallback callback, gpointer data); - -void gnt_menuitem_set_submenu(GntMenuItem *item, GntMenu *menu); - -G_END_DECLS - -#endif /* GNT_MENUITEM_H */ diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gntmenuitemcheck.c --- a/console/libgnt/gntmenuitemcheck.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -#include "gntmenuitemcheck.h" - -static GntMenuItemClass *parent_class = NULL; - -static void -gnt_menuitem_check_class_init(GntMenuItemCheckClass *klass) -{ - parent_class = GNT_MENUITEM_CLASS(klass); - - GNTDEBUG; -} - -static void -gnt_menuitem_check_init(GTypeInstance *instance, gpointer class) -{ - GNTDEBUG; -} - -/****************************************************************************** - * GntMenuItemCheck API - *****************************************************************************/ -GType -gnt_menuitem_check_get_gtype(void) -{ - static GType type = 0; - - if(type == 0) - { - static const GTypeInfo info = { - sizeof(GntMenuItemCheckClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc)gnt_menuitem_check_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof(GntMenuItemCheck), - 0, /* n_preallocs */ - gnt_menuitem_check_init, /* instance_init */ - NULL /* value_table */ - }; - - type = g_type_register_static(GNT_TYPE_MENUITEM, - "GntMenuItemCheck", - &info, 0); - } - - return type; -} - -GntMenuItem *gnt_menuitem_check_new(const char *text) -{ - GntMenuItem *item = g_object_new(GNT_TYPE_MENUITEM_CHECK, NULL); - GntMenuItem *menuitem = GNT_MENUITEM(item); - - menuitem->text = g_strdup(text); - return item; -} - -gboolean gnt_menuitem_check_get_checked(GntMenuItemCheck *item) -{ - return item->checked; -} - -void gnt_menuitem_check_set_checked(GntMenuItemCheck *item, gboolean set) -{ - item->checked = set; -} - diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gntmenuitemcheck.h --- a/console/libgnt/gntmenuitemcheck.h Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -#ifndef GNT_MENUITEM_CHECK_H -#define GNT_MENUITEM_CHECK_H - -#include "gnt.h" -#include "gntcolors.h" -#include "gntkeys.h" -#include "gntmenuitem.h" - -#define GNT_TYPE_MENUITEM_CHECK (gnt_menuitem_check_get_gtype()) -#define GNT_MENUITEM_CHECK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNT_TYPE_MENUITEM_CHECK, GntMenuItemCheck)) -#define GNT_MENUITEM_CHECK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GNT_TYPE_MENUITEM_CHECK, GntMenuItemCheckClass)) -#define GNT_IS_MENUITEM_CHECK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GNT_TYPE_MENUITEM_CHECK)) -#define GNT_IS_MENUITEM_CHECK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GNT_TYPE_MENUITEM_CHECK)) -#define GNT_MENUITEM_CHECK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GNT_TYPE_MENUITEM_CHECK, GntMenuItemCheckClass)) - -#define GNT_MENUITEM_CHECK_FLAGS(obj) (GNT_MENUITEM_CHECK(obj)->priv.flags) -#define GNT_MENUITEM_CHECK_SET_FLAGS(obj, flags) (GNT_MENUITEM_CHECK_FLAGS(obj) |= flags) -#define GNT_MENUITEM_CHECK_UNSET_FLAGS(obj, flags) (GNT_MENUITEM_CHECK_FLAGS(obj) &= ~(flags)) - -typedef struct _GnMenuItemCheck GntMenuItemCheck; -typedef struct _GnMenuItemCheckPriv GntMenuItemCheckPriv; -typedef struct _GnMenuItemCheckClass GntMenuItemCheckClass; - -struct _GnMenuItemCheck -{ - GntMenuItem parent; - gboolean checked; -}; - -struct _GnMenuItemCheckClass -{ - GntMenuItemClass parent; - - void (*gnt_reserved1)(void); - void (*gnt_reserved2)(void); - void (*gnt_reserved3)(void); - void (*gnt_reserved4)(void); -}; - -G_BEGIN_DECLS - -GType gnt_menuitem_check_get_gtype(void); - -GntMenuItem *gnt_menuitem_check_new(const char *text); - -gboolean gnt_menuitem_check_get_checked(GntMenuItemCheck *item); - -void gnt_menuitem_check_set_checked(GntMenuItemCheck *item, gboolean set); - -G_END_DECLS - -#endif /* GNT_MENUITEM_CHECK_H */ diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gntrc.sample --- a/console/libgnt/gntrc.sample Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,21 +0,0 @@ -[general] -shadow = 0 - -[colors] -black = 0; 0; 0 -red = 1000; 0; 0 -green = 0; 1000; 0 -blue = 250; 250; 700 -white = 1000; 1000; 1000 -gray = 700; 700; 700 -darkgray = 256; 256; 256 - -[colorpairs] -normal = black; white -highlight = white; blue -highlightd = black; gray -shadow = black; darkgray -title = white; blue -titled = white; gray -text = white; blue -disabled = gray; white diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gntstyle.c --- a/console/libgnt/gntstyle.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,268 +0,0 @@ -#include "gntstyle.h" -#include "gntcolors.h" - -#include -#include - -#if GLIB_CHECK_VERSION(2,6,0) -static GKeyFile *gkfile; -#endif - -static char * str_styles[GNT_STYLES]; -static int int_styles[GNT_STYLES]; -static int bool_styles[GNT_STYLES]; - -const char *gnt_style_get(GntStyle style) -{ - return str_styles[style]; -} - -gboolean gnt_style_get_bool(GntStyle style, gboolean def) -{ - int i; - const char * str; - - if (bool_styles[style] != -1) - return bool_styles[style]; - - str = gnt_style_get(style); - - if (str) - { - if (strcmp(str, "false") == 0) - def = FALSE; - else if (strcmp(str, "true") == 0) - def = TRUE; - else if (sscanf(str, "%d", &i) == 1) - { - if (i) - def = TRUE; - else - def = FALSE; - } - } - - bool_styles[style] = def; - return bool_styles[style]; -} - -static void -refine(char *text) -{ - char *s = text, *t = text; - - while (*s) - { - if (*s == '^' && *(s + 1) == '[') - { - *t = '\033'; /* escape */ - s++; - } - else if (*s == '\\') - { - if (*(s + 1) == '\0') - *t = ' '; - else - { - s++; - if (*s == 'r' || *s == 'n') - *t = '\r'; - else if (*s == 't') - *t = '\t'; - else - *t = *s; - } - } - else - *t = *s; - t++; - s++; - } - *t = '\0'; -} - -static char * -parse_key(const char *key) -{ - return (char *)gnt_key_translate(key); -} - -void gnt_style_read_actions(GType type, GntBindableClass *klass) -{ -#if GLIB_CHECK_VERSION(2,6,0) - char *name; - GError *error = NULL; - - name = g_strdup_printf("%s::binding", g_type_name(type)); - - if (g_key_file_has_group(gkfile, name)) - { - gsize len = 0; - char **keys; - - keys = g_key_file_get_keys(gkfile, name, &len, &error); - if (error) - { - g_printerr("GntStyle: %s\n", error->message); - g_error_free(error); - g_free(name); - return; - } - - while (len--) - { - char *key, *action; - - key = g_strdup(keys[len]); - action = g_key_file_get_string(gkfile, name, keys[len], &error); - - if (error) - { - g_printerr("GntStyle: %s\n", error->message); - g_error_free(error); - error = NULL; - } - else - { - const char *keycode = parse_key(key); - if (keycode == NULL) { - g_printerr("GntStyle: Invalid key-binding %s\n", key); - } else { - gnt_bindable_register_binding(klass, action, keycode, NULL); - } - } - g_free(key); - g_free(action); - } - g_strfreev(keys); - } - g_free(name); -#endif -} - -void gnt_styles_get_keyremaps(GType type, GHashTable *hash) -{ -#if GLIB_CHECK_VERSION(2,6,0) - char *name; - GError *error = NULL; - - name = g_strdup_printf("%s::remap", g_type_name(type)); - - if (g_key_file_has_group(gkfile, name)) - { - gsize len = 0; - char **keys; - - keys = g_key_file_get_keys(gkfile, name, &len, &error); - if (error) - { - g_printerr("GntStyle: %s\n", error->message); - g_error_free(error); - g_free(name); - return; - } - - while (len--) - { - char *key, *replace; - - key = g_strdup(keys[len]); - replace = g_key_file_get_string(gkfile, name, keys[len], &error); - - if (error) - { - g_printerr("GntStyle: %s\n", error->message); - g_error_free(error); - error = NULL; - g_free(key); - } - else - { - refine(key); - refine(replace); - g_hash_table_insert(hash, key, replace); - } - } - g_strfreev(keys); - } - - g_free(name); -#endif -} - -#if GLIB_CHECK_VERSION(2,6,0) -static void -read_general_style(GKeyFile *kfile) -{ - GError *error = NULL; - gsize nkeys; - char **keys = g_key_file_get_keys(kfile, "general", &nkeys, &error); - int i; - struct - { - const char *style; - GntStyle en; - } styles[] = {{"shadow", GNT_STYLE_SHADOW}, - {"customcolor", GNT_STYLE_COLOR}, - {"mouse", GNT_STYLE_MOUSE}, - {"wm", GNT_STYLE_WM}, - {"remember_position", GNT_STYLE_REMPOS}, - {NULL, 0}}; - - if (error) - { - g_printerr("GntStyle: %s\n", error->message); - g_error_free(error); - } - else - { - for (i = 0; styles[i].style; i++) - { - error = NULL; - str_styles[styles[i].en] = - g_key_file_get_string(kfile, "general", styles[i].style, &error); - } - } - g_strfreev(keys); -} -#endif - -void gnt_style_read_configure_file(const char *filename) -{ -#if GLIB_CHECK_VERSION(2,6,0) - GError *error = NULL; - gkfile = g_key_file_new(); - - if (!g_key_file_load_from_file(gkfile, filename, G_KEY_FILE_NONE, &error)) - { - g_printerr("GntStyle: %s\n", error->message); - g_error_free(error); - return; - } - gnt_colors_parse(gkfile); - read_general_style(gkfile); -#endif -} - -void gnt_init_styles() -{ - int i; - for (i = 0; i < GNT_STYLES; i++) - { - str_styles[i] = NULL; - int_styles[i] = -1; - bool_styles[i] = -1; - } -} - -void gnt_uninit_styles() -{ - int i; - for (i = 0; i < GNT_STYLES; i++) - g_free(str_styles[i]); - -#if GLIB_CHECK_VERSION(2,6,0) - g_key_file_free(gkfile); -#endif -} - diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gntstyle.h --- a/console/libgnt/gntstyle.h Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -#include "gnt.h" - -typedef enum -{ - GNT_STYLE_SHADOW = 0, - GNT_STYLE_COLOR = 1, - GNT_STYLE_MOUSE = 2, - GNT_STYLE_WM = 3, - GNT_STYLE_REMPOS = 4, - GNT_STYLES -} GntStyle; - -void gnt_style_read_configure_file(const char *filename); - -const char *gnt_style_get(GntStyle style); - -gboolean gnt_style_get_bool(GntStyle style, gboolean def); - -/* This should be called only once for the each type */ -void gnt_styles_get_keyremaps(GType type, GHashTable *hash); - -void gnt_style_read_actions(GType type, GntBindableClass *klass); - -void gnt_init_styles(void); - -void gnt_uninit_styles(void); - diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gnttextview.c --- a/console/libgnt/gnttextview.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,727 +0,0 @@ -#include "gnttextview.h" -#include "gntutils.h" - -#include - -enum -{ - SIGS = 1, -}; - -typedef struct -{ - GntTextFormatFlags tvflag; - chtype flags; - int start; - int end; /* This is the next byte of the last character of this segment */ -} GntTextSegment; - -typedef struct -{ - GList *segments; /* A list of GntTextSegments */ - int length; /* The current length of the line so far (ie. onscreen width) */ - gboolean soft; /* TRUE if it's an overflow from prev. line */ -} GntTextLine; - -typedef struct -{ - char *name; - int start; - int end; -} GntTextTag; - -static GntWidgetClass *parent_class = NULL; - -static gchar *select_start; -static gchar *select_end; -static gboolean double_click; - -static void -gnt_text_view_draw(GntWidget *widget) -{ - GntTextView *view = GNT_TEXT_VIEW(widget); - int i = 0; - GList *lines; - int rows, scrcol; - - werase(widget->window); - - for (i = 0, lines = view->list; i < widget->priv.height && lines; i++, lines = lines->next) - { - GList *iter; - GntTextLine *line = lines->data; - - wmove(widget->window, widget->priv.height - 1 - i, 0); - - for (iter = line->segments; iter; iter = iter->next) - { - GntTextSegment *seg = iter->data; - char *end = view->string->str + seg->end; - char back = *end; - chtype fl = seg->flags; - *end = '\0'; - if (select_start < view->string->str + seg->start && select_end > view->string->str + seg->end) { - fl |= A_REVERSE; - wattrset(widget->window, fl); - wprintw(widget->window, "%s", (view->string->str + seg->start)); - } else if (select_start && select_end && - ((select_start >= view->string->str + seg->start && select_start <= view->string->str + seg->end) || - (select_end <= view->string->str + seg->end && select_start <= view->string->str + seg->start))) { - char *cur = view->string->str + seg->start; - while (*cur != '\0') { - gchar *last = g_utf8_next_char(cur); - gchar *str; - if (cur >= select_start && cur <= select_end) - fl |= A_REVERSE; - else - fl = seg->flags; - str = g_strndup(cur, last - cur); - wattrset(widget->window, fl); - waddstr(widget->window, str); - g_free(str); - cur = g_utf8_next_char(cur); - } - } else { - wattrset(widget->window, fl); - wprintw(widget->window, "%s", (view->string->str + seg->start)); - } - *end = back; - } - wattroff(widget->window, A_UNDERLINE | A_BLINK | A_REVERSE); - whline(widget->window, ' ', widget->priv.width - line->length - 1); - } - - scrcol = widget->priv.width - 1; - rows = widget->priv.height - 2; - if (rows > 0) - { - int total = g_list_length(g_list_first(view->list)); - int showing, position, up, down; - - showing = rows * rows / total + 1; - showing = MIN(rows, showing); - - total -= rows; - up = g_list_length(lines); - down = total - up; - - position = (rows - showing) * up / MAX(1, up + down); - position = MAX((lines != NULL), position); - - if (showing + position > rows) - position = rows - showing; - - if (showing + position == rows && view->list && view->list->prev) - position = MAX(1, rows - 1 - showing); - else if (showing + position < rows && view->list && !view->list->prev) - position = rows - showing; - - mvwvline(widget->window, position + 1, scrcol, - ACS_CKBOARD | COLOR_PAIR(GNT_COLOR_HIGHLIGHT_D), showing); - } - - mvwaddch(widget->window, 0, scrcol, - (lines ? ACS_UARROW : ' ') | COLOR_PAIR(GNT_COLOR_HIGHLIGHT_D)); - mvwaddch(widget->window, widget->priv.height - 1, scrcol, - ((view->list && view->list->prev) ? ACS_DARROW : ' ') | - COLOR_PAIR(GNT_COLOR_HIGHLIGHT_D)); - - GNTDEBUG; -} - -static void -gnt_text_view_size_request(GntWidget *widget) -{ - if (!GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_MAPPED)) - { - gnt_widget_set_size(widget, 64, 20); - } -} - -static void -gnt_text_view_map(GntWidget *widget) -{ - if (widget->priv.width == 0 || widget->priv.height == 0) - gnt_widget_size_request(widget); - GNTDEBUG; -} - -static gboolean -gnt_text_view_key_pressed(GntWidget *widget, const char *text) -{ - return FALSE; -} - -static void -free_text_segment(gpointer data, gpointer null) -{ - GntTextSegment *seg = data; - g_free(seg); -} - -static void -free_text_line(gpointer data, gpointer null) -{ - GntTextLine *line = data; - g_list_foreach(line->segments, free_text_segment, NULL); - g_list_free(line->segments); - g_free(line); -} - -static void -free_tag(gpointer data, gpointer null) -{ - GntTextTag *tag = data; - g_free(tag->name); - g_free(tag); -} - -static void -gnt_text_view_destroy(GntWidget *widget) -{ - GntTextView *view = GNT_TEXT_VIEW(widget); - view->list = g_list_first(view->list); - g_list_foreach(view->list, free_text_line, NULL); - g_list_free(view->list); - g_list_foreach(view->tags, free_tag, NULL); - g_list_free(view->tags); - g_string_free(view->string, TRUE); -} - -static char * -gnt_text_view_get_p(GntTextView *view, int x, int y) -{ - int i = 0; - GntWidget *wid = GNT_WIDGET(view); - GntTextLine *line; - GList *lines; - GList *segs; - GntTextSegment *seg; - gchar *pos; - - y = wid->priv.height - y; - if (g_list_length(view->list) < y) { - x = 0; - y = g_list_length(view->list) - 1; - } - - lines = g_list_nth(view->list, y - 1); - if (!lines) - return NULL; - do { - line = lines->data; - lines = lines->next; - } while (line && !line->segments && lines); - - if (!line || !line->segments) /* no valid line */ - return NULL; - segs = line->segments; - seg = (GntTextSegment *)segs->data; - pos = view->string->str + seg->start; - x = MIN(x, line->length); - while (++i <= x) { - gunichar *u; - pos = g_utf8_next_char(pos); - u = g_utf8_to_ucs4(pos, -1, NULL, NULL, NULL); - if (u && g_unichar_iswide(*u)) - i++; - g_free(u); - } - return pos; -} - -static GString * -select_word_text(GntTextView *view, gchar *c) -{ - gchar *start = c; - gchar *end = c; - gchar *t, *endsize; - while ((t = g_utf8_prev_char(start))) { - if (!g_ascii_isspace(*t)) { - if (start == view->string->str) - break; - start = t; - } else - break; - } - while ((t = g_utf8_next_char(end))) { - if (!g_ascii_isspace(*t)) - end = t; - else - break; - } - select_start = start; - select_end = end; - endsize = g_utf8_next_char(select_end); /* End at the correct byte */ - return g_string_new_len(start, endsize - start); -} - -static gboolean too_slow(gpointer n) -{ - double_click = FALSE; - return FALSE; -} - -static gboolean -gnt_text_view_clicked(GntWidget *widget, GntMouseEvent event, int x, int y) -{ - if (event == GNT_MOUSE_SCROLL_UP) { - gnt_text_view_scroll(GNT_TEXT_VIEW(widget), -1); - } else if (event == GNT_MOUSE_SCROLL_DOWN) { - gnt_text_view_scroll(GNT_TEXT_VIEW(widget), 1); - } else if (event == GNT_LEFT_MOUSE_DOWN) { - select_start = gnt_text_view_get_p(GNT_TEXT_VIEW(widget), x - widget->priv.x, y - widget->priv.y); - g_timeout_add(500, too_slow, NULL); - } else if (event == GNT_MOUSE_UP) { - if (select_start) { - GString *clip; - select_end = gnt_text_view_get_p(GNT_TEXT_VIEW(widget), x - widget->priv.x, y - widget->priv.y); - if (select_end < select_start) { - gchar *t = select_start; - select_start = select_end; - select_end = t; - } - if (select_start == select_end) { - if (double_click) { - clip = select_word_text(GNT_TEXT_VIEW(widget), select_start); - double_click = FALSE; - } else { - double_click = TRUE; - select_start = 0; - select_end = 0; - gnt_widget_draw(widget); - return TRUE; - } - } else { - gchar *endsize = g_utf8_next_char(select_end); /* End at the correct byte */ - clip = g_string_new_len(select_start, endsize - select_start); - } - gnt_widget_draw(widget); - gnt_set_clipboard_string(clip->str); - g_string_free(clip, TRUE); - } - } else - return FALSE; - return TRUE; -} - -static void -gnt_text_view_reflow(GntTextView *view) -{ - /* This is pretty ugly, and inefficient. Someone do something about it. */ - GntTextLine *line; - GList *back, *iter, *list; - GString *string; - int pos = 0; /* no. of 'real' lines */ - - list = view->list; - while (list->prev) { - line = list->data; - if (!line->soft) - pos++; - list = list->prev; - } - - back = g_list_last(view->list); - view->list = NULL; - - string = view->string; - view->string = NULL; - gnt_text_view_clear(view); - - view->string = g_string_set_size(view->string, string->len); - view->string->len = 0; - GNT_WIDGET_SET_FLAGS(GNT_WIDGET(view), GNT_WIDGET_DRAWING); - - for (; back; back = back->prev) { - line = back->data; - if (back->next && !line->soft) { - gnt_text_view_append_text_with_flags(view, "\n", GNT_TEXT_FLAG_NORMAL); - } - - for (iter = line->segments; iter; iter = iter->next) { - GntTextSegment *seg = iter->data; - char *start = string->str + seg->start; - char *end = string->str + seg->end; - char back = *end; - *end = '\0'; - gnt_text_view_append_text_with_flags(view, start, seg->tvflag); - *end = back; - } - free_text_line(line, NULL); - } - g_list_free(list); - - list = view->list = g_list_first(view->list); - /* Go back to the line that was in view before resizing started */ - while (pos--) { - while (((GntTextLine*)list->data)->soft) - list = list->next; - list = list->next; - } - view->list = list; - GNT_WIDGET_UNSET_FLAGS(GNT_WIDGET(view), GNT_WIDGET_DRAWING); - if (GNT_WIDGET(view)->window) - gnt_widget_draw(GNT_WIDGET(view)); - g_string_free(string, TRUE); -} - -static void -gnt_text_view_size_changed(GntWidget *widget, int w, int h) -{ - if (w != widget->priv.width) { - gnt_text_view_reflow(GNT_TEXT_VIEW(widget)); - } -} - -static void -gnt_text_view_class_init(GntTextViewClass *klass) -{ - parent_class = GNT_WIDGET_CLASS(klass); - parent_class->destroy = gnt_text_view_destroy; - parent_class->draw = gnt_text_view_draw; - parent_class->map = gnt_text_view_map; - parent_class->size_request = gnt_text_view_size_request; - parent_class->key_pressed = gnt_text_view_key_pressed; - parent_class->clicked = gnt_text_view_clicked; - parent_class->size_changed = gnt_text_view_size_changed; - - GNTDEBUG; -} - -static void -gnt_text_view_init(GTypeInstance *instance, gpointer class) -{ - GntWidget *widget = GNT_WIDGET(instance); - - GNT_WIDGET_SET_FLAGS(GNT_WIDGET(instance), GNT_WIDGET_GROW_Y | GNT_WIDGET_GROW_X); - - widget->priv.minw = 5; - widget->priv.minh = 2; - GNTDEBUG; -} - -/****************************************************************************** - * GntTextView API - *****************************************************************************/ -GType -gnt_text_view_get_gtype(void) -{ - static GType type = 0; - - if(type == 0) - { - static const GTypeInfo info = { - sizeof(GntTextViewClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc)gnt_text_view_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof(GntTextView), - 0, /* n_preallocs */ - gnt_text_view_init, /* instance_init */ - NULL /* value_table */ - }; - - type = g_type_register_static(GNT_TYPE_WIDGET, - "GntTextView", - &info, 0); - } - - return type; -} - -GntWidget *gnt_text_view_new() -{ - GntWidget *widget = g_object_new(GNT_TYPE_TEXTVIEW, NULL); - GntTextView *view = GNT_TEXT_VIEW(widget); - GntTextLine *line = g_new0(GntTextLine, 1); - - GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW); - - view->string = g_string_new(NULL); - view->list = g_list_append(view->list, line); - - return widget; -} - -void gnt_text_view_append_text_with_flags(GntTextView *view, const char *text, GntTextFormatFlags flags) -{ - gnt_text_view_append_text_with_tag(view, text, flags, NULL); -} - -void gnt_text_view_append_text_with_tag(GntTextView *view, const char *text, - GntTextFormatFlags flags, const char *tagname) -{ - GntWidget *widget = GNT_WIDGET(view); - int fl = 0; - const char *start, *end; - GList *list = view->list; - GntTextLine *line; - int len; - - if (text == NULL || *text == '\0') - return; - - fl = gnt_text_format_flag_to_chtype(flags); - - len = view->string->len; - view->string = g_string_append(view->string, text); - - if (tagname) { - GntTextTag *tag = g_new0(GntTextTag, 1); - tag->name = g_strdup(tagname); - tag->start = len; - tag->end = view->string->len; - view->tags = g_list_append(view->tags, tag); - } - - view->list = g_list_first(view->list); - - start = end = view->string->str + len; - - while (*start) { - GntTextSegment *seg = NULL; - - if (*end == '\n' || *end == '\r') { - end++; - start = end; - gnt_text_view_next_line(view); - view->list = g_list_first(view->list); - continue; - } - - line = view->list->data; - if (line->length == widget->priv.width - 1) { - /* The last added line was exactly the same width as the widget */ - line = g_new0(GntTextLine, 1); - line->soft = TRUE; - view->list = g_list_prepend(view->list, line); - } - - if ((end = strchr(start, '\n')) != NULL || - (end = strchr(start, '\r')) != NULL) { - len = gnt_util_onscreen_width(start, end - 1); - if (len >= widget->priv.width - line->length - 1) { - end = NULL; - } - } - - if (end == NULL) - end = gnt_util_onscreen_width_to_pointer(start, - widget->priv.width - line->length - 1, &len); - - /* Try to append to the previous segment if possible */ - if (line->segments) { - seg = g_list_last(line->segments)->data; - if (seg->flags != fl) - seg = NULL; - } - - if (seg == NULL) { - seg = g_new0(GntTextSegment, 1); - seg->start = start - view->string->str; - seg->tvflag = flags; - seg->flags = fl; - line->segments = g_list_append(line->segments, seg); - } - seg->end = end - view->string->str; - line->length += len; - - start = end; - if (*end && *end != '\n' && *end != '\r') { - line = g_new0(GntTextLine, 1); - line->soft = TRUE; - view->list = g_list_prepend(view->list, line); - } - } - - view->list = list; - - gnt_widget_draw(widget); -} - -void gnt_text_view_scroll(GntTextView *view, int scroll) -{ - if (scroll == 0) - { - view->list = g_list_first(view->list); - } - else if (scroll > 0) - { - GList *list = g_list_nth_prev(view->list, scroll); - if (list == NULL) - list = g_list_first(view->list); - view->list = list; - } - else if (scroll < 0) - { - GList *list = g_list_nth(view->list, -scroll); - if (list == NULL) - list = g_list_last(view->list); - view->list = list; - } - - gnt_widget_draw(GNT_WIDGET(view)); -} - -void gnt_text_view_next_line(GntTextView *view) -{ - GntTextLine *line = g_new0(GntTextLine, 1); - GList *list = view->list; - - view->list = g_list_prepend(g_list_first(view->list), line); - view->list = list; - gnt_widget_draw(GNT_WIDGET(view)); -} - -chtype gnt_text_format_flag_to_chtype(GntTextFormatFlags flags) -{ - chtype fl = 0; - - if (flags & GNT_TEXT_FLAG_BOLD) - fl |= A_BOLD; - if (flags & GNT_TEXT_FLAG_UNDERLINE) - fl |= A_UNDERLINE; - if (flags & GNT_TEXT_FLAG_BLINK) - fl |= A_BLINK; - - if (flags & GNT_TEXT_FLAG_DIM) - fl |= (A_DIM | COLOR_PAIR(GNT_COLOR_DISABLED)); - else if (flags & GNT_TEXT_FLAG_HIGHLIGHT) - fl |= (A_DIM | COLOR_PAIR(GNT_COLOR_HIGHLIGHT)); - else - fl |= COLOR_PAIR(GNT_COLOR_NORMAL); - - return fl; -} - -void gnt_text_view_clear(GntTextView *view) -{ - GntTextLine *line; - - g_list_foreach(view->list, free_text_line, NULL); - g_list_free(view->list); - view->list = NULL; - - line = g_new0(GntTextLine, 1); - view->list = g_list_append(view->list, line); - if (view->string) - g_string_free(view->string, TRUE); - view->string = g_string_new(NULL); - - if (GNT_WIDGET(view)->window) - gnt_widget_draw(GNT_WIDGET(view)); -} - -int gnt_text_view_get_lines_below(GntTextView *view) -{ - int below = 0; - GList *list = view->list; - while ((list = list->prev)) - ++below; - return below; -} - -int gnt_text_view_get_lines_above(GntTextView *view) -{ - int above = 0; - GList *list = view->list; - list = g_list_nth(view->list, GNT_WIDGET(view)->priv.height); - if (!list) - return 0; - while ((list = list->next)) - ++above; - return above; -} - -/** - * XXX: There are quite possibly more than a few bugs here. - */ -int gnt_text_view_tag_change(GntTextView *view, const char *name, const char *text, gboolean all) -{ - GList *alllines = g_list_first(view->list); - GList *list, *next, *iter, *inext; - const int text_length = text ? strlen(text) : 0; - int count = 0; - for (list = view->tags; list; list = next) { - GntTextTag *tag = list->data; - next = list->next; - if (strcmp(tag->name, name) == 0) { - int change; - char *before, *after; - - count++; - - before = g_strndup(view->string->str, tag->start); - after = g_strdup(view->string->str + tag->end); - change = (tag->end - tag->start) - text_length; - - g_string_printf(view->string, "%s%s%s", before, text ? text : "", after); - g_free(before); - g_free(after); - - /* Update the offsets of the next tags */ - for (iter = next; iter; iter = iter->next) { - GntTextTag *t = iter->data; - t->start -= change; - t->end -= change; - } - - /* Update the offsets of the segments */ - for (iter = alllines; iter; iter = inext) { - GList *segs, *snext; - GntTextLine *line = iter->data; - inext = iter->next; - for (segs = line->segments; segs; segs = snext) { - GntTextSegment *seg = segs->data; - snext = segs->next; - if (seg->start >= tag->end) { - /* The segment is somewhere after the tag */ - seg->start -= change; - seg->end -= change; - } else if (seg->end <= tag->start) { - /* This segment is somewhere in front of the tag */ - } else if (seg->start >= tag->start) { - /* This segment starts in the middle of the tag */ - if (text == NULL) { - free_text_segment(seg, NULL); - line->segments = g_list_delete_link(line->segments, segs); - if (line->segments == NULL) { - free_text_line(line, NULL); - if (view->list == iter) { - if (inext) - view->list = inext; - else - view->list = iter->prev; - } - alllines = g_list_delete_link(alllines, iter); - } - } else { - /* XXX: (null) */ - seg->start = tag->start; - seg->end = tag->end - change; - } - line->length -= change; - /* XXX: Make things work if the tagged text spans over several lines. */ - } else { - /* XXX: handle the rest of the conditions */ - g_printerr("WTF! This needs to be handled properly!!\n"); - } - } - } - if (text == NULL) { - /* Remove the tag */ - view->tags = g_list_delete_link(view->tags, list); - free_tag(tag, NULL); - } else { - tag->end -= change; - } - if (!all) - break; - } - } - return count; -} - diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gnttextview.h --- a/console/libgnt/gnttextview.h Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,86 +0,0 @@ -#ifndef GNT_TEXT_VIEW_H -#define GNT_TEXT_VIEW_H - -#include "gntwidget.h" -#include "gnt.h" -#include "gntcolors.h" -#include "gntkeys.h" - -#define GNT_TYPE_TEXTVIEW (gnt_text_view_get_gtype()) -#define GNT_TEXT_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNT_TYPE_TEXTVIEW, GntTextView)) -#define GNT_TEXT_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GNT_TYPE_TEXTVIEW, GntTextViewClass)) -#define GNT_IS_TEXTVIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GNT_TYPE_TEXTVIEW)) -#define GNT_IS_TEXTVIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GNT_TYPE_TEXTVIEW)) -#define GNT_TEXT_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GNT_TYPE_TEXTVIEW, GntTextViewClass)) - -#define GNT_TEXT_VIEW_FLAGS(obj) (GNT_TEXT_VIEW(obj)->priv.flags) -#define GNT_TEXT_VIEW_SET_FLAGS(obj, flags) (GNT_TEXT_VIEW_FLAGS(obj) |= flags) -#define GNT_TEXT_VIEW_UNSET_FLAGS(obj, flags) (GNT_TEXT_VIEW_FLAGS(obj) &= ~(flags)) - -typedef struct _GnTextView GntTextView; -typedef struct _GnTextViewPriv GntTextViewPriv; -typedef struct _GnTextViewClass GntTextViewClass; - -struct _GnTextView -{ - GntWidget parent; - - GString *string; - GList *list; /* List of GntTextLine */ - - GList *tags; /* A list of tags */ -}; - -typedef enum -{ - GNT_TEXT_FLAG_NORMAL = 0, - GNT_TEXT_FLAG_BOLD = 1 << 0, - GNT_TEXT_FLAG_UNDERLINE = 1 << 1, - GNT_TEXT_FLAG_BLINK = 1 << 2, - GNT_TEXT_FLAG_DIM = 1 << 3, - GNT_TEXT_FLAG_HIGHLIGHT = 1 << 4, -} GntTextFormatFlags; - -struct _GnTextViewClass -{ - GntWidgetClass parent; - - void (*gnt_reserved1)(void); - void (*gnt_reserved2)(void); - void (*gnt_reserved3)(void); - void (*gnt_reserved4)(void); -}; - -G_BEGIN_DECLS - -GType gnt_text_view_get_gtype(void); - -/* XXX: For now, don't set a textview to have any border. - * If you want borders real bad, put it in a box. */ -GntWidget *gnt_text_view_new(void); - -/* scroll > 0 means scroll up, < 0 means scroll down, == 0 means scroll to the end */ -void gnt_text_view_scroll(GntTextView *view, int scroll); - -void gnt_text_view_append_text_with_flags(GntTextView *view, const char *text, GntTextFormatFlags flags); - -void gnt_text_view_append_text_with_tag(GntTextView *view, const char *text, GntTextFormatFlags flags, const char *tag); - -/* Move the cursor to the beginning of the next line and resets text-attributes. - * It first completes the current line with the current text-attributes. */ -void gnt_text_view_next_line(GntTextView *view); - -chtype gnt_text_format_flag_to_chtype(GntTextFormatFlags flags); - -void gnt_text_view_clear(GntTextView *view); - -int gnt_text_view_get_lines_below(GntTextView *view); - -int gnt_text_view_get_lines_above(GntTextView *view); - -/* If text is NULL, then the tag is removed. */ -int gnt_text_view_tag_change(GntTextView *view, const char *name, const char *text, gboolean all); - -G_END_DECLS - -#endif /* GNT_TEXT_VIEW_H */ diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gnttree.c --- a/console/libgnt/gnttree.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1499 +0,0 @@ -#include "gntmarshal.h" -#include "gntstyle.h" -#include "gnttree.h" -#include "gntutils.h" - -#include -#include - -#define SEARCH_TIMEOUT 4000 /* 4 secs */ - -enum -{ - SIG_SELECTION_CHANGED, - SIG_SCROLLED, - SIG_TOGGLED, - SIGS, -}; - -#define TAB_SIZE 3 - -/* XXX: Make this one into a GObject? - * ... Probably not */ -struct _GnTreeRow -{ - void *key; - void *data; /* XXX: unused */ - - gboolean collapsed; - gboolean choice; /* Is this a choice-box? - If choice is true, then child will be NULL */ - gboolean isselected; - GntTextFormatFlags flags; - - GntTreeRow *parent; - GntTreeRow *child; - GntTreeRow *next; - GntTreeRow *prev; - - GList *columns; - GntTree *tree; -}; - -struct _GnTreeCol -{ - char *text; - int span; /* How many columns does it span? */ -}; - -static GntWidgetClass *parent_class = NULL; -static guint signals[SIGS] = { 0 }; - -/* Move the item at position old to position new */ -static GList * -g_list_reposition_child(GList *list, int old, int new) -{ - gpointer item = g_list_nth_data(list, old); - list = g_list_remove(list, item); - if (old < new) - new--; /* because the positions would have shifted after removing the item */ - list = g_list_insert(list, item, new); - return list; -} - -static GntTreeRow * -_get_next(GntTreeRow *row, gboolean godeep) -{ - if (row == NULL) - return NULL; - if (godeep && row->child) - return row->child; - if (row->next) - return row->next; - return _get_next(row->parent, FALSE); -} - -static gboolean -row_matches_search(GntTreeRow *row) -{ - GntTree *t = row->tree; - if (t->search && t->search->len > 0) { - char *one = g_utf8_casefold(((GntTreeCol*)row->columns->data)->text, -1); - char *two = g_utf8_casefold(t->search->str, -1); - char *z = strstr(one, two); - g_free(one); - g_free(two); - if (z == NULL) - return FALSE; - } - return TRUE; -} - -static GntTreeRow * -get_next(GntTreeRow *row) -{ - if (row == NULL) - return NULL; - while ((row = _get_next(row, !row->collapsed)) != NULL) { - if (row_matches_search(row)) - break; - } - return row; -} - -/* Returns the n-th next row. If it doesn't exist, returns NULL */ -static GntTreeRow * -get_next_n(GntTreeRow *row, int n) -{ - while (row && n--) - row = get_next(row); - return row; -} - -/* Returns the n-th next row. If it doesn't exist, then the last non-NULL node */ -static GntTreeRow * -get_next_n_opt(GntTreeRow *row, int n, int *pos) -{ - GntTreeRow *next = row; - int r = 0; - - if (row == NULL) - return NULL; - - while (row && n--) - { - row = get_next(row); - if (row) - { - next = row; - r++; - } - } - - if (pos) - *pos = r; - - return next; -} - -static GntTreeRow * -get_last_child(GntTreeRow *row) -{ - if (row == NULL) - return NULL; - if (!row->collapsed && row->child) - row = row->child; - else - return row; - - while(row->next) - row = row->next; - if (!row->collapsed && row->child) - row = get_last_child(row->child); - return row; -} - -static GntTreeRow * -get_prev(GntTreeRow *row) -{ - if (row == NULL) - return NULL; - while (row) { - if (row->prev) - row = get_last_child(row->prev); - else - row = row->parent; - if (!row || row_matches_search(row)) - break; - } - return row; -} - -static GntTreeRow * -get_prev_n(GntTreeRow *row, int n) -{ - while (row && n--) - row = get_prev(row); - return row; -} - -/* Distance of row from the root */ -/* XXX: This is uber-inefficient */ -static int -get_root_distance(GntTreeRow *row) -{ - if (row == NULL) - return -1; - return get_root_distance(get_prev(row)) + 1; -} - -/* Returns the distance between a and b. - * If a is 'above' b, then the distance is positive */ -static int -get_distance(GntTreeRow *a, GntTreeRow *b) -{ - /* First get the distance from a to the root. - * Then the distance from b to the root. - * Subtract. - * It's not that good, but it works. */ - int ha = get_root_distance(a); - int hb = get_root_distance(b); - - return (hb - ha); -} - -static int -find_depth(GntTreeRow *row) -{ - int dep = -1; - - while (row) - { - dep++; - row = row->parent; - } - - return dep; -} - -static char * -update_row_text(GntTree *tree, GntTreeRow *row) -{ - GString *string = g_string_new(NULL); - GList *iter; - int i; - - for (i = 0, iter = row->columns; i < tree->ncol && iter; i++, iter = iter->next) - { - GntTreeCol *col = iter->data; - const char *text; - int len = gnt_util_onscreen_width(col->text, NULL); - int fl = 0; - gboolean cut = FALSE; - - if (i == 0) - { - if (row->choice) - { - g_string_append_printf(string, "[%c] ", - row->isselected ? 'X' : ' '); - fl = 4; - } - else if (row->parent == NULL && row->child) - { - if (row->collapsed) - { - string = g_string_append(string, "+ "); - } - else - { - string = g_string_append(string, "- "); - } - fl = 2; - } - else - { - fl = TAB_SIZE * find_depth(row); - g_string_append_printf(string, "%*s", fl, ""); - } - len += fl; - } - else - g_string_append_c(string, '|'); - - if (len > tree->columns[i].width) { - len = tree->columns[i].width - 1; - cut = TRUE; - } - text = gnt_util_onscreen_width_to_pointer(col->text, len - fl, NULL); - string = g_string_append_len(string, col->text, text - col->text); - if (cut) { /* ellipsis */ - if (gnt_ascii_only()) - g_string_append_c(string, '~'); - else - string = g_string_append(string, "\342\200\246"); - len++; - } - - if (len < tree->columns[i].width && iter->next) - g_string_append_printf(string, "%*s", tree->columns[i].width - len, ""); - } - return g_string_free(string, FALSE); -} - -static void -tree_mark_columns(GntTree *tree, int pos, int y, chtype type) -{ - GntWidget *widget = GNT_WIDGET(tree); - int i; - int x = pos; - - for (i = 0; i < tree->ncol - 1; i++) - { - x += tree->columns[i].width; - mvwaddch(widget->window, y, x + i, type); - } -} - -static void -redraw_tree(GntTree *tree) -{ - int start, i; - GntWidget *widget = GNT_WIDGET(tree); - GntTreeRow *row; - int pos, up, down; - int rows, scrcol; - - if (!GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(tree), GNT_WIDGET_MAPPED)) - return; - - if (GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER)) - pos = 0; - else - pos = 1; - - if (tree->top == NULL) - tree->top = tree->root; - if (tree->current == NULL) - tree->current = tree->root; - - wbkgd(widget->window, COLOR_PAIR(GNT_COLOR_NORMAL)); - - start = 0; - if (tree->show_title) - { - int i; - int x = pos; - - mvwhline(widget->window, pos + 1, pos, ACS_HLINE | COLOR_PAIR(GNT_COLOR_NORMAL), - widget->priv.width - pos - 1); - - for (i = 0; i < tree->ncol; i++) - { - mvwaddstr(widget->window, pos, x + i, tree->columns[i].title); - x += tree->columns[i].width; - } - if (pos) - { - tree_mark_columns(tree, pos, 0, ACS_TTEE | COLOR_PAIR(GNT_COLOR_NORMAL)); - tree_mark_columns(tree, pos, widget->priv.height - pos, - ACS_BTEE | COLOR_PAIR(GNT_COLOR_NORMAL)); - } - tree_mark_columns(tree, pos, pos + 1, - (tree->show_separator ? ACS_PLUS : ACS_HLINE) | COLOR_PAIR(GNT_COLOR_NORMAL)); - tree_mark_columns(tree, pos, pos, - (tree->show_separator ? ACS_VLINE : ' ') | COLOR_PAIR(GNT_COLOR_NORMAL)); - start = 2; - } - - rows = widget->priv.height - pos * 2 - start - 1; - tree->bottom = get_next_n_opt(tree->top, rows, &down); - if (down < rows) - { - tree->top = get_prev_n(tree->bottom, rows); - if (tree->top == NULL) - tree->top = tree->root; - } - - up = get_distance(tree->top, tree->current); - if (up < 0) - tree->top = tree->current; - else if (up >= widget->priv.height - pos) - tree->top = get_prev_n(tree->current, rows); - - if (tree->top && !row_matches_search(tree->top)) - tree->top = get_next(tree->top); - row = tree->top; - scrcol = widget->priv.width - 1 - 2 * pos; /* exclude the borders and the scrollbar */ - for (i = start + pos; row && i < widget->priv.height - pos; - i++, row = get_next(row)) - { - char *str; - int wr; - - GntTextFormatFlags flags = row->flags; - int attr = 0; - - if (!row_matches_search(row)) - continue; - str = update_row_text(tree, row); - - if ((wr = gnt_util_onscreen_width(str, NULL)) > scrcol) - { - char *s = (char*)gnt_util_onscreen_width_to_pointer(str, scrcol, &wr); - *s = '\0'; - } - - if (flags & GNT_TEXT_FLAG_BOLD) - attr |= A_BOLD; - if (flags & GNT_TEXT_FLAG_UNDERLINE) - attr |= A_UNDERLINE; - if (flags & GNT_TEXT_FLAG_BLINK) - attr |= A_BLINK; - - if (row == tree->current) - { - if (gnt_widget_has_focus(widget)) - attr |= COLOR_PAIR(GNT_COLOR_HIGHLIGHT); - else - attr |= COLOR_PAIR(GNT_COLOR_HIGHLIGHT_D); - } - else - { - if (flags & GNT_TEXT_FLAG_DIM) - attr |= (A_DIM | COLOR_PAIR(GNT_COLOR_DISABLED)); - else if (flags & GNT_TEXT_FLAG_HIGHLIGHT) - attr |= (A_DIM | COLOR_PAIR(GNT_COLOR_HIGHLIGHT)); - else - attr |= COLOR_PAIR(GNT_COLOR_NORMAL); - } - - wbkgdset(widget->window, '\0' | attr); - mvwaddstr(widget->window, i, pos, str); - whline(widget->window, ' ', scrcol - wr); - tree->bottom = row; - g_free(str); - tree_mark_columns(tree, pos, i, - (tree->show_separator ? ACS_VLINE : ' ') | attr); - } - - wbkgdset(widget->window, '\0' | COLOR_PAIR(GNT_COLOR_NORMAL)); - while (i < widget->priv.height - pos) - { - mvwhline(widget->window, i, pos, ' ', - widget->priv.width - pos * 2 - 1); - tree_mark_columns(tree, pos, i, - (tree->show_separator ? ACS_VLINE : ' ')); - i++; - } - - scrcol = widget->priv.width - pos - 1; /* position of the scrollbar */ - rows--; - if (rows > 0) - { - int total; - int showing, position; - - get_next_n_opt(tree->root, g_list_length(tree->list), &total); - showing = rows * rows / MAX(total, 1) + 1; - showing = MIN(rows, showing); - - total -= rows; - up = get_distance(tree->root, tree->top); - down = total - up; - - position = (rows - showing) * up / MAX(1, up + down); - position = MAX((tree->top != tree->root), position); - - if (showing + position > rows) - position = rows - showing; - - if (showing + position == rows && row) - position = MAX(0, rows - 1 - showing); - else if (showing + position < rows && !row) - position = rows - showing; - - position += pos + start + 1; - - mvwvline(widget->window, pos + start + 1, scrcol, - ' ' | COLOR_PAIR(GNT_COLOR_NORMAL), rows); - mvwvline(widget->window, position, scrcol, - ACS_CKBOARD | COLOR_PAIR(GNT_COLOR_HIGHLIGHT_D), showing); - } - - mvwaddch(widget->window, start + pos, scrcol, - ((tree->top != tree->root) ? ACS_UARROW : ' ') | - COLOR_PAIR(GNT_COLOR_HIGHLIGHT_D)); - - mvwaddch(widget->window, widget->priv.height - pos - 1, scrcol, - (row ? ACS_DARROW : ' ') | COLOR_PAIR(GNT_COLOR_HIGHLIGHT_D)); - - gnt_widget_queue_update(widget); -} - -static void -gnt_tree_draw(GntWidget *widget) -{ - GntTree *tree = GNT_TREE(widget); - - redraw_tree(tree); - - GNTDEBUG; -} - -static void -gnt_tree_size_request(GntWidget *widget) -{ - if (widget->priv.height == 0) - widget->priv.height = 10; /* XXX: Why?! */ - if (widget->priv.width == 0) - { - GntTree *tree = GNT_TREE(widget); - int i, width = 0; - for (i = 0; i < tree->ncol; i++) - width += tree->columns[i].width; - widget->priv.width = width + i; - } -} - -static void -gnt_tree_map(GntWidget *widget) -{ - GntTree *tree = GNT_TREE(widget); - if (widget->priv.width == 0 || widget->priv.height == 0) - { - gnt_widget_size_request(widget); - } - tree->top = tree->root; - tree->current = tree->root; - GNTDEBUG; -} - -static void -tree_selection_changed(GntTree *tree, GntTreeRow *old, GntTreeRow *current) -{ - g_signal_emit(tree, signals[SIG_SELECTION_CHANGED], 0, old ? old->key : NULL, - current ? current->key : NULL); -} - -static gboolean -action_down(GntBindable *bind, GList *null) -{ - int dist; - GntTree *tree = GNT_TREE(bind); - GntTreeRow *old = tree->current; - GntTreeRow *row = get_next(tree->current); - if (row == NULL) - return FALSE; - tree->current = row; - if ((dist = get_distance(tree->current, tree->bottom)) < 0) - gnt_tree_scroll(tree, -dist); - else - redraw_tree(tree); - if (old != tree->current) - tree_selection_changed(tree, old, tree->current); - return TRUE; -} - -static gboolean -action_up(GntBindable *bind, GList *list) -{ - int dist; - GntTree *tree = GNT_TREE(bind); - GntTreeRow *old = tree->current; - GntTreeRow *row = get_prev(tree->current); - if (!row) - return FALSE; - tree->current = row; - if ((dist = get_distance(tree->current, tree->top)) > 0) - gnt_tree_scroll(tree, -dist); - else - redraw_tree(tree); - if (old != tree->current) - tree_selection_changed(tree, old, tree->current); - - return TRUE; -} - -static gboolean -action_page_down(GntBindable *bind, GList *null) -{ - GntTree *tree = GNT_TREE(bind); - GntTreeRow *old = tree->current; - GntTreeRow *row = get_next(tree->bottom); - if (row) - { - int dist = get_distance(tree->top, tree->current); - tree->top = tree->bottom; - tree->current = get_next_n_opt(tree->top, dist, NULL); - redraw_tree(tree); - } - else if (tree->current != tree->bottom) - { - tree->current = tree->bottom; - redraw_tree(tree); - } - - if (old != tree->current) - tree_selection_changed(tree, old, tree->current); - return TRUE; -} - -static gboolean -action_page_up(GntBindable *bind, GList *null) -{ - GntWidget *widget = GNT_WIDGET(bind); - GntTree *tree = GNT_TREE(bind); - GntTreeRow *row; - GntTreeRow *old = tree->current; - - if (tree->top != tree->root) - { - int dist = get_distance(tree->top, tree->current); - row = get_prev_n(tree->top, widget->priv.height - 1 - - tree->show_title * 2 - 2 * (GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER) == 0)); - if (row == NULL) - row = tree->root; - tree->top = row; - tree->current = get_next_n_opt(tree->top, dist, NULL); - redraw_tree(tree); - } - else if (tree->current != tree->top) - { - tree->current = tree->top; - redraw_tree(tree); - } - if (old != tree->current) - tree_selection_changed(tree, old, tree->current); - return TRUE; -} - -static void -end_search(GntTree *tree) -{ - if (tree->search) { - g_source_remove(tree->search_timeout); - g_string_free(tree->search, TRUE); - tree->search = NULL; - tree->search_timeout = 0; - } -} - -static gboolean -search_timeout(gpointer data) -{ - GntTree *tree = data; - - end_search(tree); - redraw_tree(tree); - - return FALSE; -} - -static gboolean -gnt_tree_key_pressed(GntWidget *widget, const char *text) -{ - GntTree *tree = GNT_TREE(widget); - GntTreeRow *old = tree->current; - - if (text[0] == '\r') { - end_search(tree); - gnt_widget_activate(widget); - } else if (tree->search) { - if (isalnum(*text)) { - tree->search = g_string_append_c(tree->search, *text); - redraw_tree(tree); - g_source_remove(tree->search_timeout); - tree->search_timeout = g_timeout_add(SEARCH_TIMEOUT, search_timeout, tree); - } - return TRUE; - } else if (text[0] == ' ' && text[1] == 0) { - /* Space pressed */ - GntTreeRow *row = tree->current; - if (row && row->child) - { - row->collapsed = !row->collapsed; - redraw_tree(tree); - } - else if (row && row->choice) - { - row->isselected = !row->isselected; - g_signal_emit(tree, signals[SIG_TOGGLED], 0, row->key); - redraw_tree(tree); - } - } - - if (old != tree->current) - { - tree_selection_changed(tree, old, tree->current); - return TRUE; - } - - return FALSE; -} - -static void -gnt_tree_destroy(GntWidget *widget) -{ - GntTree *tree = GNT_TREE(widget); - int i; - - end_search(tree); - if (tree->hash) - g_hash_table_destroy(tree->hash); - g_list_free(tree->list); - - for (i = 0; i < tree->ncol; i++) - { - g_free(tree->columns[i].title); - } - g_free(tree->columns); -} - -static gboolean -gnt_tree_clicked(GntWidget *widget, GntMouseEvent event, int x, int y) -{ - GntTree *tree = GNT_TREE(widget); - GntTreeRow *old = tree->current; - if (event == GNT_MOUSE_SCROLL_UP) { - action_up(GNT_BINDABLE(widget), NULL); - } else if (event == GNT_MOUSE_SCROLL_DOWN) { - action_down(GNT_BINDABLE(widget), NULL); - } else if (event == GNT_LEFT_MOUSE_DOWN) { - GntTreeRow *row; - GntTree *tree = GNT_TREE(widget); - int pos = 1; - if (GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER)) - pos = 0; - if (tree->show_title) - pos += 2; - pos = y - widget->priv.y - pos; - row = get_next_n(tree->top, pos); - if (row && tree->current != row) { - GntTreeRow *old = tree->current; - tree->current = row; - redraw_tree(tree); - tree_selection_changed(tree, old, tree->current); - } else if (row && row == tree->current) { - if (row->choice) { - row->isselected = !row->isselected; - g_signal_emit(tree, signals[SIG_TOGGLED], 0, row->key); - redraw_tree(tree); - } else { - gnt_widget_activate(widget); - } - } - } else { - return FALSE; - } - if (old != tree->current) { - tree_selection_changed(tree, old, tree->current); - } - return TRUE; -} - -static void -gnt_tree_size_changed(GntWidget *widget, int w, int h) -{ - GntTree *tree = GNT_TREE(widget); - int i; - int n = 0; - if (widget->priv.width <= 0) - return; - for (i = 0; i < tree->ncol; ++i) - n += tree->columns[i].width; - if (GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER)) - tree->columns[tree->ncol - 1].width += widget->priv.width - n - 1 * tree->ncol; - else - tree->columns[tree->ncol - 1].width += widget->priv.width - n - 2 - 1 * tree->ncol; -} - -static gboolean -start_search(GntBindable *bindable, GList *list) -{ - GntTree *tree = GNT_TREE(bindable); - if (tree->search) - return FALSE; - tree->search = g_string_new(NULL); - tree->search_timeout = g_timeout_add(SEARCH_TIMEOUT, search_timeout, tree); - return TRUE; -} - -static gboolean -end_search_action(GntBindable *bindable, GList *list) -{ - GntTree *tree = GNT_TREE(bindable); - if (tree->search == NULL) - return FALSE; - end_search(tree); - redraw_tree(tree); - return TRUE; -} - -static void -gnt_tree_class_init(GntTreeClass *klass) -{ - GntBindableClass *bindable = GNT_BINDABLE_CLASS(klass); - parent_class = GNT_WIDGET_CLASS(klass); - parent_class->destroy = gnt_tree_destroy; - parent_class->draw = gnt_tree_draw; - parent_class->map = gnt_tree_map; - parent_class->size_request = gnt_tree_size_request; - parent_class->key_pressed = gnt_tree_key_pressed; - parent_class->clicked = gnt_tree_clicked; - parent_class->size_changed = gnt_tree_size_changed; - - signals[SIG_SELECTION_CHANGED] = - g_signal_new("selection-changed", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GntTreeClass, selection_changed), - NULL, NULL, - gnt_closure_marshal_VOID__POINTER_POINTER, - G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER); - signals[SIG_SCROLLED] = - g_signal_new("scrolled", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__INT, - G_TYPE_NONE, 1, G_TYPE_INT); - signals[SIG_TOGGLED] = - g_signal_new("toggled", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GntTreeClass, toggled), - NULL, NULL, - g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, G_TYPE_POINTER); - - gnt_bindable_class_register_action(bindable, "move-up", action_up, - GNT_KEY_UP, NULL); - gnt_bindable_register_binding(bindable, "move-up", GNT_KEY_CTRL_P, NULL); - 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, "page-up", action_page_up, - GNT_KEY_PGUP, NULL); - gnt_bindable_class_register_action(bindable, "page-down", action_page_down, - GNT_KEY_PGDOWN, NULL); - gnt_bindable_class_register_action(bindable, "start-search", start_search, - "/", NULL); - gnt_bindable_class_register_action(bindable, "end-search", end_search_action, - "\033", NULL); - - gnt_style_read_actions(G_OBJECT_CLASS_TYPE(klass), bindable); - GNTDEBUG; -} - -static void -gnt_tree_init(GTypeInstance *instance, gpointer class) -{ - GntWidget *widget = GNT_WIDGET(instance); - GntTree *tree = GNT_TREE(widget); - tree->show_separator = TRUE; - GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_GROW_X | GNT_WIDGET_GROW_Y); - widget->priv.minw = 4; - widget->priv.minh = 1; - GNTDEBUG; -} - -/****************************************************************************** - * GntTree API - *****************************************************************************/ -GType -gnt_tree_get_gtype(void) -{ - static GType type = 0; - - if(type == 0) - { - static const GTypeInfo info = { - sizeof(GntTreeClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc)gnt_tree_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof(GntTree), - 0, /* n_preallocs */ - gnt_tree_init, /* instance_init */ - NULL /* value_table */ - }; - - type = g_type_register_static(GNT_TYPE_WIDGET, - "GntTree", - &info, 0); - } - - return type; -} - -static void -free_tree_col(gpointer data) -{ - GntTreeCol *col = data; - - g_free(col->text); - g_free(col); -} - -static void -free_tree_row(gpointer data) -{ - GntTreeRow *row = data; - - if (!row) - return; - - g_list_foreach(row->columns, (GFunc)free_tree_col, NULL); - g_list_free(row->columns); - g_free(row); -} - -GntWidget *gnt_tree_new() -{ - return gnt_tree_new_with_columns(1); -} - -void gnt_tree_set_visible_rows(GntTree *tree, int rows) -{ - GntWidget *widget = GNT_WIDGET(tree); - widget->priv.height = rows; - if (!GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER)) - widget->priv.height += 2; -} - -int gnt_tree_get_visible_rows(GntTree *tree) -{ - GntWidget *widget = GNT_WIDGET(tree); - int ret = widget->priv.height; - if (!GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER)) - ret -= 2; - return ret; -} - -const GList *gnt_tree_get_rows(GntTree *tree) -{ - return tree->list; -} - -void gnt_tree_scroll(GntTree *tree, int count) -{ - GntTreeRow *row; - - if (count < 0) - { - if (get_root_distance(tree->top) == 0) - return; - row = get_prev_n(tree->top, -count); - if (row == NULL) - row = tree->root; - tree->top = row; - } - else - { - get_next_n_opt(tree->bottom, count, &count); - tree->top = get_next_n(tree->top, count); - } - - redraw_tree(tree); - g_signal_emit(tree, signals[SIG_SCROLLED], 0, count); -} - -static gpointer -find_position(GntTree *tree, gpointer key, gpointer parent) -{ - GntTreeRow *row; - - if (tree->compare == NULL) - return NULL; - - if (parent == NULL) - row = tree->root; - else - row = g_hash_table_lookup(tree->hash, parent); - - if (!row) - return NULL; - - if (parent) - row = row->child; - - while (row) - { - if (tree->compare(key, row->key) < 0) - return (row->prev ? row->prev->key : NULL); - if (row->next) - row = row->next; - else - return row->key; - } - return NULL; -} - -void gnt_tree_sort_row(GntTree *tree, gpointer key) -{ - GntTreeRow *row, *q, *s; - int current, newp; - - if (!tree->compare) - return; - - row = g_hash_table_lookup(tree->hash, key); - g_return_if_fail(row != NULL); - - current = g_list_index(tree->list, key); - - if (row->parent) - s = row->parent->child; - else - s = tree->root; - - q = NULL; - while (s) { - if (tree->compare(row->key, s->key) < 0) - break; - q = s; - s = s->next; - } - - /* Move row between q and s */ - if (row == q || row == s) - return; - - if (q == NULL) { - /* row becomes the first child of its parent */ - row->prev->next = row->next; /* row->prev cannot be NULL at this point */ - if (row->next) - row->next->prev = row->prev; - if (row->parent) - row->parent->child = row; - else - tree->root = row; - row->next = s; - s->prev = row; /* s cannot be NULL */ - row->prev = NULL; - newp = g_list_index(tree->list, s) - 1; - } else { - if (row->prev) { - row->prev->next = row->next; - } else { - /* row was the first child of its parent */ - if (row->parent) - row->parent->child = row->next; - else - tree->top = row->next; - } - - if (row->next) - row->next->prev = row->prev; - - q->next = row; - row->prev = q; - if (s) - s->prev = row; - row->next = s; - newp = g_list_index(tree->list, q) + 1; - } - tree->list = g_list_reposition_child(tree->list, current, newp); - - redraw_tree(tree); -} - -GntTreeRow *gnt_tree_add_row_after(GntTree *tree, void *key, GntTreeRow *row, void *parent, void *bigbro) -{ - GntTreeRow *pr = NULL; - - g_hash_table_replace(tree->hash, key, row); - row->tree = tree; - - if (bigbro == NULL && tree->compare) - { - bigbro = find_position(tree, key, parent); - } - - if (tree->root == NULL) - { - tree->root = row; - tree->list = g_list_prepend(tree->list, key); - } - else - { - int position = 0; - - if (bigbro) - { - pr = g_hash_table_lookup(tree->hash, bigbro); - if (pr) - { - if (pr->next) pr->next->prev = row; - row->next = pr->next; - row->prev = pr; - pr->next = row; - row->parent = pr->parent; - - position = g_list_index(tree->list, bigbro); - } - } - - if (pr == NULL && parent) - { - pr = g_hash_table_lookup(tree->hash, parent); - if (pr) - { - if (pr->child) pr->child->prev = row; - row->next = pr->child; - pr->child = row; - row->parent = pr; - - position = g_list_index(tree->list, parent); - } - } - - if (pr == NULL) - { - GntTreeRow *r = tree->root; - row->next = r; - if (r) r->prev = row; - if (tree->current == tree->root) - tree->current = row; - tree->root = row; - tree->list = g_list_prepend(tree->list, key); - } - else - { - tree->list = g_list_insert(tree->list, key, position + 1); - } - } - - row->key = key; - row->data = NULL; - - redraw_tree(tree); - - return row; -} - -GntTreeRow *gnt_tree_add_row_last(GntTree *tree, void *key, GntTreeRow *row, void *parent) -{ - GntTreeRow *pr = NULL, *br = NULL; - - if (parent) - pr = g_hash_table_lookup(tree->hash, parent); - - if (pr) - br = pr->child; - else - br = tree->root; - - if (br) - { - while (br->next) - br = br->next; - } - - return gnt_tree_add_row_after(tree, key, row, parent, br ? br->key : NULL); -} - -gpointer gnt_tree_get_selection_data(GntTree *tree) -{ - if (tree->current) - return tree->current->key; /* XXX: perhaps we should just get rid of 'data' */ - return NULL; -} - -char *gnt_tree_get_selection_text(GntTree *tree) -{ - if (tree->current) - return update_row_text(tree, tree->current); - return NULL; -} - -GList *gnt_tree_get_selection_text_list(GntTree *tree) -{ - GList *list = NULL, *iter; - int i; - - if (!tree->current) - return NULL; - - for (i = 0, iter = tree->current->columns; i < tree->ncol && iter; - i++, iter = iter->next) - { - GntTreeCol *col = iter->data; - list = g_list_append(list, g_strdup(col->text)); - } - - return list; -} - -void gnt_tree_remove(GntTree *tree, gpointer key) -{ - GntTreeRow *row = g_hash_table_lookup(tree->hash, key); - static int depth = 0; /* Only redraw after all child nodes are removed */ - if (row) - { - gboolean redraw = FALSE; - - if (row->child) { - depth++; - while (row->child) { - gnt_tree_remove(tree, row->child->key); - } - depth--; - } - - if (get_distance(tree->top, row) >= 0 && get_distance(row, tree->bottom) >= 0) - redraw = TRUE; - - /* Update root/top/current/bottom if necessary */ - if (tree->root == row) - tree->root = get_next(row); - if (tree->top == row) - { - if (tree->top != tree->root) - tree->top = get_prev(row); - else - tree->top = get_next(row); - } - if (tree->current == row) - { - if (tree->current != tree->root) - tree->current = get_prev(row); - else - tree->current = get_next(row); - tree_selection_changed(tree, row, tree->current); - } - if (tree->bottom == row) - { - tree->bottom = get_prev(row); - } - - /* Fix the links */ - if (row->next) - row->next->prev = row->prev; - if (row->parent && row->parent->child == row) - row->parent->child = row->next; - if (row->prev) - row->prev->next = row->next; - - g_hash_table_remove(tree->hash, key); - tree->list = g_list_remove(tree->list, key); - - if (redraw && depth == 0) - { - redraw_tree(tree); - } - } -} - -static gboolean -return_true(gpointer key, gpointer data, gpointer null) -{ - return TRUE; -} - -void gnt_tree_remove_all(GntTree *tree) -{ - tree->root = NULL; - g_hash_table_foreach_remove(tree->hash, (GHRFunc)return_true, tree); - g_list_free(tree->list); - tree->list = NULL; - tree->current = tree->top = tree->bottom = NULL; -} - -int gnt_tree_get_selection_visible_line(GntTree *tree) -{ - return get_distance(tree->top, tree->current) + - !!(GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(tree), GNT_WIDGET_NO_BORDER)); -} - -void gnt_tree_change_text(GntTree *tree, gpointer key, int colno, const char *text) -{ - GntTreeRow *row; - GntTreeCol *col; - - g_return_if_fail(colno < tree->ncol); - - row = g_hash_table_lookup(tree->hash, key); - if (row) - { - col = g_list_nth_data(row->columns, colno); - g_free(col->text); - col->text = g_strdup(text); - - if (get_distance(tree->top, row) >= 0 && get_distance(row, tree->bottom) >= 0) - redraw_tree(tree); - } -} - -GntTreeRow *gnt_tree_add_choice(GntTree *tree, void *key, GntTreeRow *row, void *parent, void *bigbro) -{ - GntTreeRow *r; - r = g_hash_table_lookup(tree->hash, key); - g_return_val_if_fail(!r || !r->choice, NULL); - - if (bigbro == NULL) { - if (tree->compare) - bigbro = find_position(tree, key, parent); - else { - r = g_hash_table_lookup(tree->hash, parent); - if (!r) - r = tree->root; - else - r = r->child; - if (r) { - while (r->next) - r = r->next; - bigbro = r->key; - } - } - } - row = gnt_tree_add_row_after(tree, key, row, parent, bigbro); - row->choice = TRUE; - - return row; -} - -void gnt_tree_set_choice(GntTree *tree, void *key, gboolean set) -{ - GntTreeRow *row = g_hash_table_lookup(tree->hash, key); - - if (!row) - return; - g_return_if_fail(row->choice); - - row->isselected = set; - redraw_tree(tree); -} - -gboolean gnt_tree_get_choice(GntTree *tree, void *key) -{ - GntTreeRow *row = g_hash_table_lookup(tree->hash, key); - - if (!row) - return FALSE; - g_return_val_if_fail(row->choice, FALSE); - - return row->isselected; -} - -void gnt_tree_set_row_flags(GntTree *tree, void *key, GntTextFormatFlags flags) -{ - GntTreeRow *row = g_hash_table_lookup(tree->hash, key); - if (!row || row->flags == flags) - return; - - row->flags = flags; - redraw_tree(tree); /* XXX: It shouldn't be necessary to redraw the whole darned tree */ -} - -void gnt_tree_set_selected(GntTree *tree , void *key) -{ - int dist; - GntTreeRow *row = g_hash_table_lookup(tree->hash, key); - if (!row) - return; - - if (tree->top == NULL) - tree->top = row; - if (tree->bottom == NULL) - tree->bottom = row; - - tree->current = row; - if ((dist = get_distance(tree->current, tree->bottom)) < 0) - gnt_tree_scroll(tree, -dist); - else if ((dist = get_distance(tree->current, tree->top)) > 0) - gnt_tree_scroll(tree, -dist); - else - redraw_tree(tree); -} - -void _gnt_tree_init_internals(GntTree *tree, int col) -{ - tree->ncol = col; - tree->hash = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, free_tree_row); - tree->columns = g_new0(struct _GntTreeColInfo, col); - while (col--) - { - tree->columns[col].width = 15; - } - tree->list = NULL; - tree->show_title = FALSE; -} - -GntWidget *gnt_tree_new_with_columns(int col) -{ - GntWidget *widget = g_object_new(GNT_TYPE_TREE, NULL); - GntTree *tree = GNT_TREE(widget); - - _gnt_tree_init_internals(tree, col); - - GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_NO_SHADOW); - gnt_widget_set_take_focus(widget, TRUE); - - return widget; -} - -GntTreeRow *gnt_tree_create_row_from_list(GntTree *tree, GList *list) -{ - GList *iter; - int i; - GntTreeRow *row = g_new0(GntTreeRow, 1); - - for (i = 0, iter = list; i < tree->ncol && iter; iter = iter->next, i++) - { - GntTreeCol *col = g_new0(GntTreeCol, 1); - col->span = 1; - col->text = g_strdup(iter->data ? iter->data : ""); - - row->columns = g_list_append(row->columns, col); - } - - return row; -} - -GntTreeRow *gnt_tree_create_row(GntTree *tree, ...) -{ - int i; - va_list args; - GList *list = NULL; - GntTreeRow *row; - - va_start(args, tree); - for (i = 0; i < tree->ncol; i++) - { - list = g_list_append(list, va_arg(args, char *)); - } - va_end(args); - - row = gnt_tree_create_row_from_list(tree, list); - g_list_free(list); - - return row; -} - -void gnt_tree_set_col_width(GntTree *tree, int col, int width) -{ - g_return_if_fail(col < tree->ncol); - - tree->columns[col].width = width; -} - -void gnt_tree_set_column_titles(GntTree *tree, ...) -{ - int i; - va_list args; - - va_start(args, tree); - for (i = 0; i < tree->ncol; i++) - { - const char *title = va_arg(args, const char *); - tree->columns[i].title = g_strdup(title); - } - va_end(args); -} - -void gnt_tree_set_show_title(GntTree *tree, gboolean set) -{ - tree->show_title = set; - GNT_WIDGET(tree)->priv.minh = (set ? 6 : 4); -} - -void gnt_tree_set_compare_func(GntTree *tree, GCompareFunc func) -{ - tree->compare = func; -} - -void gnt_tree_set_expanded(GntTree *tree, void *key, gboolean expanded) -{ - GntTreeRow *row = g_hash_table_lookup(tree->hash, key); - if (row) { - row->collapsed = !expanded; - if (GNT_WIDGET(tree)->window) - gnt_widget_draw(GNT_WIDGET(tree)); - } -} - -void gnt_tree_set_show_separator(GntTree *tree, gboolean set) -{ - tree->show_separator = set; -} - -void gnt_tree_adjust_columns(GntTree *tree) -{ - GntTreeRow *row = tree->root; - int *widths, i, twidth, height; - - widths = g_new0(int, tree->ncol); - while (row) { - GList *iter; - for (i = 0, iter = row->columns; iter; iter = iter->next, i++) { - GntTreeCol *col = iter->data; - int w = gnt_util_onscreen_width(col->text, NULL); - if (widths[i] < w) - widths[i] = w; - } - row = row->next; - } - - twidth = 1 + 2 * (!GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(tree), GNT_WIDGET_NO_BORDER)); - for (i = 0; i < tree->ncol; i++) { - gnt_tree_set_col_width(tree, i, widths[i]); - twidth += widths[i] + (tree->show_separator ? 1 : 0) + 1; - } - g_free(widths); - - gnt_widget_get_size(GNT_WIDGET(tree), NULL, &height); - gnt_widget_set_size(GNT_WIDGET(tree), twidth, height); -} - -void gnt_tree_set_hash_fns(GntTree *tree, gpointer hash, gpointer eq, gpointer kd) -{ - g_hash_table_foreach_remove(tree->hash, return_true, NULL); - g_hash_table_destroy(tree->hash); - tree->hash = g_hash_table_new_full(hash, eq, kd, free_tree_row); -} - diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gnttree.h --- a/console/libgnt/gnttree.h Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,150 +0,0 @@ -#ifndef GNT_TREE_H -#define GNT_TREE_H - -#include "gntwidget.h" -#include "gnt.h" -#include "gntcolors.h" -#include "gntkeys.h" -#include "gnttextview.h" - -#define GNT_TYPE_TREE (gnt_tree_get_gtype()) -#define GNT_TREE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNT_TYPE_TREE, GntTree)) -#define GNT_TREE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GNT_TYPE_TREE, GntTreeClass)) -#define GNT_IS_TREE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GNT_TYPE_TREE)) -#define GNT_IS_TREE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GNT_TYPE_TREE)) -#define GNT_TREE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GNT_TYPE_TREE, GntTreeClass)) - -#define GNT_TREE_FLAGS(obj) (GNT_TREE(obj)->priv.flags) -#define GNT_TREE_SET_FLAGS(obj, flags) (GNT_TREE_FLAGS(obj) |= flags) -#define GNT_TREE_UNSET_FLAGS(obj, flags) (GNT_TREE_FLAGS(obj) &= ~(flags)) - -typedef struct _GnTree GntTree; -typedef struct _GnTreePriv GntTreePriv; -typedef struct _GnTreeClass GntTreeClass; - -typedef struct _GnTreeRow GntTreeRow; -typedef struct _GnTreeCol GntTreeCol; - -struct _GnTree -{ - GntWidget parent; - - GntTreeRow *current; /* current selection */ - - GntTreeRow *top; /* The topmost visible item */ - GntTreeRow *bottom; /* The bottommost visible item */ - - GntTreeRow *root; /* The root of all evil */ - - GList *list; /* List of GntTreeRow s */ - GHashTable *hash; /* We need this for quickly referencing the rows */ - guint (*hash_func)(gconstpointer); - gboolean (*hash_eq_func)(gconstpointer, gconstpointer); - GDestroyNotify key_destroy; - GDestroyNotify value_destroy; - - int ncol; /* No. of columns */ - struct _GntTreeColInfo - { - int width; - char *title; - } *columns; /* Would a GList be better? */ - gboolean show_title; - gboolean show_separator; /* Whether to show column separators */ - - GString *search; - int search_timeout; - - GCompareFunc compare; -}; - -struct _GnTreeClass -{ - GntWidgetClass parent; - - void (*selection_changed)(GntTreeRow *old, GntTreeRow * current); - void (*toggled)(GntTree *tree, gpointer key); - - void (*gnt_reserved1)(void); - void (*gnt_reserved2)(void); - void (*gnt_reserved3)(void); - void (*gnt_reserved4)(void); -}; - -G_BEGIN_DECLS - -GType gnt_tree_get_gtype(void); - -GntWidget *gnt_tree_new(void); /* A tree with just one column */ - -GntWidget *gnt_tree_new_with_columns(int columns); - -void gnt_tree_set_visible_rows(GntTree *tree, int rows); - -int gnt_tree_get_visible_rows(GntTree *tree); - -void gnt_tree_scroll(GntTree *tree, int count); - -GntTreeRow *gnt_tree_add_row_after(GntTree *tree, void *key, GntTreeRow *row, void *parent, void *bigbro); - -GntTreeRow *gnt_tree_add_row_last(GntTree *tree, void *key, GntTreeRow *row, void *parent); - -gpointer gnt_tree_get_selection_data(GntTree *tree); - -/* Returned string needs to be freed */ -char *gnt_tree_get_selection_text(GntTree *tree); - -GList *gnt_tree_get_selection_text_list(GntTree *tree); - -const GList *gnt_tree_get_rows(GntTree *tree); - -void gnt_tree_remove(GntTree *tree, gpointer key); - -void gnt_tree_remove_all(GntTree *tree); - -/* Returns the visible line number of the selected row */ -int gnt_tree_get_selection_visible_line(GntTree *tree); - -void gnt_tree_change_text(GntTree *tree, gpointer key, int colno, const char *text); - -GntTreeRow *gnt_tree_add_choice(GntTree *tree, void *key, GntTreeRow *row, void *parent, void *bigbro); - -void gnt_tree_set_choice(GntTree *tree, void *key, gboolean set); - -gboolean gnt_tree_get_choice(GntTree *tree, void *key); - -void gnt_tree_set_row_flags(GntTree *tree, void *key, GntTextFormatFlags flags); - -void gnt_tree_set_selected(GntTree *tree , void *key); - -GntTreeRow *gnt_tree_create_row(GntTree *tree, ...); - -GntTreeRow *gnt_tree_create_row_from_list(GntTree *tree, GList *list); - -void gnt_tree_set_col_width(GntTree *tree, int col, int width); - -void gnt_tree_set_column_titles(GntTree *tree, ...); - -void gnt_tree_set_show_title(GntTree *tree, gboolean set); - -void gnt_tree_set_compare_func(GntTree *tree, GCompareFunc func); - -void gnt_tree_set_expanded(GntTree *tree, void *key, gboolean expanded); - -void gnt_tree_set_show_separator(GntTree *tree, gboolean set); - -void gnt_tree_sort_row(GntTree *tree, void *row); - -/* This will try to automatically adjust the width of the columns in the tree */ -void gnt_tree_adjust_columns(GntTree *tree); - -void gnt_tree_set_hash_fns(GntTree *tree, gpointer hash, gpointer eq, gpointer kd); - -G_END_DECLS - -/* The following functions should NOT be used by applications. */ - -/* This should be called by the subclasses of GntTree's in their _new function */ -void _gnt_tree_init_internals(GntTree *tree, int col); - -#endif /* GNT_TREE_H */ diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gntutils.c --- a/console/libgnt/gntutils.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,147 +0,0 @@ -#include "gntutils.h" - -#include -#include - -#include "config.h" - -void gnt_util_get_text_bound(const char *text, int *width, int *height) -{ - const char *s = text, *last; - int count = 1, max = 0; - int len; - - /* XXX: ew ... everyone look away */ - last = s; - if (s) - { - while (*s) - { - if (*s == '\n' || *s == '\r') - { - count++; - len = gnt_util_onscreen_width(last, s); - if (max < len) - max = len; - last = s + 1; - } - s = g_utf8_next_char(s); - } - - len = gnt_util_onscreen_width(last, s); - if (max < len) - max = len; - } - - if (height) - *height = count; - if (width) - *width = max + (count > 1); -} - -int gnt_util_onscreen_width(const char *start, const char *end) -{ - int width = 0; - - if (end == NULL) - end = start + strlen(start); - - while (start < end) { - width += g_unichar_iswide(g_utf8_get_char(start)) ? 2 : 1; - start = g_utf8_next_char(start); - } - return width; -} - -const char *gnt_util_onscreen_width_to_pointer(const char *string, int len, int *w) -{ - int size; - int width = 0; - const char *str = string; - - if (len <= 0) { - len = gnt_util_onscreen_width(string, NULL); - } - - while (width < len && *str) { - size = g_unichar_iswide(g_utf8_get_char(str)) ? 2 : 1; - if (width + size > len) - break; - str = g_utf8_next_char(str); - width += size; - } - if (w) - *w = width; - return str; -} - -char *gnt_util_onscreen_fit_string(const char *string, int maxw) -{ - const char *start, *end; - GString *str; - - if (maxw <= 0) - maxw = getmaxx(stdscr) - 4; - - start = string; - str = g_string_new(NULL); - - while (*start) { - if ((end = strchr(start, '\n')) != NULL || - (end = strchr(start, '\r')) != NULL) { - if (gnt_util_onscreen_width(start, end) > maxw) - end = NULL; - } - if (end == NULL) - end = gnt_util_onscreen_width_to_pointer(start, maxw, NULL); - str = g_string_append_len(str, start, end - start); - if (*end) { - str = g_string_append_c(str, '\n'); - if (*end == '\n' || *end == '\r') - end++; - } - start = end; - } - return g_string_free(str, FALSE); -} - -struct duplicate_fns -{ - GDupFunc key_dup; - GDupFunc value_dup; - GHashTable *table; -}; - -static void -duplicate_values(gpointer key, gpointer value, gpointer data) -{ - struct duplicate_fns *fns = data; - g_hash_table_insert(fns->table, fns->key_dup ? fns->key_dup(key) : key, - fns->value_dup ? fns->value_dup(value) : value); -} - -GHashTable *g_hash_table_duplicate(GHashTable *src, GHashFunc hash, - GEqualFunc equal, GDestroyNotify key_d, GDestroyNotify value_d, - GDupFunc key_dup, GDupFunc value_dup) -{ - GHashTable *dest = g_hash_table_new_full(hash, equal, key_d, value_d); - struct duplicate_fns fns = {key_dup, value_dup, dest}; - g_hash_table_foreach(src, duplicate_values, &fns); - return dest; -} - -gboolean gnt_boolean_handled_accumulator(GSignalInvocationHint *ihint, - GValue *return_accu, - const GValue *handler_return, - gpointer dummy) -{ - gboolean continue_emission; - gboolean signal_handled; - - signal_handled = g_value_get_boolean (handler_return); - g_value_set_boolean (return_accu, signal_handled); - continue_emission = !signal_handled; - - return continue_emission; -} - diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gntutils.h --- a/console/libgnt/gntutils.h Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +0,0 @@ -#include - -#include "gnt.h" -#include "gntwidget.h" - -typedef gpointer (*GDupFunc)(gconstpointer data); - -void gnt_util_get_text_bound(const char *text, int *width, int *height); - -/* excluding *end */ -int gnt_util_onscreen_width(const char *start, const char *end); - -const char *gnt_util_onscreen_width_to_pointer(const char *str, int len, int *w); - -/* Inserts newlines in 'string' where necessary so that its onscreen width is - * no more than 'maxw'. - * 'maxw' can be <= 0, in which case the maximum screen width is considered. - * - * Returns a newly allocated string. - */ -char *gnt_util_onscreen_fit_string(const char *string, int maxw); - -GHashTable *g_hash_table_duplicate(GHashTable *src, GHashFunc hash, - GEqualFunc equal, GDestroyNotify key_d, GDestroyNotify value_d, - GDupFunc key_dup, GDupFunc value_dup); - - -/** - * To be used with g_signal_new. Look in the key_pressed signal-definition in - * gntwidget.c for usage. - */ -gboolean gnt_boolean_handled_accumulator(GSignalInvocationHint *ihint, - GValue *return_accu, - const GValue *handler_return, - gpointer dummy); - diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gntwidget.c --- a/console/libgnt/gntwidget.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,630 +0,0 @@ -/* Stuff brutally ripped from Gflib */ - -#include "gntwidget.h" -#include "gntstyle.h" -#include "gntmarshal.h" -#include "gntutils.h" -#include "gnt.h" - -enum -{ - SIG_DESTROY, - SIG_DRAW, - SIG_HIDE, - SIG_GIVE_FOCUS, - SIG_LOST_FOCUS, - SIG_KEY_PRESSED, - SIG_MAP, - SIG_ACTIVATE, - SIG_EXPOSE, - SIG_SIZE_REQUEST, - SIG_CONFIRM_SIZE, - SIG_SIZE_CHANGED, - SIG_POSITION, - SIG_CLICKED, - SIG_CONTEXT_MENU, - SIGS -}; - -static GObjectClass *parent_class = NULL; -static guint signals[SIGS] = { 0 }; - -static void init_widget(GntWidget *widget); - -static void -gnt_widget_init(GTypeInstance *instance, gpointer class) -{ - GntWidget *widget = GNT_WIDGET(instance); - widget->priv.name = NULL; - GNTDEBUG; -} - -static void -gnt_widget_map(GntWidget *widget) -{ - /* Get some default size for the widget */ - GNTDEBUG; - g_signal_emit(widget, signals[SIG_MAP], 0); - GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_MAPPED); -} - -static void -gnt_widget_dispose(GObject *obj) -{ - GntWidget *self = GNT_WIDGET(obj); - - if(!(GNT_WIDGET_FLAGS(self) & GNT_WIDGET_DESTROYING)) { - GNT_WIDGET_SET_FLAGS(self, GNT_WIDGET_DESTROYING); - - g_signal_emit(self, signals[SIG_DESTROY], 0); - - GNT_WIDGET_UNSET_FLAGS(self, GNT_WIDGET_DESTROYING); - } - - parent_class->dispose(obj); - GNTDEBUG; -} - -static void -gnt_widget_focus_change(GntWidget *widget) -{ - if (GNT_WIDGET_FLAGS(widget) & GNT_WIDGET_MAPPED) - gnt_widget_draw(widget); -} - -static gboolean -gnt_widget_dummy_confirm_size(GntWidget *widget, int width, int height) -{ - if (width < widget->priv.minw || height < widget->priv.minh) - return FALSE; - if (widget->priv.width != width && !GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_GROW_X)) - return FALSE; - if (widget->priv.height != height && !GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_GROW_Y)) - return FALSE; - return TRUE; -} - -static gboolean -context_menu(GntBindable *bind, GList *null) -{ - gboolean ret = FALSE; - g_signal_emit(bind, signals[SIG_CONTEXT_MENU], 0, &ret); - return ret; -} - -static void -gnt_widget_class_init(GntWidgetClass *klass) -{ - GObjectClass *obj_class = G_OBJECT_CLASS(klass); - - parent_class = g_type_class_peek_parent(klass); - - obj_class->dispose = gnt_widget_dispose; - - klass->destroy = gnt_widget_destroy; - klass->show = gnt_widget_show; - klass->draw = gnt_widget_draw; - klass->expose = gnt_widget_expose; - klass->map = gnt_widget_map; - klass->lost_focus = gnt_widget_focus_change; - klass->gained_focus = gnt_widget_focus_change; - klass->confirm_size = gnt_widget_dummy_confirm_size; - - klass->key_pressed = NULL; - klass->activate = NULL; - klass->clicked = NULL; - - signals[SIG_DESTROY] = - g_signal_new("destroy", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GntWidgetClass, destroy), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - signals[SIG_GIVE_FOCUS] = - g_signal_new("gained-focus", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GntWidgetClass, gained_focus), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - signals[SIG_LOST_FOCUS] = - g_signal_new("lost-focus", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GntWidgetClass, lost_focus), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - signals[SIG_ACTIVATE] = - g_signal_new("activate", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GntWidgetClass, activate), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - signals[SIG_MAP] = - g_signal_new("map", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GntWidgetClass, map), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - signals[SIG_DRAW] = - g_signal_new("draw", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GntWidgetClass, draw), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - signals[SIG_HIDE] = - g_signal_new("hide", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GntWidgetClass, hide), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - signals[SIG_EXPOSE] = - g_signal_new("expose", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GntWidgetClass, expose), - NULL, NULL, - gnt_closure_marshal_VOID__INT_INT_INT_INT, - G_TYPE_NONE, 4, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT); - signals[SIG_POSITION] = - g_signal_new("position-set", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GntWidgetClass, set_position), - NULL, NULL, - gnt_closure_marshal_VOID__INT_INT, - G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT); - signals[SIG_SIZE_REQUEST] = - g_signal_new("size_request", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GntWidgetClass, size_request), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - signals[SIG_SIZE_CHANGED] = - g_signal_new("size_changed", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GntWidgetClass, size_changed), - NULL, NULL, - gnt_closure_marshal_VOID__INT_INT, - G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT); - signals[SIG_CONFIRM_SIZE] = - g_signal_new("confirm_size", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GntWidgetClass, confirm_size), - NULL, NULL, - gnt_closure_marshal_BOOLEAN__INT_INT, - G_TYPE_BOOLEAN, 2, G_TYPE_INT, G_TYPE_INT); - signals[SIG_KEY_PRESSED] = - g_signal_new("key_pressed", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GntWidgetClass, key_pressed), - gnt_boolean_handled_accumulator, NULL, - gnt_closure_marshal_BOOLEAN__STRING, - G_TYPE_BOOLEAN, 1, G_TYPE_STRING); - - signals[SIG_CLICKED] = - g_signal_new("clicked", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GntWidgetClass, clicked), - gnt_boolean_handled_accumulator, NULL, - gnt_closure_marshal_BOOLEAN__INT_INT_INT, - G_TYPE_BOOLEAN, 3, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT); - - signals[SIG_CONTEXT_MENU] = - g_signal_new("context-menu", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - 0, - gnt_boolean_handled_accumulator, NULL, - gnt_closure_marshal_BOOLEAN__VOID, - G_TYPE_BOOLEAN, 0); - - /* This is relevant for all widgets */ - gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "context-menu", context_menu, - GNT_KEY_POPUP, NULL); - gnt_bindable_register_binding(GNT_BINDABLE_CLASS(klass), "context-menu", GNT_KEY_F11, NULL); - - gnt_style_read_actions(G_OBJECT_CLASS_TYPE(klass), GNT_BINDABLE_CLASS(klass)); - GNTDEBUG; -} - -/****************************************************************************** - * GntWidget API - *****************************************************************************/ -GType -gnt_widget_get_gtype(void) -{ - static GType type = 0; - - if(type == 0) { - static const GTypeInfo info = { - sizeof(GntWidgetClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc)gnt_widget_class_init, - NULL, - NULL, /* class_data */ - sizeof(GntWidget), - 0, /* n_preallocs */ - gnt_widget_init, /* instance_init */ - NULL /* value_table */ - }; - - type = g_type_register_static(GNT_TYPE_BINDABLE, - "GntWidget", - &info, G_TYPE_FLAG_ABSTRACT); - } - - return type; -} - -void gnt_widget_set_take_focus(GntWidget *widget, gboolean can) -{ - if (can) - GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_CAN_TAKE_FOCUS); - else - GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_CAN_TAKE_FOCUS); -} - -/** - * gnt_widget_destroy: - * @obj: The #GntWidget instance. - * - * Emits the "destroy" signal notifying all reference holders that they - * should release @obj. - */ -void -gnt_widget_destroy(GntWidget *obj) -{ - g_return_if_fail(GNT_IS_WIDGET(obj)); - - gnt_widget_hide(obj); - delwin(obj->window); - if(!(GNT_WIDGET_FLAGS(obj) & GNT_WIDGET_DESTROYING)) - g_object_run_dispose(G_OBJECT(obj)); - GNTDEBUG; -} - -void -gnt_widget_show(GntWidget *widget) -{ - gnt_widget_draw(widget); - gnt_screen_occupy(widget); -} - -void -gnt_widget_draw(GntWidget *widget) -{ - /* Draw the widget */ - if (GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_DRAWING)) - return; - - GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_DRAWING); - if (!(GNT_WIDGET_FLAGS(widget) & GNT_WIDGET_MAPPED)) { - gnt_widget_map(widget); - } - - if (widget->window == NULL) - { -#if 0 - int x, y, maxx, maxy, w, h; - int oldw, oldh; - gboolean shadow = TRUE; - - if (!gnt_widget_has_shadow(widget)) - shadow = FALSE; - - x = widget->priv.x; - y = widget->priv.y; - w = oldw = widget->priv.width + shadow; - h = oldh = widget->priv.height + shadow; - - getmaxyx(stdscr, maxy, maxx); - maxy -= 1; /* room for the taskbar */ - - x = MAX(0, x); - y = MAX(0, y); - if (x + w >= maxx) - x = MAX(0, maxx - w); - if (y + h >= maxy) - y = MAX(0, maxy - h); - - w = MIN(w, maxx); - h = MIN(h, maxy); - - widget->priv.x = x; - widget->priv.y = y; - if (w != oldw || h != oldh) { - widget->priv.width = w - shadow; - widget->priv.height = h - shadow; - g_signal_emit(widget, signals[SIG_SIZE_CHANGED], 0, oldw, oldh); - } -#else - widget->window = newpad(widget->priv.height + 20, widget->priv.width + 20); /* XXX: */ -#endif - init_widget(widget); - } - - g_signal_emit(widget, signals[SIG_DRAW], 0); - gnt_widget_queue_update(widget); - GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_DRAWING); -} - -gboolean -gnt_widget_key_pressed(GntWidget *widget, const char *keys) -{ - gboolean ret; - if (!GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_CAN_TAKE_FOCUS)) - return FALSE; - - if (gnt_bindable_perform_action_key(GNT_BINDABLE(widget), keys)) - return TRUE; - - keys = gnt_bindable_remap_keys(GNT_BINDABLE(widget), keys); - g_signal_emit(widget, signals[SIG_KEY_PRESSED], 0, keys, &ret); - return ret; -} - -gboolean -gnt_widget_clicked(GntWidget *widget, GntMouseEvent event, int x, int y) -{ - gboolean ret; - g_signal_emit(widget, signals[SIG_CLICKED], 0, event, x, y, &ret); - return ret; -} - -void -gnt_widget_expose(GntWidget *widget, int x, int y, int width, int height) -{ - g_signal_emit(widget, signals[SIG_EXPOSE], 0, x, y, width, height); -} - -void -gnt_widget_hide(GntWidget *widget) -{ - g_signal_emit(widget, signals[SIG_HIDE], 0); - wbkgdset(widget->window, '\0' | COLOR_PAIR(GNT_COLOR_NORMAL)); -#if 0 - /* XXX: I have no clue why, but this seemed to be necessary. */ - if (gnt_widget_has_shadow(widget)) - mvwvline(widget->window, 1, widget->priv.width, ' ', widget->priv.height); -#endif - gnt_screen_release(widget); - GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_INVISIBLE); - GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_MAPPED); -} - -void -gnt_widget_set_position(GntWidget *wid, int x, int y) -{ - g_signal_emit(wid, signals[SIG_POSITION], 0, x, y); - /* XXX: Need to install properties for these and g_object_notify */ - wid->priv.x = x; - wid->priv.y = y; -} - -void -gnt_widget_get_position(GntWidget *wid, int *x, int *y) -{ - if (x) - *x = wid->priv.x; - if (y) - *y = wid->priv.y; -} - -void -gnt_widget_size_request(GntWidget *widget) -{ - g_signal_emit(widget, signals[SIG_SIZE_REQUEST], 0); -} - -void -gnt_widget_get_size(GntWidget *wid, int *width, int *height) -{ - gboolean shadow = TRUE; - if (!gnt_widget_has_shadow(wid)) - shadow = FALSE; - - if (width) - *width = wid->priv.width + shadow; - if (height) - *height = wid->priv.height + shadow; - -} - -static void -init_widget(GntWidget *widget) -{ - gboolean shadow = TRUE; - - if (!gnt_widget_has_shadow(widget)) - shadow = FALSE; - - wbkgd(widget->window, COLOR_PAIR(GNT_COLOR_NORMAL)); - werase(widget->window); - - if (!(GNT_WIDGET_FLAGS(widget) & GNT_WIDGET_NO_BORDER)) - { - /* - This is ugly. */ - /* - What's your point? */ - mvwvline(widget->window, 0, 0, ACS_VLINE | COLOR_PAIR(GNT_COLOR_NORMAL), widget->priv.height); - mvwvline(widget->window, 0, widget->priv.width - 1, - ACS_VLINE | COLOR_PAIR(GNT_COLOR_NORMAL), widget->priv.height); - mvwhline(widget->window, widget->priv.height - 1, 0, - ACS_HLINE | COLOR_PAIR(GNT_COLOR_NORMAL), widget->priv.width); - mvwhline(widget->window, 0, 0, ACS_HLINE | COLOR_PAIR(GNT_COLOR_NORMAL), widget->priv.width); - mvwaddch(widget->window, 0, 0, ACS_ULCORNER | COLOR_PAIR(GNT_COLOR_NORMAL)); - mvwaddch(widget->window, 0, widget->priv.width - 1, - ACS_URCORNER | COLOR_PAIR(GNT_COLOR_NORMAL)); - mvwaddch(widget->window, widget->priv.height - 1, 0, - ACS_LLCORNER | COLOR_PAIR(GNT_COLOR_NORMAL)); - mvwaddch(widget->window, widget->priv.height - 1, widget->priv.width - 1, - ACS_LRCORNER | COLOR_PAIR(GNT_COLOR_NORMAL)); - } - - if (shadow) - { - wbkgdset(widget->window, '\0' | COLOR_PAIR(GNT_COLOR_SHADOW)); - mvwvline(widget->window, 1, widget->priv.width, ' ', widget->priv.height); - mvwhline(widget->window, widget->priv.height, 1, ' ', widget->priv.width); - } -} - -gboolean -gnt_widget_set_size(GntWidget *widget, int width, int height) -{ - gboolean ret = TRUE; - - if (gnt_widget_has_shadow(widget)) - { - width--; - height--; - } - if (width <= 0) - width = widget->priv.width; - if (height <= 0) - height = widget->priv.height; - - if (GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_MAPPED)) - { - ret = gnt_widget_confirm_size(widget, width, height); - } - - if (ret) - { - gboolean shadow = TRUE; - int oldw, oldh; - - if (!gnt_widget_has_shadow(widget)) - shadow = FALSE; - - oldw = widget->priv.width; - oldh = widget->priv.height; - - widget->priv.width = width; - widget->priv.height = height; - if (width >= getmaxx(widget->window) || height >= getmaxy(widget->window)) { - delwin(widget->window); - widget->window = newpad(height + 20, width + 20); - } - - g_signal_emit(widget, signals[SIG_SIZE_CHANGED], 0, oldw, oldh); - - if (widget->window) - { - init_widget(widget); - } - if (GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_MAPPED)) - init_widget(widget); - else - GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_MAPPED); - } - - return ret; -} - -gboolean -gnt_widget_set_focus(GntWidget *widget, gboolean set) -{ - if (!(GNT_WIDGET_FLAGS(widget) & GNT_WIDGET_CAN_TAKE_FOCUS)) - return FALSE; - - if (set && !GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_HAS_FOCUS)) - { - GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_HAS_FOCUS); - g_signal_emit(widget, signals[SIG_GIVE_FOCUS], 0); - } - else if (!set) - { - GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_HAS_FOCUS); - g_signal_emit(widget, signals[SIG_LOST_FOCUS], 0); - } - else - return FALSE; - - return TRUE; -} - -void gnt_widget_set_name(GntWidget *widget, const char *name) -{ - g_free(widget->priv.name); - widget->priv.name = g_strdup(name); -} - -const char *gnt_widget_get_name(GntWidget *widget) -{ - return widget->priv.name; -} - -void gnt_widget_activate(GntWidget *widget) -{ - g_signal_emit(widget, signals[SIG_ACTIVATE], 0); -} - -static gboolean -update_queue_callback(gpointer data) -{ - GntWidget *widget = GNT_WIDGET(data); - - if (!g_object_get_data(G_OBJECT(widget), "gnt:queue_update")) - return FALSE; - if (GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_MAPPED)) - gnt_screen_update(widget); - g_object_set_data(G_OBJECT(widget), "gnt:queue_update", NULL); - return FALSE; -} - -void gnt_widget_queue_update(GntWidget *widget) -{ - if (widget->window == NULL) - return; - while (widget->parent) - widget = widget->parent; - - if (!g_object_get_data(G_OBJECT(widget), "gnt:queue_update")) - { - int id = g_timeout_add(0, update_queue_callback, widget); - g_object_set_data_full(G_OBJECT(widget), "gnt:queue_update", GINT_TO_POINTER(id), - (GDestroyNotify)g_source_remove); - } -} - -gboolean gnt_widget_confirm_size(GntWidget *widget, int width, int height) -{ - gboolean ret = FALSE; - g_signal_emit(widget, signals[SIG_CONFIRM_SIZE], 0, width, height, &ret); - return ret; -} - -void gnt_widget_set_visible(GntWidget *widget, gboolean set) -{ - if (set) - GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_INVISIBLE); - else - GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_INVISIBLE); -} - -gboolean gnt_widget_has_shadow(GntWidget *widget) -{ - return (!GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_SHADOW) && - gnt_style_get_bool(GNT_STYLE_SHADOW, FALSE)); -} - diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gntwidget.h --- a/console/libgnt/gntwidget.h Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,152 +0,0 @@ -#ifndef GNT_WIDGET_H -#define GNT_WIDGET_H - -#include -#include -#include - -#include "gntbindable.h" - -#define GNT_TYPE_WIDGET (gnt_widget_get_gtype()) -#define GNT_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNT_TYPE_WIDGET, GntWidget)) -#define GNT_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GNT_TYPE_WIDGET, GntWidgetClass)) -#define GNT_IS_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GNT_TYPE_WIDGET)) -#define GNT_IS_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GNT_TYPE_WIDGET)) -#define GNT_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GNT_TYPE_WIDGET, GntWidgetClass)) - -#define GNT_WIDGET_FLAGS(obj) (GNT_WIDGET(obj)->priv.flags) -#define GNT_WIDGET_SET_FLAGS(obj, flags) (GNT_WIDGET_FLAGS(obj) |= flags) -#define GNT_WIDGET_UNSET_FLAGS(obj, flags) (GNT_WIDGET_FLAGS(obj) &= ~(flags)) -#define GNT_WIDGET_IS_FLAG_SET(obj, flags) (GNT_WIDGET_FLAGS(obj) & (flags)) - -typedef struct _GnWidget GntWidget; -typedef struct _GnWidgetPriv GntWidgetPriv; -typedef struct _GnWidgetClass GntWidgetClass; - -typedef enum _GnWidgetFlags -{ - GNT_WIDGET_DESTROYING = 1 << 0, - GNT_WIDGET_CAN_TAKE_FOCUS = 1 << 1, - GNT_WIDGET_MAPPED = 1 << 2, - /* XXX: Need to set the following two as properties, and setup a callback whenever these - * get chnaged. */ - GNT_WIDGET_NO_BORDER = 1 << 3, - GNT_WIDGET_NO_SHADOW = 1 << 4, - GNT_WIDGET_HAS_FOCUS = 1 << 5, - GNT_WIDGET_DRAWING = 1 << 6, - GNT_WIDGET_URGENT = 1 << 7, - GNT_WIDGET_GROW_X = 1 << 8, - GNT_WIDGET_GROW_Y = 1 << 9, - GNT_WIDGET_INVISIBLE = 1 << 10, - GNT_WIDGET_TRANSIENT = 1 << 11, -} GntWidgetFlags; - -/* XXX: This will probably move elsewhere */ -typedef enum _GnMouseEvent -{ - GNT_LEFT_MOUSE_DOWN = 1, - GNT_RIGHT_MOUSE_DOWN, - GNT_MIDDLE_MOUSE_DOWN, - GNT_MOUSE_UP, - GNT_MOUSE_SCROLL_UP, - GNT_MOUSE_SCROLL_DOWN -} GntMouseEvent; - -/* XXX: I'll have to ask grim what he's using this for in guifications. */ -typedef enum _GnParamFlags -{ - GNT_PARAM_SERIALIZABLE = 1 << G_PARAM_USER_SHIFT -} GntParamFlags; - -struct _GnWidgetPriv -{ - int x, y; - int width, height; - GntWidgetFlags flags; - char *name; - - int minw, minh; /* Minimum size for the widget */ -}; - -struct _GnWidget -{ - GntBindable inherit; - - GntWidget *parent; - - GntWidgetPriv priv; - WINDOW *window; - - void (*gnt_reserved1)(void); - void (*gnt_reserved2)(void); - void (*gnt_reserved3)(void); - void (*gnt_reserved4)(void); -}; - -struct _GnWidgetClass -{ - GntBindableClass parent; - - void (*map)(GntWidget *obj); - void (*show)(GntWidget *obj); /* This will call draw() and take focus (if it can take focus) */ - void (*destroy)(GntWidget *obj); - void (*draw)(GntWidget *obj); /* This will draw the widget */ - void (*hide)(GntWidget *obj); - void (*expose)(GntWidget *widget, int x, int y, int width, int height); - void (*gained_focus)(GntWidget *widget); - void (*lost_focus)(GntWidget *widget); - - void (*size_request)(GntWidget *widget); - gboolean (*confirm_size)(GntWidget *widget, int x, int y); - void (*size_changed)(GntWidget *widget, int w, int h); - void (*set_position)(GntWidget *widget, int x, int y); - gboolean (*key_pressed)(GntWidget *widget, const char *key); - void (*activate)(GntWidget *widget); - gboolean (*clicked)(GntWidget *widget, GntMouseEvent event, int x, int y); - - void (*gnt_reserved1)(void); - void (*gnt_reserved2)(void); - void (*gnt_reserved3)(void); - void (*gnt_reserved4)(void); -}; - -G_BEGIN_DECLS - -GType gnt_widget_get_gtype(void); -void gnt_widget_destroy(GntWidget *widget); -void gnt_widget_show(GntWidget *widget); -void gnt_widget_draw(GntWidget *widget); -void gnt_widget_expose(GntWidget *widget, int x, int y, int width, int height); -void gnt_widget_hide(GntWidget *widget); - -void gnt_widget_get_position(GntWidget *widget, int *x, int *y); -void gnt_widget_set_position(GntWidget *widget, int x, int y); -void gnt_widget_size_request(GntWidget *widget); -void gnt_widget_get_size(GntWidget *widget, int *width, int *height); -gboolean gnt_widget_set_size(GntWidget *widget, int width, int height); -gboolean gnt_widget_confirm_size(GntWidget *widget, int width, int height); - -gboolean gnt_widget_key_pressed(GntWidget *widget, const char *keys); - -gboolean gnt_widget_clicked(GntWidget *widget, GntMouseEvent event, int x, int y); - -gboolean gnt_widget_set_focus(GntWidget *widget, gboolean set); -void gnt_widget_activate(GntWidget *widget); - -void gnt_widget_set_name(GntWidget *widget, const char *name); - -const char *gnt_widget_get_name(GntWidget *widget); - -/* Widget-subclasses should call this from the draw-callback. - * Applications should just call gnt_widget_draw instead of this. */ -void gnt_widget_queue_update(GntWidget *widget); - -void gnt_widget_set_take_focus(GntWidget *widget, gboolean set); - -void gnt_widget_set_visible(GntWidget *widget, gboolean set); - -gboolean gnt_widget_has_shadow(GntWidget *widget); - -G_END_DECLS - -#endif /* GNT_WIDGET_H */ diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gntwindow.c --- a/console/libgnt/gntwindow.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,119 +0,0 @@ -#include "gntstyle.h" -#include "gntwindow.h" - -#include - -enum -{ - SIGS = 1, -}; - -static GntBoxClass *parent_class = NULL; - -static void (*org_destroy)(GntWidget *widget); - -static gboolean -show_menu(GntBindable *bind, GList *null) -{ - GntWindow *win = GNT_WINDOW(bind); - if (win->menu) { - gnt_screen_menu_show(win->menu); - return TRUE; - } - return FALSE; -} - -static void -gnt_window_destroy(GntWidget *widget) -{ - GntWindow *window = GNT_WINDOW(widget); - if (window->menu) - gnt_widget_destroy(GNT_WIDGET(window->menu)); - org_destroy(widget); -} - -static void -gnt_window_class_init(GntWindowClass *klass) -{ - GntBindableClass *bindable = GNT_BINDABLE_CLASS(klass); - GntWidgetClass *wid_class = GNT_WIDGET_CLASS(klass); - parent_class = GNT_BOX_CLASS(klass); - - org_destroy = wid_class->destroy; - wid_class->destroy = gnt_window_destroy; - - gnt_bindable_class_register_action(bindable, "show-menu", show_menu, - GNT_KEY_CTRL_O, NULL); - gnt_bindable_register_binding(bindable, "show-menu", GNT_KEY_F10, NULL); - gnt_style_read_actions(G_OBJECT_CLASS_TYPE(klass), bindable); - - GNTDEBUG; -} - -static void -gnt_window_init(GTypeInstance *instance, gpointer class) -{ - GntWidget *widget = GNT_WIDGET(instance); - GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW); - GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_CAN_TAKE_FOCUS); - GNTDEBUG; -} - -/****************************************************************************** - * GntWindow API - *****************************************************************************/ -GType -gnt_window_get_gtype(void) -{ - static GType type = 0; - - if(type == 0) - { - static const GTypeInfo info = { - sizeof(GntWindowClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc)gnt_window_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof(GntWindow), - 0, /* n_preallocs */ - gnt_window_init, /* instance_init */ - NULL /* value_table */ - }; - - type = g_type_register_static(GNT_TYPE_BOX, - "GntWindow", - &info, 0); - } - - return type; -} - -GntWidget *gnt_window_new() -{ - GntWidget *widget = g_object_new(GNT_TYPE_WINDOW, NULL); - - return widget; -} - -GntWidget *gnt_window_box_new(gboolean homo, gboolean vert) -{ - GntWidget *wid = gnt_window_new(); - GntBox *box = GNT_BOX(wid); - - box->homogeneous = homo; - box->vertical = vert; - box->alignment = vert ? GNT_ALIGN_LEFT : GNT_ALIGN_MID; - - return wid; -} - -void gnt_window_set_menu(GntWindow *window, GntMenu *menu) -{ - /* If a menu already existed, then destroy that first. */ - if (window->menu) - gnt_widget_destroy(GNT_WIDGET(window->menu)); - window->menu = menu; -} - diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gntwindow.h --- a/console/libgnt/gntwindow.h Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -#ifndef GNT_WINDOW_H -#define GNT_WINDOW_H - -#include "gnt.h" -#include "gntbox.h" -#include "gntcolors.h" -#include "gntkeys.h" -#include "gntmenu.h" - -#define GNT_TYPE_WINDOW (gnt_window_get_gtype()) -#define GNT_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNT_TYPE_WINDOW, GntWindow)) -#define GNT_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GNT_TYPE_WINDOW, GntWindowClass)) -#define GNT_IS_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GNT_TYPE_WINDOW)) -#define GNT_IS_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GNT_TYPE_WINDOW)) -#define GNT_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GNT_TYPE_WINDOW, GntWindowClass)) - -#define GNT_WINDOW_FLAGS(obj) (GNT_WINDOW(obj)->priv.flags) -#define GNT_WINDOW_SET_FLAGS(obj, flags) (GNT_WINDOW_FLAGS(obj) |= flags) -#define GNT_WINDOW_UNSET_FLAGS(obj, flags) (GNT_WINDOW_FLAGS(obj) &= ~(flags)) - -typedef struct _GnWindow GntWindow; -typedef struct _GnWindowPriv GntWindowPriv; -typedef struct _GnWindowClass GntWindowClass; - -struct _GnWindow -{ - GntBox parent; - GntMenu *menu; -}; - -struct _GnWindowClass -{ - GntBoxClass parent; - - void (*gnt_reserved1)(void); - void (*gnt_reserved2)(void); - void (*gnt_reserved3)(void); - void (*gnt_reserved4)(void); -}; - -G_BEGIN_DECLS - -GType gnt_window_get_gtype(void); - -#define gnt_vwindow_new(homo) gnt_window_box_new(homo, TRUE) -#define gnt_hwindow_new(homo) gnt_window_box_new(homo, FALSE) - -GntWidget *gnt_window_new(void); - -GntWidget *gnt_window_box_new(gboolean homo, gboolean vert); - -void gnt_window_set_menu(GntWindow *window, GntMenu *menu); - -G_END_DECLS - -#endif /* GNT_WINDOW_H */ diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gntwm.c --- a/console/libgnt/gntwm.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1504 +0,0 @@ -#define _GNU_SOURCE -#if defined(__APPLE__) -#define _XOPEN_SOURCE_EXTENDED -#endif - -#include "config.h" - -#include -#include -#include -#include - -#include "gntwm.h" -#include "gntstyle.h" -#include "gntmarshal.h" -#include "gnt.h" -#include "gntbox.h" -#include "gntmenu.h" -#include "gnttextview.h" -#include "gnttree.h" -#include "gntutils.h" - -#define IDLE_CHECK_INTERVAL 5 /* 5 seconds */ - -enum -{ - SIG_NEW_WIN, - SIG_DECORATE_WIN, - SIG_CLOSE_WIN, - SIG_CONFIRM_RESIZE, - SIG_RESIZED, - SIG_CONFIRM_MOVE, - SIG_MOVED, - SIG_UPDATE_WIN, - SIG_GIVE_FOCUS, - SIG_KEY_PRESS, - SIG_MOUSE_CLICK, - SIGS -}; - -static guint signals[SIGS] = { 0 }; -static void gnt_wm_new_window_real(GntWM *wm, GntWidget *widget); -static void gnt_wm_win_resized(GntWM *wm, GntNode *node); -static void gnt_wm_win_moved(GntWM *wm, GntNode *node); -static void gnt_wm_give_focus(GntWM *wm, GntWidget *widget); -static void update_window_in_list(GntWM *wm, GntWidget *wid); -static void shift_window(GntWM *wm, GntWidget *widget, int dir); - -static gboolean write_already(gpointer data); -static int write_timeout; -static time_t last_active_time; -static gboolean idle_update; - -static GList * -g_list_bring_to_front(GList *list, gpointer data) -{ - list = g_list_remove(list, data); - list = g_list_prepend(list, data); - return list; -} - -static void -free_node(gpointer data) -{ - GntNode *node = data; - hide_panel(node->panel); - del_panel(node->panel); - g_free(node); -} - -static void -draw_taskbar(GntWM *wm, gboolean reposition) -{ - static WINDOW *taskbar = NULL; - GList *iter; - int n, width = 0; - int i; - - if (taskbar == NULL) { - taskbar = newwin(1, getmaxx(stdscr), getmaxy(stdscr) - 1, 0); - } else if (reposition) { - int Y_MAX = getmaxy(stdscr) - 1; - mvwin(taskbar, Y_MAX, 0); - } - - wbkgdset(taskbar, '\0' | COLOR_PAIR(GNT_COLOR_NORMAL)); - werase(taskbar); - - n = g_list_length(wm->list); - if (n) - width = getmaxx(stdscr) / n; - - for (i = 0, iter = wm->list; iter; iter = iter->next, i++) - { - GntWidget *w = iter->data; - int color; - const char *title; - - if (w == wm->ordered->data) { - /* This is the current window in focus */ - color = GNT_COLOR_TITLE; - } else if (GNT_WIDGET_IS_FLAG_SET(w, GNT_WIDGET_URGENT)) { - /* This is a window with the URGENT hint set */ - color = GNT_COLOR_URGENT; - } else { - color = GNT_COLOR_NORMAL; - } - wbkgdset(taskbar, '\0' | COLOR_PAIR(color)); - if (iter->next) - mvwhline(taskbar, 0, width * i, ' ' | COLOR_PAIR(color), width); - else - mvwhline(taskbar, 0, width * i, ' ' | COLOR_PAIR(color), getmaxx(stdscr) - width * i); - title = GNT_BOX(w)->title; - mvwprintw(taskbar, 0, width * i, "%s", title ? title : ""); - if (i) - mvwaddch(taskbar, 0, width *i - 1, ACS_VLINE | A_STANDOUT | COLOR_PAIR(GNT_COLOR_NORMAL)); - - update_window_in_list(wm, w); - } - - wrefresh(taskbar); -} - -static void -copy_win(GntWidget *widget, GntNode *node) -{ - WINDOW *src, *dst; - int shadow; - if (!node) - return; - src = widget->window; - dst = node->window; - shadow = gnt_widget_has_shadow(widget) ? 1 : 0; - copywin(src, dst, node->scroll, 0, 0, 0, getmaxy(dst) - 1, getmaxx(dst) - 1, 0); -} - -static gboolean -update_screen(GntWM *wm) -{ - if (wm->menu) { - GntMenu *top = wm->menu; - while (top) { - GntNode *node = g_hash_table_lookup(wm->nodes, top); - if (node) - top_panel(node->panel); - top = top->submenu; - } - } - update_panels(); - doupdate(); - return TRUE; -} - -static gboolean -sanitize_position(GntWidget *widget, int *x, int *y) -{ - int X_MAX = getmaxx(stdscr); - int Y_MAX = getmaxy(stdscr) - 1; - int w, h; - int nx, ny; - gboolean changed = FALSE; - - gnt_widget_get_size(widget, &w, &h); - if (x) { - if (*x + w > X_MAX) { - nx = MAX(0, X_MAX - w); - if (nx != *x) { - *x = nx; - changed = TRUE; - } - } - } - if (y) { - if (*y + h > Y_MAX) { - ny = MAX(0, Y_MAX - h); - if (ny != *y) { - *y = ny; - changed = TRUE; - } - } - } - return changed; -} - -static void -refresh_node(GntWidget *widget, GntNode *node, gpointer null) -{ - int x, y, w, h; - int nw, nh; - - int X_MAX = getmaxx(stdscr); - int Y_MAX = getmaxy(stdscr) - 1; - - gnt_widget_get_position(widget, &x, &y); - gnt_widget_get_size(widget, &w, &h); - - if (sanitize_position(widget, &x, &y)) - gnt_screen_move_widget(widget, x, y); - - nw = MIN(w, X_MAX); - nh = MIN(h, Y_MAX); - if (nw != w || nh != h) - gnt_screen_resize_widget(widget, nw, nh); -} - -static void -read_window_positions(GntWM *wm) -{ -#if GLIB_CHECK_VERSION(2,6,0) - GKeyFile *gfile = g_key_file_new(); - char *filename = g_build_filename(g_get_home_dir(), ".gntpositions", NULL); - GError *error = NULL; - char **keys; - gsize nk; - - if (!g_key_file_load_from_file(gfile, filename, G_KEY_FILE_NONE, &error)) { - g_printerr("GntWM: %s\n", error->message); - g_error_free(error); - g_free(filename); - return; - } - - keys = g_key_file_get_keys(gfile, "positions", &nk, &error); - if (error) { - g_printerr("GntWM: %s\n", error->message); - g_error_free(error); - error = NULL; - } else { - while (nk--) { - char *title = keys[nk]; - gsize l; - char **coords = g_key_file_get_string_list(gfile, "positions", title, &l, NULL); - if (l == 2) { - int x = atoi(coords[0]); - int y = atoi(coords[1]); - GntPosition *p = g_new0(GntPosition, 1); - p->x = x; - p->y = y; - g_hash_table_replace(wm->positions, g_strdup(title + 1), p); - } else { - g_printerr("GntWM: Invalid number of arguments for positioing a window.\n"); - } - g_strfreev(coords); - } - g_strfreev(keys); - } - - g_free(filename); -#endif -} - -static gboolean check_idle(gpointer n) -{ - if (idle_update) { - time(&last_active_time); - idle_update = FALSE; - } - return TRUE; -} - -static void -gnt_wm_init(GTypeInstance *instance, gpointer class) -{ - GntWM *wm = GNT_WM(instance); - wm->list = NULL; - wm->ordered = NULL; - wm->event_stack = FALSE; - wm->windows = NULL; - wm->actions = NULL; - wm->nodes = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, free_node); - wm->positions = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); - if (gnt_style_get_bool(GNT_STYLE_REMPOS, TRUE)) - read_window_positions(wm); - g_timeout_add(IDLE_CHECK_INTERVAL * 1000, check_idle, NULL); - time(&last_active_time); -} - -static void -switch_window(GntWM *wm, int direction) -{ - GntWidget *w = NULL, *wid = NULL; - int pos; - - if (wm->_list.window || wm->menu) - return; - - if (!wm->ordered || !wm->ordered->next) - return; - - w = wm->ordered->data; - pos = g_list_index(wm->list, w); - pos += direction; - - if (pos < 0) - wid = g_list_last(wm->list)->data; - else if (pos >= g_list_length(wm->list)) - wid = wm->list->data; - else if (pos >= 0) - wid = g_list_nth_data(wm->list, pos); - - wm->ordered = g_list_bring_to_front(wm->ordered, wid); - - gnt_wm_raise_window(wm, wm->ordered->data); - - if (w != wid) { - gnt_widget_set_focus(w, FALSE); - } -} - -static gboolean -window_next(GntBindable *bindable, GList *null) -{ - GntWM *wm = GNT_WM(bindable); - switch_window(wm, 1); - return TRUE; -} - -static gboolean -window_prev(GntBindable *bindable, GList *null) -{ - GntWM *wm = GNT_WM(bindable); - switch_window(wm, -1); - return TRUE; -} - -static gboolean -switch_window_n(GntBindable *bind, GList *list) -{ - GntWM *wm = GNT_WM(bind); - GntWidget *w = NULL; - GList *l; - int n; - - if (!wm->ordered) - return TRUE; - - if (list) - n = GPOINTER_TO_INT(list->data); - else - n = 0; - - w = wm->ordered->data; - - if ((l = g_list_nth(wm->list, n)) != NULL) - { - gnt_wm_raise_window(wm, l->data); - } - - if (l && w != l->data) - { - gnt_widget_set_focus(w, FALSE); - } - return TRUE; -} - -static gboolean -window_scroll_up(GntBindable *bindable, GList *null) -{ - GntWM *wm = GNT_WM(bindable); - GntWidget *window; - GntNode *node; - - if (!wm->ordered) - return TRUE; - - window = wm->ordered->data; - node = g_hash_table_lookup(wm->nodes, window); - if (!node) - return TRUE; - - if (node->scroll) { - node->scroll--; - copy_win(window, node); - update_screen(wm); - } - return TRUE; -} - -static gboolean -window_scroll_down(GntBindable *bindable, GList *null) -{ - GntWM *wm = GNT_WM(bindable); - GntWidget *window; - GntNode *node; - int w, h; - - if (!wm->ordered) - return TRUE; - - window = wm->ordered->data; - node = g_hash_table_lookup(wm->nodes, window); - if (!node) - return TRUE; - - gnt_widget_get_size(window, &w, &h); - if (h - node->scroll > getmaxy(node->window)) { - node->scroll++; - copy_win(window, node); - update_screen(wm); - } - return TRUE; -} - -static gboolean -window_close(GntBindable *bindable, GList *null) -{ - GntWM *wm = GNT_WM(bindable); - - if (wm->_list.window) - return TRUE; - - if (wm->ordered) { - gnt_widget_destroy(wm->ordered->data); - } - - return TRUE; -} - -static void -destroy__list(GntWidget *widget, GntWM *wm) -{ - wm->_list.window = NULL; - wm->_list.tree = NULL; - wm->windows = NULL; - wm->actions = NULL; - update_screen(wm); -} - -static void -setup__list(GntWM *wm) -{ - GntWidget *tree, *win; - win = wm->_list.window = gnt_box_new(FALSE, FALSE); - gnt_box_set_toplevel(GNT_BOX(win), TRUE); - gnt_box_set_pad(GNT_BOX(win), 0); - GNT_WIDGET_SET_FLAGS(win, GNT_WIDGET_TRANSIENT); - - tree = wm->_list.tree = gnt_tree_new(); - gnt_box_add_widget(GNT_BOX(win), tree); - - g_signal_connect(G_OBJECT(win), "destroy", G_CALLBACK(destroy__list), wm); -} - -static void -window_list_activate(GntTree *tree, GntWM *wm) -{ - GntWidget *widget = gnt_tree_get_selection_data(GNT_TREE(tree)); - - if (!wm->ordered || !widget) - return; - - gnt_widget_destroy(wm->_list.window); - gnt_wm_raise_window(wm, widget); -} - -static void -populate_window_list(GntWM *wm) -{ - GList *iter; - GntTree *tree = GNT_TREE(wm->windows->tree); - for (iter = wm->list; iter; iter = iter->next) { - GntBox *box = GNT_BOX(iter->data); - - gnt_tree_add_row_last(tree, box, - gnt_tree_create_row(tree, box->title), NULL); - update_window_in_list(wm, GNT_WIDGET(box)); - } -} - -static gboolean -window_list_key_pressed(GntWidget *widget, const char *text, GntWM *wm) -{ - if (text[1] == 0 && wm->ordered) { - GntWidget *sel = gnt_tree_get_selection_data(GNT_TREE(widget)); - switch (text[0]) { - case '-': - case '<': - shift_window(wm, sel, -1); - break; - case '+': - case '>': - shift_window(wm, sel, 1); - break; - default: - return FALSE; - } - gnt_tree_remove_all(GNT_TREE(widget)); - populate_window_list(wm); - gnt_tree_set_selected(GNT_TREE(widget), sel); - return TRUE; - } - return FALSE; -} - -static gboolean -window_list(GntBindable *bindable, GList *null) -{ - GntWM *wm = GNT_WM(bindable); - GntWidget *tree, *win; - - if (wm->_list.window || wm->menu) - return TRUE; - - if (!wm->ordered) - return TRUE; - - setup__list(wm); - wm->windows = &wm->_list; - - win = wm->windows->window; - tree = wm->windows->tree; - - gnt_box_set_title(GNT_BOX(win), "Window List"); - - populate_window_list(wm); - - gnt_tree_set_selected(GNT_TREE(tree), wm->ordered->data); - g_signal_connect(G_OBJECT(tree), "activate", G_CALLBACK(window_list_activate), wm); - g_signal_connect(G_OBJECT(tree), "key_pressed", G_CALLBACK(window_list_key_pressed), wm); - - gnt_tree_set_col_width(GNT_TREE(tree), 0, getmaxx(stdscr) / 3); - gnt_widget_set_size(tree, 0, getmaxy(stdscr) / 2); - gnt_widget_set_position(win, getmaxx(stdscr) / 3, getmaxy(stdscr) / 4); - - gnt_widget_show(win); - return TRUE; -} - -static gboolean -dump_screen(GntBindable *bindable, GList *null) -{ - int x, y; - chtype old = 0, now = 0; - FILE *file = fopen("dump.html", "w"); - - fprintf(file, "
");
-	for (y = 0; y < getmaxy(stdscr); y++) {
-		for (x = 0; x < getmaxx(stdscr); x++) {
-			char ch;
-			now = mvwinch(curscr, y, x);
-			ch = now & A_CHARTEXT;
-			now ^= ch;
-
-#define CHECK(attr, start, end) \
-			do \
-			{  \
-				if (now & attr)  \
-				{  \
-					if (!(old & attr))  \
-						fprintf(file, "%s", start);  \
-				}  \
-				else if (old & attr)  \
-				{  \
-					fprintf(file, "%s", end);  \
-				}  \
-			} while (0) 
-
-			CHECK(A_BOLD, "", "");
-			CHECK(A_UNDERLINE, "", "");
-			CHECK(A_BLINK, "", "");
-
-			if ((now & A_COLOR) != (old & A_COLOR) ||
-				(now & A_REVERSE) != (old & A_REVERSE))
-			{
-				int ret;
-				short fgp, bgp, r, g, b;
-				struct
-				{
-					int r, g, b;
-				} fg, bg;
-
-				ret = pair_content(PAIR_NUMBER(now & A_COLOR), &fgp, &bgp);
-				if (fgp == -1)
-					fgp = COLOR_BLACK;
-				if (bgp == -1)
-					bgp = COLOR_WHITE;
-				if (now & A_REVERSE)
-					fgp ^= bgp ^= fgp ^= bgp;  /* *wink* */
-				ret = color_content(fgp, &r, &g, &b);
-				fg.r = r; fg.b = b; fg.g = g;
-				ret = color_content(bgp, &r, &g, &b);
-				bg.r = r; bg.b = b; bg.g = g;
-#define ADJUST(x) (x = x * 255 / 1000)
-				ADJUST(fg.r);
-				ADJUST(fg.g);
-				ADJUST(fg.b);
-				ADJUST(bg.r);
-				ADJUST(bg.b);
-				ADJUST(bg.g);
-				
-				if (x) fprintf(file, "");
-				fprintf(file, "",
-						bg.r, bg.g, bg.b, fg.r, fg.g, fg.b);
-			}
-			if (now & A_ALTCHARSET)
-			{
-				switch (ch)
-				{
-					case 'q':
-						ch = '-'; break;
-					case 't':
-					case 'u':
-					case 'x':
-						ch = '|'; break;
-					case 'v':
-					case 'w':
-					case 'l':
-					case 'm':
-					case 'k':
-					case 'j':
-					case 'n':
-						ch = '+'; break;
-					case '-':
-						ch = '^'; break;
-					case '.':
-						ch = 'v'; break;
-					case 'a':
-						ch = '#'; break;
-					default:
-						ch = ' '; break;
-				}
-			}
-			if (ch == '&')
-				fprintf(file, "&");
-			else if (ch == '<')
-				fprintf(file, "<");
-			else if (ch == '>')
-				fprintf(file, ">");
-			else
-				fprintf(file, "%c", ch);
-			old = now;
-		}
-		fprintf(file, "\n");
-		old = 0;
-	}
-	fprintf(file, "
"); - fclose(file); - return TRUE; -} - -static void -shift_window(GntWM *wm, GntWidget *widget, int dir) -{ - GList *all = wm->list; - GList *list = g_list_find(all, widget); - int length, pos; - if (!list) - return; - - length = g_list_length(all); - pos = g_list_position(all, list); - - pos += dir; - if (dir > 0) - pos++; - - if (pos < 0) - pos = length; - else if (pos > length) - pos = 0; - - all = g_list_insert(all, widget, pos); - all = g_list_delete_link(all, list); - wm->list = all; - draw_taskbar(wm, FALSE); -} - -static gboolean -shift_left(GntBindable *bindable, GList *null) -{ - GntWM *wm = GNT_WM(bindable); - if (wm->_list.window) - return TRUE; - - shift_window(wm, wm->ordered->data, -1); - return TRUE; -} - -static gboolean -shift_right(GntBindable *bindable, GList *null) -{ - GntWM *wm = GNT_WM(bindable); - if (wm->_list.window) - return TRUE; - - shift_window(wm, wm->ordered->data, 1); - return TRUE; -} - -static void -action_list_activate(GntTree *tree, GntWM *wm) -{ - GntAction *action = gnt_tree_get_selection_data(tree); - action->callback(); - gnt_widget_destroy(wm->_list.window); -} - -static int -compare_action(gconstpointer p1, gconstpointer p2) -{ - const GntAction *a1 = p1; - const GntAction *a2 = p2; - - return g_utf8_collate(a1->label, a2->label); -} - -static gboolean -list_actions(GntBindable *bindable, GList *null) -{ - GntWidget *tree, *win; - GList *iter; - GntWM *wm = GNT_WM(bindable); - if (wm->_list.window || wm->menu) - return TRUE; - - if (wm->acts == NULL) - return TRUE; - - setup__list(wm); - wm->actions = &wm->_list; - - win = wm->actions->window; - tree = wm->actions->tree; - - gnt_box_set_title(GNT_BOX(win), "Actions"); - GNT_WIDGET_SET_FLAGS(tree, GNT_WIDGET_NO_BORDER); - /* XXX: Do we really want this? */ - gnt_tree_set_compare_func(GNT_TREE(tree), compare_action); - - for (iter = wm->acts; iter; iter = iter->next) { - GntAction *action = iter->data; - gnt_tree_add_row_last(GNT_TREE(tree), action, - gnt_tree_create_row(GNT_TREE(tree), action->label), NULL); - } - g_signal_connect(G_OBJECT(tree), "activate", G_CALLBACK(action_list_activate), wm); - gnt_widget_set_size(tree, 0, g_list_length(wm->acts)); - gnt_widget_set_position(win, 0, getmaxy(stdscr) - 3 - g_list_length(wm->acts)); - - gnt_widget_show(win); - return TRUE; -} - -#ifndef NO_WIDECHAR -static int -widestringwidth(wchar_t *wide) -{ - int len, ret; - char *string; - - len = wcstombs(NULL, wide, 0) + 1; - string = g_new0(char, len); - wcstombs(string, wide, len); - ret = gnt_util_onscreen_width(string, NULL); - g_free(string); - return ret; -} -#endif - -/* Returns the onscreen width of the character at the position */ -static int -reverse_char(WINDOW *d, int y, int x, gboolean set) -{ -#define DECIDE(ch) (set ? ((ch) | A_REVERSE) : ((ch) & ~A_REVERSE)) - -#ifdef NO_WIDECHAR - chtype ch; - ch = mvwinch(d, y, x); - mvwaddch(d, y, x, DECIDE(ch)); - return 1; -#else - cchar_t ch; - int wc = 1; - if (mvwin_wch(d, y, x, &ch) == OK) { - wc = widestringwidth(ch.chars); - ch.attr = DECIDE(ch.attr); - ch.attr &= WA_ATTRIBUTES; /* XXX: This is a workaround for a bug */ - mvwadd_wch(d, y, x, &ch); - } - - return wc; -#endif -} - -static void -window_reverse(GntWidget *win, gboolean set, GntWM *wm) -{ - int i; - int w, h; - WINDOW *d; - - if (GNT_WIDGET_IS_FLAG_SET(win, GNT_WIDGET_NO_BORDER)) - return; - - d = win->window; - gnt_widget_get_size(win, &w, &h); - - if (gnt_widget_has_shadow(win)) { - --w; - --h; - } - - /* the top and bottom */ - for (i = 0; i < w; i += reverse_char(d, 0, i, set)); - for (i = 0; i < w; i += reverse_char(d, h-1, i, set)); - - /* the left and right */ - for (i = 0; i < h; i += reverse_char(d, i, 0, set)); - for (i = 0; i < h; i += reverse_char(d, i, w-1, set)); - - copy_win(win, g_hash_table_lookup(wm->nodes, win)); - update_screen(wm); -} - -static gboolean -start_move(GntBindable *bindable, GList *null) -{ - GntWM *wm = GNT_WM(bindable); - if (wm->_list.window || wm->menu) - return TRUE; - if (!wm->ordered) - return TRUE; - - wm->mode = GNT_KP_MODE_MOVE; - window_reverse(GNT_WIDGET(wm->ordered->data), TRUE, wm); - - return TRUE; -} - -static gboolean -start_resize(GntBindable *bindable, GList *null) -{ - GntWM *wm = GNT_WM(bindable); - if (wm->_list.window || wm->menu) - return TRUE; - if (!wm->ordered) - return TRUE; - - wm->mode = GNT_KP_MODE_RESIZE; - window_reverse(GNT_WIDGET(wm->ordered->data), TRUE, wm); - - return TRUE; -} - -static gboolean -wm_quit(GntBindable *bindable, GList *list) -{ - GntWM *wm = GNT_WM(bindable); - if (write_timeout) - write_already(wm); - g_main_loop_quit(wm->loop); - return TRUE; -} - -static gboolean -return_true(GntWM *wm, GntWidget *w, int *a, int *b) -{ - return TRUE; -} - -static gboolean -refresh_screen(GntBindable *bindable, GList *null) -{ - GntWM *wm = GNT_WM(bindable); - - endwin(); - refresh(); - curs_set(0); /* endwin resets the cursor to normal */ - - g_hash_table_foreach(wm->nodes, (GHFunc)refresh_node, NULL); - update_screen(wm); - draw_taskbar(wm, TRUE); - - return FALSE; -} - -static void -gnt_wm_class_init(GntWMClass *klass) -{ - int i; - - klass->new_window = gnt_wm_new_window_real; - klass->decorate_window = NULL; - klass->close_window = NULL; - klass->window_resize_confirm = return_true; - klass->window_resized = gnt_wm_win_resized; - klass->window_move_confirm = return_true; - klass->window_moved = gnt_wm_win_moved; - klass->window_update = NULL; - klass->key_pressed = NULL; - klass->mouse_clicked = NULL; - klass->give_focus = gnt_wm_give_focus; - - signals[SIG_NEW_WIN] = - g_signal_new("new_win", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GntWMClass, new_window), - NULL, NULL, - g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, G_TYPE_POINTER); - signals[SIG_DECORATE_WIN] = - g_signal_new("decorate_win", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GntWMClass, decorate_window), - NULL, NULL, - g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, G_TYPE_POINTER); - signals[SIG_CLOSE_WIN] = - g_signal_new("close_win", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GntWMClass, close_window), - NULL, NULL, - g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, G_TYPE_POINTER); - signals[SIG_CONFIRM_RESIZE] = - g_signal_new("confirm_resize", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GntWMClass, window_resize_confirm), - gnt_boolean_handled_accumulator, NULL, - gnt_closure_marshal_BOOLEAN__POINTER_POINTER_POINTER, - G_TYPE_BOOLEAN, 3, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER); - - signals[SIG_CONFIRM_MOVE] = - g_signal_new("confirm_move", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GntWMClass, window_move_confirm), - gnt_boolean_handled_accumulator, NULL, - gnt_closure_marshal_BOOLEAN__POINTER_POINTER_POINTER, - G_TYPE_BOOLEAN, 3, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER); - - signals[SIG_RESIZED] = - g_signal_new("window_resized", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GntWMClass, window_resized), - NULL, NULL, - g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, G_TYPE_POINTER); - signals[SIG_MOVED] = - g_signal_new("window_moved", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GntWMClass, window_moved), - NULL, NULL, - g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, G_TYPE_POINTER); - signals[SIG_UPDATE_WIN] = - g_signal_new("window_update", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GntWMClass, window_update), - NULL, NULL, - g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, G_TYPE_POINTER); - - signals[SIG_GIVE_FOCUS] = - g_signal_new("give_focus", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GntWMClass, give_focus), - NULL, NULL, - g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, G_TYPE_POINTER); - - signals[SIG_MOUSE_CLICK] = - g_signal_new("mouse_clicked", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GntWMClass, mouse_clicked), - gnt_boolean_handled_accumulator, NULL, - gnt_closure_marshal_BOOLEAN__INT_INT_INT_POINTER, - G_TYPE_BOOLEAN, 4, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_POINTER); - - gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "window-next", window_next, - "\033" "n", NULL); - gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "window-prev", window_prev, - "\033" "p", NULL); - gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "window-close", window_close, - "\033" "c", NULL); - gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "window-list", window_list, - "\033" "w", NULL); - gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "dump-screen", dump_screen, - "\033" "d", NULL); - gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "shift-left", shift_left, - "\033" ",", NULL); - gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "shift-right", shift_right, - "\033" ".", NULL); - gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "action-list", list_actions, - "\033" "a", NULL); - gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "start-move", start_move, - "\033" "m", NULL); - gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "start-resize", start_resize, - "\033" "r", NULL); - gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "wm-quit", wm_quit, - "\033" "q", NULL); - gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "refresh-screen", refresh_screen, - "\033" "l", NULL); - gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "switch-window-n", switch_window_n, - NULL, NULL); - gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "window-scroll-down", window_scroll_down, - "\033" GNT_KEY_CTRL_J, NULL); - gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "window-scroll-up", window_scroll_up, - "\033" GNT_KEY_CTRL_K, NULL); - - gnt_style_read_actions(G_OBJECT_CLASS_TYPE(klass), GNT_BINDABLE_CLASS(klass)); - - /* Make sure Alt+x are detected properly. */ - for (i = '0'; i <= '9'; i++) { - char str[] = "\033X"; - str[1] = i; - gnt_keys_add_combination(str); - } - - GNTDEBUG; -} - -/****************************************************************************** - * GntWM API - *****************************************************************************/ -GType -gnt_wm_get_gtype(void) -{ - static GType type = 0; - - if(type == 0) { - static const GTypeInfo info = { - sizeof(GntWMClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc)gnt_wm_class_init, - NULL, - NULL, /* class_data */ - sizeof(GntWM), - 0, /* n_preallocs */ - gnt_wm_init, /* instance_init */ - NULL /* value_table */ - }; - - type = g_type_register_static(GNT_TYPE_BINDABLE, - "GntWM", - &info, 0); - } - - return type; -} -static void -update_window_in_list(GntWM *wm, GntWidget *wid) -{ - GntTextFormatFlags flag = 0; - - if (wm->windows == NULL) - return; - - if (wid == wm->ordered->data) - flag |= GNT_TEXT_FLAG_DIM; - else if (GNT_WIDGET_IS_FLAG_SET(wid, GNT_WIDGET_URGENT)) - flag |= GNT_TEXT_FLAG_BOLD; - - gnt_tree_set_row_flags(GNT_TREE(wm->windows->tree), wid, flag); -} - -static void -gnt_wm_new_window_real(GntWM *wm, GntWidget *widget) -{ - GntNode *node; - gboolean transient = FALSE; - - if (widget->window == NULL) - return; - - node = g_new0(GntNode, 1); - node->me = widget; - node->scroll = 0; - - g_hash_table_replace(wm->nodes, widget, node); - - refresh_node(widget, node, NULL); - - transient = !!GNT_WIDGET_IS_FLAG_SET(node->me, GNT_WIDGET_TRANSIENT); - -#if 1 - { - int x, y, w, h, maxx, maxy; - gboolean shadow = TRUE; - - if (!gnt_widget_has_shadow(widget)) - shadow = FALSE; - x = widget->priv.x; - y = widget->priv.y; - w = widget->priv.width; - h = widget->priv.height; - - getmaxyx(stdscr, maxy, maxx); - maxy -= 1; /* room for the taskbar */ - maxy -= shadow; - maxx -= shadow; - - x = MAX(0, x); - y = MAX(0, y); - if (x + w >= maxx) - x = MAX(0, maxx - w); - if (y + h >= maxy) - y = MAX(0, maxy - h); - - w = MIN(w, maxx); - h = MIN(h, maxy); - node->window = newwin(h + shadow, w + shadow, y, x); - copy_win(widget, node); - } -#endif - - node->panel = new_panel(node->window); - set_panel_userptr(node->panel, node); - - if (!transient) { - if (node->me != wm->_list.window) { - GntWidget *w = NULL; - - if (wm->ordered) - w = wm->ordered->data; - - wm->list = g_list_append(wm->list, widget); - - if (wm->event_stack) - wm->ordered = g_list_prepend(wm->ordered, widget); - else - wm->ordered = g_list_append(wm->ordered, widget); - - gnt_widget_set_focus(widget, TRUE); - if (w) - gnt_widget_set_focus(w, FALSE); - } - - if (wm->event_stack || node->me == wm->_list.window) { - gnt_wm_raise_window(wm, node->me); - } else { - bottom_panel(node->panel); /* New windows should not grab focus */ - gnt_widget_set_urgent(node->me); - } - } -} - -void gnt_wm_new_window(GntWM *wm, GntWidget *widget) -{ - while (widget->parent) - widget = widget->parent; - - if (GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_INVISIBLE) || - g_hash_table_lookup(wm->nodes, widget)) { - update_screen(wm); - return; - } - - if (GNT_IS_BOX(widget)) { - const char *title = GNT_BOX(widget)->title; - GntPosition *p = NULL; - if (title && (p = g_hash_table_lookup(wm->positions, title)) != NULL) { - sanitize_position(widget, &p->x, &p->y); - gnt_widget_set_position(widget, p->x, p->y); - mvwin(widget->window, p->y, p->x); - } - } - - g_signal_emit(wm, signals[SIG_NEW_WIN], 0, widget); - g_signal_emit(wm, signals[SIG_DECORATE_WIN], 0, widget); - - if (wm->windows && !GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_TRANSIENT)) { - if ((GNT_IS_BOX(widget) && GNT_BOX(widget)->title) && wm->_list.window != widget - && GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_CAN_TAKE_FOCUS)) { - gnt_tree_add_row_last(GNT_TREE(wm->windows->tree), widget, - gnt_tree_create_row(GNT_TREE(wm->windows->tree), GNT_BOX(widget)->title), - NULL); - update_window_in_list(wm, widget); - } - } - - update_screen(wm); - draw_taskbar(wm, FALSE); -} - -void gnt_wm_window_decorate(GntWM *wm, GntWidget *widget) -{ - g_signal_emit(wm, signals[SIG_DECORATE_WIN], 0, widget); -} - -void gnt_wm_window_close(GntWM *wm, GntWidget *widget) -{ - GntNode *node; - int pos; - - if ((node = g_hash_table_lookup(wm->nodes, widget)) == NULL) - return; - - g_signal_emit(wm, signals[SIG_CLOSE_WIN], 0, widget); - g_hash_table_remove(wm->nodes, widget); - - if (wm->windows) { - gnt_tree_remove(GNT_TREE(wm->windows->tree), widget); - } - - pos = g_list_index(wm->list, widget); - - if (pos != -1) { - wm->list = g_list_remove(wm->list, widget); - wm->ordered = g_list_remove(wm->ordered, widget); - - if (wm->ordered) - gnt_wm_raise_window(wm, wm->ordered->data); - } - - update_screen(wm); - draw_taskbar(wm, FALSE); -} - -time_t gnt_wm_get_idle_time() -{ - return time(NULL) - last_active_time; -} - -gboolean gnt_wm_process_input(GntWM *wm, const char *keys) -{ - gboolean ret = FALSE; - - keys = gnt_bindable_remap_keys(GNT_BINDABLE(wm), keys); - - idle_update = TRUE; - - if (gnt_bindable_perform_action_key(GNT_BINDABLE(wm), keys)) - return TRUE; - - /* Do some manual checking */ - if (wm->ordered && wm->mode != GNT_KP_MODE_NORMAL) { - int xmin = 0, ymin = 0, xmax = getmaxx(stdscr), ymax = getmaxy(stdscr) - 1; - int x, y, w, h; - GntWidget *widget = GNT_WIDGET(wm->ordered->data); - int ox, oy, ow, oh; - - gnt_widget_get_position(widget, &x, &y); - gnt_widget_get_size(widget, &w, &h); - ox = x; oy = y; - ow = w; oh = h; - - if (wm->mode == GNT_KP_MODE_MOVE) { - if (strcmp(keys, GNT_KEY_LEFT) == 0) { - if (x > xmin) - x--; - } else if (strcmp(keys, GNT_KEY_RIGHT) == 0) { - if (x + w < xmax) - x++; - } else if (strcmp(keys, GNT_KEY_UP) == 0) { - if (y > ymin) - y--; - } else if (strcmp(keys, GNT_KEY_DOWN) == 0) { - if (y + h < ymax) - y++; - } - if (ox != x || oy != y) { - gnt_screen_move_widget(widget, x, y); - window_reverse(widget, TRUE, wm); - return TRUE; - } - } else if (wm->mode == GNT_KP_MODE_RESIZE) { - if (strcmp(keys, GNT_KEY_LEFT) == 0) { - w--; - } else if (strcmp(keys, GNT_KEY_RIGHT) == 0) { - if (x + w < xmax) - w++; - } else if (strcmp(keys, GNT_KEY_UP) == 0) { - h--; - } else if (strcmp(keys, GNT_KEY_DOWN) == 0) { - if (y + h < ymax) - h++; - } - if (oh != h || ow != w) { - gnt_screen_resize_widget(widget, w, h); - window_reverse(widget, TRUE, wm); - return TRUE; - } - } - if (strcmp(keys, "\r") == 0 || strcmp(keys, "\033") == 0) { - window_reverse(widget, FALSE, wm); - wm->mode = GNT_KP_MODE_NORMAL; - } - return TRUE; - } - - wm->event_stack = TRUE; - - /* Escape to close the window-list or action-list window */ - if (strcmp(keys, "\033") == 0) { - if (wm->_list.window) { - gnt_widget_destroy(wm->_list.window); - wm->event_stack = FALSE; - return TRUE; - } - } else if (keys[0] == '\033' && isdigit(keys[1]) && keys[2] == '\0') { - /* Alt+x for quick switch */ - int n = *(keys + 1) - '0'; - GList *list = NULL; - - if (n == 0) - n = 10; - - list = g_list_append(list, GINT_TO_POINTER(n - 1)); - switch_window_n(GNT_BINDABLE(wm), list); - g_list_free(list); - return TRUE; - } - - if (wm->menu) - ret = gnt_widget_key_pressed(GNT_WIDGET(wm->menu), keys); - else if (wm->_list.window) - ret = gnt_widget_key_pressed(wm->_list.window, keys); - else if (wm->ordered) - ret = gnt_widget_key_pressed(GNT_WIDGET(wm->ordered->data), keys); - wm->event_stack = FALSE; - return ret; -} - -static void -gnt_wm_win_resized(GntWM *wm, GntNode *node) -{ - /*refresh_node(node->me, node, NULL);*/ -} - -static void -gnt_wm_win_moved(GntWM *wm, GntNode *node) -{ - refresh_node(node->me, node, NULL); -} - -void gnt_wm_resize_window(GntWM *wm, GntWidget *widget, int width, int height) -{ - gboolean ret = TRUE; - GntNode *node; - int shadow; - int maxx, maxy; - - while (widget->parent) - widget = widget->parent; - node = g_hash_table_lookup(wm->nodes, widget); - if (!node) - return; - - g_signal_emit(wm, signals[SIG_CONFIRM_RESIZE], 0, widget, &width, &height, &ret); - if (!ret) - return; /* resize is not permitted */ - hide_panel(node->panel); - gnt_widget_set_size(widget, width, height); - gnt_widget_draw(widget); - - shadow = gnt_widget_has_shadow(widget) ? 1 : 0; - maxx = getmaxx(stdscr) - shadow; - maxy = getmaxy(stdscr) - 1 - shadow; - height = MIN(height, maxy); - width = MIN(width, maxx); - wresize(node->window, height + shadow, width + shadow); - replace_panel(node->panel, node->window); - - g_signal_emit(wm, signals[SIG_RESIZED], 0, node); - - show_panel(node->panel); - update_screen(wm); -} - -static void -write_gdi(gpointer key, gpointer value, gpointer data) -{ - GntPosition *p = value; - fprintf(data, ".%s = %d;%d\n", (char *)key, p->x, p->y); -} - -static gboolean -write_already(gpointer data) -{ - GntWM *wm = data; - FILE *file; - char *filename; - - filename = g_build_filename(g_get_home_dir(), ".gntpositions", NULL); - - file = fopen(filename, "wb"); - if (file == NULL) { - g_printerr("GntWM: error opening file to save positions\n"); - } else { - fprintf(file, "[positions]\n"); - g_hash_table_foreach(wm->positions, write_gdi, file); - fclose(file); - } - - g_free(filename); - g_source_remove(write_timeout); - write_timeout = 0; - return FALSE; -} - -static void -write_positions_to_file(GntWM *wm) -{ - if (write_timeout) { - g_source_remove(write_timeout); - } - write_timeout = g_timeout_add(10000, write_already, wm); -} - -void gnt_wm_move_window(GntWM *wm, GntWidget *widget, int x, int y) -{ - gboolean ret = TRUE; - GntNode *node; - - while (widget->parent) - widget = widget->parent; - node = g_hash_table_lookup(wm->nodes, widget); - if (!node) - return; - - g_signal_emit(wm, signals[SIG_CONFIRM_MOVE], 0, widget, &x, &y, &ret); - if (!ret) - return; /* resize is not permitted */ - - gnt_widget_set_position(widget, x, y); - move_panel(node->panel, y, x); - - g_signal_emit(wm, signals[SIG_MOVED], 0, node); - if (gnt_style_get_bool(GNT_STYLE_REMPOS, TRUE) && GNT_IS_BOX(widget)) { - const char *title = GNT_BOX(widget)->title; - if (title) { - GntPosition *p = g_new0(GntPosition, 1); - GntWidget *wid = node->me; - p->x = wid->priv.x; - p->y = wid->priv.y; - g_hash_table_replace(wm->positions, g_strdup(title), p); - write_positions_to_file(wm); - } - } - - update_screen(wm); -} - -static void -gnt_wm_give_focus(GntWM *wm, GntWidget *widget) -{ - GntNode *node = g_hash_table_lookup(wm->nodes, widget); - - if (!node) - return; - - if (widget != wm->_list.window && !GNT_IS_MENU(widget) && - wm->ordered->data != widget) { - GntWidget *w = wm->ordered->data; - wm->ordered = g_list_bring_to_front(wm->ordered, widget); - gnt_widget_set_focus(w, FALSE); - } - - gnt_widget_set_focus(widget, TRUE); - GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_URGENT); - gnt_widget_draw(widget); - top_panel(node->panel); - - if (wm->_list.window) { - GntNode *nd = g_hash_table_lookup(wm->nodes, wm->_list.window); - top_panel(nd->panel); - } - update_screen(wm); - draw_taskbar(wm, FALSE); -} - -void gnt_wm_update_window(GntWM *wm, GntWidget *widget) -{ - GntNode *node; - - while (widget->parent) - widget = widget->parent; - if (!GNT_IS_MENU(widget)) - gnt_box_sync_children(GNT_BOX(widget)); - - node = g_hash_table_lookup(wm->nodes, widget); - if (node == NULL) { - gnt_wm_new_window(wm, widget); - } else - g_signal_emit(wm, signals[SIG_UPDATE_WIN], 0, node); - - copy_win(widget, node); - update_screen(wm); - draw_taskbar(wm, FALSE); -} - -gboolean gnt_wm_process_click(GntWM *wm, GntMouseEvent event, int x, int y, GntWidget *widget) -{ - gboolean ret = TRUE; - idle_update = TRUE; - g_signal_emit(wm, signals[SIG_MOUSE_CLICK], 0, event, x, y, widget, &ret); - return ret; -} - -void gnt_wm_raise_window(GntWM *wm, GntWidget *widget) -{ - g_signal_emit(wm, signals[SIG_GIVE_FOCUS], 0, widget); -} - diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/gntwm.h --- a/console/libgnt/gntwm.h Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,168 +0,0 @@ - -#include "gntwidget.h" -#include "gntmenu.h" - -#include - -#define GNT_TYPE_WM (gnt_wm_get_gtype()) -#define GNT_WM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNT_TYPE_WM, GntWM)) -#define GNT_WM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GNT_TYPE_WM, GntWMClass)) -#define GNT_IS_WM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GNT_TYPE_WM)) -#define GNT_IS_WM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GNT_TYPE_WM)) -#define GNT_WM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GNT_TYPE_WM, GntWMClass)) - -typedef enum -{ - GNT_KP_MODE_NORMAL, - GNT_KP_MODE_RESIZE, - GNT_KP_MODE_MOVE, -} GntKeyPressMode; - -typedef struct -{ - GntWidget *me; - - WINDOW *window; - int scroll; - PANEL *panel; -} GntNode; - -typedef struct _GntWM GntWM; - -typedef struct _GnPosition -{ - int x; - int y; -} GntPosition; - -/** - * An application can register actions which will show up in a 'start-menu' like popup - */ -typedef struct _GnAction -{ - const char *label; - void (*callback)(); -} GntAction; - -struct _GntWM -{ - GntBindable inherit; - - GMainLoop *loop; - - GList *list; /* List of windows ordered on their creation time */ - GList *ordered; /* List of windows ordered on their focus */ - - struct { - GntWidget *window; - GntWidget *tree; - } _list, - *windows, /* Window-list window */ - *actions; /* Action-list window */ - - GHashTable *nodes; /* GntWidget -> GntNode */ - - GList *acts; /* List of actions */ - - /** - * There can be at most one menu at a time on the screen. - * If there is a menu being displayed, then all the keystrokes will be sent to - * the menu until it is closed, either when the user activates a menuitem, or - * presses Escape to cancel the menu. - */ - GntMenu *menu; /* Currently active menu */ - - /** - * 'event_stack' will be set to TRUE when a user-event, ie. a mouse-click - * or a key-press is being processed. This variable will be used to determine - * whether to give focus to a new window. - */ - gboolean event_stack; - - GntKeyPressMode mode; - - GHashTable *positions; - - void *res1; - void *res2; - void *res3; - void *res4; -}; - -typedef struct _GnWMClass GntWMClass; - -struct _GnWMClass -{ - GntBindableClass parent; - - /* This is called when a new window is shown */ - void (*new_window)(GntWM *wm, GntWidget *win); - - void (*decorate_window)(GntWM *wm, GntWidget *win); - /* This is called when a window is being closed */ - gboolean (*close_window)(GntWM *wm, GntWidget *win); - - /* The WM may want to confirm a size for a window first */ - gboolean (*window_resize_confirm)(GntWM *wm, GntWidget *win, int *w, int *h); - - void (*window_resized)(GntWM *wm, GntNode *node); - - /* The WM may want to confirm the position of a window */ - gboolean (*window_move_confirm)(GntWM *wm, GntWidget *win, int *x, int *y); - - void (*window_moved)(GntWM *wm, GntNode *node); - - /* This gets called when: - * - the title of the window changes - * - the 'urgency' of the window changes - */ - void (*window_update)(GntWM *wm, GntNode *node); - - /* This should usually return NULL if the keys were processed by the WM. - * If not, the WM can simply return the original string, which will be - * processed by the default WM. The custom WM can also return a different - * static string for the default WM to process. - */ - gboolean (*key_pressed)(GntWM *wm, const char *key); - - gboolean (*mouse_clicked)(GntWM *wm, GntMouseEvent event, int x, int y, GntWidget *widget); - - /* Whatever the WM wants to do when a window is given focus */ - void (*give_focus)(GntWM *wm, GntWidget *widget); - - /* List of windows. Although the WM can keep a list of its own for the windows, - * it'd be better if there was a way to share between the 'core' and the WM. - */ - /*const GList *(*window_list)();*/ - - void (*res1)(void); - void (*res2)(void); - void (*res3)(void); - void (*res4)(void); -}; - -G_BEGIN_DECLS - -GType gnt_wm_get_gtype(void); - -void gnt_wm_new_window(GntWM *wm, GntWidget *widget); - -void gnt_wm_window_decorate(GntWM *wm, GntWidget *widget); - -void gnt_wm_window_close(GntWM *wm, GntWidget *widget); - -gboolean gnt_wm_process_input(GntWM *wm, const char *string); - -gboolean gnt_wm_process_click(GntWM *wm, GntMouseEvent event, int x, int y, GntWidget *widget); - -void gnt_wm_resize_window(GntWM *wm, GntWidget *widget, int width, int height); - -void gnt_wm_move_window(GntWM *wm, GntWidget *widget, int x, int y); - -void gnt_wm_update_window(GntWM *wm, GntWidget *widget); - -void gnt_wm_raise_window(GntWM *wm, GntWidget *widget); - -time_t gnt_wm_get_idle_time(void); - -G_END_DECLS diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/test.c --- a/console/libgnt/test.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,125 +0,0 @@ -#include "gntbutton.h" -#include "gnt.h" -#include "gntkeys.h" -#include "gnttree.h" -#include "gntbox.h" - -static gboolean -key_pressed(GntWidget *widget, const char *text, gpointer null) -{ - GntWidget *w = null; - GntWidget *box = gnt_box_new(FALSE, FALSE); - GntWidget *label = gnt_label_new("so wassup!!"); - - gnt_box_add_widget(GNT_BOX(box), label); - GNT_WIDGET_UNSET_FLAGS(box, GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW); - gnt_box_set_title(GNT_BOX(box), "This is a test"); - - gnt_widget_show(box); -#if 0 - - gnt_widget_set_focus(w, TRUE); - - /* XXX: This is to just test stuff */ - if (text[0] == 27) - { - if (strcmp(text+1, GNT_KEY_LEFT) == 0 && w->priv.x) - (w->priv.x)--; - else if (strcmp(text+1, GNT_KEY_RIGHT) == 0) - (w->priv.x)++; - else if (strcmp(text+1, GNT_KEY_UP) == 0 && w->priv.y) - (w->priv.y)--; - else if (strcmp(text+1, GNT_KEY_DOWN) == 0) - (w->priv.y)++; - } - - gnt_widget_draw(w); -#endif - - return FALSE; -} - -static void -button1(GntWidget *widget, gpointer null) -{ - printf("OLAAA"); - gnt_widget_destroy(null); -} - -static void -button2(GntWidget *widget, gpointer null) -{ - printf("BOOYAA"); -} - -static gboolean -w_scroll(GntWidget *tree) -{ - g_return_val_if_fail(GNT_IS_TREE(tree), FALSE); - gnt_tree_scroll(GNT_TREE(tree), 1); - /*wscrl(tree->window, 1);*/ - /*box(tree->window, ACS_VLINE, ACS_HLINE);*/ - /*wrefresh(tree->window);*/ - /*char *s = 0;*/ - /**s = 'a';*/ - return TRUE; -} - -int main() -{ - gnt_init(); - - GntWidget *widget = gnt_button_new("Button 1"); - GntWidget *widget2 = gnt_button_new("Button 2 has a longish text with a UTF-8 thing …"); - GntWidget *label = gnt_label_new("So wassup dudes and dudettes!!\nSo this is, like,\nthe third line!! \\o/"); - GntWidget *vbox, *hbox, *tree; - WINDOW *test; - - box(stdscr, 0, 0); - wrefresh(stdscr); - - vbox = gnt_box_new(FALSE, FALSE); - hbox = gnt_box_new(FALSE, TRUE); - - gnt_widget_set_name(vbox, "vbox"); - gnt_widget_set_name(hbox, "hbox"); - gnt_widget_set_name(widget, "widget"); - gnt_widget_set_name(widget2, "widget2"); - - gnt_box_add_widget(GNT_BOX(vbox), widget); - gnt_box_add_widget(GNT_BOX(vbox), widget2); - - gnt_box_add_widget(GNT_BOX(hbox), label); - /*gnt_box_add_widget(GNT_BOX(hbox), vbox);*/ - - gnt_box_add_widget(GNT_BOX(hbox), gnt_entry_new("a")); - - tree = gnt_tree_new(); - gnt_box_add_widget(GNT_BOX(hbox), tree); - - gnt_tree_add_row_after(GNT_TREE(tree), "a", "a", NULL, NULL); - gnt_tree_add_row_after(GNT_TREE(tree), "c", "c", NULL, NULL); - gnt_tree_add_row_after(GNT_TREE(tree), "d", "d", NULL, NULL); - gnt_tree_add_row_after(GNT_TREE(tree), "e", "e", "a", NULL); - gnt_tree_add_row_after(GNT_TREE(tree), "b", "b", "d", NULL); - - GNT_WIDGET_UNSET_FLAGS(hbox, GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW); - gnt_box_set_title(GNT_BOX(hbox), "111111111111111111111111111111111111111111111111111111111111111This is the title …"); - - /*gnt_widget_set_take_focus(vbox, TRUE);*/ - /*gnt_widget_set_take_focus(hbox, TRUE);*/ - /*gnt_widget_set_position(hbox, 10, 10);*/ - - gnt_widget_show(hbox); - - g_signal_connect(hbox, "key_pressed", G_CALLBACK(key_pressed), tree); - g_signal_connect(widget, "activate", G_CALLBACK(button1), hbox); - g_signal_connect(widget2, "activate", G_CALLBACK(button2), hbox); - - /*g_timeout_add(1000, (GSourceFunc)w_scroll, tree);*/ - - gnt_main(); - - return 0; -} - diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/test/Makefile --- a/console/libgnt/test/Makefile Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,16 +0,0 @@ -CC=gcc -CFLAGS=`pkg-config --cflags gobject-2.0 gmodule-2.0` -g -I../ -DSTANDALONE -LDFLAGS=`pkg-config --libs gobject-2.0 gmodule-2.0 gnt` -pg - -EXAMPLES=combo focus tv multiwin keys menu - -all: - make examples - -clean: - rm -f $(EXAMPLES) *.so wm - -WM: wm - for i in $(EXAMPLES); do gcc -shared $(CFLAGS) -USTANDALONE $(LDFLAGS) $${i}.c -o $${i}.so ; done - -examples: $(EXAMPLES) diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/test/combo.c --- a/console/libgnt/test/combo.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,82 +0,0 @@ -#include -#include -#include -#include -#include -#include - -static void -button_activated(GntWidget *b, GntComboBox *combo) -{ - GntWidget *w = b->parent; - - gnt_box_add_widget(GNT_BOX(w), - gnt_label_new(gnt_combo_box_get_selected_data(GNT_COMBO_BOX(combo)))); - fprintf(stderr, "%s\n", gnt_combo_box_get_selected_data(GNT_COMBO_BOX(combo))); - gnt_box_readjust(GNT_BOX(w->parent)); -} - -int main() -{ - GntWidget *box, *combo, *button; - GntWidget *hbox; - -#ifdef STANDALONE - freopen(".error", "w", stderr); - gnt_init(); -#endif - - box = gnt_box_new(FALSE, TRUE); - gnt_widget_set_name(box, "box"); - gnt_box_set_alignment(GNT_BOX(box), GNT_ALIGN_MID); - gnt_box_set_pad(GNT_BOX(box), 0); - - gnt_box_set_toplevel(GNT_BOX(box), TRUE); - gnt_box_set_title(GNT_BOX(box), "Checkbox"); - - hbox = gnt_box_new(FALSE, FALSE); - gnt_box_set_pad(GNT_BOX(hbox), 0); - gnt_box_set_alignment(GNT_BOX(hbox), GNT_ALIGN_MID); - gnt_widget_set_name(hbox, "upper"); - - combo = gnt_combo_box_new(); - gnt_combo_box_add_data(GNT_COMBO_BOX(combo), "1", "1"); - gnt_combo_box_add_data(GNT_COMBO_BOX(combo), "2", "2"); - gnt_combo_box_add_data(GNT_COMBO_BOX(combo), "3", "3abcdefghijklmnopqrstuvwxyz"); - gnt_combo_box_add_data(GNT_COMBO_BOX(combo), "4", "4"); - gnt_combo_box_add_data(GNT_COMBO_BOX(combo), "5", "5"); - gnt_combo_box_add_data(GNT_COMBO_BOX(combo), "6", "6"); - gnt_combo_box_add_data(GNT_COMBO_BOX(combo), "7", "7"); - gnt_combo_box_add_data(GNT_COMBO_BOX(combo), "8", "8"); - gnt_combo_box_add_data(GNT_COMBO_BOX(combo), "9", "9"); - - GntWidget *l = gnt_label_new("Select"); - gnt_box_add_widget(GNT_BOX(hbox), l); - gnt_widget_set_size(l, 0, 1); - gnt_box_add_widget(GNT_BOX(hbox), combo); - - gnt_box_add_widget(GNT_BOX(box), hbox); - - hbox = gnt_box_new(TRUE, FALSE); - gnt_box_set_alignment(GNT_BOX(hbox), GNT_ALIGN_MID); - gnt_widget_set_name(hbox, "lower"); - - button = gnt_button_new("OK"); - gnt_box_add_widget(GNT_BOX(hbox), button); - g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(button_activated), combo); - - gnt_box_add_widget(GNT_BOX(box), hbox); - - gnt_box_add_widget(GNT_BOX(box), gnt_check_box_new("check box")); - - gnt_widget_show(box); - -#ifdef STANDALONE - gnt_main(); - - gnt_quit(); -#endif - - return 0; -} - diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/test/focus.c --- a/console/libgnt/test/focus.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,92 +0,0 @@ -#include "gntbutton.h" -#include "gnt.h" -#include "gntkeys.h" -#include "gnttree.h" -#include "gntbox.h" -#include "gntentry.h" -#include "gntlabel.h" - -static void -toggled(GntWidget *tree, gpointer key, gpointer null) -{ - GntWidget *w = gnt_box_new(FALSE, FALSE); - - gnt_box_set_toplevel(GNT_BOX(w), TRUE); - - gnt_box_add_widget(GNT_BOX(w), - gnt_label_new(gnt_tree_get_choice(GNT_TREE(tree), key) ? "Selected" : "NOT")); - gnt_widget_show(w); -} - -int main() -{ -#ifdef STANDALONE - freopen(".error", "w", stderr); - gnt_init(); -#endif - - GntWidget *label = gnt_label_new("So wassup dudes and dudettes!!\u4e0a1\u6d772\u67003\u4f4e4\u67085\nSo this is, like,\nthe third line!! \\o/"); - GntWidget *vbox, *hbox, *tree, *box, *button; - WINDOW *test; - - vbox = gnt_box_new(FALSE, FALSE); - hbox = gnt_box_new(FALSE, TRUE); - gnt_box_set_alignment(GNT_BOX(hbox), GNT_ALIGN_MID); - - gnt_widget_set_name(vbox, "vbox"); - gnt_widget_set_name(hbox, "hbox"); - - gnt_box_add_widget(GNT_BOX(hbox), label); - - GntWidget *entry = gnt_entry_new("a"); - gnt_widget_set_name(entry, "entry"); - gnt_box_add_widget(GNT_BOX(hbox), entry); - - box = gnt_box_new(FALSE, FALSE); - tree = gnt_tree_new(); - gnt_tree_set_compare_func(GNT_TREE(tree), g_utf8_collate); - gnt_widget_set_name(tree, "tree"); - gnt_box_add_widget(GNT_BOX(box), tree); - gnt_box_add_widget(GNT_BOX(hbox), box); - - gnt_tree_add_row_after(GNT_TREE(tree), "c", gnt_tree_create_row(GNT_TREE(tree), "c"), NULL, NULL); - gnt_tree_add_row_after(GNT_TREE(tree), "a", gnt_tree_create_row(GNT_TREE(tree), "a"), NULL, NULL); - gnt_tree_add_row_after(GNT_TREE(tree), "z", gnt_tree_create_row(GNT_TREE(tree), "z"), "a", NULL); - gnt_tree_add_row_after(GNT_TREE(tree), "y", gnt_tree_create_row(GNT_TREE(tree), "y"), "a", NULL); - gnt_tree_add_row_after(GNT_TREE(tree), "g", gnt_tree_create_row(GNT_TREE(tree), "g"), "a", NULL); - gnt_tree_add_row_after(GNT_TREE(tree), "d", gnt_tree_create_row(GNT_TREE(tree), "d"), NULL, NULL); - gnt_tree_add_row_after(GNT_TREE(tree), "x", gnt_tree_create_row(GNT_TREE(tree), "x"), "a", NULL); - gnt_tree_add_row_after(GNT_TREE(tree), "k", gnt_tree_create_row(GNT_TREE(tree), "k"), "a", NULL); - gnt_tree_add_row_after(GNT_TREE(tree), "e", gnt_tree_create_row(GNT_TREE(tree), "e"), "a", NULL); - gnt_tree_add_choice(GNT_TREE(tree), "b", gnt_tree_create_row(GNT_TREE(tree), "b"), "d", NULL); - - GNT_WIDGET_UNSET_FLAGS(hbox, GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW); - gnt_box_set_title(GNT_BOX(hbox), "\u4e0a\u6d77\u6700\u4f4e\u6708\u5de5 \u4e0a\u6d77\u6700\u4f4e\u6708\u5de5 ……\u4e0a\u6d77\u6700\u4f4e\u6708\u5de5 …"); - - g_signal_connect(G_OBJECT(tree), "toggled", G_CALLBACK(toggled), NULL); - - button = gnt_button_new("one"); - gnt_widget_set_name(button, "one"); - gnt_box_add_widget(GNT_BOX(vbox), button); - - button = gnt_button_new("two"); - gnt_widget_set_name(button, "two"); - gnt_box_add_widget(GNT_BOX(vbox), button); - - button = gnt_button_new("three"); - gnt_widget_set_name(button, "three"); - gnt_box_add_widget(GNT_BOX(vbox), button); - - gnt_box_add_widget(GNT_BOX(hbox), vbox); - - gnt_widget_show(hbox); - -#ifdef STANDALONE - gnt_main(); - - gnt_quit(); -#endif - - return 0; -} - diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/test/key.c --- a/console/libgnt/test/key.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,18 +0,0 @@ -#include - -int main() -{ - int ch; - initscr(); - - noecho(); - - while ((ch = getch())) { - printw("%d ", ch); - refresh(); - } - - endwin(); - return 0; -} - diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/test/keys.c --- a/console/libgnt/test/keys.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -#include -#include -#include -#include - -static gboolean -print_keycode(GntEntry *entry, const char *text, gpointer null) -{ - char *s = g_strdup_printf("%s ", text); - gnt_entry_set_text(entry, s); - g_free(s); - if (text[0] == 27) - { - if (strncmp(text + 1, "[M ", 3) == 0) - { - int x = (unsigned)text[4]; - int y = (unsigned)text[5]; - if (x < 0) x += 256; - if (y < 0) y += 256; - x -= 33; - y -= 33; - s = g_strdup_printf("ldown %d %d", x, y); - gnt_entry_set_text(entry, s); - g_free(s); - } - else if (strncmp(text + 1, "[M#", 3) == 0) - gnt_entry_set_text(entry, "up"); - else - return FALSE; - return TRUE; - } - else - return TRUE; -} - -int main() -{ - GntWidget *window, *entry; - - gnt_init(); - - freopen(".error", "w", stderr); - - window = gnt_hbox_new(FALSE); - gnt_box_set_toplevel(GNT_BOX(window), TRUE); - - gnt_box_add_widget(GNT_BOX(window), gnt_label_new("Press any key: ")); - - entry = gnt_entry_new(NULL); - gnt_box_add_widget(GNT_BOX(window), entry); - g_signal_connect(G_OBJECT(entry), "key_pressed", G_CALLBACK(print_keycode), NULL); - - gnt_widget_set_position(window, getmaxx(stdscr) / 2 - 12, getmaxy(stdscr) / 2 - 3); - gnt_widget_show(window); - - gnt_main(); - gnt_quit(); - return 0; -} - diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/test/menu.c --- a/console/libgnt/test/menu.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -#include "gnt.h" -#include "gntbox.h" -#include "gntlabel.h" -#include "gntmenu.h" -#include "gntmenuitem.h" -#include "gntwindow.h" - -void dothis(GntMenuItem *item, gpointer null) -{ - GntWidget *w = gnt_vbox_new(FALSE); - gnt_box_set_toplevel(GNT_BOX(w), TRUE); - gnt_box_add_widget(GNT_BOX(w), - gnt_label_new("Callback to a menuitem")); - gnt_widget_show(w); -} - -int main() -{ - freopen(".error", "w", stderr); - gnt_init(); - - GntWidget *menu = gnt_menu_new(GNT_MENU_TOPLEVEL); - GObject *item = gnt_menuitem_new("File"); - - gnt_menu_add_item(GNT_MENU(menu), GNT_MENUITEM(item)); - - item = gnt_menuitem_new("Edit"); - gnt_menu_add_item(GNT_MENU(menu), GNT_MENUITEM(item)); - - item = gnt_menuitem_new("Help"); - gnt_menu_add_item(GNT_MENU(menu), GNT_MENUITEM(item)); - - GntWidget *sub = gnt_menu_new(GNT_MENU_POPUP); - gnt_menuitem_set_submenu(GNT_MENUITEM(item), GNT_MENU(sub)); - - item = gnt_menuitem_new("Online Help"); - gnt_menu_add_item(GNT_MENU(sub), GNT_MENUITEM(item)); - - item = gnt_menuitem_new("About"); - gnt_menu_add_item(GNT_MENU(sub), GNT_MENUITEM(item)); - - sub = gnt_menu_new(GNT_MENU_POPUP); - gnt_menuitem_set_submenu(GNT_MENUITEM(item), GNT_MENU(sub)); - - item = gnt_menuitem_new("Online Help"); - gnt_menu_add_item(GNT_MENU(sub), GNT_MENUITEM(item)); - gnt_menuitem_set_callback(GNT_MENUITEM(item), dothis, NULL); - - gnt_screen_menu_show(menu); - - GntWidget *win = gnt_window_new(); - gnt_box_add_widget(GNT_BOX(win), - gnt_label_new("...")); - gnt_box_set_title(GNT_BOX(win), "Title"); - gnt_window_set_menu(GNT_WINDOW(win), GNT_MENU(menu)); - gnt_widget_show(win); - - gnt_main(); - - gnt_quit(); - - return 0; -} - diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/test/multiwin.c --- a/console/libgnt/test/multiwin.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,87 +0,0 @@ -#include "gnt.h" -#include "gntbutton.h" -#include "gntentry.h" -#include "gntkeys.h" -#include "gntlabel.h" -#include "gnttree.h" -#include "gntbox.h" - -gboolean show(GntWidget *w) -{ - return FALSE; -} - -int main() -{ -#ifdef STANDALONE - freopen(".error", "w", stderr); - gnt_init(); -#endif - - GntWidget *hbox, *tree, *box2; - - hbox = gnt_box_new(FALSE, TRUE); - box2 = gnt_box_new(FALSE, TRUE); - - gnt_widget_set_name(hbox, "hbox"); - gnt_widget_set_name(box2, "box2"); - - tree = gnt_tree_new_with_columns(3); - GNT_WIDGET_SET_FLAGS(tree, GNT_WIDGET_NO_BORDER); - gnt_tree_set_column_titles(GNT_TREE(tree), "12345678901234567890", "column 2", "column3"); - gnt_tree_set_show_title(GNT_TREE(tree), TRUE); - gnt_widget_set_name(tree, "tree"); - gnt_box_add_widget(GNT_BOX(hbox), tree); - - gnt_box_set_toplevel(GNT_BOX(hbox), TRUE); - gnt_box_set_title(GNT_BOX(hbox), "Testing the tree widget"); - - gnt_box_set_toplevel(GNT_BOX(box2), TRUE); - gnt_box_set_title(GNT_BOX(box2), "On top"); - - gnt_box_add_widget(GNT_BOX(box2), gnt_label_new("asdasd")); - gnt_box_add_widget(GNT_BOX(box2), gnt_entry_new(NULL)); - - gnt_widget_show(hbox); - gnt_widget_set_position(box2, 80, 40); - gnt_widget_show(box2); - - gnt_tree_add_row_after(GNT_TREE(tree), "a", - gnt_tree_create_row(GNT_TREE(tree), "alaskdjfkashfashfah kfalkdhflsiafhlasf", " long text", "a2"), NULL, NULL); - gnt_tree_add_row_after(GNT_TREE(tree), "c", - gnt_tree_create_row(GNT_TREE(tree), "casdgertqhyeqgasfeytwfga fg arf agfwa ", " long text", "a2"), NULL, NULL); - gnt_tree_add_row_after(GNT_TREE(tree), "d", gnt_tree_create_row(GNT_TREE(tree), "d", " long text", "a2"), NULL, NULL); - gnt_tree_add_row_after(GNT_TREE(tree), "e", gnt_tree_create_row(GNT_TREE(tree), "e", " long text", "a2"), "a", NULL); - gnt_tree_add_row_after(GNT_TREE(tree), "b", gnt_tree_create_row(GNT_TREE(tree), "b", "this is", "a2"), "d", NULL); - - gnt_tree_add_choice(GNT_TREE(tree), "1", gnt_tree_create_row(GNT_TREE(tree), "1", " long text", "a2"), NULL, NULL); - gnt_tree_add_row_after(GNT_TREE(tree), "2", gnt_tree_create_row(GNT_TREE(tree), "2", " long text", "a2"), NULL, NULL); - gnt_tree_add_row_after(GNT_TREE(tree), "3", gnt_tree_create_row(GNT_TREE(tree), "3", " long text", "a2"), NULL, NULL); - gnt_tree_add_row_after(GNT_TREE(tree), "4", gnt_tree_create_row(GNT_TREE(tree), "4", " long text", "a2"), "a", NULL); - gnt_tree_add_row_after(GNT_TREE(tree), "5", gnt_tree_create_row(GNT_TREE(tree), "5", " long text", "a2"), "d", NULL); - - gnt_tree_add_row_after(GNT_TREE(tree), "6", gnt_tree_create_row(GNT_TREE(tree), "6", " long text", "a2"), "4", NULL); - - int i; - for (i = 110; i < 430; i++) - { - char *s; - s = g_strdup_printf("%d", i); /* XXX: yes, leaking */ - gnt_tree_add_row_after(GNT_TREE(tree), s, gnt_tree_create_row(GNT_TREE(tree), s, " long text", "a2"), "4", NULL); - } - - gnt_tree_set_row_flags(GNT_TREE(tree), "e", GNT_TEXT_FLAG_DIM); - - gnt_tree_set_selected(GNT_TREE(tree), "2"); - - g_timeout_add(5000, (GSourceFunc)show, box2); - -#ifdef STANDALONE - gnt_main(); - - gnt_quit(); -#endif - - return 0; -} - diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/test/tv.c --- a/console/libgnt/test/tv.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,107 +0,0 @@ -#include "gntbutton.h" -#include "gnt.h" -#include "gntkeys.h" -#include "gnttree.h" -#include "gntbox.h" -#include "gntentry.h" -#include "gnttextview.h" - -static gboolean -key_pressed(GntWidget *w, const char *key, GntWidget *view) -{ - if (key[0] == '\r' && key[1] == 0) - { - gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(view), - gnt_entry_get_text(GNT_ENTRY(w)), - GNT_TEXT_FLAG_UNDERLINE | GNT_TEXT_FLAG_HIGHLIGHT); - gnt_entry_add_to_history(GNT_ENTRY(w), gnt_entry_get_text(GNT_ENTRY(w))); - gnt_text_view_next_line(GNT_TEXT_VIEW(view)); - gnt_entry_clear(GNT_ENTRY(w)); - if (gnt_text_view_get_lines_below(GNT_TEXT_VIEW(view)) <= 1) - gnt_text_view_scroll(GNT_TEXT_VIEW(view), 0); - gnt_entry_remove_suggest(GNT_ENTRY(w), "acb"); - - return TRUE; - } - else if (key[0] == 27) - { - if (strcmp(key, GNT_KEY_UP) == 0) - gnt_text_view_scroll(GNT_TEXT_VIEW(view), -1); - else if (strcmp(key, GNT_KEY_DOWN) == 0) - gnt_text_view_scroll(GNT_TEXT_VIEW(view), 1); - else - return FALSE; - return TRUE; - } - - return FALSE; -} - -int main() -{ - GntWidget *hbox, *entry, *view; - -#ifdef STANDALONE - freopen(".error", "w", stderr); - - gnt_init(); -#endif - - hbox = gnt_box_new(FALSE, TRUE); - gnt_widget_set_name(hbox, "hbox"); - gnt_box_set_toplevel(GNT_BOX(hbox), TRUE); - gnt_box_set_fill(GNT_BOX(hbox), FALSE); - gnt_box_set_title(GNT_BOX(hbox), "Textview test"); - gnt_box_set_alignment(GNT_BOX(hbox), GNT_ALIGN_MID); - - entry = gnt_entry_new(NULL); - gnt_widget_set_name(entry, "entry"); - GNT_WIDGET_SET_FLAGS(entry, GNT_WIDGET_CAN_TAKE_FOCUS); - - gnt_entry_set_word_suggest(GNT_ENTRY(entry), TRUE); - gnt_entry_set_always_suggest(GNT_ENTRY(entry), FALSE); - gnt_entry_add_suggest(GNT_ENTRY(entry), "a"); - gnt_entry_add_suggest(GNT_ENTRY(entry), "ab"); - gnt_entry_add_suggest(GNT_ENTRY(entry), "abe"); - gnt_entry_add_suggest(GNT_ENTRY(entry), "abc"); - gnt_entry_add_suggest(GNT_ENTRY(entry), "abcde"); - gnt_entry_add_suggest(GNT_ENTRY(entry), "abcd"); - gnt_entry_add_suggest(GNT_ENTRY(entry), "acb"); - - view = gnt_text_view_new(); - gnt_widget_set_name(view, "view"); - - gnt_widget_set_size(view, 20, 15); - gnt_widget_set_size(entry, 20, 1); - - gnt_box_add_widget(GNT_BOX(hbox), view); - gnt_box_add_widget(GNT_BOX(hbox), entry); - gnt_box_add_widget(GNT_BOX(hbox), gnt_button_new("OK")); - - gnt_widget_show(hbox); - - gnt_entry_set_history_length(GNT_ENTRY(entry), -1); - g_signal_connect_after(G_OBJECT(entry), "key_pressed", G_CALLBACK(key_pressed), view); - - gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(view), "\n", GNT_TEXT_FLAG_NORMAL); - gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(view), "plugins: ", GNT_TEXT_FLAG_BOLD); - gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(view), "this is the 1st line\n", GNT_TEXT_FLAG_NORMAL); - - gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(view), "plugins: ", GNT_TEXT_FLAG_BOLD); - gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(view), "this is the 2nd line\n", GNT_TEXT_FLAG_NORMAL); - - gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(view), "plugins: ", GNT_TEXT_FLAG_BOLD); - gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(view), "this is the 3rd line\n", GNT_TEXT_FLAG_NORMAL); - - gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(view), "plugins: ", GNT_TEXT_FLAG_BOLD); - gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(view), "this is the 4th line\n", GNT_TEXT_FLAG_NORMAL); - -#ifdef STANDALONE - gnt_main(); - - gnt_quit(); -#endif - - return 0; -} - diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/test/wm.c --- a/console/libgnt/test/wm.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -#include - -#include -#include -#include -#include - -static gboolean -key_pressed(GntEntry *entry, const char *text, gpointer null) -{ - if (*text != '\r') - return FALSE; - - { - const char *cmd; - void *handle; - void (*func)(); - - cmd = gnt_entry_get_text(entry); - handle = g_module_open(cmd, G_MODULE_BIND_LOCAL); - if (handle && g_module_symbol(handle, "main", (gpointer)&func)) - { - char *argv[] = {cmd, NULL}; - gnt_entry_clear(entry); - func(1, argv); - } - else - { - GntWidget *widget = gnt_vbox_new(FALSE); - gnt_box_set_toplevel(GNT_BOX(widget), TRUE); - gnt_box_set_title(GNT_BOX(widget), "Error"); - gnt_box_add_widget(GNT_BOX(widget), gnt_label_new("Could not execute.")); - gnt_box_add_widget(GNT_BOX(widget), gnt_label_new(g_module_error())); - - gnt_widget_show(widget); - } - } - - return TRUE; -} - -int main() -{ - GntWidget *window, *entry; - - freopen(".error", "w", stderr); - - gnt_init(); - - window = gnt_hbox_new(FALSE); - - gnt_box_add_widget(GNT_BOX(window), gnt_label_new("Command")); - - entry = gnt_entry_new(NULL); - g_signal_connect(G_OBJECT(entry), "key_pressed", G_CALLBACK(key_pressed), NULL); - gnt_box_add_widget(GNT_BOX(window), entry); - - gnt_widget_set_position(window, 0, getmaxy(stdscr) - 2); - gnt_widget_show(window); - - gnt_main(); - - gnt_quit(); - - return 0; -} - diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/wms/Makefile.am --- a/console/libgnt/wms/Makefile.am Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -s_la_LDFLAGS = -module -avoid-version - -plugin_LTLIBRARIES = \ - s.la - -plugindir = $(libdir)/gaim - -s_la_SOURCES = s.c -s_la_LIBADD = \ - $(GLIB_LIBS) \ - $(top_builddir)/console/libgnt/libgnt.la \ - $(top_builddir)/libpurple/libpurple.la - -EXTRA_DIST = - -AM_CPPFLAGS = \ - -DDATADIR=\"$(datadir)\" \ - -DVERSION=\"$(VERSION)\" \ - -I$(top_srcdir)/libpurple \ - -I$(top_srcdir)/console \ - -I$(top_srcdir)/console/libgnt \ - $(DEBUG_CFLAGS) \ - $(GLIB_CFLAGS) \ - $(GNT_CFLAGS) \ - $(PLUGIN_CFLAGS) - diff -r 317e7613e581 -r 0e3a8505ebbe console/libgnt/wms/s.c --- a/console/libgnt/wms/s.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,247 +0,0 @@ -#include -#include - -#include "gnt.h" -#include "gntbox.h" -#include "gntmenu.h" -#include "gntstyle.h" -#include "gntwm.h" -#include "gntwindow.h" -#include "gntlabel.h" - -#include "blist.h" - -#define TYPE_S (s_get_gtype()) - -typedef struct _S -{ - GntWM inherit; -} S; - -typedef struct _SClass -{ - GntWMClass inherit; -} SClass; - -GType s_get_gtype(void); -void gntwm_init(GntWM **wm); - -static void (*org_new_window)(GntWM *wm, GntWidget *win); - -static void -envelope_buddylist(GntWidget *win) -{ - int w, h; - gnt_widget_get_size(win, &w, &h); - wresize(win->window, h, w + 1); - mvwvline(win->window, 0, w, ACS_VLINE | COLOR_PAIR(GNT_COLOR_NORMAL), h); - touchwin(win->window); -} - -static void -envelope_normal_window(GntWidget *win) -{ - int w, h; - - if (GNT_WIDGET_IS_FLAG_SET(win, GNT_WIDGET_NO_BORDER | GNT_WIDGET_TRANSIENT)) - return; - - gnt_widget_get_size(win, &w, &h); - wbkgdset(win->window, ' ' | COLOR_PAIR(GNT_COLOR_NORMAL)); - mvwprintw(win->window, 0, w - 4, "[X]"); -} - -static void -s_decorate_window(GntWM *wm, GntWidget *win) -{ - const char *name; - - name = gnt_widget_get_name(win); - if (name && strcmp(name, "buddylist") == 0) { - envelope_buddylist(win); - } else { - envelope_normal_window(win); - } -} - -static void -s_window_update(GntWM *wm, GntNode *node) -{ - s_decorate_window(wm, node->me); -} - -static void -s_new_window(GntWM *wm, GntWidget *win) -{ - int x, y, w, h; - int maxx, maxy; - const char *name; - gboolean blist = FALSE; - - if (!GNT_IS_MENU(win)) { - getmaxyx(stdscr, maxy, maxx); - - gnt_widget_get_position(win, &x, &y); - gnt_widget_get_size(win, &w, &h); - - name = gnt_widget_get_name(win); - - if (name && strcmp(name, "buddylist") == 0) { - /* The buddylist doesn't have no border nor nothing! */ - x = 0; - y = 0; - h = maxy - 1; - blist = TRUE; - - gnt_box_set_toplevel(GNT_BOX(win), FALSE); - GNT_WIDGET_SET_FLAGS(win, GNT_WIDGET_CAN_TAKE_FOCUS); - - gnt_widget_set_position(win, x, y); - mvwin(win->window, y, x); - - gnt_widget_set_size(win, -1, h + 2); /* XXX: Why is the +2 needed here? -- sadrul */ - } else if (!GNT_WIDGET_IS_FLAG_SET(win, GNT_WIDGET_TRANSIENT)) { - const char *title = GNT_BOX(win)->title; - if (title == NULL || !g_hash_table_lookup(wm->positions, title)) { - /* In the middle of the screen */ - x = (maxx - w) / 2; - y = (maxy - h) / 2; - - gnt_widget_set_position(win, x, y); - mvwin(win->window, y, x); - } - } - } - org_new_window(wm, win); - - if (blist) - gnt_wm_raise_window(wm, win); -} - -static GntWidget * -find_widget(GntWM *wm, const char *wname) -{ - const GList *iter = wm->list; - for (; iter; iter = iter->next) { - GntWidget *widget = iter->data; - const char *name = gnt_widget_get_name(widget); - if (name && strcmp(name, wname) == 0) { - return widget; - } - } - return NULL; -} - -static gboolean -s_mouse_clicked(GntWM *wm, GntMouseEvent event, int cx, int cy, GntWidget *widget) -{ - int x, y, w, h; - - if (!widget) - return FALSE; - /* This might be a place to bring up a context menu */ - - if (event != GNT_LEFT_MOUSE_DOWN || - GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER)) - return FALSE; - - gnt_widget_get_position(widget, &x, &y); - gnt_widget_get_size(widget, &w, &h); - - if (cy == y && cx == x + w - 3) { - gnt_widget_destroy(widget); - return TRUE; - } - - return FALSE; -} - -static gboolean -toggle_buddylist(GntBindable *bindable, GList *null) -{ - GntWM *wm = GNT_WM(bindable); - GntWidget *blist = find_widget(wm, "buddylist"); - if (blist) - gnt_widget_destroy(blist); - else - gaim_blist_show(); - return TRUE; -} - -static gboolean -toggle_clipboard(GntBindable *bindable, GList *n) -{ - static GntWidget *clip; - gchar *text; - int maxx, maxy; - if (clip) { - gnt_widget_destroy(clip); - clip = NULL; - return TRUE; - } - getmaxyx(stdscr, maxy, maxx); - text = gnt_get_clipboard_string(); - clip = gnt_hwindow_new(FALSE); - GNT_WIDGET_SET_FLAGS(clip, GNT_WIDGET_TRANSIENT); - GNT_WIDGET_SET_FLAGS(clip, GNT_WIDGET_NO_BORDER); - gnt_box_set_pad(GNT_BOX(clip), 0); - gnt_box_add_widget(GNT_BOX(clip), gnt_label_new(" ")); - gnt_box_add_widget(GNT_BOX(clip), gnt_label_new(text)); - gnt_box_add_widget(GNT_BOX(clip), gnt_label_new(" ")); - gnt_widget_set_position(clip, 0, 0); - gnt_widget_draw(clip); - g_free(text); - return TRUE; -} - -static void -s_class_init(SClass *klass) -{ - GntWMClass *pclass = GNT_WM_CLASS(klass); - - org_new_window = pclass->new_window; - - pclass->new_window = s_new_window; - pclass->decorate_window = s_decorate_window; - pclass->window_update = s_window_update; - pclass->mouse_clicked = s_mouse_clicked; - - gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "toggle-buddylist", - toggle_buddylist, "\033" "b", NULL); - gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "toggle-clipboard", - toggle_clipboard, "\033" "C", NULL); - gnt_style_read_actions(G_OBJECT_CLASS_TYPE(klass), GNT_BINDABLE_CLASS(klass)); - GNTDEBUG; -} - -void gntwm_init(GntWM **wm) -{ - *wm = g_object_new(TYPE_S, NULL); -} - -GType s_get_gtype(void) -{ - static GType type = 0; - - if(type == 0) { - static const GTypeInfo info = { - sizeof(SClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc)s_class_init, - NULL, - NULL, /* class_data */ - sizeof(S), - 0, /* n_preallocs */ - NULL, /* instance_init */ - NULL - }; - - type = g_type_register_static(GNT_TYPE_WM, - "GntS", - &info, 0); - } - - return type; -} - diff -r 317e7613e581 -r 0e3a8505ebbe console/plugins/Makefile.am --- a/console/plugins/Makefile.am Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -gntgf_la_LDFLAGS = -module -avoid-version -gnthistory_la_LDFLAGS = -module -avoid-version -gntlastlog_la_LDFLAGS = -module -avoid-version - -if PLUGINS - -plugin_LTLIBRARIES = \ - gntgf.la \ - gnthistory.la \ - gntlastlog.la - -plugindir = $(libdir)/gaim - -gntgf_la_SOURCES = gntgf.c -gnthistory_la_SOURCES = gnthistory.c -gntlastlog_la_SOURCES = lastlog.c - -gntgf_la_CFLAGS = $(X11_CFLAGS) - -gntgf_la_LIBADD = $(GLIB_LIBS) $(X11_LIBS) $(top_builddir)/console/libgnt/libgnt.la -gnthistory_la_LIBADD = $(GLIB_LIBS) -gntlastlog_la_LIBADD = $(GLIB_LIBS) - -endif # PLUGINS - -EXTRA_DIST = - -AM_CPPFLAGS = \ - -DDATADIR=\"$(datadir)\" \ - -DVERSION=\"$(VERSION)\" \ - -I$(top_builddir)/libpurple \ - -I$(top_srcdir)/libpurple \ - -I$(top_srcdir) \ - -I$(top_srcdir)/console \ - -I$(top_srcdir)/console/libgnt \ - $(DEBUG_CFLAGS) \ - $(GLIB_CFLAGS) \ - $(GNT_CFLAGS) \ - $(PLUGIN_CFLAGS) - -# -# This part allows people to build their own plugins in here. -# Yes, it's a mess. -# -SUFFIXES = .c .so -.c.so: - $(LIBTOOL) --mode=compile $(CC) -DHAVE_CONFIG_H -I$(top_srcdir) $(AM_CPPFLAGS) $(CFLAGS) -c $< -o tmp$@.lo $(PLUGIN_CFLAGS) - $(LIBTOOL) --mode=link $(CC) $(CFLAGS) -o libtmp$@.la -rpath $(plugindir) tmp$@.lo $(LIBS) $(LDFLAGS) -module -avoid-version $(PLUGIN_LIBS) - @rm -f tmp$@.lo tmp$@.o libtmp$@.la - @cp .libs/libtmp$@.so* $@ - @rm -f .libs/libtmp$@.* diff -r 317e7613e581 -r 0e3a8505ebbe console/plugins/gntclipboard.c --- a/console/plugins/gntclipboard.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,168 +0,0 @@ -/** - * @file gntclipboard.c - * - * Copyright (C) 2007 Richard Nelson - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include "internal.h" -#include - -#define PLUGIN_STATIC_NAME "GntClipboard" - -#ifdef HAVE_X11 -#include -#include -#include -#endif - -#include -#include - -#include - -#include -#include -#include -#include - -#include - -static pid_t child = 0; - -static gulong sig_handle; - -static void -set_clip(gchar *string) -{ -#ifdef HAVE_X11 - Window w; - XEvent e, respond; - XSelectionRequestEvent *req; - const char *ids; - Display *dpy = XOpenDisplay(NULL); - - if (!dpy) - return; - ids = getenv("WINDOWID"); - if (ids == NULL) - return; - w = atoi(ids); - XSetSelectionOwner(dpy, XA_PRIMARY, w, CurrentTime); - XFlush(dpy); - XSelectInput(dpy, w, StructureNotifyMask); - while (TRUE) { - XNextEvent(dpy, &e); /* this blocks. */ - req = &e.xselectionrequest; - if (e.type == SelectionRequest) { - XChangeProperty(dpy, - req->requestor, - req->property, - XA_STRING, - 8, PropModeReplace, - (unsigned char *)string, - strlen(string)); - respond.xselection.property = req->property; - respond.xselection.type = SelectionNotify; - respond.xselection.display = req->display; - respond.xselection.requestor = req->requestor; - respond.xselection.selection = req->selection; - respond.xselection.target= req->target; - respond.xselection.time = req->time; - XSendEvent(dpy, req->requestor, 0, 0, &respond); - XFlush (dpy); - } else if (e.type == SelectionClear) { - return; - } - } -#endif - return; -} - -static void -clipboard_changed(GntWM *wm, gchar *string) -{ -#ifdef HAVE_X11 - if (child) { - kill(child, SIGTERM); - } - if ((child = fork() == 0)) { - set_clip(string); - _exit(0); - } -#endif -} - -static gboolean -plugin_load(GaimPlugin *plugin) -{ - if (!XOpenDisplay(NULL)) { - gaim_debug_warning("gntclipboard", "Couldn't find X display\n"); - return FALSE; - } - if (!getenv("WINDOWID")) { - gaim_debug_warning("gntclipboard", "Couldn't find window\n"); - return FALSE; - } - sig_handle = g_signal_connect(G_OBJECT(gnt_get_clipboard()), "clipboard_changed", G_CALLBACK(clipboard_changed), NULL); - return TRUE; -} - -static gboolean -plugin_unload(GaimPlugin *plugin) -{ - if (child) { - kill(child, SIGTERM); - child = 0; - } - g_signal_handler_disconnect(G_OBJECT(gnt_get_clipboard()), sig_handle); - return TRUE; -} - -static GaimPluginInfo info = -{ - GAIM_PLUGIN_MAGIC, - GAIM_MAJOR_VERSION, - GAIM_MINOR_VERSION, - GAIM_PLUGIN_STANDARD, - GAIM_GNT_PLUGIN_TYPE, - 0, - NULL, - GAIM_PRIORITY_DEFAULT, - "gntclipboard", - N_("GntClipboard"), - VERSION, - N_("Clipboard plugin"), - N_("When the gnt clipboard contents change, " - "the contents are made available to X, if possible."), - "Richard Nelson ", - "http://gaim.sourceforge.net", - plugin_load, - plugin_unload, - NULL, - NULL, - NULL, - NULL, - NULL -}; - -static void -init_plugin(GaimPlugin *plugin) -{ -} - -GAIM_INIT_PLUGIN(PLUGIN_STATIC_NAME, init_plugin, info) diff -r 317e7613e581 -r 0e3a8505ebbe console/plugins/gntgf.c --- a/console/plugins/gntgf.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,390 +0,0 @@ -/** - * @file gntgf.c Minimal toaster plugin in Gnt. - * - * Copyright (C) 2006 Sadrul Habib Chowdhury - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include "internal.h" - -#define PLUGIN_STATIC_NAME "GntGf" - -#define PREFS_PREFIX "/plugins/gnt/gntgf" -#define PREFS_EVENT PREFS_PREFIX "/events" -#define PREFS_EVENT_SIGNONF PREFS_EVENT "/signonf" -#define PREFS_EVENT_IM_MSG PREFS_EVENT "/immsg" -#define PREFS_EVENT_CHAT_MSG PREFS_EVENT "/chatmsg" -#define PREFS_EVENT_CHAT_NICK PREFS_EVENT "/chatnick" -#define PREFS_BEEP PREFS_PREFIX "/beep" - -#define MAX_COLS 3 - -#ifdef HAVE_X11 -#define PREFS_URGENT PREFS_PREFIX "/urgent" - -#include -#include -#endif - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - -typedef struct -{ - GntWidget *window; - int timer; - int column; -} GntToast; - -static GList *toasters; -static int gpsy[MAX_COLS]; -static int gpsw[MAX_COLS]; - -static void -destroy_toaster(GntToast *toast) -{ - toasters = g_list_remove(toasters, toast); - gnt_widget_destroy(toast->window); - g_source_remove(toast->timer); - g_free(toast); -} - -static gboolean -remove_toaster(GntToast *toast) -{ - GList *iter; - int h; - int col; - int nwin[MAX_COLS]; - - gnt_widget_get_size(toast->window, NULL, &h); - gpsy[toast->column] -= h; - col = toast->column; - - memset(&nwin, 0, sizeof(nwin)); - destroy_toaster(toast); - - for (iter = toasters; iter; iter = iter->next) - { - int x, y; - toast = iter->data; - nwin[toast->column]++; - if (toast->column != col) continue; - gnt_widget_get_position(toast->window, &x, &y); - y += h; - gnt_screen_move_widget(toast->window, x, y); - } - - if (nwin[col] == 0) - gpsw[col] = 0; - - return FALSE; -} - -#ifdef HAVE_X11 -static void -urgent() -{ - /* This is from deryni/tuomov's urgent_test.c */ - Display *dpy; - Window id; - const char *ids; - XWMHints *hints; - - ids = getenv("WINDOWID"); - if (ids == NULL) - return; - - id = atoi(ids); - - dpy = XOpenDisplay(NULL); - if (dpy == NULL) - return; - - hints = XGetWMHints(dpy, id); - hints->flags|=XUrgencyHint; - XSetWMHints(dpy, id, hints); - - XFlush(dpy); - XCloseDisplay(dpy); -} -#endif - -static void -notify(const char *fmt, ...) -{ - GntWidget *window; - GntToast *toast; - char *str; - int h, w, i; - va_list args; - - if (gaim_prefs_get_bool(PREFS_BEEP)) - beep(); -#ifdef HAVE_X11 - if (gaim_prefs_get_bool(PREFS_URGENT)) - urgent(); -#endif - - window = gnt_vbox_new(FALSE); - GNT_WIDGET_SET_FLAGS(window, GNT_WIDGET_TRANSIENT); - GNT_WIDGET_UNSET_FLAGS(window, GNT_WIDGET_NO_BORDER); - - va_start(args, fmt); - str = g_strdup_vprintf(fmt, args); - va_end(args); - - gnt_box_add_widget(GNT_BOX(window), - gnt_label_new_with_format(str, GNT_TEXT_FLAG_HIGHLIGHT)); - - g_free(str); - gnt_widget_size_request(window); - gnt_widget_get_size(window, &w, &h); - for (i = 0; i < MAX_COLS && gpsy[i] + h >= getmaxy(stdscr) ; ++i) - ; - if (i >= MAX_COLS) { - gaim_debug_warning("GntGf", "Dude, that's way too many popups\n"); - gnt_widget_destroy(window); - return; - } - - toast = g_new0(GntToast, 1); - toast->window = window; - toast->column = i; - gpsy[i] += h; - if (w > gpsw[i]) { - if (i == 0) - gpsw[i] = w; - else - gpsw[i] = gpsw[i - 1] + w + 1; - } - - if (i == 0 || (w + gpsw[i - 1] >= getmaxx(stdscr))) { - /* if it's going to be too far left, overlap. */ - gnt_widget_set_position(window, getmaxx(stdscr) - w - 1, - getmaxy(stdscr) - gpsy[i] - 1); - } else { - gnt_widget_set_position(window, getmaxx(stdscr) - gpsw[i - 1] - w - 1, - getmaxy(stdscr) - gpsy[i] - 1); - } - gnt_widget_draw(window); - - toast->timer = g_timeout_add(4000, (GSourceFunc)remove_toaster, toast); - toasters = g_list_prepend(toasters, toast); -} - -static void -buddy_signed_on(GaimBuddy *buddy, gpointer null) -{ - if (gaim_prefs_get_bool(PREFS_EVENT_SIGNONF)) - notify(_("%s just signed on"), gaim_buddy_get_alias(buddy)); -} - -static void -buddy_signed_off(GaimBuddy *buddy, gpointer null) -{ - if (gaim_prefs_get_bool(PREFS_EVENT_SIGNONF)) - notify(_("%s just signed off"), gaim_buddy_get_alias(buddy)); -} - -static void -received_im_msg(GaimAccount *account, const char *sender, const char *msg, - GaimConversation *conv, GaimMessageFlags flags, gpointer null) -{ - if (gaim_prefs_get_bool(PREFS_EVENT_IM_MSG)) - notify(_("%s sent you a message"), sender); -} - -static void -received_chat_msg(GaimAccount *account, const char *sender, const char *msg, - GaimConversation *conv, GaimMessageFlags flags, gpointer null) -{ - const char *nick; - - if (flags & GAIM_MESSAGE_WHISPER) - return; - - nick = GAIM_CONV_CHAT(conv)->nick; - - if (g_utf8_collate(sender, nick) == 0) - return; - - if (gaim_prefs_get_bool(PREFS_EVENT_CHAT_NICK) && - (gaim_utf8_has_word(msg, nick))) - notify(_("%s said your nick in %s"), sender, gaim_conversation_get_name(conv)); - else if (gaim_prefs_get_bool(PREFS_EVENT_CHAT_MSG)) - notify(_("%s sent a message in %s"), sender, gaim_conversation_get_name(conv)); -} - -static gboolean -plugin_load(GaimPlugin *plugin) -{ - gaim_signal_connect(gaim_blist_get_handle(), "buddy-signed-on", plugin, - GAIM_CALLBACK(buddy_signed_on), NULL); - gaim_signal_connect(gaim_blist_get_handle(), "buddy-signed-off", plugin, - GAIM_CALLBACK(buddy_signed_off), NULL); - gaim_signal_connect(gaim_conversations_get_handle(), "received-im-msg", plugin, - GAIM_CALLBACK(received_im_msg), NULL); - gaim_signal_connect(gaim_conversations_get_handle(), "received-chat-msg", plugin, - GAIM_CALLBACK(received_chat_msg), NULL); - - memset(&gpsy, 0, sizeof(gpsy)); - memset(&gpsw, 0, sizeof(gpsw)); - - return TRUE; -} - -static gboolean -plugin_unload(GaimPlugin *plugin) -{ - while (toasters) - { - GntToast *toast = toasters->data; - destroy_toaster(toast); - } - return TRUE; -} - -static struct -{ - char *pref; - char *display; -} prefs[] = -{ - {PREFS_EVENT_SIGNONF, N_("Buddy signs on/off")}, - {PREFS_EVENT_IM_MSG, N_("You receive an IM")}, - {PREFS_EVENT_CHAT_MSG, N_("Someone speaks in a chat")}, - {PREFS_EVENT_CHAT_NICK, N_("Someone says your name in a chat")}, - {NULL, NULL} -}; - -static void -pref_toggled(GntTree *tree, char *key, gpointer null) -{ - gaim_prefs_set_bool(key, gnt_tree_get_choice(tree, key)); -} - -static void -toggle_option(GntCheckBox *check, gpointer str) -{ - gaim_prefs_set_bool(str, gnt_check_box_get_checked(check)); -} - -static GntWidget * -config_frame() -{ - GntWidget *window, *tree, *check; - int i; - - window = gnt_vbox_new(FALSE); - gnt_box_set_pad(GNT_BOX(window), 0); - gnt_box_set_alignment(GNT_BOX(window), GNT_ALIGN_MID); - gnt_box_set_fill(GNT_BOX(window), TRUE); - - gnt_box_add_widget(GNT_BOX(window), - gnt_label_new(_("Notify with a toaster when"))); - - tree = gnt_tree_new(); - gnt_box_add_widget(GNT_BOX(window), tree); - - for (i = 0; prefs[i].pref; i++) - { - gnt_tree_add_choice(GNT_TREE(tree), prefs[i].pref, - gnt_tree_create_row(GNT_TREE(tree), prefs[i].display), NULL, NULL); - gnt_tree_set_choice(GNT_TREE(tree), prefs[i].pref, - gaim_prefs_get_bool(prefs[i].pref)); - } - gnt_tree_set_col_width(GNT_TREE(tree), 0, 40); - g_signal_connect(G_OBJECT(tree), "toggled", G_CALLBACK(pref_toggled), NULL); - - check = gnt_check_box_new(_("Beep too!")); - gnt_check_box_set_checked(GNT_CHECK_BOX(check), gaim_prefs_get_bool(PREFS_BEEP)); - g_signal_connect(G_OBJECT(check), "toggled", G_CALLBACK(toggle_option), PREFS_BEEP); - gnt_box_add_widget(GNT_BOX(window), check); - -#ifdef HAVE_X11 - check = gnt_check_box_new(_("Set URGENT for the terminal window.")); - gnt_check_box_set_checked(GNT_CHECK_BOX(check), gaim_prefs_get_bool(PREFS_URGENT)); - g_signal_connect(G_OBJECT(check), "toggled", G_CALLBACK(toggle_option), PREFS_URGENT); - gnt_box_add_widget(GNT_BOX(window), check); -#endif - - return window; -} - -static GaimPluginInfo info = -{ - GAIM_PLUGIN_MAGIC, - GAIM_MAJOR_VERSION, - GAIM_MINOR_VERSION, - GAIM_PLUGIN_STANDARD, - GAIM_GNT_PLUGIN_TYPE, - 0, - NULL, - GAIM_PRIORITY_DEFAULT, - "gntgf", - N_("GntGf"), - VERSION, - N_("Toaster plugin"), - N_("Toaster plugin"), - "Sadrul H Chowdhury ", - "http://gaim.sourceforge.net", - plugin_load, - plugin_unload, - NULL, - config_frame, - NULL, - NULL, - NULL -}; - -static void -init_plugin(GaimPlugin *plugin) -{ - gaim_prefs_add_none("/plugins"); - gaim_prefs_add_none("/plugins/gnt"); - - gaim_prefs_add_none("/plugins/gnt/gntgf"); - gaim_prefs_add_none(PREFS_EVENT); - - gaim_prefs_add_bool(PREFS_EVENT_SIGNONF, TRUE); - gaim_prefs_add_bool(PREFS_EVENT_IM_MSG, TRUE); - gaim_prefs_add_bool(PREFS_EVENT_CHAT_MSG, TRUE); - gaim_prefs_add_bool(PREFS_EVENT_CHAT_NICK, TRUE); - - gaim_prefs_add_bool(PREFS_BEEP, TRUE); -#ifdef HAVE_X11 - gaim_prefs_add_bool(PREFS_URGENT, FALSE); -#endif -} - -GAIM_INIT_PLUGIN(PLUGIN_STATIC_NAME, init_plugin, info) diff -r 317e7613e581 -r 0e3a8505ebbe console/plugins/gnthistory.c --- a/console/plugins/gnthistory.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,202 +0,0 @@ -/** - * @file gnthistory.c Show log from previous conversation - * - * Copyright (C) 2006 Sadrul Habib Chowdhury - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* Ripped from gtk/plugins/history.c */ - -#include "internal.h" - -#include "conversation.h" -#include "debug.h" -#include "log.h" -#include "notify.h" -#include "prefs.h" -#include "signals.h" -#include "util.h" -#include "version.h" - -#include "gntplugin.h" - -#define HISTORY_PLUGIN_ID "gnt-history" - -#define HISTORY_SIZE (4 * 1024) - -static void historize(GaimConversation *c) -{ - GaimAccount *account = gaim_conversation_get_account(c); - const char *name = gaim_conversation_get_name(c); - GaimConversationType convtype; - GList *logs = NULL; - const char *alias = name; - GaimLogReadFlags flags; - char *history; - char *header; - GaimMessageFlags mflag; - - convtype = gaim_conversation_get_type(c); - if (convtype == GAIM_CONV_TYPE_IM) - { - GSList *buddies; - GSList *cur; - - /* If we're not logging, don't show anything. - * Otherwise, we might show a very old log. */ - if (!gaim_prefs_get_bool("/core/logging/log_ims")) - return; - - /* Find buddies for this conversation. */ - buddies = gaim_find_buddies(account, name); - - /* If we found at least one buddy, save the first buddy's alias. */ - if (buddies != NULL) - alias = gaim_buddy_get_contact_alias((GaimBuddy *)buddies->data); - - for (cur = buddies; cur != NULL; cur = cur->next) - { - GaimBlistNode *node = cur->data; - if ((node != NULL) && ((node->prev != NULL) || (node->next != NULL))) - { - GaimBlistNode *node2; - - alias = gaim_buddy_get_contact_alias((GaimBuddy *)node); - - /* We've found a buddy that matches this conversation. It's part of a - * GaimContact with more than one GaimBuddy. Loop through the GaimBuddies - * in the contact and get all the logs. */ - for (node2 = node->parent->child ; node2 != NULL ; node2 = node2->next) - { - logs = g_list_concat( - gaim_log_get_logs(GAIM_LOG_IM, - gaim_buddy_get_name((GaimBuddy *)node2), - gaim_buddy_get_account((GaimBuddy *)node2)), - logs); - } - break; - } - } - g_slist_free(buddies); - - if (logs == NULL) - logs = gaim_log_get_logs(GAIM_LOG_IM, name, account); - else - logs = g_list_sort(logs, gaim_log_compare); - } - else if (convtype == GAIM_CONV_TYPE_CHAT) - { - /* If we're not logging, don't show anything. - * Otherwise, we might show a very old log. */ - if (!gaim_prefs_get_bool("/core/logging/log_chats")) - return; - - logs = gaim_log_get_logs(GAIM_LOG_CHAT, name, account); - } - - if (logs == NULL) - return; - - mflag = GAIM_MESSAGE_NO_LOG | GAIM_MESSAGE_SYSTEM | GAIM_MESSAGE_DELAYED; - history = gaim_log_read((GaimLog*)logs->data, &flags); - - header = g_strdup_printf(_("Conversation with %s on %s:
"), alias, - gaim_date_format_full(localtime(&((GaimLog *)logs->data)->time))); - gaim_conversation_write(c, "", header, mflag, time(NULL)); - g_free(header); - - if (flags & GAIM_LOG_READ_NO_NEWLINE) - gaim_str_strip_char(history, '\n'); - gaim_conversation_write(c, "", history, mflag, time(NULL)); - g_free(history); - - gaim_conversation_write(c, "", "
", mflag, time(NULL)); - - g_list_foreach(logs, (GFunc)gaim_log_free, NULL); - g_list_free(logs); -} - -static void -history_prefs_check(GaimPlugin *plugin) -{ - if (!gaim_prefs_get_bool("/core/logging/log_ims") && - !gaim_prefs_get_bool("/core/logging/log_chats")) - { - gaim_notify_warning(plugin, NULL, _("History Plugin Requires Logging"), - _("Logging can be enabled from Tools -> Preferences -> Logging.\n\n" - "Enabling logs for instant messages and/or chats will activate " - "history for the same conversation type(s).")); - } -} - -static void history_prefs_cb(const char *name, GaimPrefType type, - gconstpointer val, gpointer data) -{ - history_prefs_check((GaimPlugin *)data); -} - -static gboolean -plugin_load(GaimPlugin *plugin) -{ - gaim_signal_connect(gaim_conversations_get_handle(), - "conversation-created", - plugin, GAIM_CALLBACK(historize), NULL); - - gaim_prefs_connect_callback(plugin, "/core/logging/log_ims", - history_prefs_cb, plugin); - gaim_prefs_connect_callback(plugin, "/core/logging/log_chats", - history_prefs_cb, plugin); - - history_prefs_check(plugin); - - return TRUE; -} - -static GaimPluginInfo info = -{ - GAIM_PLUGIN_MAGIC, - GAIM_MAJOR_VERSION, - GAIM_MINOR_VERSION, - GAIM_PLUGIN_STANDARD, - NULL, - 0, - NULL, - GAIM_PRIORITY_DEFAULT, - HISTORY_PLUGIN_ID, - N_("GntHistory"), - VERSION, - N_("Shows recently logged conversations in new conversations."), - N_("When a new conversation is opened this plugin will insert " - "the last conversation into the current conversation."), - "Sean Egan \n" - "Sadrul H Chowdhury ", - GAIM_WEBSITE, - plugin_load, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL -}; - -static void -init_plugin(GaimPlugin *plugin) -{ -} - -GAIM_INIT_PLUGIN(gnthistory, init_plugin, info) - diff -r 317e7613e581 -r 0e3a8505ebbe console/plugins/lastlog.c --- a/console/plugins/lastlog.c Sun Mar 18 18:17:14 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,142 +0,0 @@ -/** - * @file lastlog.c Lastlog plugin for gaim-text. - * - * Copyright (C) 2006 Sadrul Habib Chowdhury - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#define PLUGIN_STATIC_NAME "GntLastlog" - -#include "internal.h" - -#include -#include - -#include - -#include -#include -#include - -#include -#include - -static GaimCmdId cmd; - -static gboolean -window_kpress_cb(GntWidget *wid, const char *key, GntTextView *view) -{ - if (key[0] == 27) - { - if (strcmp(key, GNT_KEY_DOWN) == 0) - gnt_text_view_scroll(view, 1); - else if (strcmp(key, GNT_KEY_UP) == 0) - gnt_text_view_scroll(view, -1); - else if (strcmp(key, GNT_KEY_PGDOWN) == 0) - gnt_text_view_scroll(view, wid->priv.height - 2); - else if (strcmp(key, GNT_KEY_PGUP) == 0) - gnt_text_view_scroll(view, -(wid->priv.height - 2)); - else - return FALSE; - return TRUE; - } - return FALSE; -} - -static GaimCmdRet -lastlog_cb(GaimConversation *conv, const char *cmd, char **args, char **error, gpointer null) -{ - GGConv *ggconv = conv->ui_data; - char **strings = g_strsplit(GNT_TEXT_VIEW(ggconv->tv)->string->str, "\n", 0); - GntWidget *win, *tv; - int i, j; - - win = gnt_window_new(); - gnt_box_set_title(GNT_BOX(win), _("Lastlog")); - - tv = gnt_text_view_new(); - gnt_box_add_widget(GNT_BOX(win), tv); - - gnt_widget_show(win); - - for (i = 0; strings[i]; i++) { - if (strstr(strings[i], args[0]) != NULL) { - char **finds = g_strsplit(strings[i], args[0], 0); - for (j = 0; finds[j]; j++) { - if (j) - gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(tv), args[0], GNT_TEXT_FLAG_BOLD); - gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(tv), finds[j], GNT_TEXT_FLAG_NORMAL); - } - g_strfreev(finds); - gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(tv), "\n", GNT_TEXT_FLAG_NORMAL); - } - } - - g_signal_connect(G_OBJECT(win), "key_pressed", G_CALLBACK(window_kpress_cb), tv); - g_strfreev(strings); - return GAIM_CMD_STATUS_OK; -} - -static gboolean -plugin_load(GaimPlugin *plugin) -{ - cmd = gaim_cmd_register("lastlog", "s", GAIM_CMD_P_DEFAULT, - GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_IM, NULL, - lastlog_cb, _("lastlog: Searches for a substring in the backlog."), NULL); - return TRUE; -} - -static gboolean -plugin_unload(GaimPlugin *plugin) -{ - gaim_cmd_unregister(cmd); - return TRUE; -} - -static GaimPluginInfo info = -{ - GAIM_PLUGIN_MAGIC, - GAIM_MAJOR_VERSION, - GAIM_MINOR_VERSION, - GAIM_PLUGIN_STANDARD, - GAIM_GNT_PLUGIN_TYPE, - 0, - NULL, - GAIM_PRIORITY_DEFAULT, - "gntlastlog", - N_("GntLastlog"), - VERSION, - N_("Lastlog plugin."), - N_("Lastlog plugin."), - "Sadrul H Chowdhury ", - "http://gaim.sourceforge.net", - plugin_load, - plugin_unload, - NULL, - NULL, - NULL, - NULL, - NULL -}; - -static void -init_plugin(GaimPlugin *plugin) -{ -} - -GAIM_INIT_PLUGIN(PLUGIN_STATIC_NAME, init_plugin, info) - diff -r 317e7613e581 -r 0e3a8505ebbe finch/Makefile.am --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/Makefile.am Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,77 @@ +if ENABLE_GNT + +EXTRA_DIST = \ + getopt.c \ + getopt.h \ + getopt1.c + +SUBDIRS = libgnt plugins + +bin_PROGRAMS = finch + +finch_SOURCES = \ + gntaccount.c \ + gntblist.c \ + gntconn.c \ + gntconv.c \ + gntdebug.c \ + gntft.c \ + gntgaim.c \ + gntidle.c \ + gntnotify.c \ + gntplugin.c \ + gntpounce.c \ + gntprefs.c \ + gntrequest.c \ + gntstatus.c \ + gntui.c + +finch_headers = \ + gntaccount.h \ + gntblist.h \ + gntconn.h \ + gntconv.h \ + gntdebug.h \ + gntft.h \ + gntgaim.h \ + gntidle.h \ + gntnotify.h \ + gntplugin.h \ + gntpounce.h \ + gntprefs.h \ + gntrequest.h \ + gntstatus.h \ + gntui.h + +finchincludedir=$(includedir)/gaim/gnt +finchinclude_HEADERS = \ + $(finch_headers) + +finch_DEPENDENCIES = @LIBOBJS@ +finch_LDFLAGS = -export-dynamic +finch_LDADD = \ + @LIBOBJS@ \ + $(DBUS_LIBS) \ + $(INTLLIBS) \ + $(GLIB_LIBS) \ + $(LIBXML_LIBS) \ + $(GNT_LIBS) \ + ./libgnt/libgnt.la \ + $(top_builddir)/libpurple/libpurple.la + +AM_CPPFLAGS = \ + -DSTANDALONE \ + -DBR_PTHREADS=0 \ + -DDATADIR=\"$(datadir)\" \ + -DLIBDIR=\"$(libdir)/gaim/\" \ + -DLOCALEDIR=\"$(datadir)/locale\" \ + -DSYSCONFDIR=\"$(sysconfdir)\" \ + -I$(top_srcdir)/libpurple/ \ + -I$(top_srcdir) \ + -I$(srcdir)/libgnt/ \ + $(DEBUG_CFLAGS) \ + $(GLIB_CFLAGS) \ + $(DBUS_CFLAGS) \ + $(LIBXML_CFLAGS) \ + $(GNT_CFLAGS) +endif diff -r 317e7613e581 -r 0e3a8505ebbe finch/getopt.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/getopt.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,737 @@ +/* Getopt for GNU. + NOTE: getopt is now part of the C library, so if you don't know what + "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu + before changing it! + + Gaim is the legal property of its developers, whose names are too numerous + to list here. Please refer to the COPYRIGHT file distributed with this + source distribution. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* NOTE!!! AIX requires this to be the first thing in the file. + Do not put ANYTHING before it! */ +#if !defined (__GNUC__) && defined (_AIX) + #pragma alloca +#endif + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* Alver says we need this for IRIX. */ +#if HAVE_STRING_H +#include "string.h" +#endif + +#ifdef __GNUC__ +#define alloca __builtin_alloca +#else /* not __GNUC__ */ +#if defined (HAVE_ALLOCA_H) || (defined(sparc) && (defined(sun) || (!defined(USG) && !defined(SVR4) && !defined(__svr4__)))) +#include +#else +#ifndef _AIX +char *alloca (); +#endif +#endif /* alloca.h */ +#endif /* not __GNUC__ */ + +#if !__STDC__ && !defined(const) && IN_GCC +#define const +#endif + +/* This tells Alpha OSF/1 not to define a getopt prototype in . */ +#ifndef _NO_PROTO +#define _NO_PROTO +#endif + +#include + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#if defined (_LIBC) || !defined (__GNU_LIBRARY__) + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +#undef alloca +/* Don't include stdlib.h for non-GNU C libraries because some of them + contain conflicting prototypes for getopt. */ +#include +#else /* Not GNU C library. */ +#define __alloca alloca +#endif /* GNU C library. */ + +/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a + long-named option. Because this is not POSIX.2 compliant, it is + being phased out. */ +/* #define GETOPT_COMPAT */ + +/* This version of `getopt' appears to the caller like standard Unix `getopt' + but it behaves differently for the user, since it allows the user + to intersperse the options with the other arguments. + + As `getopt' works, it permutes the elements of ARGV so that, + when it is done, all the options precede everything else. Thus + all application programs are extended to handle flexible argument order. + + Setting the environment variable POSIXLY_CORRECT disables permutation. + Then the behavior is completely standard. + + GNU application programs can use a third alternative mode in which + they can distinguish the relative order of options and other arguments. */ + +#include "getopt.h" + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +char *optarg = 0; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns EOF, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +/* XXX 1003.2 says this must be 1 before any call. */ +int optind = 0; + +/* The next char to be scanned in the option-element + in which the last option character we returned was found. + This allows us to pick up the scan where we left off. + + If this is zero, or a null string, it means resume the scan + by advancing to the next ARGV-element. */ + +static char *nextchar; + +/* Callers store zero here to inhibit the error message + for unrecognized options. */ + +int opterr = 1; + +/* Set to an option character which was unrecognized. + This must be initialized on some systems to avoid linking in the + system's own getopt implementation. */ + +int optopt = '?'; + +/* Describe how to deal with options that follow non-option ARGV-elements. + + If the caller did not specify anything, + the default is REQUIRE_ORDER if the environment variable + POSIXLY_CORRECT is defined, PERMUTE otherwise. + + REQUIRE_ORDER means don't recognize them as options; + stop option processing when the first non-option is seen. + This is what Unix does. + This mode of operation is selected by either setting the environment + variable POSIXLY_CORRECT, or using `+' as the first character + of the list of option characters. + + PERMUTE is the default. We permute the contents of ARGV as we scan, + so that eventually all the non-options are at the end. This allows options + to be given in any order, even with programs that were not written to + expect this. + + RETURN_IN_ORDER is an option available to programs that were written + to expect options and other ARGV-elements in any order and that care about + the ordering of the two. We describe each non-option ARGV-element + as if it were the argument of an option with character code 1. + Using `-' as the first character of the list of option characters + selects this mode of operation. + + The special argument `--' forces an end of option-scanning regardless + of the value of `ordering'. In the case of RETURN_IN_ORDER, only + `--' can cause `getopt' to return EOF with `optind' != ARGC. */ + +static enum +{ + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER +} ordering; + +#ifdef __GNU_LIBRARY__ +/* We want to avoid inclusion of string.h with non-GNU libraries + because there are many ways it can cause trouble. + On some systems, it contains special magic macros that don't work + in GCC. */ +#include +#define my_index strchr +#define my_bcopy(src, dst, n) memcpy ((dst), (src), (n)) +#else + +/* Avoid depending on library functions or files + whose names are inconsistent. */ + +char *getenv (); + +static char * +my_index (str, chr) + const char *str; + int chr; +{ + while (*str) + { + if (*str == chr) + return (char *) str; + str++; + } + return 0; +} + +static void +my_bcopy (from, to, size) + const char *from; + char *to; + int size; +{ + int i; + for (i = 0; i < size; i++) + to[i] = from[i]; +} +#endif /* GNU C library. */ + +/* Handle permutation of arguments. */ + +/* Describe the part of ARGV that contains non-options that have + been skipped. `first_nonopt' is the index in ARGV of the first of them; + `last_nonopt' is the index after the last of them. */ + +static int first_nonopt; +static int last_nonopt; + +/* Exchange two adjacent subsequences of ARGV. + One subsequence is elements [first_nonopt,last_nonopt) + which contains all the non-options that have been skipped so far. + The other is elements [last_nonopt,optind), which contains all + the options processed since those non-options were skipped. + + `first_nonopt' and `last_nonopt' are relocated so that they describe + the new indices of the non-options in ARGV after they are moved. */ + +static void +exchange (argv) + char **argv; +{ + int nonopts_size = (last_nonopt - first_nonopt) * sizeof (char *); + char **temp = (char **) __alloca (nonopts_size); + + /* Interchange the two blocks of data in ARGV. */ + + my_bcopy ((char *) &argv[first_nonopt], (char *) temp, nonopts_size); + my_bcopy ((char *) &argv[last_nonopt], (char *) &argv[first_nonopt], + (optind - last_nonopt) * sizeof (char *)); + my_bcopy ((char *) temp, + (char *) &argv[first_nonopt + optind - last_nonopt], + nonopts_size); + + /* Update records for the slots the non-options now occupy. */ + + first_nonopt += (optind - last_nonopt); + last_nonopt = optind; +} + +/* Scan elements of ARGV (whose length is ARGC) for option characters + given in OPTSTRING. + + If an element of ARGV starts with '-', and is not exactly "-" or "--", + then it is an option element. The characters of this element + (aside from the initial '-') are option characters. If `getopt' + is called repeatedly, it returns successively each of the option characters + from each of the option elements. + + If `getopt' finds another option character, it returns that character, + updating `optind' and `nextchar' so that the next call to `getopt' can + resume the scan with the following option character or ARGV-element. + + If there are no more option characters, `getopt' returns `EOF'. + Then `optind' is the index in ARGV of the first ARGV-element + that is not an option. (The ARGV-elements have been permuted + so that those that are not options now come last.) + + OPTSTRING is a string containing the legitimate option characters. + If an option character is seen that is not listed in OPTSTRING, + return '?' after printing an error message. If you set `opterr' to + zero, the error message is suppressed but we still return '?'. + + If a char in OPTSTRING is followed by a colon, that means it wants an arg, + so the following text in the same ARGV-element, or the text of the following + ARGV-element, is returned in `optarg'. Two colons mean an option that + wants an optional arg; if there is text in the current ARGV-element, + it is returned in `optarg', otherwise `optarg' is set to zero. + + If OPTSTRING starts with `-' or `+', it requests different methods of + handling the non-option ARGV-elements. + See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + + Long-named options begin with `--' instead of `-'. + Their names may be abbreviated as long as the abbreviation is unique + or is an exact match for some defined option. If they have an + argument, it follows the option name in the same ARGV-element, separated + from the option name by a `=', or else the in next ARGV-element. + When `getopt' finds a long-named option, it returns 0 if that option's + `flag' field is nonzero, the value of the option's `val' field + if the `flag' field is zero. + + The elements of ARGV aren't really const, because we permute them. + But we pretend they're const in the prototype to be compatible + with other systems. + + LONGOPTS is a vector of `struct option' terminated by an + element containing a name which is zero. + + LONGIND returns the index in LONGOPT of the long-named option found. + It is only valid when a long-named option has been found by the most + recent call. + + If LONG_ONLY is nonzero, '-' as well as '--' can introduce + long-named options. */ + +int +_getopt_internal (argc, argv, optstring, longopts, longind, long_only) + int argc; + char *const *argv; + const char *optstring; + const struct option *longopts; + int *longind; + int long_only; +{ + int option_index; + + optarg = 0; + + /* Initialize the internal data when the first call is made. + Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + if (optind == 0) + { + first_nonopt = last_nonopt = optind = 1; + + nextchar = NULL; + + /* Determine how to handle the ordering of options and nonoptions. */ + + if (optstring[0] == '-') + { + ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == '+') + { + ordering = REQUIRE_ORDER; + ++optstring; + } + else if (getenv ("POSIXLY_CORRECT") != NULL) + ordering = REQUIRE_ORDER; + else + ordering = PERMUTE; + } + + if (nextchar == NULL || *nextchar == '\0') + { + if (ordering == PERMUTE) + { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (last_nonopt != optind) + first_nonopt = optind; + + /* Now skip any additional non-options + and extend the range of non-options previously skipped. */ + + while (optind < argc + && (argv[optind][0] != '-' || argv[optind][1] == '\0') +#ifdef GETOPT_COMPAT + && (longopts == NULL + || argv[optind][0] != '+' || argv[optind][1] == '\0') +#endif /* GETOPT_COMPAT */ + ) + optind++; + last_nonopt = optind; + } + + /* Special ARGV-element `--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ + + if (optind != argc && !strcmp (argv[optind], "--")) + { + optind++; + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (first_nonopt == last_nonopt) + first_nonopt = optind; + last_nonopt = argc; + + optind = argc; + } + + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ + + if (optind == argc) + { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (first_nonopt != last_nonopt) + optind = first_nonopt; + return EOF; + } + + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass it by. */ + + if ((argv[optind][0] != '-' || argv[optind][1] == '\0') +#ifdef GETOPT_COMPAT + && (longopts == NULL + || argv[optind][0] != '+' || argv[optind][1] == '\0') +#endif /* GETOPT_COMPAT */ + ) + { + if (ordering == REQUIRE_ORDER) + return EOF; + optarg = argv[optind++]; + return 1; + } + + /* We have found another option-ARGV-element. + Start decoding its characters. */ + + nextchar = (argv[optind] + 1 + + (longopts != NULL && argv[optind][1] == '-')); + } + + if (longopts != NULL + && ((argv[optind][0] == '-' + && (argv[optind][1] == '-' || long_only)) +#ifdef GETOPT_COMPAT + || argv[optind][0] == '+' +#endif /* GETOPT_COMPAT */ + )) + { + const struct option *p; + char *s = nextchar; + int exact = 0; + int ambig = 0; + const struct option *pfound = NULL; + int indfound; + + while (*s && *s != '=') + s++; + + /* Test all options for either exact match or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; + p++, option_index++) + if (!strncmp (p->name, nextchar, s - nextchar)) + { + if (s - nextchar == strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second nonexact match found. */ + ambig = 1; + } + + if (ambig && !exact) + { + if (opterr) + fprintf (stderr, "%s: option `%s' is ambiguous\n", + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + return '?'; + } + + if (pfound != NULL) + { + option_index = indfound; + optind++; + if (*s) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = s + 1; + else + { + if (opterr) + { + if (argv[optind - 1][1] == '-') + /* --option */ + fprintf (stderr, + "%s: option `--%s' doesn't allow an argument\n", + argv[0], pfound->name); + else + /* +option or -option */ + fprintf (stderr, + "%s: option `%c%s' doesn't allow an argument\n", + argv[0], argv[optind - 1][0], pfound->name); + } + nextchar += strlen (nextchar); + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (opterr) + fprintf (stderr, "%s: option `%s' requires an argument\n", + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + /* Can't find it as a long option. If this is not getopt_long_only, + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ + if (!long_only || argv[optind][1] == '-' +#ifdef GETOPT_COMPAT + || argv[optind][0] == '+' +#endif /* GETOPT_COMPAT */ + || my_index (optstring, *nextchar) == NULL) + { + if (opterr) + { + if (argv[optind][1] == '-') + /* --option */ + fprintf (stderr, "%s: unrecognized option `--%s'\n", + argv[0], nextchar); + else + /* +option or -option */ + fprintf (stderr, "%s: unrecognized option `%c%s'\n", + argv[0], argv[optind][0], nextchar); + } + nextchar = (char *) ""; + optind++; + return '?'; + } + } + + /* Look at and handle the next option-character. */ + + { + char c = *nextchar++; + char *temp = my_index (optstring, c); + + /* Increment `optind' when we start to process its last character. */ + if (*nextchar == '\0') + ++optind; + + if (temp == NULL || c == ':') + { + if (opterr) + { +#if 0 + if (c < 040 || c >= 0177) + fprintf (stderr, "%s: unrecognized option, character code 0%o\n", + argv[0], c); + else + fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c); +#else + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c); +#endif + } + optopt = c; + return '?'; + } + if (temp[1] == ':') + { + if (temp[2] == ':') + { + /* This is an option that accepts an argument optionally. */ + if (*nextchar != '\0') + { + optarg = nextchar; + optind++; + } + else + optarg = 0; + nextchar = NULL; + } + else + { + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (opterr) + { +#if 0 + fprintf (stderr, "%s: option `-%c' requires an argument\n", + argv[0], c); +#else + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, "%s: option requires an argument -- %c\n", + argv[0], c); +#endif + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + nextchar = NULL; + } + } + return c; + } +} + +int +getopt (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + return _getopt_internal (argc, argv, optstring, + (const struct option *) 0, + (int *) 0, + 0); +} + +#endif /* _LIBC or not __GNU_LIBRARY__. */ + +#ifdef TEST + +/* Compile with -DTEST to make an executable for use in testing + the above definition of `getopt'. */ + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + + c = getopt (argc, argv, "abc:d:0123456789"); + if (c == EOF) + break; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff -r 317e7613e581 -r 0e3a8505ebbe finch/getopt.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/getopt.h Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,136 @@ +/* Declarations for getopt. + + NOTE: getopt is now part of the C library, so if you don't know what + "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu + before changing it! + + Gaim is the legal property of its developers, whose names are too numerous + to list here. Please refer to the COPYRIGHT file distributed with this + source distribution. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef _GETOPT_H +#define _GETOPT_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +extern char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns EOF, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +extern int optind; + +/* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ + +extern int opterr; + +/* Set to an option character which was unrecognized. */ + +extern int optopt; + +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +struct option +{ +#if __STDC__ + const char *name; +#else + char *name; +#endif + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* Names for the values of the `has_arg' field of `struct option'. */ + +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +#if __STDC__ +#if defined(__GNU_LIBRARY__) +/* Many other libraries have conflicting prototypes for getopt, with + differences in the consts, in stdlib.h. To avoid compilation + errors, only prototype getopt for the GNU C library. */ +extern int getopt (int argc, char *const *argv, const char *shortopts); +#else /* not __GNU_LIBRARY__ */ +extern int getopt (); +#endif /* not __GNU_LIBRARY__ */ +extern int getopt_long (int argc, char *const *argv, const char *shortopts, + const struct option *longopts, int *longind); +extern int getopt_long_only (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind); + +/* Internal only. Users should not call this directly. */ +extern int _getopt_internal (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind, + int long_only); +#else /* not __STDC__ */ +extern int getopt (); +extern int getopt_long (); +extern int getopt_long_only (); + +extern int _getopt_internal (); +#endif /* not __STDC__ */ + +#ifdef __cplusplus +} +#endif + +#endif /* _GETOPT_H */ diff -r 317e7613e581 -r 0e3a8505ebbe finch/getopt1.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/getopt1.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,177 @@ +/* getopt_long and getopt_long_only entry points for GNU getopt. + Gaim is the legal property of its developers, whose names are too numerous + to list here. Please refer to the COPYRIGHT file distributed with this + source distribution. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "getopt.h" + +#if !__STDC__ && !defined(const) && IN_GCC +#define const +#endif + +#include + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#if defined (_LIBC) || !defined (__GNU_LIBRARY__) + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +#include +#else +char *getenv (); +#endif + +#ifndef NULL +#define NULL 0 +#endif + +int +getopt_long (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 0); +} + +/* Like getopt_long, but '-' as well as '--' can indicate a long option. + If an option that starts with '-' (not '--') doesn't match a long option, + but does match a short option, it is parsed as a short option + instead. */ + +int +getopt_long_only (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 1); +} + + +#endif /* _LIBC or not __GNU_LIBRARY__. */ + +#ifdef TEST + +#include + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + int option_index = 0; + static struct option long_options[] = + { + {"add", 1, 0, 0}, + {"append", 0, 0, 0}, + {"delete", 1, 0, 0}, + {"verbose", 0, 0, 0}, + {"create", 0, 0, 0}, + {"file", 1, 0, 0}, + {0, 0, 0, 0} + }; + + c = getopt_long (argc, argv, "abc:d:0123456789", + long_options, &option_index); + if (c == EOF) + break; + + switch (c) + { + case 0: + printf ("option %s", long_options[option_index].name); + if (optarg) + printf (" with arg %s", optarg); + printf ("\n"); + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case 'd': + printf ("option d with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff -r 317e7613e581 -r 0e3a8505ebbe finch/gntaccount.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/gntaccount.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,936 @@ +/** + * @file gntaccount.c GNT Account API + * @ingroup gntui + * + * gaim + * + * Gaim is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "gntaccount.h" +#include "gntgaim.h" + +#include + +typedef struct +{ + GntWidget *window; + GntWidget *tree; +} FinchAccountList; + +static FinchAccountList accounts; + +typedef struct +{ + GaimAccount *account; /* NULL for a new account */ + + GntWidget *window; + + GntWidget *protocol; + GntWidget *screenname; + GntWidget *password; + GntWidget *alias; + + GntWidget *splits; + GList *split_entries; + + GList *prpl_entries; + GntWidget *prpls; + + GntWidget *newmail; + GntWidget *remember; +} AccountEditDialog; + +/* This is necessary to close an edit-dialog when an account is deleted */ +static GList *accountdialogs; + +static void +account_add(GaimAccount *account) +{ + gnt_tree_add_choice(GNT_TREE(accounts.tree), account, + gnt_tree_create_row(GNT_TREE(accounts.tree), + gaim_account_get_username(account), + gaim_account_get_protocol_name(account)), + NULL, NULL); + gnt_tree_set_choice(GNT_TREE(accounts.tree), account, + gaim_account_get_enabled(account, GAIM_GNT_UI)); +} + +static void +edit_dialog_destroy(AccountEditDialog *dialog) +{ + accountdialogs = g_list_remove(accountdialogs, dialog); + g_list_free(dialog->prpl_entries); + g_list_free(dialog->split_entries); + g_free(dialog); +} + +static void +save_account_cb(AccountEditDialog *dialog) +{ + GaimAccount *account; + GaimPlugin *plugin; + GaimPluginProtocolInfo *prplinfo; + const char *value; + GString *username; + + /* XXX: Do some error checking first. */ + + plugin = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(dialog->protocol)); + prplinfo = GAIM_PLUGIN_PROTOCOL_INFO(plugin); + + /* Screenname && user-splits */ + value = gnt_entry_get_text(GNT_ENTRY(dialog->screenname)); + + if (value == NULL || *value == '\0') + { + gaim_notify_error(NULL, _("Error"), _("Account was not added"), + _("Screenname of an account must be non-empty.")); + return; + } + + username = g_string_new(value); + + if (prplinfo != NULL) + { + GList *iter, *entries; + for (iter = prplinfo->user_splits, entries = dialog->split_entries; + iter && entries; iter = iter->next, entries = entries->next) + { + GaimAccountUserSplit *split = iter->data; + GntWidget *entry = entries->data; + + value = gnt_entry_get_text(GNT_ENTRY(entry)); + if (value == NULL || *value == '\0') + value = gaim_account_user_split_get_default_value(split); + g_string_append_printf(username, "%c%s", + gaim_account_user_split_get_separator(split), + value); + } + } + + if (dialog->account == NULL) + { + account = gaim_account_new(username->str, gaim_plugin_get_id(plugin)); + gaim_accounts_add(account); + } + else + { + account = dialog->account; + + /* Protocol */ + gaim_account_set_protocol_id(account, gaim_plugin_get_id(plugin)); + gaim_account_set_username(account, username->str); + } + g_string_free(username, TRUE); + + /* Alias */ + value = gnt_entry_get_text(GNT_ENTRY(dialog->alias)); + if (value && *value) + gaim_account_set_alias(account, value); + + /* Remember password and password */ + gaim_account_set_remember_password(account, + gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->remember))); + value = gnt_entry_get_text(GNT_ENTRY(dialog->password)); + if (value && *value && gaim_account_get_remember_password(account)) + gaim_account_set_password(account, value); + else + gaim_account_set_password(account, NULL); + + /* Mail notification */ + gaim_account_set_check_mail(account, + gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->newmail))); + + /* Protocol options */ + if (prplinfo) + { + GList *iter, *entries; + + for (iter = prplinfo->protocol_options, entries = dialog->prpl_entries; + iter && entries; iter = iter->next, entries = entries->next) + { + GaimAccountOption *option = iter->data; + GntWidget *entry = entries->data; + GaimPrefType type = gaim_account_option_get_type(option); + const char *setting = gaim_account_option_get_setting(option); + + if (type == GAIM_PREF_STRING) + { + const char *value = gnt_entry_get_text(GNT_ENTRY(entry)); + gaim_account_set_string(account, setting, value); + } + else if (type == GAIM_PREF_INT) + { + const char *str = gnt_entry_get_text(GNT_ENTRY(entry)); + int value = 0; + if (str) + value = atoi(str); + gaim_account_set_int(account, setting, value); + } + else if (type == GAIM_PREF_BOOLEAN) + { + gboolean value = gnt_check_box_get_checked(GNT_CHECK_BOX(entry)); + gaim_account_set_bool(account, setting, value); + } + else if (type == GAIM_PREF_STRING_LIST) + { + /* TODO: */ + } + else + { + g_assert_not_reached(); + } + } + } + + /* XXX: Proxy options */ + + gnt_widget_destroy(dialog->window); +} + +static void +update_user_splits(AccountEditDialog *dialog) +{ + GntWidget *hbox; + GaimPlugin *plugin; + GaimPluginProtocolInfo *prplinfo; + GList *iter, *entries; + char *username = NULL; + + if (dialog->splits) + { + gnt_box_remove_all(GNT_BOX(dialog->splits)); + g_list_free(dialog->split_entries); + } + else + { + dialog->splits = gnt_vbox_new(FALSE); + gnt_box_set_pad(GNT_BOX(dialog->splits), 0); + gnt_box_set_fill(GNT_BOX(dialog->splits), TRUE); + } + + dialog->split_entries = NULL; + + plugin = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(dialog->protocol)); + if (!plugin) + return; + prplinfo = GAIM_PLUGIN_PROTOCOL_INFO(plugin); + + username = dialog->account ? g_strdup(gaim_account_get_username(dialog->account)) : NULL; + + for (iter = prplinfo->user_splits; iter; iter = iter->next) + { + GaimAccountUserSplit *split = iter->data; + GntWidget *entry; + char *buf; + + hbox = gnt_hbox_new(TRUE); + gnt_box_add_widget(GNT_BOX(dialog->splits), hbox); + + buf = g_strdup_printf("%s:", gaim_account_user_split_get_text(split)); + gnt_box_add_widget(GNT_BOX(hbox), gnt_label_new(buf)); + + entry = gnt_entry_new(NULL); + gnt_box_add_widget(GNT_BOX(hbox), entry); + + dialog->split_entries = g_list_append(dialog->split_entries, entry); + g_free(buf); + } + + for (iter = g_list_last(prplinfo->user_splits), entries = g_list_last(dialog->split_entries); + iter && entries; iter = iter->prev, entries = entries->prev) + { + GntWidget *entry = entries->data; + GaimAccountUserSplit *split = iter->data; + const char *value = NULL; + char *s; + + if (dialog->account) + { + s = strrchr(username, gaim_account_user_split_get_separator(split)); + if (s != NULL) + { + *s = '\0'; + s++; + value = s; + } + } + if (value == NULL) + value = gaim_account_user_split_get_default_value(split); + + if (value != NULL) + gnt_entry_set_text(GNT_ENTRY(entry), value); + } + + if (username != NULL) + gnt_entry_set_text(GNT_ENTRY(dialog->screenname), username); + + g_free(username); +} + +static void +add_protocol_options(AccountEditDialog *dialog) +{ + GaimPlugin *plugin; + GaimPluginProtocolInfo *prplinfo; + GList *iter; + GntWidget *vbox, *box; + GaimAccount *account; + + if (dialog->prpls) + gnt_box_remove_all(GNT_BOX(dialog->prpls)); + else + { + dialog->prpls = vbox = gnt_vbox_new(FALSE); + gnt_box_set_pad(GNT_BOX(vbox), 0); + gnt_box_set_alignment(GNT_BOX(vbox), GNT_ALIGN_LEFT); + gnt_box_set_fill(GNT_BOX(vbox), TRUE); + } + + if (dialog->prpl_entries) + { + g_list_free(dialog->prpl_entries); + dialog->prpl_entries = NULL; + } + + vbox = dialog->prpls; + + plugin = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(dialog->protocol)); + if (!plugin) + return; + + prplinfo = GAIM_PLUGIN_PROTOCOL_INFO(plugin); + + account = dialog->account; + + for (iter = prplinfo->protocol_options; iter; iter = iter->next) + { + GaimAccountOption *option = iter->data; + GaimPrefType type = gaim_account_option_get_type(option); + + box = gnt_hbox_new(TRUE); + gnt_box_set_pad(GNT_BOX(box), 0); + gnt_box_add_widget(GNT_BOX(vbox), box); + + if (type == GAIM_PREF_BOOLEAN) + { + GntWidget *widget = gnt_check_box_new(gaim_account_option_get_text(option)); + gnt_box_add_widget(GNT_BOX(box), widget); + dialog->prpl_entries = g_list_append(dialog->prpl_entries, widget); + + if (account) + gnt_check_box_set_checked(GNT_CHECK_BOX(widget), + gaim_account_get_bool(account, + gaim_account_option_get_setting(option), + gaim_account_option_get_default_bool(option))); + else + gnt_check_box_set_checked(GNT_CHECK_BOX(widget), + gaim_account_option_get_default_bool(option)); + } + else + { + gnt_box_add_widget(GNT_BOX(box), + gnt_label_new(gaim_account_option_get_text(option))); + + if (type == GAIM_PREF_STRING_LIST) + { + /* TODO: Use a combobox */ + /* Don't forget to append the widget to prpl_entries */ + } + else + { + GntWidget *entry = gnt_entry_new(NULL); + gnt_box_add_widget(GNT_BOX(box), entry); + dialog->prpl_entries = g_list_append(dialog->prpl_entries, entry); + + if (type == GAIM_PREF_STRING) + { + const char *dv = gaim_account_option_get_default_string(option); + + if (account) + gnt_entry_set_text(GNT_ENTRY(entry), + gaim_account_get_string(account, + gaim_account_option_get_setting(option), dv)); + else + gnt_entry_set_text(GNT_ENTRY(entry), dv); + } + else if (type == GAIM_PREF_INT) + { + char str[32]; + int value = gaim_account_option_get_default_int(option); + if (account) + value = gaim_account_get_int(account, + gaim_account_option_get_setting(option), value); + snprintf(str, sizeof(str), "%d", value); + gnt_entry_set_flag(GNT_ENTRY(entry), GNT_ENTRY_FLAG_INT); + gnt_entry_set_text(GNT_ENTRY(entry), str); + } + else + { + g_assert_not_reached(); + } + } + } + } +} + +static void +update_user_options(AccountEditDialog *dialog) +{ + GaimPlugin *plugin; + GaimPluginProtocolInfo *prplinfo; + + plugin = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(dialog->protocol)); + if (!plugin) + return; + + prplinfo = GAIM_PLUGIN_PROTOCOL_INFO(plugin); + + if (dialog->newmail == NULL) + dialog->newmail = gnt_check_box_new(_("New mail notifications")); + if (dialog->account) + gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->newmail), + gaim_account_get_check_mail(dialog->account)); + if (!prplinfo || !(prplinfo->options & OPT_PROTO_MAIL_CHECK)) + gnt_widget_set_visible(dialog->newmail, FALSE); + else + gnt_widget_set_visible(dialog->newmail, TRUE); + + if (dialog->remember == NULL) + dialog->remember = gnt_check_box_new(_("Remember password")); + if (dialog->account) + gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->remember), + gaim_account_get_remember_password(dialog->account)); +} + +static void +prpl_changed_cb(GntWidget *combo, GaimPlugin *old, GaimPlugin *new, AccountEditDialog *dialog) +{ + update_user_splits(dialog); + add_protocol_options(dialog); + update_user_options(dialog); /* This may not be necessary here */ + gnt_box_readjust(GNT_BOX(dialog->window)); + gnt_widget_draw(dialog->window); +} + +static void +edit_account(GaimAccount *account) +{ + GntWidget *window, *hbox; + GntWidget *combo, *button, *entry; + GList *list, *iter; + AccountEditDialog *dialog; + + if (account) + { + GList *iter; + for (iter = accountdialogs; iter; iter = iter->next) + { + AccountEditDialog *dlg = iter->data; + if (dlg->account == account) + return; + } + } + + dialog = g_new0(AccountEditDialog, 1); + accountdialogs = g_list_prepend(accountdialogs, dialog); + + dialog->window = window = gnt_vbox_new(FALSE); + dialog->account = account; + gnt_box_set_toplevel(GNT_BOX(window), TRUE); + gnt_box_set_title(GNT_BOX(window), account ? _("Modify Account") : _("New Account")); + gnt_box_set_alignment(GNT_BOX(window), GNT_ALIGN_MID); + gnt_box_set_pad(GNT_BOX(window), 0); + gnt_widget_set_name(window, "edit-account"); + gnt_box_set_fill(GNT_BOX(window), TRUE); + + hbox = gnt_hbox_new(TRUE); + gnt_box_set_pad(GNT_BOX(hbox), 0); + gnt_box_add_widget(GNT_BOX(window), hbox); + + dialog->protocol = combo = gnt_combo_box_new(); + list = gaim_plugins_get_protocols(); + for (iter = list; iter; iter = iter->next) + { + gnt_combo_box_add_data(GNT_COMBO_BOX(combo), iter->data, + ((GaimPlugin*)iter->data)->info->name); + } + + if (account) + gnt_combo_box_set_selected(GNT_COMBO_BOX(combo), + gaim_plugins_find_with_id(gaim_account_get_protocol_id(account))); + else + gnt_combo_box_set_selected(GNT_COMBO_BOX(combo), list->data); + + g_signal_connect(G_OBJECT(combo), "selection-changed", G_CALLBACK(prpl_changed_cb), dialog); + + gnt_box_add_widget(GNT_BOX(hbox), gnt_label_new(_("Protocol:"))); + gnt_box_add_widget(GNT_BOX(hbox), combo); + + hbox = gnt_hbox_new(TRUE); + gnt_box_set_pad(GNT_BOX(hbox), 0); + gnt_box_add_widget(GNT_BOX(window), hbox); + + dialog->screenname = entry = gnt_entry_new(NULL); + gnt_box_add_widget(GNT_BOX(hbox), gnt_label_new(_("Screen name:"))); + gnt_box_add_widget(GNT_BOX(hbox), entry); + + /* User splits */ + update_user_splits(dialog); + gnt_box_add_widget(GNT_BOX(window), dialog->splits); + + hbox = gnt_hbox_new(TRUE); + gnt_box_set_pad(GNT_BOX(hbox), 0); + gnt_box_add_widget(GNT_BOX(window), hbox); + + dialog->password = entry = gnt_entry_new(NULL); + gnt_entry_set_masked(GNT_ENTRY(entry), TRUE); + gnt_box_add_widget(GNT_BOX(hbox), gnt_label_new(_("Password:"))); + gnt_box_add_widget(GNT_BOX(hbox), entry); + if (account) + gnt_entry_set_text(GNT_ENTRY(entry), gaim_account_get_password(account)); + + hbox = gnt_hbox_new(TRUE); + gnt_box_set_pad(GNT_BOX(hbox), 0); + gnt_box_add_widget(GNT_BOX(window), hbox); + + dialog->alias = entry = gnt_entry_new(NULL); + gnt_box_add_widget(GNT_BOX(hbox), gnt_label_new(_("Alias:"))); + gnt_box_add_widget(GNT_BOX(hbox), entry); + if (account) + gnt_entry_set_text(GNT_ENTRY(entry), gaim_account_get_alias(account)); + + /* User options */ + update_user_options(dialog); + gnt_box_add_widget(GNT_BOX(window), dialog->remember); + gnt_box_add_widget(GNT_BOX(window), dialog->newmail); + + gnt_box_add_widget(GNT_BOX(window), gnt_line_new(FALSE)); + + /* The advanced box */ + add_protocol_options(dialog); + gnt_box_add_widget(GNT_BOX(window), dialog->prpls); + + /* TODO: Add proxy options */ + + /* The button box */ + hbox = gnt_hbox_new(FALSE); + gnt_box_add_widget(GNT_BOX(window), hbox); + gnt_box_set_alignment(GNT_BOX(hbox), GNT_ALIGN_MID); + + button = gnt_button_new(_("Cancel")); + gnt_box_add_widget(GNT_BOX(hbox), button); + g_signal_connect_swapped(G_OBJECT(button), "activate", G_CALLBACK(gnt_widget_destroy), window); + + button = gnt_button_new(_("Save")); + gnt_box_add_widget(GNT_BOX(hbox), button); + g_signal_connect_swapped(G_OBJECT(button), "activate", G_CALLBACK(save_account_cb), dialog); + + g_signal_connect_swapped(G_OBJECT(window), "destroy", G_CALLBACK(edit_dialog_destroy), dialog); + + gnt_widget_show(window); + gnt_box_readjust(GNT_BOX(window)); + gnt_widget_draw(window); +} + +static void +add_account_cb(GntWidget *widget, gpointer null) +{ + edit_account(NULL); +} + +static void +modify_account_cb(GntWidget *widget, GntTree *tree) +{ + GaimAccount *account = gnt_tree_get_selection_data(tree); + if (!account) + return; + edit_account(account); +} + +static void +really_delete_account(GaimAccount *account) +{ + GList *iter; + for (iter = accountdialogs; iter; iter = iter->next) + { + AccountEditDialog *dlg = iter->data; + if (dlg->account == account) + { + gnt_widget_destroy(dlg->window); + break; + } + } + gaim_request_close_with_handle(account); /* Close any other opened delete window */ + gaim_accounts_delete(account); +} + +static void +delete_account_cb(GntWidget *widget, GntTree *tree) +{ + GaimAccount *account; + char *prompt; + + account = gnt_tree_get_selection_data(tree); + if (!account) + return; + + prompt = g_strdup_printf(_("Are you sure you want to delete %s?"), + gaim_account_get_username(account)); + + gaim_request_action(account, _("Delete Account"), prompt, NULL, 0, account, 2, + _("Delete"), really_delete_account, _("Cancel"), NULL); + g_free(prompt); +} + +static void +account_toggled(GntWidget *widget, void *key, gpointer null) +{ + GaimAccount *account = key; + + gaim_account_set_enabled(account, GAIM_GNT_UI, gnt_tree_get_choice(GNT_TREE(widget), key)); +} + +static void +reset_accounts_win(GntWidget *widget, gpointer null) +{ + accounts.window = NULL; + accounts.tree = NULL; +} + +void finch_accounts_show_all() +{ + GList *iter; + GntWidget *box, *button; + + if (accounts.window) + return; + + accounts.window = gnt_vbox_new(FALSE); + gnt_box_set_toplevel(GNT_BOX(accounts.window), TRUE); + gnt_box_set_title(GNT_BOX(accounts.window), _("Accounts")); + gnt_box_set_pad(GNT_BOX(accounts.window), 0); + gnt_box_set_alignment(GNT_BOX(accounts.window), GNT_ALIGN_MID); + gnt_widget_set_name(accounts.window, "accounts"); + + gnt_box_add_widget(GNT_BOX(accounts.window), + gnt_label_new(_("You can enable/disable accounts from the following list."))); + + gnt_box_add_widget(GNT_BOX(accounts.window), gnt_line_new(FALSE)); + + accounts.tree = gnt_tree_new_with_columns(2); + GNT_WIDGET_SET_FLAGS(accounts.tree, GNT_WIDGET_NO_BORDER); + + for (iter = gaim_accounts_get_all(); iter; iter = iter->next) + { + GaimAccount *account = iter->data; + account_add(account); + } + + g_signal_connect(G_OBJECT(accounts.tree), "toggled", G_CALLBACK(account_toggled), NULL); + + gnt_tree_set_col_width(GNT_TREE(accounts.tree), 0, 40); + gnt_tree_set_col_width(GNT_TREE(accounts.tree), 1, 10); + gnt_box_add_widget(GNT_BOX(accounts.window), accounts.tree); + + gnt_box_add_widget(GNT_BOX(accounts.window), gnt_line_new(FALSE)); + + box = gnt_hbox_new(FALSE); + + button = gnt_button_new(_("Add")); + gnt_box_add_widget(GNT_BOX(box), button); + g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(add_account_cb), NULL); + + button = gnt_button_new(_("Modify")); + gnt_box_add_widget(GNT_BOX(box), button); + g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(modify_account_cb), accounts.tree); + + button = gnt_button_new(_("Delete")); + gnt_box_add_widget(GNT_BOX(box), button); + g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(delete_account_cb), accounts.tree); + + gnt_box_add_widget(GNT_BOX(accounts.window), box); + + g_signal_connect(G_OBJECT(accounts.window), "destroy", G_CALLBACK(reset_accounts_win), NULL); + + gnt_widget_show(accounts.window); +} + +static gpointer +finch_accounts_get_handle() +{ + static int handle; + + return &handle; +} + +static void +account_added_callback(GaimAccount *account) +{ + if (accounts.window == NULL) + return; + account_add(account); + gnt_widget_draw(accounts.tree); +} + +static void +account_removed_callback(GaimAccount *account) +{ + if (accounts.window == NULL) + return; + + gnt_tree_remove(GNT_TREE(accounts.tree), account); +} + +void finch_accounts_init() +{ + GList *iter; + + gaim_signal_connect(gaim_accounts_get_handle(), "account-added", + finch_accounts_get_handle(), GAIM_CALLBACK(account_added_callback), + NULL); + gaim_signal_connect(gaim_accounts_get_handle(), "account-removed", + finch_accounts_get_handle(), GAIM_CALLBACK(account_removed_callback), + NULL); + + for (iter = gaim_accounts_get_all(); iter; iter = iter->next) { + if (gaim_account_get_enabled(iter->data, GAIM_GNT_UI)) + break; + } + if (!iter) + finch_accounts_show_all(); +} + +void finch_accounts_uninit() +{ + if (accounts.window) + gnt_widget_destroy(accounts.window); +} + +/* The following uiops stuff are copied from gtkaccount.c */ +typedef struct +{ + GaimAccount *account; + char *username; + char *alias; +} AddUserData; + +static char * +make_info(GaimAccount *account, GaimConnection *gc, const char *remote_user, + const char *id, const char *alias, const char *msg) +{ + if (msg != NULL && *msg == '\0') + msg = NULL; + + return g_strdup_printf(_("%s%s%s%s has made %s his or her buddy%s%s"), + remote_user, + (alias != NULL ? " (" : ""), + (alias != NULL ? alias : ""), + (alias != NULL ? ")" : ""), + (id != NULL + ? id + : (gaim_connection_get_display_name(gc) != NULL + ? gaim_connection_get_display_name(gc) + : gaim_account_get_username(account))), + (msg != NULL ? ": " : "."), + (msg != NULL ? msg : "")); +} + +static void +notify_added(GaimAccount *account, const char *remote_user, + const char *id, const char *alias, + const char *msg) +{ + char *buffer; + GaimConnection *gc; + + gc = gaim_account_get_connection(account); + + buffer = make_info(account, gc, remote_user, id, alias, msg); + + gaim_notify_info(NULL, NULL, buffer, NULL); + + g_free(buffer); +} + +static void +free_add_user_data(AddUserData *data) +{ + g_free(data->username); + + if (data->alias != NULL) + g_free(data->alias); + + g_free(data); +} + +static void +add_user_cb(AddUserData *data) +{ + GaimConnection *gc = gaim_account_get_connection(data->account); + + if (g_list_find(gaim_connections_get_all(), gc)) + { + gaim_blist_request_add_buddy(data->account, data->username, + NULL, data->alias); + } + + free_add_user_data(data); +} + +static void +request_add(GaimAccount *account, const char *remote_user, + const char *id, const char *alias, + const char *msg) +{ + char *buffer; + GaimConnection *gc; + AddUserData *data; + + gc = gaim_account_get_connection(account); + + data = g_new0(AddUserData, 1); + data->account = account; + data->username = g_strdup(remote_user); + data->alias = (alias != NULL ? g_strdup(alias) : NULL); + + buffer = make_info(account, gc, remote_user, id, alias, msg); + gaim_request_action(NULL, NULL, _("Add buddy to your list?"), + buffer, GAIM_DEFAULT_ACTION_NONE, data, 2, + _("Add"), G_CALLBACK(add_user_cb), + _("Cancel"), G_CALLBACK(free_add_user_data)); + g_free(buffer); +} + +/* Copied from gtkaccount.c */ +typedef struct { + GaimAccountRequestAuthorizationCb auth_cb; + GaimAccountRequestAuthorizationCb deny_cb; + void *data; + char *username; + char *alias; + GaimAccount *account; +} auth_and_add; + +static void +authorize_and_add_cb(auth_and_add *aa) +{ + aa->auth_cb(aa->data); + gaim_blist_request_add_buddy(aa->account, aa->username, + NULL, aa->alias); + + g_free(aa->username); + g_free(aa->alias); + g_free(aa); +} + +static void +deny_no_add_cb(auth_and_add *aa) +{ + aa->deny_cb(aa->data); + + g_free(aa->username); + g_free(aa->alias); + g_free(aa); +} + +static void * +finch_request_authorize(GaimAccount *account, const char *remote_user, + const char *id, const char *alias, const char *message, gboolean on_list, + GCallback auth_cb, GCallback deny_cb, void *user_data) +{ + char *buffer; + GaimConnection *gc; + void *uihandle; + + gc = gaim_account_get_connection(account); + if (message != NULL && *message == '\0') + message = NULL; + + buffer = g_strdup_printf(_("%s%s%s%s wants to add %s to his or her buddy list%s%s"), + remote_user, + (alias != NULL ? " (" : ""), + (alias != NULL ? alias : ""), + (alias != NULL ? ")" : ""), + (id != NULL + ? id + : (gaim_connection_get_display_name(gc) != NULL + ? gaim_connection_get_display_name(gc) + : gaim_account_get_username(account))), + (message != NULL ? ": " : "."), + (message != NULL ? message : "")); + if (!on_list) { + auth_and_add *aa = g_new(auth_and_add, 1); + aa->auth_cb = (GaimAccountRequestAuthorizationCb)auth_cb; + aa->deny_cb = (GaimAccountRequestAuthorizationCb)deny_cb; + aa->data = user_data; + aa->username = g_strdup(remote_user); + aa->alias = g_strdup(alias); + aa->account = account; + uihandle = gaim_request_action(NULL, _("Authorize buddy?"), buffer, NULL, + GAIM_DEFAULT_ACTION_NONE, aa, 2, + _("Authorize"), authorize_and_add_cb, + _("Deny"), deny_no_add_cb); + } else { + uihandle = gaim_request_action(NULL, _("Authorize buddy?"), buffer, NULL, + GAIM_DEFAULT_ACTION_NONE, user_data, 2, + _("Authorize"), auth_cb, + _("Deny"), deny_cb); + } + g_free(buffer); + return uihandle; +} + +static void +finch_request_close(void *uihandle) +{ + gaim_request_close(GAIM_REQUEST_ACTION, uihandle); +} + +static GaimAccountUiOps ui_ops = +{ + .notify_added = notify_added, + .status_changed = NULL, + .request_add = request_add, + .request_authorize = finch_request_authorize, + .close_account_request = finch_request_close +}; + +GaimAccountUiOps *finch_accounts_get_ui_ops() +{ + return &ui_ops; +} + diff -r 317e7613e581 -r 0e3a8505ebbe finch/gntaccount.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/gntaccount.h Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,59 @@ +/** + * @file gntaccount.h GNT Account API + * @ingroup gntui + * + * gaim + * + * Gaim is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _GNT_ACCOUNT_H +#define _GNT_ACCOUNT_H + +#include "account.h" + +/********************************************************************** + * @name GNT Account API + **********************************************************************/ +/*@{*/ + +/** + * Get the ui-functions. + * + * @return The GaimAccountUiOps structure populated with the appropriate functions. + */ +GaimAccountUiOps *finch_accounts_get_ui_ops(void); + +/** + * Perform necessary initializations. + */ +void finch_accounts_init(void); + +/** + * Perform necessary uninitializations. + */ +void finch_accounts_uninit(void); + +/** + * Show the account-manager dialog. + */ +void finch_accounts_show_all(void); + +/*@}*/ + +#endif diff -r 317e7613e581 -r 0e3a8505ebbe finch/gntblist.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/gntblist.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,2233 @@ +/** + * @file gntblist.c GNT BuddyList API + * @ingroup gntui + * + * gaim + * + * Gaim is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "debug.h" + +#include "gntgaim.h" +#include "gntbox.h" +#include "gntcombobox.h" +#include "gntentry.h" +#include "gntft.h" +#include "gntlabel.h" +#include "gntline.h" +#include "gntmenu.h" +#include "gntmenuitem.h" +#include "gntmenuitemcheck.h" +#include "gntpounce.h" +#include "gnttree.h" +#include "gntutils.h" +#include "gntwindow.h" + +#include "gntblist.h" +#include "gntconv.h" +#include "gntstatus.h" +#include + +#define PREF_ROOT "/gaim/gnt/blist" +#define TYPING_TIMEOUT 4000 + +typedef struct +{ + GntWidget *window; + GntWidget *tree; + + GntWidget *tooltip; + GaimBlistNode *tnode; /* Who is the tooltip being displayed for? */ + GList *tagged; /* A list of tagged blistnodes */ + + GntWidget *context; + GaimBlistNode *cnode; + + /* XXX: I am KISSing */ + GntWidget *status; /* Dropdown with the statuses */ + GntWidget *statustext; /* Status message */ + int typing; + + GntWidget *menu; + /* These are the menuitems that get regenerated */ + GntMenuItem *accounts; + GntMenuItem *plugins; +} FinchBlist; + +typedef enum +{ + STATUS_PRIMITIVE = 0, + STATUS_SAVED_POPULAR, + STATUS_SAVED_ALL, + STATUS_SAVED_NEW +} StatusType; + +typedef struct +{ + StatusType type; + union + { + GaimStatusPrimitive prim; + GaimSavedStatus *saved; + } u; +} StatusBoxItem; + +FinchBlist *ggblist; + +static void add_buddy(GaimBuddy *buddy, FinchBlist *ggblist); +static void add_contact(GaimContact *contact, FinchBlist *ggblist); +static void add_group(GaimGroup *group, FinchBlist *ggblist); +static void add_chat(GaimChat *chat, FinchBlist *ggblist); +static void add_node(GaimBlistNode *node, FinchBlist *ggblist); +static void draw_tooltip(FinchBlist *ggblist); +static gboolean remove_typing_cb(gpointer null); +static void remove_peripherals(FinchBlist *ggblist); +static const char * get_display_name(GaimBlistNode *node); +static void savedstatus_changed(GaimSavedStatus *now, GaimSavedStatus *old); +static void blist_show(GaimBuddyList *list); +static void update_buddy_display(GaimBuddy *buddy, FinchBlist *ggblist); +static void account_signed_on_cb(void); + +/* Sort functions */ +static int blist_node_compare_text(GaimBlistNode *n1, GaimBlistNode *n2); +static int blist_node_compare_status(GaimBlistNode *n1, GaimBlistNode *n2); +static int blist_node_compare_log(GaimBlistNode *n1, GaimBlistNode *n2); + +static gboolean +is_contact_online(GaimContact *contact) +{ + GaimBlistNode *node; + for (node = ((GaimBlistNode*)contact)->child; node; node = node->next) { + if (GAIM_BUDDY_IS_ONLINE((GaimBuddy*)node)) + return TRUE; + } + return FALSE; +} + +static gboolean +is_group_online(GaimGroup *group) +{ + GaimBlistNode *node; + for (node = ((GaimBlistNode*)group)->child; node; node = node->next) { + if (GAIM_BLIST_NODE_IS_CHAT(node)) + return TRUE; + else if (is_contact_online((GaimContact*)node)) + return TRUE; + } + return FALSE; +} + +static void +new_node(GaimBlistNode *node) +{ +} + +static void add_node(GaimBlistNode *node, FinchBlist *ggblist) +{ + if (GAIM_BLIST_NODE_IS_BUDDY(node)) + add_buddy((GaimBuddy*)node, ggblist); + else if (GAIM_BLIST_NODE_IS_CONTACT(node)) + add_contact((GaimContact*)node, ggblist); + else if (GAIM_BLIST_NODE_IS_GROUP(node)) + add_group((GaimGroup*)node, ggblist); + else if (GAIM_BLIST_NODE_IS_CHAT(node)) + add_chat((GaimChat *)node, ggblist); + draw_tooltip(ggblist); +} + +static void +remove_tooltip(FinchBlist *ggblist) +{ + gnt_widget_destroy(ggblist->tooltip); + ggblist->tooltip = NULL; + ggblist->tnode = NULL; +} + +static void +node_remove(GaimBuddyList *list, GaimBlistNode *node) +{ + FinchBlist *ggblist = list->ui_data; + + if (ggblist == NULL || node->ui_data == NULL) + return; + + gnt_tree_remove(GNT_TREE(ggblist->tree), node); + node->ui_data = NULL; + if (ggblist->tagged) + ggblist->tagged = g_list_remove(ggblist->tagged, node); + + if (GAIM_BLIST_NODE_IS_BUDDY(node)) { + GaimContact *contact = (GaimContact*)node->parent; + if ((!gaim_prefs_get_bool(PREF_ROOT "/showoffline") && !is_contact_online(contact)) || + contact->currentsize < 1) + node_remove(list, (GaimBlistNode*)contact); + } else if (GAIM_BLIST_NODE_IS_CONTACT(node)) { + GaimGroup *group = (GaimGroup*)node->parent; + if ((!gaim_prefs_get_bool(PREF_ROOT "/showoffline") && !is_group_online(group)) || + group->currentsize < 1) + node_remove(list, node->parent); + for (node = node->child; node; node = node->next) + node->ui_data = NULL; + } + + draw_tooltip(ggblist); +} + +static void +node_update(GaimBuddyList *list, GaimBlistNode *node) +{ + /* It really looks like this should never happen ... but it does. + This will at least emit a warning to the log when it + happens, so maybe someone will figure it out. */ + g_return_if_fail(node != NULL); + + if (list->ui_data == NULL) + return; /* XXX: this is probably the place to auto-join chats */ + + if (node->ui_data != NULL) { + gnt_tree_change_text(GNT_TREE(ggblist->tree), node, + 0, get_display_name(node)); + gnt_tree_sort_row(GNT_TREE(ggblist->tree), node); + } + + if (GAIM_BLIST_NODE_IS_BUDDY(node)) { + GaimBuddy *buddy = (GaimBuddy*)node; + if (gaim_account_is_connected(buddy->account) && + (GAIM_BUDDY_IS_ONLINE(buddy) || gaim_prefs_get_bool(PREF_ROOT "/showoffline"))) + add_node((GaimBlistNode*)buddy, list->ui_data); + else + node_remove(gaim_get_blist(), node); + + node_update(list, node->parent); + } else if (GAIM_BLIST_NODE_IS_CHAT(node)) { + add_chat((GaimChat *)node, list->ui_data); + } else if (GAIM_BLIST_NODE_IS_CONTACT(node)) { + GaimContact *contact = (GaimContact*)node; + if ((!gaim_prefs_get_bool(PREF_ROOT "/showoffline") && !is_contact_online(contact)) || + contact->currentsize < 1) + node_remove(gaim_get_blist(), node); + else + add_node(node, list->ui_data); + } else if (GAIM_BLIST_NODE_IS_GROUP(node)) { + GaimGroup *group = (GaimGroup*)node; + if ((!gaim_prefs_get_bool(PREF_ROOT "/showoffline") && !is_group_online(group)) || + group->currentsize < 1) + node_remove(list, node); + } +} + +static void +new_list(GaimBuddyList *list) +{ + if (ggblist) + return; + + ggblist = g_new0(FinchBlist, 1); + list->ui_data = ggblist; +} + +static void +add_buddy_cb(void *data, GaimRequestFields *allfields) +{ + const char *username = gaim_request_fields_get_string(allfields, "screenname"); + const char *alias = gaim_request_fields_get_string(allfields, "alias"); + const char *group = gaim_request_fields_get_string(allfields, "group"); + GaimAccount *account = gaim_request_fields_get_account(allfields, "account"); + const char *error = NULL; + GaimGroup *grp; + GaimBuddy *buddy; + + if (!username) + error = _("You must provide a screename for the buddy."); + else if (!group) + error = _("You must provide a group."); + else if (!account) + error = _("You must select an account."); + + if (error) + { + gaim_notify_error(NULL, _("Error"), _("Error adding buddy"), error); + return; + } + + grp = gaim_find_group(group); + if (!grp) + { + grp = gaim_group_new(group); + gaim_blist_add_group(grp, NULL); + } + + buddy = gaim_buddy_new(account, username, alias); + gaim_blist_add_buddy(buddy, NULL, grp, NULL); + gaim_account_add_buddy(account, buddy); +} + +static void +finch_request_add_buddy(GaimAccount *account, const char *username, const char *grp, const char *alias) +{ + GaimRequestFields *fields = gaim_request_fields_new(); + GaimRequestFieldGroup *group = gaim_request_field_group_new(NULL); + GaimRequestField *field; + + gaim_request_fields_add_group(fields, group); + + field = gaim_request_field_string_new("screenname", _("Screen Name"), username, FALSE); + gaim_request_field_group_add_field(group, field); + + field = gaim_request_field_string_new("alias", _("Alias"), alias, FALSE); + gaim_request_field_group_add_field(group, field); + + field = gaim_request_field_string_new("group", _("Group"), grp, FALSE); + gaim_request_field_group_add_field(group, field); + + field = gaim_request_field_account_new("account", _("Account"), NULL); + gaim_request_field_account_set_show_all(field, FALSE); + if (account) + gaim_request_field_account_set_value(field, account); + gaim_request_field_group_add_field(group, field); + + gaim_request_fields(NULL, _("Add Buddy"), NULL, _("Please enter buddy information."), + fields, _("Add"), G_CALLBACK(add_buddy_cb), _("Cancel"), NULL, NULL); +} + +static void +add_chat_cb(void *data, GaimRequestFields *allfields) +{ + GaimAccount *account; + const char *alias, *name, *group; + GaimChat *chat; + GaimGroup *grp; + GHashTable *hash = NULL; + GaimConnection *gc; + + account = gaim_request_fields_get_account(allfields, "account"); + name = gaim_request_fields_get_string(allfields, "name"); + alias = gaim_request_fields_get_string(allfields, "alias"); + group = gaim_request_fields_get_string(allfields, "group"); + + if (!gaim_account_is_connected(account) || !name || !*name) + return; + + if (!group || !*group) + group = _("Chats"); + + gc = gaim_account_get_connection(account); + + if (GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info_defaults != NULL) + hash = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info_defaults(gc, name); + + chat = gaim_chat_new(account, name, hash); + + if (chat != NULL) { + if ((grp = gaim_find_group(group)) == NULL) { + grp = gaim_group_new(group); + gaim_blist_add_group(grp, NULL); + } + gaim_blist_add_chat(chat, grp, NULL); + gaim_blist_alias_chat(chat, alias); + } +} + +static void +finch_request_add_chat(GaimAccount *account, GaimGroup *grp, const char *alias, const char *name) +{ + GaimRequestFields *fields = gaim_request_fields_new(); + GaimRequestFieldGroup *group = gaim_request_field_group_new(NULL); + GaimRequestField *field; + + gaim_request_fields_add_group(fields, group); + + field = gaim_request_field_account_new("account", _("Account"), NULL); + gaim_request_field_account_set_show_all(field, FALSE); + if (account) + gaim_request_field_account_set_value(field, account); + gaim_request_field_group_add_field(group, field); + + field = gaim_request_field_string_new("name", _("Name"), name, FALSE); + gaim_request_field_group_add_field(group, field); + + field = gaim_request_field_string_new("alias", _("Alias"), alias, FALSE); + gaim_request_field_group_add_field(group, field); + + field = gaim_request_field_string_new("group", _("Group"), grp ? grp->name : NULL, FALSE); + gaim_request_field_group_add_field(group, field); + + gaim_request_fields(NULL, _("Add Chat"), NULL, + _("You can edit more information from the context menu later."), + fields, _("Add"), G_CALLBACK(add_chat_cb), _("Cancel"), NULL, NULL); +} + +static void +add_group_cb(gpointer null, const char *group) +{ + GaimGroup *grp; + + if (!group || !*group) + { + gaim_notify_error(NULL, _("Error"), _("Error adding group"), + _("You must give a name for the group to add.")); + return; + } + + grp = gaim_find_group(group); + if (!grp) + { + grp = gaim_group_new(group); + gaim_blist_add_group(grp, NULL); + } + else + { + gaim_notify_error(NULL, _("Error"), _("Error adding group"), + _("A group with the name already exists.")); + } +} + +static void +finch_request_add_group() +{ + gaim_request_input(NULL, _("Add Group"), NULL, _("Enter the name of the group"), + NULL, FALSE, FALSE, NULL, + _("Add"), G_CALLBACK(add_group_cb), _("Cancel"), NULL, NULL); +} + +static GaimBlistUiOps blist_ui_ops = +{ + new_list, + new_node, + blist_show, + node_update, + node_remove, + NULL, + NULL, + .request_add_buddy = finch_request_add_buddy, + .request_add_chat = finch_request_add_chat, + .request_add_group = finch_request_add_group +}; + +static gpointer +finch_blist_get_handle() +{ + static int handle; + + return &handle; +} + +static void +add_group(GaimGroup *group, FinchBlist *ggblist) +{ + GaimBlistNode *node = (GaimBlistNode *)group; + if (node->ui_data) + return; + node->ui_data = gnt_tree_add_row_after(GNT_TREE(ggblist->tree), group, + gnt_tree_create_row(GNT_TREE(ggblist->tree), get_display_name(node)), NULL, NULL); +} + +static const char * +get_display_name(GaimBlistNode *node) +{ + static char text[2096]; + char status[8] = " "; + const char *name = NULL; + + if (GAIM_BLIST_NODE_IS_CONTACT(node)) + node = (GaimBlistNode*)gaim_contact_get_priority_buddy((GaimContact*)node); /* XXX: this can return NULL?! */ + + if (node == NULL) + return NULL; + + if (GAIM_BLIST_NODE_IS_BUDDY(node)) + { + GaimBuddy *buddy = (GaimBuddy *)node; + GaimStatusPrimitive prim; + GaimPresence *presence; + GaimStatus *now; + gboolean ascii = gnt_ascii_only(); + + presence = gaim_buddy_get_presence(buddy); + now = gaim_presence_get_active_status(presence); + + prim = gaim_status_type_get_primitive(gaim_status_get_type(now)); + + switch(prim) + { + case GAIM_STATUS_OFFLINE: + strncpy(status, ascii ? "x" : "⊗", sizeof(status) - 1); + break; + case GAIM_STATUS_AVAILABLE: + strncpy(status, ascii ? "o" : "◯", sizeof(status) - 1); + break; + default: + strncpy(status, ascii ? "." : "⊖", sizeof(status) - 1); + break; + } + name = gaim_buddy_get_alias(buddy); + } + else if (GAIM_BLIST_NODE_IS_CHAT(node)) + { + GaimChat *chat = (GaimChat*)node; + name = gaim_chat_get_name(chat); + + strncpy(status, "~", sizeof(status) - 1); + } + else if (GAIM_BLIST_NODE_IS_GROUP(node)) + return ((GaimGroup*)node)->name; + + snprintf(text, sizeof(text) - 1, "%s %s", status, name); + + return text; +} + +static void +add_chat(GaimChat *chat, FinchBlist *ggblist) +{ + GaimGroup *group; + GaimBlistNode *node = (GaimBlistNode *)chat; + if (node->ui_data) + return; + if (!gaim_account_is_connected(chat->account)) + return; + + group = gaim_chat_get_group(chat); + add_node((GaimBlistNode*)group, ggblist); + + node->ui_data = gnt_tree_add_row_after(GNT_TREE(ggblist->tree), chat, + gnt_tree_create_row(GNT_TREE(ggblist->tree), get_display_name(node)), + group, NULL); +} + +static void +add_contact(GaimContact *contact, FinchBlist *ggblist) +{ + GaimGroup *group; + GaimBlistNode *node = (GaimBlistNode*)contact; + const char *name; + + if (node->ui_data) + return; + + name = get_display_name(node); + if (name == NULL) + return; + + group = (GaimGroup*)node->parent; + add_node((GaimBlistNode*)group, ggblist); + + node->ui_data = gnt_tree_add_row_after(GNT_TREE(ggblist->tree), contact, + gnt_tree_create_row(GNT_TREE(ggblist->tree), name), + group, NULL); + + gnt_tree_set_expanded(GNT_TREE(ggblist->tree), contact, FALSE); +} + +static void +add_buddy(GaimBuddy *buddy, FinchBlist *ggblist) +{ + GaimContact *contact; + GaimBlistNode *node = (GaimBlistNode *)buddy; + if (node->ui_data) + return; + + contact = (GaimContact*)node->parent; + if (!contact) /* When a new buddy is added and show-offline is set */ + return; + add_node((GaimBlistNode*)contact, ggblist); + + node->ui_data = gnt_tree_add_row_after(GNT_TREE(ggblist->tree), buddy, + gnt_tree_create_row(GNT_TREE(ggblist->tree), get_display_name(node)), + contact, NULL); + if (gaim_presence_is_idle(gaim_buddy_get_presence(buddy))) { + gnt_tree_set_row_flags(GNT_TREE(ggblist->tree), buddy, GNT_TEXT_FLAG_DIM); + gnt_tree_set_row_flags(GNT_TREE(ggblist->tree), contact, GNT_TEXT_FLAG_DIM); + } else { + gnt_tree_set_row_flags(GNT_TREE(ggblist->tree), buddy, 0); + gnt_tree_set_row_flags(GNT_TREE(ggblist->tree), contact, 0); + } +} + +#if 0 +static void +buddy_signed_on(GaimBuddy *buddy, FinchBlist *ggblist) +{ + add_node((GaimBlistNode*)buddy, ggblist); +} + +static void +buddy_signed_off(GaimBuddy *buddy, FinchBlist *ggblist) +{ + node_remove(gaim_get_blist(), (GaimBlistNode*)buddy); +} +#endif + +GaimBlistUiOps *finch_blist_get_ui_ops() +{ + return &blist_ui_ops; +} + +static void +selection_activate(GntWidget *widget, FinchBlist *ggblist) +{ + GntTree *tree = GNT_TREE(ggblist->tree); + GaimBlistNode *node = gnt_tree_get_selection_data(tree); + + if (!node) + return; + + if (GAIM_BLIST_NODE_IS_CONTACT(node)) + node = (GaimBlistNode*)gaim_contact_get_priority_buddy((GaimContact*)node); + + if (GAIM_BLIST_NODE_IS_BUDDY(node)) + { + GaimBuddy *buddy = (GaimBuddy *)node; + GaimConversation *conv = gaim_conversation_new(GAIM_CONV_TYPE_IM, + gaim_buddy_get_account(buddy), + gaim_buddy_get_name(buddy)); + finch_conversation_set_active(conv); + } + else if (GAIM_BLIST_NODE_IS_CHAT(node)) + { + GaimChat *chat = (GaimChat*)node; + serv_join_chat(chat->account->gc, chat->components); + } +} + +static void +context_menu_callback(GntMenuItem *item, gpointer data) +{ + GaimMenuAction *action = data; + GaimBlistNode *node = ggblist->cnode; + if (action) { + void (*callback)(GaimBlistNode *, gpointer); + callback = (void (*)(GaimBlistNode *, gpointer))action->callback; + if (callback) + callback(action->data, node); + else + return; + } +} + +static void +gnt_append_menu_action(GntMenu *menu, GaimMenuAction *action, gpointer parent) +{ + GList *list; + GntMenuItem *item; + + if (action == NULL) + return; + + item = gnt_menuitem_new(action->label); + if (action->callback) + gnt_menuitem_set_callback(GNT_MENUITEM(item), context_menu_callback, action); + gnt_menu_add_item(menu, GNT_MENUITEM(item)); + + if (action->children) { + GntWidget *sub = gnt_menu_new(GNT_MENU_POPUP); + gnt_menuitem_set_submenu(item, GNT_MENU(sub)); + for (list = action->children; list; list = list->next) + gnt_append_menu_action(GNT_MENU(sub), list->data, action); + } +} + +static void +append_proto_menu(GntMenu *menu, GaimConnection *gc, GaimBlistNode *node) +{ + GList *list; + GaimPluginProtocolInfo *prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl); + + if(!prpl_info || !prpl_info->blist_node_menu) + return; + + for(list = prpl_info->blist_node_menu(node); list; + list = g_list_delete_link(list, list)) + { + GaimMenuAction *act = (GaimMenuAction *) list->data; + act->data = node; + gnt_append_menu_action(menu, act, NULL); + } +} + +static void +add_custom_action(GntMenu *menu, const char *label, GaimCallback callback, + gpointer data) +{ + GaimMenuAction *action = gaim_menu_action_new(label, callback, data, NULL); + gnt_append_menu_action(menu, action, NULL); + g_signal_connect_swapped(G_OBJECT(menu), "destroy", + G_CALLBACK(gaim_menu_action_free), action); +} + +static void +chat_components_edit_ok(GaimChat *chat, GaimRequestFields *allfields) +{ + GList *groups, *fields; + + for (groups = gaim_request_fields_get_groups(allfields); groups; groups = groups->next) { + fields = gaim_request_field_group_get_fields(groups->data); + for (; fields; fields = fields->next) { + GaimRequestField *field = fields->data; + const char *id; + char *val; + + id = gaim_request_field_get_id(field); + if (gaim_request_field_get_type(field) == GAIM_REQUEST_FIELD_INTEGER) + val = g_strdup_printf("%d", gaim_request_field_int_get_value(field)); + else + val = g_strdup(gaim_request_field_string_get_value(field)); + + g_hash_table_replace(chat->components, g_strdup(id), val); /* val should not be free'd */ + } + } +} + +static void +chat_components_edit(GaimChat *chat, GaimBlistNode *selected) +{ + GaimRequestFields *fields = gaim_request_fields_new(); + GaimRequestFieldGroup *group = gaim_request_field_group_new(NULL); + GaimRequestField *field; + GList *parts, *iter; + struct proto_chat_entry *pce; + + gaim_request_fields_add_group(fields, group); + + parts = GAIM_PLUGIN_PROTOCOL_INFO(chat->account->gc->prpl)->chat_info(chat->account->gc); + + for (iter = parts; iter; iter = iter->next) { + pce = iter->data; + if (pce->is_int) { + int val; + const char *str = g_hash_table_lookup(chat->components, pce->identifier); + if (!str || sscanf(str, "%d", &val) != 1) + val = pce->min; + field = gaim_request_field_int_new(pce->identifier, pce->label, val); + } else { + field = gaim_request_field_string_new(pce->identifier, pce->label, + g_hash_table_lookup(chat->components, pce->identifier), FALSE); + } + + gaim_request_field_group_add_field(group, field); + g_free(pce); + } + + g_list_free(parts); + + gaim_request_fields(NULL, _("Edit Chat"), NULL, _("Please Update the necessary fields."), + fields, _("Edit"), G_CALLBACK(chat_components_edit_ok), _("Cancel"), NULL, chat); +} + +static void +autojoin_toggled(GntMenuItem *item, gpointer data) +{ + GaimMenuAction *action = data; + gaim_blist_node_set_bool(action->data, "gnt-autojoin", + gnt_menuitem_check_get_checked(GNT_MENUITEM_CHECK(item))); +} + +static void +create_chat_menu(GntMenu *menu, GaimChat *chat) +{ + GaimMenuAction *action = gaim_menu_action_new(_("Auto-join"), NULL, chat, NULL); + GntMenuItem *check = gnt_menuitem_check_new(action->label); + gnt_menuitem_check_set_checked(GNT_MENUITEM_CHECK(check), + gaim_blist_node_get_bool((GaimBlistNode*)chat, "gnt-autojoin")); + gnt_menu_add_item(menu, check); + gnt_menuitem_set_callback(check, autojoin_toggled, action); + g_signal_connect_swapped(G_OBJECT(menu), "destroy", + G_CALLBACK(gaim_menu_action_free), action); + + add_custom_action(menu, _("Edit Settings"), (GaimCallback)chat_components_edit, chat); +} + +static void +finch_add_buddy(GaimGroup *grp, GaimBlistNode *selected) +{ + gaim_blist_request_add_buddy(NULL, NULL, grp ? grp->name : NULL, NULL); +} + +static void +finch_add_group(GaimGroup *grp, GaimBlistNode *selected) +{ + gaim_blist_request_add_group(); +} + +static void +finch_add_chat(GaimGroup *grp, GaimBlistNode *selected) +{ + gaim_blist_request_add_chat(NULL, grp, NULL, NULL); +} + +static void +create_group_menu(GntMenu *menu, GaimGroup *group) +{ + add_custom_action(menu, _("Add Buddy"), + GAIM_CALLBACK(finch_add_buddy), group); + add_custom_action(menu, _("Add Chat"), + GAIM_CALLBACK(finch_add_chat), group); + add_custom_action(menu, _("Add Group"), + GAIM_CALLBACK(finch_add_group), group); +} + +static void +finch_blist_get_buddy_info_cb(GaimBuddy *buddy, GaimBlistNode *selected) +{ + serv_get_info(buddy->account->gc, gaim_buddy_get_name(buddy)); +} + +static void +finch_blist_menu_send_file_cb(GaimBuddy *buddy, GaimBlistNode *selected) +{ + serv_send_file(buddy->account->gc, buddy->name, NULL); +} + +static void +finch_blist_pounce_node_cb(GaimBlistNode *node, GaimBlistNode *selected) +{ + GaimBuddy *b; + if (GAIM_BLIST_NODE_IS_CONTACT(node)) + b = gaim_contact_get_priority_buddy((GaimContact *)node); + else + b = (GaimBuddy *)node; + finch_pounce_editor_show(b->account, b->name, NULL); +} + + +static void +create_buddy_menu(GntMenu *menu, GaimBuddy *buddy) +{ + GaimPluginProtocolInfo *prpl_info; + + prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(buddy->account->gc->prpl); + if (prpl_info && prpl_info->get_info) + { + add_custom_action(menu, _("Get Info"), + GAIM_CALLBACK(finch_blist_get_buddy_info_cb), buddy); + } + + add_custom_action(menu, _("Add Buddy Pounce"), + GAIM_CALLBACK(finch_blist_pounce_node_cb), buddy); + + if (prpl_info && prpl_info->send_file) + { + if (!prpl_info->can_receive_file || + prpl_info->can_receive_file(buddy->account->gc, buddy->name)) + add_custom_action(menu, _("Send File"), + GAIM_CALLBACK(finch_blist_menu_send_file_cb), buddy); + } +#if 0 + add_custom_action(tree, _("View Log"), + GAIM_CALLBACK(finch_blist_view_log_cb)), buddy); +#endif + + /* Protocol actions */ + append_proto_menu(menu, + gaim_account_get_connection(gaim_buddy_get_account(buddy)), + (GaimBlistNode*)buddy); +} + +static void +append_extended_menu(GntMenu *menu, GaimBlistNode *node) +{ + GList *iter; + + for (iter = gaim_blist_node_get_extended_menu(node); + iter; iter = g_list_delete_link(iter, iter)) + { + gnt_append_menu_action(menu, iter->data, NULL); + } +} + +/* Xerox'd from gtkdialogs.c:gaim_gtkdialogs_remove_contact_cb */ +static void +remove_contact(GaimContact *contact) +{ + GaimBlistNode *bnode, *cnode; + GaimGroup *group; + + cnode = (GaimBlistNode *)contact; + group = (GaimGroup*)cnode->parent; + for (bnode = cnode->child; bnode; bnode = bnode->next) { + GaimBuddy *buddy = (GaimBuddy*)bnode; + if (gaim_account_is_connected(buddy->account)) + gaim_account_remove_buddy(buddy->account, buddy, group); + } + gaim_blist_remove_contact(contact); +} + +static void +rename_blist_node(GaimBlistNode *node, const char *newname) +{ + const char *name = newname; + if (name && !*name) + name = NULL; + + if (GAIM_BLIST_NODE_IS_CONTACT(node)) { + GaimContact *contact = (GaimContact*)node; + GaimBuddy *buddy = gaim_contact_get_priority_buddy(contact); + gaim_blist_alias_contact(contact, name); + gaim_blist_alias_buddy(buddy, name); + serv_alias_buddy(buddy); + } else if (GAIM_BLIST_NODE_IS_BUDDY(node)) { + gaim_blist_alias_buddy((GaimBuddy*)node, name); + serv_alias_buddy((GaimBuddy*)node); + } else if (GAIM_BLIST_NODE_IS_CHAT(node)) + gaim_blist_alias_chat((GaimChat*)node, name); + else if (GAIM_BLIST_NODE_IS_GROUP(node) && (name != NULL)) + gaim_blist_rename_group((GaimGroup*)node, name); + else + g_return_if_reached(); +} + +static void +finch_blist_rename_node_cb(GaimBlistNode *node, GaimBlistNode *selected) +{ + const char *name = NULL; + char *prompt; + + if (GAIM_BLIST_NODE_IS_CONTACT(node)) + name = gaim_contact_get_alias((GaimContact*)node); + else if (GAIM_BLIST_NODE_IS_BUDDY(node)) + name = gaim_buddy_get_contact_alias((GaimBuddy*)node); + else if (GAIM_BLIST_NODE_IS_CHAT(node)) + name = gaim_chat_get_name((GaimChat*)node); + else if (GAIM_BLIST_NODE_IS_GROUP(node)) + name = ((GaimGroup*)node)->name; + else + g_return_if_reached(); + + prompt = g_strdup_printf(_("Please enter the new name for %s"), name); + + gaim_request_input(node, _("Rename"), prompt, _("Enter empty string to reset the name."), + name, FALSE, FALSE, NULL, _("Rename"), G_CALLBACK(rename_blist_node), + _("Cancel"), NULL, node); + + g_free(prompt); +} + +/* Xeroxed from gtkdialogs.c:gaim_gtkdialogs_remove_group_cb*/ +static void +remove_group(GaimGroup *group) +{ + GaimBlistNode *cnode, *bnode; + + cnode = ((GaimBlistNode*)group)->child; + + while (cnode) { + if (GAIM_BLIST_NODE_IS_CONTACT(cnode)) { + bnode = cnode->child; + cnode = cnode->next; + while (bnode) { + GaimBuddy *buddy; + if (GAIM_BLIST_NODE_IS_BUDDY(bnode)) { + buddy = (GaimBuddy*)bnode; + bnode = bnode->next; + if (gaim_account_is_connected(buddy->account)) { + gaim_account_remove_buddy(buddy->account, buddy, group); + gaim_blist_remove_buddy(buddy); + } + } else { + bnode = bnode->next; + } + } + } else if (GAIM_BLIST_NODE_IS_CHAT(cnode)) { + GaimChat *chat = (GaimChat *)cnode; + cnode = cnode->next; + if (gaim_account_is_connected(chat->account)) + gaim_blist_remove_chat(chat); + } else { + cnode = cnode->next; + } + } + + gaim_blist_remove_group(group); +} + +static void +finch_blist_remove_node(GaimBlistNode *node) +{ + if (GAIM_BLIST_NODE_IS_CONTACT(node)) { + remove_contact((GaimContact*)node); + } else if (GAIM_BLIST_NODE_IS_BUDDY(node)) { + GaimBuddy *buddy = (GaimBuddy*)node; + GaimGroup *group = gaim_buddy_get_group(buddy); + gaim_account_remove_buddy(gaim_buddy_get_account(buddy), buddy, group); + gaim_blist_remove_buddy(buddy); + } else if (GAIM_BLIST_NODE_IS_CHAT(node)) { + gaim_blist_remove_chat((GaimChat*)node); + } else if (GAIM_BLIST_NODE_IS_GROUP(node)) { + remove_group((GaimGroup*)node); + } +} + +static void +finch_blist_remove_node_cb(GaimBlistNode *node, GaimBlistNode *selected) +{ + char *primary; + const char *name, *sec = NULL; + + /* XXX: could be a contact */ + if (GAIM_BLIST_NODE_IS_CONTACT(node)) { + GaimContact *c = (GaimContact*)node; + name = gaim_contact_get_alias(c); + if (c->totalsize > 1) + sec = _("Removing this contact will also remove all the buddies in the contact"); + } else if (GAIM_BLIST_NODE_IS_BUDDY(node)) + name = gaim_buddy_get_name((GaimBuddy*)node); + else if (GAIM_BLIST_NODE_IS_CHAT(node)) + name = gaim_chat_get_name((GaimChat*)node); + else if (GAIM_BLIST_NODE_IS_GROUP(node)) + { + name = ((GaimGroup*)node)->name; + sec = _("Removing this group will also remove all the buddies in the group"); + } + else + return; + + primary = g_strdup_printf(_("Are you sure you want to remove %s?"), name); + + /* XXX: anything to do with the returned ui-handle? */ + gaim_request_action(node, _("Confirm Remove"), + primary, sec, + 1, node, 2, + _("Remove"), finch_blist_remove_node, + _("Cancel"), NULL); + g_free(primary); +} + +static void +finch_blist_toggle_tag_buddy(GaimBlistNode *node) +{ + GList *iter; + if (node == NULL) + return; + if (GAIM_BLIST_NODE_IS_CHAT(node) || GAIM_BLIST_NODE_IS_GROUP(node)) + return; + if (ggblist->tagged && (iter = g_list_find(ggblist->tagged, node)) != NULL) { + ggblist->tagged = g_list_delete_link(ggblist->tagged, iter); + } else { + ggblist->tagged = g_list_prepend(ggblist->tagged, node); + } + if (GAIM_BLIST_NODE_IS_CONTACT(node)) + node = (GaimBlistNode*)gaim_contact_get_priority_buddy((GaimContact*)node); + update_buddy_display((GaimBuddy*)node, ggblist); +} + +static void +finch_blist_place_tagged(GaimBlistNode *target) +{ + GaimGroup *tg = NULL; + GaimContact *tc = NULL; + + if (target == NULL) + return; + + /* This target resolution probably needs more clarification; for + * example, if I tag a buddy in a contact, then place on + * another buddy in the same contact, I probably intend to + * place the tagged buddy immediately after (before?) the + * target buddy -- this will simply move the tagged buddy + * within the same contact without reference to position. */ + if (GAIM_BLIST_NODE_IS_GROUP(target)) + tg = (GaimGroup*)target; + else if (GAIM_BLIST_NODE_IS_CONTACT(target)) + tc = (GaimContact*)target; + else /* Buddy or Chat */ + tc = (GaimContact*)target->parent; + + if (ggblist->tagged) { + GList *list = ggblist->tagged; + ggblist->tagged = NULL; + + while (list) { + GaimBlistNode *node = list->data; + list = g_list_delete_link(list, list); + if (tg) { + if (GAIM_BLIST_NODE_IS_CONTACT(node)) + gaim_blist_add_contact((GaimContact*)node, tg, NULL); + else + gaim_blist_add_buddy((GaimBuddy*)node, NULL, tg, NULL); + } else { + if (GAIM_BLIST_NODE_IS_BUDDY(node)) + gaim_blist_add_buddy((GaimBuddy*)node, tc, + gaim_buddy_get_group(gaim_contact_get_priority_buddy(tc)), NULL); + else if (GAIM_BLIST_NODE_IS_CONTACT(node)) + gaim_blist_merge_contact((GaimContact*)node, target); + } + } + } +} + +static void +context_menu_destroyed(GntWidget *widget, FinchBlist *ggblist) +{ + ggblist->context = NULL; +} + +static void +draw_context_menu(FinchBlist *ggblist) +{ + GaimBlistNode *node = NULL; + GntWidget *context = NULL; + GntTree *tree = NULL; + int x, y, top, width; + char *title = NULL; + + tree = GNT_TREE(ggblist->tree); + + node = gnt_tree_get_selection_data(tree); + + if (ggblist->tooltip) + remove_tooltip(ggblist); + + ggblist->cnode = node; + + ggblist->context = context = gnt_menu_new(GNT_MENU_POPUP); + g_signal_connect(G_OBJECT(context), "destroy", G_CALLBACK(context_menu_destroyed), ggblist); + + if (!node) { + create_group_menu(GNT_MENU(context), NULL); + title = g_strdup(_("Buddy List")); + } else if (GAIM_BLIST_NODE_IS_CONTACT(node)) { + create_buddy_menu(GNT_MENU(context), + gaim_contact_get_priority_buddy((GaimContact*)node)); + title = g_strdup(gaim_contact_get_alias((GaimContact*)node)); + } else if (GAIM_BLIST_NODE_IS_BUDDY(node)) { + GaimBuddy *buddy = (GaimBuddy *)node; + create_buddy_menu(GNT_MENU(context), buddy); + title = g_strdup(gaim_buddy_get_name(buddy)); + } else if (GAIM_BLIST_NODE_IS_CHAT(node)) { + GaimChat *chat = (GaimChat*)node; + create_chat_menu(GNT_MENU(context), chat); + title = g_strdup(gaim_chat_get_name(chat)); + } else if (GAIM_BLIST_NODE_IS_GROUP(node)) { + GaimGroup *group = (GaimGroup *)node; + create_group_menu(GNT_MENU(context), group); + title = g_strdup(group->name); + } + + append_extended_menu(GNT_MENU(context), node); + + /* These are common for everything */ + if (node) { + add_custom_action(GNT_MENU(context), _("Rename"), + GAIM_CALLBACK(finch_blist_rename_node_cb), node); + add_custom_action(GNT_MENU(context), _("Remove"), + GAIM_CALLBACK(finch_blist_remove_node_cb), node); + + if (ggblist->tagged && (GAIM_BLIST_NODE_IS_CONTACT(node) + || GAIM_BLIST_NODE_IS_GROUP(node))) { + add_custom_action(GNT_MENU(context), _("Place tagged"), + GAIM_CALLBACK(finch_blist_place_tagged), node); + } + + if (GAIM_BLIST_NODE_IS_BUDDY(node) || GAIM_BLIST_NODE_IS_CONTACT(node)) { + add_custom_action(GNT_MENU(context), _("Toggle Tag"), + GAIM_CALLBACK(finch_blist_toggle_tag_buddy), node); + } + } + + /* Set the position for the popup */ + gnt_widget_get_position(GNT_WIDGET(tree), &x, &y); + gnt_widget_get_size(GNT_WIDGET(tree), &width, NULL); + top = gnt_tree_get_selection_visible_line(tree); + + x += width; + y += top - 1; + + gnt_widget_set_position(context, x, y); + gnt_screen_menu_show(GNT_MENU(context)); + g_free(title); +} + +static void +tooltip_for_buddy(GaimBuddy *buddy, GString *str) +{ + GaimPlugin *prpl; + GaimPluginProtocolInfo *prpl_info; + GaimAccount *account; + GaimNotifyUserInfo *user_info; + const char *alias = gaim_buddy_get_alias(buddy); + char *tmp, *strip; + + user_info = gaim_notify_user_info_new(); + + account = gaim_buddy_get_account(buddy); + + if (g_utf8_collate(gaim_buddy_get_name(buddy), alias)) + gaim_notify_user_info_add_pair(user_info, _("Nickname"), alias); + + tmp = g_strdup_printf("%s (%s)", + gaim_account_get_username(account), + gaim_account_get_protocol_name(account)); + gaim_notify_user_info_add_pair(user_info, _("Account"), tmp); + g_free(tmp); + + prpl = gaim_find_prpl(gaim_account_get_protocol_id(account)); + prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(prpl); + if (prpl_info && prpl_info->tooltip_text) { + prpl_info->tooltip_text(buddy, user_info, TRUE); + } + + if (gaim_prefs_get_bool("/gaim/gnt/blist/idletime")) { + GaimPresence *pre = gaim_buddy_get_presence(buddy); + if (gaim_presence_is_idle(pre)) { + time_t idle = gaim_presence_get_idle_time(pre); + if (idle > 0) { + char *st = gaim_str_seconds_to_string(time(NULL) - idle); + gaim_notify_user_info_add_pair(user_info, _("Idle"), st); + g_free(st); + } + } + } + + tmp = gaim_notify_user_info_get_text_with_newline(user_info, "
"); + gaim_notify_user_info_destroy(user_info); + + strip = gaim_markup_strip_html(tmp); + g_string_append(str, strip); + g_free(strip); + g_free(tmp); +} + +static GString* +make_sure_text_fits(GString *string) +{ + int maxw = getmaxx(stdscr) - 3; + char *str = gnt_util_onscreen_fit_string(string->str, maxw); + string = g_string_assign(string, str); + g_free(str); + return string; +} + +static gboolean +draw_tooltip_real(FinchBlist *ggblist) +{ + GaimBlistNode *node; + int x, y, top, width, w, h; + GString *str; + GntTree *tree; + GntWidget *widget, *box, *tv; + char *title = NULL; + int lastseen = 0; + + widget = ggblist->tree; + tree = GNT_TREE(widget); + + if (!gnt_widget_has_focus(ggblist->tree) || + (ggblist->context && !GNT_WIDGET_IS_FLAG_SET(ggblist->context, GNT_WIDGET_INVISIBLE))) + return FALSE; + + if (ggblist->tooltip) + { + /* XXX: Once we can properly redraw on expose events, this can be removed at the end + * to avoid the blinking*/ + remove_tooltip(ggblist); + } + + node = gnt_tree_get_selection_data(tree); + if (!node) + return FALSE; + + str = g_string_new(""); + + if (GAIM_BLIST_NODE_IS_CONTACT(node)) { + GaimBuddy *pr = gaim_contact_get_priority_buddy((GaimContact*)node); + gboolean offline = !GAIM_BUDDY_IS_ONLINE(pr); + gboolean showoffline = gaim_prefs_get_bool(PREF_ROOT "/showoffline"); + const char *name = gaim_buddy_get_name(pr); + + title = g_strdup(name); + tooltip_for_buddy(pr, str); + for (node = node->child; node; node = node->next) { + GaimBuddy *buddy = (GaimBuddy*)node; + if (offline) { + int value = gaim_blist_node_get_int(node, "last_seen"); + if (value > lastseen) + lastseen = value; + } + if (node == (GaimBlistNode*)pr) + continue; + if (!gaim_account_is_connected(buddy->account)) + continue; + if (!showoffline && !GAIM_BUDDY_IS_ONLINE(buddy)) + continue; + str = g_string_append(str, "\n----------\n"); + tooltip_for_buddy(buddy, str); + } + } else if (GAIM_BLIST_NODE_IS_BUDDY(node)) { + GaimBuddy *buddy = (GaimBuddy *)node; + tooltip_for_buddy(buddy, str); + title = g_strdup(gaim_buddy_get_name(buddy)); + if (!GAIM_BUDDY_IS_ONLINE((GaimBuddy*)node)) + lastseen = gaim_blist_node_get_int(node, "last_seen"); + } else if (GAIM_BLIST_NODE_IS_GROUP(node)) { + GaimGroup *group = (GaimGroup *)node; + + g_string_append_printf(str, _("Online: %d\nTotal: %d"), + gaim_blist_get_group_online_count(group), + gaim_blist_get_group_size(group, FALSE)); + + title = g_strdup(group->name); + } else if (GAIM_BLIST_NODE_IS_CHAT(node)) { + GaimChat *chat = (GaimChat *)node; + GaimAccount *account = chat->account; + + g_string_append_printf(str, _("Account: %s (%s)"), + gaim_account_get_username(account), + gaim_account_get_protocol_name(account)); + + title = g_strdup(gaim_chat_get_name(chat)); + } else { + g_string_free(str, TRUE); + return FALSE; + } + + if (lastseen > 0) { + char *tmp = gaim_str_seconds_to_string(time(NULL) - lastseen); + g_string_append_printf(str, _("\nLast Seen: %s ago"), tmp); + g_free(tmp); + } + + gnt_widget_get_position(widget, &x, &y); + gnt_widget_get_size(widget, &width, NULL); + top = gnt_tree_get_selection_visible_line(tree); + + x += width; + y += top - 1; + + box = gnt_box_new(FALSE, FALSE); + gnt_box_set_toplevel(GNT_BOX(box), TRUE); + GNT_WIDGET_SET_FLAGS(box, GNT_WIDGET_NO_SHADOW); + gnt_box_set_title(GNT_BOX(box), title); + + str = make_sure_text_fits(str); + gnt_util_get_text_bound(str->str, &w, &h); + h = MAX(2, h); + tv = gnt_text_view_new(); + gnt_widget_set_size(tv, w + 1, h); + gnt_box_add_widget(GNT_BOX(box), tv); + + gnt_widget_set_position(box, x, y); + GNT_WIDGET_UNSET_FLAGS(box, GNT_WIDGET_CAN_TAKE_FOCUS); + GNT_WIDGET_SET_FLAGS(box, GNT_WIDGET_TRANSIENT); + gnt_widget_draw(box); + + gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(tv), str->str, GNT_TEXT_FLAG_NORMAL); + gnt_text_view_scroll(GNT_TEXT_VIEW(tv), 0); + + g_free(title); + g_string_free(str, TRUE); + ggblist->tooltip = box; + ggblist->tnode = node; + + gnt_widget_set_name(ggblist->tooltip, "tooltip"); + return FALSE; +} + +static void +draw_tooltip(FinchBlist *ggblist) +{ + /* When an account has signed off, it removes one buddy at a time. + * Drawing the tooltip after removing each buddy is expensive. On + * top of that, if the selected buddy belongs to the disconnected + * account, then retreiving the tooltip for that causes crash. So + * let's make sure we wait for all the buddies to be removed first.*/ + int id = g_timeout_add(0, (GSourceFunc)draw_tooltip_real, ggblist); + g_object_set_data_full(G_OBJECT(ggblist->window), "draw_tooltip_calback", + GINT_TO_POINTER(id), (GDestroyNotify)g_source_remove); +} + +static void +selection_changed(GntWidget *widget, gpointer old, gpointer current, FinchBlist *ggblist) +{ + draw_tooltip(ggblist); +} + +static gboolean +context_menu(GntWidget *widget, FinchBlist *ggblist) +{ + draw_context_menu(ggblist); + return TRUE; +} + +static gboolean +key_pressed(GntWidget *widget, const char *text, FinchBlist *ggblist) +{ + if (text[0] == 27 && text[1] == 0) { + /* Escape was pressed */ + remove_peripherals(ggblist); + } else if (strcmp(text, GNT_KEY_CTRL_O) == 0) { + gaim_prefs_set_bool(PREF_ROOT "/showoffline", + !gaim_prefs_get_bool(PREF_ROOT "/showoffline")); + } else if (GNT_TREE(ggblist->tree)->search == NULL) { + if (strcmp(text, "t") == 0) { + finch_blist_toggle_tag_buddy(gnt_tree_get_selection_data(GNT_TREE(ggblist->tree))); + gnt_bindable_perform_action_named(GNT_BINDABLE(ggblist->tree), "move-down"); + } else if (strcmp(text, "a") == 0) { + finch_blist_place_tagged(gnt_tree_get_selection_data(GNT_TREE(ggblist->tree))); + } else + return FALSE; + } else + return FALSE; + + return TRUE; +} + +static void +update_buddy_display(GaimBuddy *buddy, FinchBlist *ggblist) +{ + GaimContact *contact; + GntTextFormatFlags bflag = 0, cflag = 0; + + contact = gaim_buddy_get_contact(buddy); + + gnt_tree_change_text(GNT_TREE(ggblist->tree), buddy, 0, get_display_name((GaimBlistNode*)buddy)); + gnt_tree_change_text(GNT_TREE(ggblist->tree), contact, 0, get_display_name((GaimBlistNode*)contact)); + + if (ggblist->tagged && g_list_find(ggblist->tagged, buddy)) + bflag |= GNT_TEXT_FLAG_BOLD; + if (ggblist->tagged && g_list_find(ggblist->tagged, contact)) + cflag |= GNT_TEXT_FLAG_BOLD; + + if (ggblist->tnode == (GaimBlistNode*)buddy) + draw_tooltip(ggblist); + + if (gaim_presence_is_idle(gaim_buddy_get_presence(buddy))) { + gnt_tree_set_row_flags(GNT_TREE(ggblist->tree), buddy, bflag | GNT_TEXT_FLAG_DIM); + gnt_tree_set_row_flags(GNT_TREE(ggblist->tree), contact, cflag | GNT_TEXT_FLAG_DIM); + } else { + gnt_tree_set_row_flags(GNT_TREE(ggblist->tree), buddy, bflag); + gnt_tree_set_row_flags(GNT_TREE(ggblist->tree), contact, cflag); + } +} + +static void +buddy_status_changed(GaimBuddy *buddy, GaimStatus *old, GaimStatus *now, FinchBlist *ggblist) +{ + update_buddy_display(buddy, ggblist); +} + +static void +buddy_idle_changed(GaimBuddy *buddy, int old, int new, FinchBlist *ggblist) +{ + update_buddy_display(buddy, ggblist); +} + +static void +remove_peripherals(FinchBlist *ggblist) +{ + if (ggblist->tooltip) + remove_tooltip(ggblist); + else if (ggblist->context) + gnt_widget_destroy(ggblist->context); +} + +static void +size_changed_cb(GntWidget *w, int wi, int h) +{ + int width, height; + gnt_widget_get_size(w, &width, &height); + gaim_prefs_set_int(PREF_ROOT "/size/width", width); + gaim_prefs_set_int(PREF_ROOT "/size/height", height); +} + +static void +save_position_cb(GntWidget *w, int x, int y) +{ + gaim_prefs_set_int(PREF_ROOT "/position/x", x); + gaim_prefs_set_int(PREF_ROOT "/position/y", y); +} + +static void +reset_blist_window(GntWidget *window, gpointer null) +{ + GaimBlistNode *node; + gaim_signals_disconnect_by_handle(finch_blist_get_handle()); + gaim_get_blist()->ui_data = NULL; + + node = gaim_blist_get_root(); + while (node) { + node->ui_data = NULL; + node = gaim_blist_node_next(node, TRUE); + } + + if (ggblist->typing) + g_source_remove(ggblist->typing); + remove_peripherals(ggblist); + if (ggblist->tagged) + g_list_free(ggblist->tagged); + g_free(ggblist); + ggblist = NULL; +} + +static void +populate_buddylist() +{ + GaimBlistNode *node; + GaimBuddyList *list; + + if (strcmp(gaim_prefs_get_string(PREF_ROOT "/sort_type"), "text") == 0) { + gnt_tree_set_compare_func(GNT_TREE(ggblist->tree), + (GCompareFunc)blist_node_compare_text); + } else if (strcmp(gaim_prefs_get_string(PREF_ROOT "/sort_type"), "status") == 0) { + gnt_tree_set_compare_func(GNT_TREE(ggblist->tree), + (GCompareFunc)blist_node_compare_status); + } else if (strcmp(gaim_prefs_get_string(PREF_ROOT "/sort_type"), "log") == 0) { + gnt_tree_set_compare_func(GNT_TREE(ggblist->tree), + (GCompareFunc)blist_node_compare_log); + } + + list = gaim_get_blist(); + node = gaim_blist_get_root(); + while (node) + { + node_update(list, node); + node = gaim_blist_node_next(node, FALSE); + } +} + +static void +destroy_status_list(GList *list) +{ + g_list_foreach(list, (GFunc)g_free, NULL); + g_list_free(list); +} + +static void +populate_status_dropdown() +{ + int i; + GList *iter; + GList *items = NULL; + StatusBoxItem *item = NULL; + + /* First the primitives */ + GaimStatusPrimitive prims[] = {GAIM_STATUS_AVAILABLE, GAIM_STATUS_AWAY, + GAIM_STATUS_INVISIBLE, GAIM_STATUS_OFFLINE, GAIM_STATUS_UNSET}; + + gnt_combo_box_remove_all(GNT_COMBO_BOX(ggblist->status)); + + for (i = 0; prims[i] != GAIM_STATUS_UNSET; i++) + { + item = g_new0(StatusBoxItem, 1); + item->type = STATUS_PRIMITIVE; + item->u.prim = prims[i]; + items = g_list_prepend(items, item); + gnt_combo_box_add_data(GNT_COMBO_BOX(ggblist->status), item, + gaim_primitive_get_name_from_type(prims[i])); + } + + /* Now the popular statuses */ + for (iter = gaim_savedstatuses_get_popular(6); iter; iter = iter->next) + { + item = g_new0(StatusBoxItem, 1); + item->type = STATUS_SAVED_POPULAR; + item->u.saved = iter->data; + items = g_list_prepend(items, item); + gnt_combo_box_add_data(GNT_COMBO_BOX(ggblist->status), item, + gaim_savedstatus_get_title(iter->data)); + } + + /* New savedstatus */ + item = g_new0(StatusBoxItem, 1); + item->type = STATUS_SAVED_NEW; + items = g_list_prepend(items, item); + gnt_combo_box_add_data(GNT_COMBO_BOX(ggblist->status), item, + _("New...")); + + /* More savedstatuses */ + item = g_new0(StatusBoxItem, 1); + item->type = STATUS_SAVED_ALL; + items = g_list_prepend(items, item); + gnt_combo_box_add_data(GNT_COMBO_BOX(ggblist->status), item, + _("Saved...")); + + /* The keys for the combobox are created here, and never used + * anywhere else. So make sure the keys are freed when the widget + * is destroyed. */ + g_object_set_data_full(G_OBJECT(ggblist->status), "list of statuses", + items, (GDestroyNotify)destroy_status_list); +} + +static void +redraw_blist(const char *name, GaimPrefType type, gconstpointer val, gpointer data) +{ + GaimBlistNode *node, *sel; + if (ggblist == NULL || ggblist->window == NULL) + return; + + sel = gnt_tree_get_selection_data(GNT_TREE(ggblist->tree)); + gnt_tree_remove_all(GNT_TREE(ggblist->tree)); + node = gaim_blist_get_root(); + for (; node; node = gaim_blist_node_next(node, TRUE)) + node->ui_data = NULL; + populate_buddylist(); + gnt_tree_set_selected(GNT_TREE(ggblist->tree), sel); + draw_tooltip(ggblist); +} + +void finch_blist_init() +{ + gaim_prefs_add_none(PREF_ROOT); + gaim_prefs_add_none(PREF_ROOT "/size"); + gaim_prefs_add_int(PREF_ROOT "/size/width", 20); + gaim_prefs_add_int(PREF_ROOT "/size/height", 17); + gaim_prefs_add_none(PREF_ROOT "/position"); + gaim_prefs_add_int(PREF_ROOT "/position/x", 0); + gaim_prefs_add_int(PREF_ROOT "/position/y", 0); + gaim_prefs_add_bool(PREF_ROOT "/idletime", TRUE); + gaim_prefs_add_bool(PREF_ROOT "/showoffline", FALSE); + gaim_prefs_add_string(PREF_ROOT "/sort_type", "text"); + + gaim_prefs_connect_callback(finch_blist_get_handle(), + PREF_ROOT "/showoffline", redraw_blist, NULL); + gaim_prefs_connect_callback(finch_blist_get_handle(), + PREF_ROOT "/sort_type", redraw_blist, NULL); + + gaim_signal_connect(gaim_connections_get_handle(), "signed-on", gaim_blist_get_handle(), + G_CALLBACK(account_signed_on_cb), NULL); + return; +} + +static gboolean +remove_typing_cb(gpointer null) +{ + GaimSavedStatus *current; + const char *message, *newmessage; + GaimStatusPrimitive prim, newprim; + StatusBoxItem *item; + + current = gaim_savedstatus_get_current(); + message = gaim_savedstatus_get_message(current); + prim = gaim_savedstatus_get_type(current); + + newmessage = gnt_entry_get_text(GNT_ENTRY(ggblist->statustext)); + item = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(ggblist->status)); + g_return_val_if_fail(item->type == STATUS_PRIMITIVE, FALSE); + newprim = item->u.prim; + + if (newprim != prim || ((message && !newmessage) || + (!message && newmessage) || + (message && newmessage && g_utf8_collate(message, newmessage) != 0))) + { + GaimSavedStatus *status = gaim_savedstatus_find_transient_by_type_and_message(newprim, newmessage); + /* Holy Crap! That's a LAWNG function name */ + if (status == NULL) + { + status = gaim_savedstatus_new(NULL, newprim); + gaim_savedstatus_set_message(status, newmessage); + } + + gaim_savedstatus_activate(status); + } + + gnt_box_give_focus_to_child(GNT_BOX(ggblist->window), ggblist->tree); + if (ggblist->typing) + g_source_remove(ggblist->typing); + ggblist->typing = 0; + return FALSE; +} + +static void +status_selection_changed(GntComboBox *box, StatusBoxItem *old, StatusBoxItem *now, gpointer null) +{ + gnt_entry_set_text(GNT_ENTRY(ggblist->statustext), NULL); + if (now->type == STATUS_SAVED_POPULAR) + { + /* Set the status immediately */ + gaim_savedstatus_activate(now->u.saved); + } + else if (now->type == STATUS_PRIMITIVE) + { + /* Move the focus to the entry box */ + /* XXX: Make sure the selected status can have a message */ + gnt_box_move_focus(GNT_BOX(ggblist->window), 1); + ggblist->typing = g_timeout_add(TYPING_TIMEOUT, (GSourceFunc)remove_typing_cb, NULL); + } + else if (now->type == STATUS_SAVED_ALL) + { + /* Restore the selection to reflect current status. */ + savedstatus_changed(gaim_savedstatus_get_current(), NULL); + gnt_box_give_focus_to_child(GNT_BOX(ggblist->window), ggblist->tree); + finch_savedstatus_show_all(); + } + else if (now->type == STATUS_SAVED_NEW) + { + savedstatus_changed(gaim_savedstatus_get_current(), NULL); + gnt_box_give_focus_to_child(GNT_BOX(ggblist->window), ggblist->tree); + finch_savedstatus_edit(NULL); + } + else + g_return_if_reached(); +} + +static gboolean +status_text_changed(GntEntry *entry, const char *text, gpointer null) +{ + if ((text[0] == 27 || (text[0] == '\t' && text[1] == '\0')) && ggblist->typing == 0) + return FALSE; + + if (ggblist->typing) + g_source_remove(ggblist->typing); + ggblist->typing = 0; + + if (text[0] == '\r' && text[1] == 0) + { + /* Set the status only after you press 'Enter' */ + remove_typing_cb(NULL); + return TRUE; + } + + ggblist->typing = g_timeout_add(TYPING_TIMEOUT, (GSourceFunc)remove_typing_cb, NULL); + return FALSE; +} + +static void +savedstatus_changed(GaimSavedStatus *now, GaimSavedStatus *old) +{ + GList *list; + GaimStatusPrimitive prim; + const char *message; + gboolean found = FALSE, saved = TRUE; + + if (!ggblist) + return; + + /* Block the signals we don't want to emit */ + g_signal_handlers_block_matched(ggblist->status, G_SIGNAL_MATCH_FUNC, + 0, 0, NULL, status_selection_changed, NULL); + g_signal_handlers_block_matched(ggblist->statustext, G_SIGNAL_MATCH_FUNC, + 0, 0, NULL, status_text_changed, NULL); + + prim = gaim_savedstatus_get_type(now); + message = gaim_savedstatus_get_message(now); + + /* Rebuild the status dropdown */ + populate_status_dropdown(); + + while (!found) { + list = g_object_get_data(G_OBJECT(ggblist->status), "list of statuses"); + for (; list; list = list->next) + { + StatusBoxItem *item = list->data; + if ((saved && item->type != STATUS_PRIMITIVE && item->u.saved == now) || + (!saved && item->type == STATUS_PRIMITIVE && item->u.prim == prim)) + { + char *mess = gaim_unescape_html(message); + gnt_combo_box_set_selected(GNT_COMBO_BOX(ggblist->status), item); + gnt_entry_set_text(GNT_ENTRY(ggblist->statustext), mess); + gnt_widget_draw(ggblist->status); + g_free(mess); + found = TRUE; + break; + } + } + if (!saved) + break; + saved = FALSE; + } + + g_signal_handlers_unblock_matched(ggblist->status, G_SIGNAL_MATCH_FUNC, + 0, 0, NULL, status_selection_changed, NULL); + g_signal_handlers_unblock_matched(ggblist->statustext, G_SIGNAL_MATCH_FUNC, + 0, 0, NULL, status_text_changed, NULL); +} + +static int +blist_node_compare_text(GaimBlistNode *n1, GaimBlistNode *n2) +{ + const char *s1, *s2; + char *us1, *us2; + int ret; + + g_return_val_if_fail(n1->type == n2->type, -1); + + switch (n1->type) + { + case GAIM_BLIST_GROUP_NODE: + s1 = ((GaimGroup*)n1)->name; + s2 = ((GaimGroup*)n2)->name; + break; + case GAIM_BLIST_CHAT_NODE: + s1 = gaim_chat_get_name((GaimChat*)n1); + s2 = gaim_chat_get_name((GaimChat*)n2); + break; + case GAIM_BLIST_BUDDY_NODE: + return gaim_presence_compare(gaim_buddy_get_presence((GaimBuddy*)n1), + gaim_buddy_get_presence((GaimBuddy*)n2)); + break; + case GAIM_BLIST_CONTACT_NODE: + s1 = gaim_contact_get_alias((GaimContact*)n1); + s2 = gaim_contact_get_alias((GaimContact*)n2); + break; + default: + return -1; + } + + us1 = g_utf8_strup(s1, -1); + us2 = g_utf8_strup(s2, -1); + ret = g_utf8_collate(us1, us2); + g_free(us1); + g_free(us2); + + return ret; +} + +static int +blist_node_compare_status(GaimBlistNode *n1, GaimBlistNode *n2) +{ + int ret; + + g_return_val_if_fail(n1->type == n2->type, -1); + + switch (n1->type) { + case GAIM_BLIST_CONTACT_NODE: + n1 = (GaimBlistNode*)gaim_contact_get_priority_buddy((GaimContact*)n1); + n2 = (GaimBlistNode*)gaim_contact_get_priority_buddy((GaimContact*)n2); + /* now compare the presence of the priority buddies */ + case GAIM_BLIST_BUDDY_NODE: + ret = gaim_presence_compare(gaim_buddy_get_presence((GaimBuddy*)n1), + gaim_buddy_get_presence((GaimBuddy*)n2)); + if (ret != 0) + return ret; + break; + default: + break; + } + + /* Sort alphabetically if presence is not comparable */ + ret = blist_node_compare_text(n1, n2); + + return ret; +} + +static int +get_contact_log_size(GaimBlistNode *c) +{ + int log = 0; + GaimBlistNode *node; + + for (node = c->child; node; node = node->next) { + GaimBuddy *b = (GaimBuddy*)node; + log += gaim_log_get_total_size(GAIM_LOG_IM, b->name, b->account); + } + + return log; +} + +static int +blist_node_compare_log(GaimBlistNode *n1, GaimBlistNode *n2) +{ + int ret; + GaimBuddy *b1, *b2; + + g_return_val_if_fail(n1->type == n2->type, -1); + + switch (n1->type) { + case GAIM_BLIST_BUDDY_NODE: + b1 = (GaimBuddy*)n1; + b2 = (GaimBuddy*)n2; + ret = gaim_log_get_total_size(GAIM_LOG_IM, b2->name, b2->account) - + gaim_log_get_total_size(GAIM_LOG_IM, b1->name, b1->account); + if (ret != 0) + return ret; + break; + case GAIM_BLIST_CONTACT_NODE: + ret = get_contact_log_size(n2) - get_contact_log_size(n1); + if (ret != 0) + return ret; + break; + default: + break; + } + ret = blist_node_compare_text(n1, n2); + return ret; +} + +static gboolean +blist_clicked(GntTree *tree, GntMouseEvent event, int x, int y, gpointer ggblist) +{ + if (event == GNT_RIGHT_MOUSE_DOWN) { + draw_context_menu(ggblist); + } + return FALSE; +} + +static void +plugin_action(GntMenuItem *item, gpointer data) +{ + GaimPluginAction *action = data; + if (action && action->callback) + action->callback(action); +} + +static void +build_plugin_actions(GntMenuItem *item, GaimPlugin *plugin, gpointer context) +{ + GntWidget *sub = gnt_menu_new(GNT_MENU_POPUP); + GList *actions; + GntMenuItem *menuitem; + + gnt_menuitem_set_submenu(item, GNT_MENU(sub)); + for (actions = GAIM_PLUGIN_ACTIONS(plugin, context); actions; + actions = g_list_delete_link(actions, actions)) { + if (actions->data) { + GaimPluginAction *action = actions->data; + action->plugin = plugin; + action->context = context; + menuitem = gnt_menuitem_new(action->label); + gnt_menu_add_item(GNT_MENU(sub), menuitem); + + gnt_menuitem_set_callback(menuitem, plugin_action, action); + g_object_set_data_full(G_OBJECT(menuitem), "plugin_action", + action, (GDestroyNotify)gaim_plugin_action_free); + } + } +} + +static void +reconstruct_plugins_menu() +{ + GntWidget *sub; + GntMenuItem *plg; + GList *iter; + + if (!ggblist) + return; + + if (ggblist->plugins == NULL) + ggblist->plugins = gnt_menuitem_new(_("Plugins")); + + plg = ggblist->plugins; + sub = gnt_menu_new(GNT_MENU_POPUP); + gnt_menuitem_set_submenu(plg, GNT_MENU(sub)); + + for (iter = gaim_plugins_get_loaded(); iter; iter = iter->next) { + GaimPlugin *plugin = iter->data; + GntMenuItem *item; + if (GAIM_IS_PROTOCOL_PLUGIN(plugin)) + continue; + + if (!GAIM_PLUGIN_HAS_ACTIONS(plugin)) + continue; + + item = gnt_menuitem_new(_(plugin->info->name)); + gnt_menu_add_item(GNT_MENU(sub), item); + build_plugin_actions(item, plugin, NULL); + } +} + +static void +reconstruct_accounts_menu() +{ + GntWidget *sub; + GntMenuItem *acc, *item; + GList *iter; + + if (!ggblist) + return; + + if (ggblist->accounts == NULL) + ggblist->accounts = gnt_menuitem_new(_("Accounts")); + + acc = ggblist->accounts; + sub = gnt_menu_new(GNT_MENU_POPUP); + gnt_menuitem_set_submenu(acc, GNT_MENU(sub)); + + for (iter = gaim_accounts_get_all_active(); iter; + iter = g_list_delete_link(iter, iter)) { + GaimAccount *account = iter->data; + GaimConnection *gc = gaim_account_get_connection(account); + GaimPlugin *prpl; + + if (!gc || !GAIM_CONNECTION_IS_CONNECTED(gc)) + continue; + prpl = gc->prpl; + + if (GAIM_PLUGIN_HAS_ACTIONS(prpl)) { + item = gnt_menuitem_new(gaim_account_get_username(account)); + gnt_menu_add_item(GNT_MENU(sub), item); + build_plugin_actions(item, prpl, gc); + } + } +} + +static void +account_signed_on_cb() +{ + GaimBlistNode *node; + + for (node = gaim_blist_get_root(); node; + node = gaim_blist_node_next(node, FALSE)) { + if (GAIM_BLIST_NODE_IS_CHAT(node)) { + GaimChat *chat = (GaimChat*)node; + if (gaim_blist_node_get_bool(node, "gnt-autojoin")) + serv_join_chat(gaim_account_get_connection(chat->account), chat->components); + } + } +} + +static void show_offline_cb(GntMenuItem *item, gpointer n) +{ + gaim_prefs_set_bool(PREF_ROOT "/showoffline", + !gaim_prefs_get_bool(PREF_ROOT "/showoffline")); +} + +static void sort_blist_change_cb(GntMenuItem *item, gpointer n) +{ + gaim_prefs_set_string(PREF_ROOT "/sort_type", n); +} + +/* XXX: send_im_select* -- Xerox */ +static void +send_im_select_cb(gpointer data, GaimRequestFields *fields) +{ + GaimAccount *account; + const char *username; + + account = gaim_request_fields_get_account(fields, "account"); + username = gaim_request_fields_get_string(fields, "screenname"); + + gaim_conversation_new(GAIM_CONV_TYPE_IM, account, username); +} + +static void +send_im_select(GntMenuItem *item, gpointer n) +{ + GaimRequestFields *fields; + GaimRequestFieldGroup *group; + GaimRequestField *field; + + fields = gaim_request_fields_new(); + + group = gaim_request_field_group_new(NULL); + gaim_request_fields_add_group(fields, group); + + field = gaim_request_field_string_new("screenname", _("_Name"), NULL, FALSE); + gaim_request_field_set_type_hint(field, "screenname"); + gaim_request_field_set_required(field, TRUE); + gaim_request_field_group_add_field(group, field); + + field = gaim_request_field_account_new("account", _("_Account"), NULL); + gaim_request_field_set_type_hint(field, "account"); + gaim_request_field_set_visible(field, + (gaim_connections_get_all() != NULL && + gaim_connections_get_all()->next != NULL)); + gaim_request_field_set_required(field, TRUE); + gaim_request_field_group_add_field(group, field); + + gaim_request_fields(gaim_get_blist(), _("New Instant Message"), + NULL, + _("Please enter the screen name or alias of the person " + "you would like to IM."), + fields, + _("OK"), G_CALLBACK(send_im_select_cb), + _("Cancel"), NULL, + NULL); +} + +static void +create_menu() +{ + GntWidget *menu, *sub; + GntMenuItem *item; + GntWindow *window; + + if (!ggblist) + return; + + window = GNT_WINDOW(ggblist->window); + ggblist->menu = menu = gnt_menu_new(GNT_MENU_TOPLEVEL); + gnt_window_set_menu(window, GNT_MENU(menu)); + + item = gnt_menuitem_new(_("Options")); + gnt_menu_add_item(GNT_MENU(menu), item); + + sub = gnt_menu_new(GNT_MENU_POPUP); + gnt_menuitem_set_submenu(item, GNT_MENU(sub)); + + item = gnt_menuitem_new(_("Send IM...")); + gnt_menu_add_item(GNT_MENU(sub), item); + gnt_menuitem_set_callback(GNT_MENUITEM(item), send_im_select, NULL); + + item = gnt_menuitem_check_new(_("Toggle offline buddies")); + gnt_menuitem_check_set_checked(GNT_MENUITEM_CHECK(item), + gaim_prefs_get_bool(PREF_ROOT "/showoffline")); + gnt_menu_add_item(GNT_MENU(sub), item); + gnt_menuitem_set_callback(GNT_MENUITEM(item), show_offline_cb, NULL); + + item = gnt_menuitem_new(_("Sort by status")); + gnt_menu_add_item(GNT_MENU(sub), item); + gnt_menuitem_set_callback(GNT_MENUITEM(item), sort_blist_change_cb, "status"); + + item = gnt_menuitem_new(_("Sort alphabetically")); + gnt_menu_add_item(GNT_MENU(sub), item); + gnt_menuitem_set_callback(GNT_MENUITEM(item), sort_blist_change_cb, "text"); + + item = gnt_menuitem_new(_("Sort by log size")); + gnt_menu_add_item(GNT_MENU(sub), item); + gnt_menuitem_set_callback(GNT_MENUITEM(item), sort_blist_change_cb, "log"); + + reconstruct_accounts_menu(); + gnt_menu_add_item(GNT_MENU(menu), ggblist->accounts); + + reconstruct_plugins_menu(); + gnt_menu_add_item(GNT_MENU(menu), ggblist->plugins); +} + +void finch_blist_show() +{ + blist_show(gaim_get_blist()); +} + +static void +blist_show(GaimBuddyList *list) +{ + if (ggblist == NULL) + new_list(list); + else if (ggblist->window) + return; + + ggblist->window = gnt_vwindow_new(FALSE); + gnt_widget_set_name(ggblist->window, "buddylist"); + gnt_box_set_toplevel(GNT_BOX(ggblist->window), TRUE); + gnt_box_set_title(GNT_BOX(ggblist->window), _("Buddy List")); + gnt_box_set_pad(GNT_BOX(ggblist->window), 0); + + ggblist->tree = gnt_tree_new(); + + GNT_WIDGET_SET_FLAGS(ggblist->tree, GNT_WIDGET_NO_BORDER); + gnt_widget_set_size(ggblist->tree, gaim_prefs_get_int(PREF_ROOT "/size/width"), + gaim_prefs_get_int(PREF_ROOT "/size/height")); + gnt_widget_set_position(ggblist->window, gaim_prefs_get_int(PREF_ROOT "/position/x"), + gaim_prefs_get_int(PREF_ROOT "/position/y")); + + gnt_tree_set_col_width(GNT_TREE(ggblist->tree), 0, + gaim_prefs_get_int(PREF_ROOT "/size/width") - 1); + + gnt_box_add_widget(GNT_BOX(ggblist->window), ggblist->tree); + + ggblist->status = gnt_combo_box_new(); + gnt_box_add_widget(GNT_BOX(ggblist->window), ggblist->status); + ggblist->statustext = gnt_entry_new(NULL); + gnt_box_add_widget(GNT_BOX(ggblist->window), ggblist->statustext); + + gnt_widget_show(ggblist->window); + + gaim_signal_connect(gaim_connections_get_handle(), "signed-on", finch_blist_get_handle(), + GAIM_CALLBACK(reconstruct_accounts_menu), NULL); + gaim_signal_connect(gaim_connections_get_handle(), "signed-off", finch_blist_get_handle(), + GAIM_CALLBACK(reconstruct_accounts_menu), NULL); + gaim_signal_connect(gaim_blist_get_handle(), "buddy-status-changed", finch_blist_get_handle(), + GAIM_CALLBACK(buddy_status_changed), ggblist); + gaim_signal_connect(gaim_blist_get_handle(), "buddy-idle-changed", finch_blist_get_handle(), + GAIM_CALLBACK(buddy_idle_changed), ggblist); + + gaim_signal_connect(gaim_plugins_get_handle(), "plugin-load", finch_blist_get_handle(), + GAIM_CALLBACK(reconstruct_plugins_menu), NULL); + gaim_signal_connect(gaim_plugins_get_handle(), "plugin-unload", finch_blist_get_handle(), + GAIM_CALLBACK(reconstruct_plugins_menu), NULL); + +#if 0 + gaim_signal_connect(gaim_blist_get_handle(), "buddy-signed-on", finch_blist_get_handle(), + GAIM_CALLBACK(buddy_signed_on), ggblist); + gaim_signal_connect(gaim_blist_get_handle(), "buddy-signed-off", finch_blist_get_handle(), + GAIM_CALLBACK(buddy_signed_off), ggblist); + + /* These I plan to use to indicate unread-messages etc. */ + gaim_signal_connect(gaim_conversations_get_handle(), "received-im-msg", finch_blist_get_handle(), + GAIM_CALLBACK(received_im_msg), list); + gaim_signal_connect(gaim_conversations_get_handle(), "sent-im-msg", finch_blist_get_handle(), + GAIM_CALLBACK(sent_im_msg), NULL); + + gaim_signal_connect(gaim_conversations_get_handle(), "received-chat-msg", finch_blist_get_handle(), + GAIM_CALLBACK(received_chat_msg), list); +#endif + + g_signal_connect(G_OBJECT(ggblist->tree), "selection_changed", G_CALLBACK(selection_changed), ggblist); + g_signal_connect(G_OBJECT(ggblist->tree), "key_pressed", G_CALLBACK(key_pressed), ggblist); + g_signal_connect(G_OBJECT(ggblist->tree), "context-menu", G_CALLBACK(context_menu), ggblist); + g_signal_connect_after(G_OBJECT(ggblist->tree), "clicked", G_CALLBACK(blist_clicked), ggblist); + g_signal_connect(G_OBJECT(ggblist->tree), "activate", G_CALLBACK(selection_activate), ggblist); + g_signal_connect_data(G_OBJECT(ggblist->tree), "gained-focus", G_CALLBACK(draw_tooltip), + ggblist, 0, G_CONNECT_AFTER | G_CONNECT_SWAPPED); + g_signal_connect_data(G_OBJECT(ggblist->tree), "lost-focus", G_CALLBACK(remove_peripherals), + ggblist, 0, G_CONNECT_AFTER | G_CONNECT_SWAPPED); + g_signal_connect(G_OBJECT(ggblist->tree), "size_changed", G_CALLBACK(size_changed_cb), NULL); + g_signal_connect(G_OBJECT(ggblist->window), "position_set", G_CALLBACK(save_position_cb), NULL); + g_signal_connect(G_OBJECT(ggblist->window), "destroy", G_CALLBACK(reset_blist_window), NULL); + + /* Status signals */ + gaim_signal_connect(gaim_savedstatuses_get_handle(), "savedstatus-changed", finch_blist_get_handle(), + GAIM_CALLBACK(savedstatus_changed), NULL); + g_signal_connect(G_OBJECT(ggblist->status), "selection_changed", + G_CALLBACK(status_selection_changed), NULL); + g_signal_connect(G_OBJECT(ggblist->statustext), "key_pressed", + G_CALLBACK(status_text_changed), NULL); + + create_menu(); + + populate_buddylist(); + + savedstatus_changed(gaim_savedstatus_get_current(), NULL); +} + +void finch_blist_uninit() +{ + if (ggblist == NULL) + return; + + gnt_widget_destroy(ggblist->window); + g_free(ggblist); + ggblist = NULL; +} + +gboolean finch_blist_get_position(int *x, int *y) +{ + if (!ggblist || !ggblist->window) + return FALSE; + gnt_widget_get_position(ggblist->window, x, y); + return TRUE; +} + +void finch_blist_set_position(int x, int y) +{ + gnt_widget_set_position(ggblist->window, x, y); +} + +gboolean finch_blist_get_size(int *width, int *height) +{ + if (!ggblist || !ggblist->window) + return FALSE; + gnt_widget_get_size(ggblist->window, width, height); + return TRUE; +} + +void finch_blist_set_size(int width, int height) +{ + gnt_widget_set_size(ggblist->window, width, height); +} + diff -r 317e7613e581 -r 0e3a8505ebbe finch/gntblist.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/gntblist.h Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,95 @@ +/** + * @file gntblist.h GNT BuddyList API + * @ingroup gntui + * + * gaim + * + * Gaim is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _GNT_BLIST_H +#define _GNT_BLIST_H + +#include "blist.h" + +/********************************************************************** + * @name GNT BuddyList API + **********************************************************************/ +/*@{*/ + +/** + * Get the ui-functions. + * + * @return The GaimBlistUiOps structure populated with the appropriate functions. + */ +GaimBlistUiOps * finch_blist_get_ui_ops(void); + +/** + * Perform necessary initializations. + */ +void finch_blist_init(void); + +/** + * Perform necessary uninitializations. + */ +void finch_blist_uninit(void); + +/** + * Show the buddy list. + */ +void finch_blist_show(void); + +/** + * Get the position of the buddy list. + * + * @param x The x-coordinate is set here if not @ NULL. + * @param y The y-coordinate is set here if not @c NULL. + * + * @return Returns @c TRUE if the values were set, @c FALSE otherwise. + */ +gboolean finch_blist_get_position(int *x, int *y); + +/** + * Set the position of the buddy list. + * + * @param x The x-coordinate of the buddy list. + * @param y The y-coordinate of the buddy list. + */ +void finch_blist_set_position(int x, int y); + +/** + * Get the size of the buddy list. + * + * @param width The width is set here if not @ NULL. + * @param height The height is set here if not @c NULL. + * + * @return Returns @c TRUE if the values were set, @c FALSE otherwise. + */ +gboolean finch_blist_get_size(int *width, int *height); + +/** + * Set the size of the buddy list. + * + * @param width The width of the buddy list. + * @param height The height of the buddy list. + */ +void finch_blist_set_size(int width, int height); + +/*@}*/ + +#endif diff -r 317e7613e581 -r 0e3a8505ebbe finch/gntconn.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/gntconn.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,75 @@ +/** + * @file gntconn.c GNT Connection API + * @ingroup gntui + * + * gaim + * + * Gaim is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "account.h" +#include "core.h" +#include "request.h" + +#include "gntconn.h" +#include "gntgaim.h" + +static void +finch_connection_report_disconnect(GaimConnection *gc, const char *text) +{ + char *act, *primary, *secondary; + GaimAccount *account = gaim_connection_get_account(gc); + + act = g_strdup_printf(_("%s (%s)"), gaim_account_get_username(account), + gaim_account_get_protocol_name(account)); + + primary = g_strdup_printf(_("%s disconnected."), act); + secondary = g_strdup_printf(_("%s was disconnected due to the following error:\n%s"), + act, text); + + gaim_request_action(account, _("Connection Error"), primary, secondary, 1, + account, 2, + _("OK"), NULL, + _("Connect"), + GAIM_CALLBACK(gaim_account_connect)); + + g_free(act); + g_free(primary); + g_free(secondary); +} + +static GaimConnectionUiOps ops = +{ + .connect_progress = NULL, + .connected = NULL, + .disconnected = NULL, + .notice = NULL, + .report_disconnect = finch_connection_report_disconnect +}; + +GaimConnectionUiOps *finch_connections_get_ui_ops() +{ + return &ops; +} + +void finch_connections_init() +{} + +void finch_connections_uninit() +{} + diff -r 317e7613e581 -r 0e3a8505ebbe finch/gntconn.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/gntconn.h Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,54 @@ +/** + * @file gntconn.h GNT Connection API + * @ingroup gntui + * + * gaim + * + * Gaim is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _GNT_CONN_H +#define _GNT_CONN_H + +#include "connection.h" + +/********************************************************************** + * @name GNT Connection API + **********************************************************************/ +/*@{*/ + +/** + * Get the ui-functions. + * + * @return The GaimConnectionUiOps structure populated with the appropriate functions. + */ +GaimConnectionUiOps *finch_connections_get_ui_ops(void); + +/** + * Perform necessary initializations. + */ +void finch_connections_init(void); + +/** + * Perform necessary uninitializations. + */ +void finch_connections_uninit(void); + +/*@}*/ + +#endif diff -r 317e7613e581 -r 0e3a8505ebbe finch/gntconv.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/gntconv.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,760 @@ +/** + * @file gntconv.c GNT Conversation API + * @ingroup gntui + * + * gaim + * + * Gaim is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include + +#include +#include +#include +#include + +#include "gntgaim.h" +#include "gntaccount.h" +#include "gntblist.h" +#include "gntconv.h" +#include "gntdebug.h" +#include "gntplugin.h" +#include "gntprefs.h" +#include "gntstatus.h" + +#include "gnt.h" +#include "gntbox.h" +#include "gntentry.h" +#include "gnttextview.h" + +#define PREF_ROOT "/gaim/gnt/conversations" + +#include "config.h" + +static void +send_typing_notification(GntWidget *w, FinchConv *ggconv) +{ + const char *text = gnt_entry_get_text(GNT_ENTRY(ggconv->entry)); + gboolean empty = (!text || !*text); + if (gaim_prefs_get_bool("/gaim/gnt/conversations/notify_typing")) { + GaimConversation *conv = ggconv->active_conv; + GaimConvIm *im = GAIM_CONV_IM(conv); + if (!empty) { + gboolean send = (gaim_conv_im_get_send_typed_timeout(im) == 0); + + gaim_conv_im_stop_send_typed_timeout(im); + gaim_conv_im_start_send_typed_timeout(im); + if (send || (gaim_conv_im_get_type_again(im) != 0 && + time(NULL) > gaim_conv_im_get_type_again(im))) { + unsigned int timeout; + timeout = serv_send_typing(gaim_conversation_get_gc(conv), + gaim_conversation_get_name(conv), + GAIM_TYPING); + gaim_conv_im_set_type_again(im, timeout); + } + } else { + gaim_conv_im_stop_send_typed_timeout(im); + + serv_send_typing(gaim_conversation_get_gc(conv), + gaim_conversation_get_name(conv), + GAIM_NOT_TYPING); + } + } +} + +static gboolean +entry_key_pressed(GntWidget *w, const char *key, FinchConv *ggconv) +{ + if (key[0] == '\r' && key[1] == 0) + { + const char *text = gnt_entry_get_text(GNT_ENTRY(ggconv->entry)); + if (*text == '/') + { + GaimConversation *conv = ggconv->active_conv; + GaimCmdStatus status; + const char *cmdline = text + 1; + char *error = NULL, *escape; + + escape = g_markup_escape_text(cmdline, -1); + status = gaim_cmd_do_command(conv, cmdline, escape, &error); + g_free(escape); + + switch (status) + { + case GAIM_CMD_STATUS_OK: + break; + case GAIM_CMD_STATUS_NOT_FOUND: + gaim_conversation_write(conv, "", _("No such command."), + GAIM_MESSAGE_NO_LOG, time(NULL)); + break; + case GAIM_CMD_STATUS_WRONG_ARGS: + gaim_conversation_write(conv, "", _("Syntax Error: You typed the wrong number of arguments " + "to that command."), + GAIM_MESSAGE_NO_LOG, time(NULL)); + break; + case GAIM_CMD_STATUS_FAILED: + gaim_conversation_write(conv, "", error ? error : _("Your command failed for an unknown reason."), + GAIM_MESSAGE_NO_LOG, time(NULL)); + break; + case GAIM_CMD_STATUS_WRONG_TYPE: + if(gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM) + gaim_conversation_write(conv, "", _("That command only works in chats, not IMs."), + GAIM_MESSAGE_NO_LOG, time(NULL)); + else + gaim_conversation_write(conv, "", _("That command only works in IMs, not chats."), + GAIM_MESSAGE_NO_LOG, time(NULL)); + break; + case GAIM_CMD_STATUS_WRONG_PRPL: + gaim_conversation_write(conv, "", _("That command doesn't work on this protocol."), + GAIM_MESSAGE_NO_LOG, time(NULL)); + break; + } + g_free(error); +#if 0 + gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(ggconv->tv), + _("Commands are not supported yet. Message was NOT sent."), + GNT_TEXT_FLAG_DIM | GNT_TEXT_FLAG_UNDERLINE); + gnt_text_view_next_line(GNT_TEXT_VIEW(ggconv->tv)); + gnt_text_view_scroll(GNT_TEXT_VIEW(ggconv->tv), 0); +#endif + } + else + { + char *escape = g_markup_escape_text(text, -1); + char *apos = gaim_strreplace(escape, "'", "'"); + g_free(escape); + escape = apos; + switch (gaim_conversation_get_type(ggconv->active_conv)) + { + case GAIM_CONV_TYPE_IM: + gaim_conv_im_send_with_flags(GAIM_CONV_IM(ggconv->active_conv), escape, GAIM_MESSAGE_SEND); + break; + case GAIM_CONV_TYPE_CHAT: + gaim_conv_chat_send(GAIM_CONV_CHAT(ggconv->active_conv), escape); + break; + default: + g_free(escape); + g_return_val_if_reached(FALSE); + } + g_free(escape); + gaim_idle_touch(); + } + gnt_entry_add_to_history(GNT_ENTRY(ggconv->entry), text); + gnt_entry_clear(GNT_ENTRY(ggconv->entry)); + return TRUE; + } + else if (key[0] == 27) + { + if (strcmp(key, GNT_KEY_DOWN) == 0) + gnt_text_view_scroll(GNT_TEXT_VIEW(ggconv->tv), 1); + else if (strcmp(key, GNT_KEY_UP) == 0) + gnt_text_view_scroll(GNT_TEXT_VIEW(ggconv->tv), -1); + else if (strcmp(key, GNT_KEY_PGDOWN) == 0) + gnt_text_view_scroll(GNT_TEXT_VIEW(ggconv->tv), ggconv->tv->priv.height - 2); + else if (strcmp(key, GNT_KEY_PGUP) == 0) + gnt_text_view_scroll(GNT_TEXT_VIEW(ggconv->tv), -(ggconv->tv->priv.height - 2)); + else + return FALSE; + return TRUE; + } + else + { + } + + return FALSE; +} + +static void +closing_window(GntWidget *window, FinchConv *ggconv) +{ + GList *list = ggconv->list; + ggconv->window = NULL; + while (list) { + GaimConversation *conv = list->data; + list = list->next; + gaim_conversation_destroy(conv); + } +} + +static void +size_changed_cb(GntWidget *widget, int width, int height) +{ + int w, h; + gnt_widget_get_size(widget, &w, &h); + gaim_prefs_set_int(PREF_ROOT "/size/width", w); + gaim_prefs_set_int(PREF_ROOT "/size/height", h); +} + +static void +save_position_cb(GntWidget *w, int x, int y) +{ + gaim_prefs_set_int(PREF_ROOT "/position/x", x); + gaim_prefs_set_int(PREF_ROOT "/position/y", y); +} + +static GaimConversation * +find_conv_with_contact(GaimConversation *conv) +{ + GaimBlistNode *node; + GaimBuddy *buddy = gaim_find_buddy(conv->account, conv->name); + GaimConversation *ret = NULL; + + if (!buddy) + return NULL; + + for (node = ((GaimBlistNode*)buddy)->parent->child; node; node = node->next) { + if (node == (GaimBlistNode*)buddy) + continue; + if ((ret = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, + ((GaimBuddy*)node)->name, ((GaimBuddy*)node)->account)) != NULL) + break; + } + return ret; +} + +static char * +get_conversation_title(GaimConversation *conv, GaimAccount *account) +{ + return g_strdup_printf(_("%s (%s -- %s)"), gaim_conversation_get_title(conv), + gaim_account_get_username(account), gaim_account_get_protocol_name(account)); +} + +static void +update_buddy_typing(GaimAccount *account, const char *who, gpointer null) +{ + GaimConversation *conv; + FinchConv *ggc; + GaimConvIm *im = NULL; + char *title, *str; + + conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, who, account); + + if (!conv) + return; + + im = GAIM_CONV_IM(conv); + ggc = conv->ui_data; + + if (gaim_conv_im_get_typing_state(im) == GAIM_TYPING) { + int scroll; + str = get_conversation_title(conv, account); + title = g_strdup_printf(_("%s [%s]"), str, + gnt_ascii_only() ? "T" : "\342\243\277"); + g_free(str); + + scroll = gnt_text_view_get_lines_below(GNT_TEXT_VIEW(ggc->tv)); + str = g_strdup_printf(_("\n%s is typing..."), gaim_conversation_get_name(conv)); + /* Updating is a little buggy. So just remove and add a new one */ + gnt_text_view_tag_change(GNT_TEXT_VIEW(ggc->tv), "typing", NULL, TRUE); + gnt_text_view_append_text_with_tag(GNT_TEXT_VIEW(ggc->tv), + str, GNT_TEXT_FLAG_DIM, "typing"); + g_free(str); + if (scroll <= 1) + gnt_text_view_scroll(GNT_TEXT_VIEW(ggc->tv), 0); + } else { + title = get_conversation_title(conv, account); + gnt_text_view_tag_change(GNT_TEXT_VIEW(ggc->tv), "typing", NULL, TRUE); + } + gnt_screen_rename_widget(ggc->window, title); + g_free(title); +} + +static gpointer +finch_conv_get_handle() +{ + static int handle; + return &handle; +} + +static void +finch_create_conversation(GaimConversation *conv) +{ + FinchConv *ggc = conv->ui_data; + char *title; + GaimConversationType type; + GaimConversation *cc; + GaimAccount *account; + + if (ggc) + return; + + cc = find_conv_with_contact(conv); + if (cc && cc->ui_data) + ggc = cc->ui_data; + else + ggc = g_new0(FinchConv, 1); + + ggc->list = g_list_prepend(ggc->list, conv); + ggc->active_conv = conv; + conv->ui_data = ggc; + + if (cc && cc->ui_data) { + finch_conversation_set_active(conv); + return; + } + + account = gaim_conversation_get_account(conv); + type = gaim_conversation_get_type(conv); + title = get_conversation_title(conv, account); + + ggc->window = gnt_box_new(FALSE, TRUE); + gnt_box_set_title(GNT_BOX(ggc->window), title); + gnt_box_set_toplevel(GNT_BOX(ggc->window), TRUE); + gnt_box_set_pad(GNT_BOX(ggc->window), 0); + gnt_widget_set_name(ggc->window, "conversation-window"); + + ggc->tv = gnt_text_view_new(); + gnt_box_add_widget(GNT_BOX(ggc->window), ggc->tv); + gnt_widget_set_name(ggc->tv, "conversation-window-textview"); + gnt_widget_set_size(ggc->tv, gaim_prefs_get_int(PREF_ROOT "/size/width"), + gaim_prefs_get_int(PREF_ROOT "/size/height")); + + ggc->entry = gnt_entry_new(NULL); + gnt_box_add_widget(GNT_BOX(ggc->window), ggc->entry); + gnt_widget_set_name(ggc->entry, "conversation-window-entry"); + gnt_entry_set_history_length(GNT_ENTRY(ggc->entry), -1); + gnt_entry_set_word_suggest(GNT_ENTRY(ggc->entry), TRUE); + gnt_entry_set_always_suggest(GNT_ENTRY(ggc->entry), FALSE); + + g_signal_connect_after(G_OBJECT(ggc->entry), "key_pressed", G_CALLBACK(entry_key_pressed), ggc); + g_signal_connect(G_OBJECT(ggc->window), "destroy", G_CALLBACK(closing_window), ggc); + + gnt_widget_set_position(ggc->window, gaim_prefs_get_int(PREF_ROOT "/position/x"), + gaim_prefs_get_int(PREF_ROOT "/position/y")); + gnt_widget_show(ggc->window); + + g_signal_connect(G_OBJECT(ggc->tv), "size_changed", G_CALLBACK(size_changed_cb), NULL); + g_signal_connect(G_OBJECT(ggc->window), "position_set", G_CALLBACK(save_position_cb), NULL); + + if (type == GAIM_CONV_TYPE_IM) { + g_signal_connect(G_OBJECT(ggc->entry), "text_changed", G_CALLBACK(send_typing_notification), ggc); + gaim_signal_connect(gaim_conversations_get_handle(), "buddy-typing", finch_conv_get_handle(), + GAIM_CALLBACK(update_buddy_typing), NULL); + gaim_signal_connect(gaim_conversations_get_handle(), "buddy-typing-stopped", finch_conv_get_handle(), + GAIM_CALLBACK(update_buddy_typing), NULL); + } + + g_free(title); +} + +static void +finch_destroy_conversation(GaimConversation *conv) +{ + /* do stuff here */ + FinchConv *ggc = conv->ui_data; + ggc->list = g_list_remove(ggc->list, conv); + if (ggc->list && conv == ggc->active_conv) + ggc->active_conv = ggc->list->data; + + if (ggc->list == NULL) { + gnt_widget_destroy(ggc->window); + g_free(ggc); + } +} + +static void +finch_write_common(GaimConversation *conv, const char *who, const char *message, + GaimMessageFlags flags, time_t mtime) +{ + FinchConv *ggconv = conv->ui_data; + char *strip, *newline; + GntTextFormatFlags fl = 0; + int pos; + gboolean notify; + + g_return_if_fail(ggconv != NULL); + + if (ggconv->active_conv != conv) { + if (flags & (GAIM_MESSAGE_SEND | GAIM_MESSAGE_RECV)) + finch_conversation_set_active(conv); + else + return; + } + + pos = gnt_text_view_get_lines_below(GNT_TEXT_VIEW(ggconv->tv)); + + notify = !!gnt_text_view_tag_change(GNT_TEXT_VIEW(ggconv->tv), "typing", NULL, TRUE); + gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(ggconv->tv), "\n", GNT_TEXT_FLAG_NORMAL); + + /* Unnecessary to print the timestamp for delayed message */ + if (!(flags & GAIM_MESSAGE_DELAYED) && + gaim_prefs_get_bool("/gaim/gnt/conversations/timestamps")) + gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(ggconv->tv), + gaim_utf8_strftime("(%H:%M:%S) ", localtime(&mtime)), GNT_TEXT_FLAG_DIM); + + if (flags & GAIM_MESSAGE_AUTO_RESP) + gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(ggconv->tv), + _(" "), GNT_TEXT_FLAG_BOLD); + + if (who && *who && (flags & (GAIM_MESSAGE_SEND | GAIM_MESSAGE_RECV))) + { + char * name = NULL; + + if (gaim_message_meify((char*)message, -1)) + name = g_strdup_printf("*** %s ", who); + else + name = g_strdup_printf("%s: ", who); + + gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(ggconv->tv), + name, GNT_TEXT_FLAG_BOLD); + g_free(name); + } + else + fl = GNT_TEXT_FLAG_DIM; + + if (flags & GAIM_MESSAGE_ERROR) + fl |= GNT_TEXT_FLAG_BOLD; + if (flags & GAIM_MESSAGE_NICK) + fl |= GNT_TEXT_FLAG_UNDERLINE; + + /* XXX: Remove this workaround when textview can parse messages. */ + newline = gaim_strdup_withhtml(message); + strip = gaim_markup_strip_html(newline); + gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(ggconv->tv), + strip, fl); + + g_free(newline); + g_free(strip); + + if (notify) { + strip = g_strdup_printf(_("\n%s is typing..."), gaim_conversation_get_name(conv)); + gnt_text_view_append_text_with_tag(GNT_TEXT_VIEW(ggconv->tv), + strip, GNT_TEXT_FLAG_DIM, "typing"); + g_free(strip); + } + + if (pos <= 1) + gnt_text_view_scroll(GNT_TEXT_VIEW(ggconv->tv), 0); + + if (flags & (GAIM_MESSAGE_RECV | GAIM_MESSAGE_NICK | GAIM_MESSAGE_ERROR)) + gnt_widget_set_urgent(ggconv->tv); +} + +static void +finch_write_chat(GaimConversation *conv, const char *who, const char *message, + GaimMessageFlags flags, time_t mtime) +{ + gaim_conversation_write(conv, who, message, flags, mtime); +} + +static void +finch_write_im(GaimConversation *conv, const char *who, const char *message, + GaimMessageFlags flags, time_t mtime) +{ + GaimAccount *account = gaim_conversation_get_account(conv); + if (flags & GAIM_MESSAGE_SEND) + { + who = gaim_connection_get_display_name(gaim_account_get_connection(account)); + if (!who) + who = gaim_account_get_alias(account); + if (!who) + who = gaim_account_get_username(account); + } + else if (flags & GAIM_MESSAGE_RECV) + { + GaimBuddy *buddy; + who = gaim_conversation_get_name(conv); + buddy = gaim_find_buddy(account, who); + if (buddy) + who = gaim_buddy_get_contact_alias(buddy); + } + + gaim_conversation_write(conv, who, message, flags, mtime); +} + +static void +finch_write_conv(GaimConversation *conv, const char *who, const char *alias, + const char *message, GaimMessageFlags flags, time_t mtime) +{ + const char *name; + if (alias && *alias) + name = alias; + else if (who && *who) + name = who; + else + name = NULL; + + finch_write_common(conv, name, message, flags, mtime); +} + +static void +finch_chat_add_users(GaimConversation *conv, GList *users, gboolean new_arrivals) +{ + FinchConv *ggc = conv->ui_data; + GntEntry *entry = GNT_ENTRY(ggc->entry); + + if (!new_arrivals) + { + /* Print the list of users in the room */ + GString *string = g_string_new(_("List of users:\n")); + GList *iter; + + for (iter = users; iter; iter = iter->next) + { + GaimConvChatBuddy *cbuddy = iter->data; + char *str; + + if ((str = cbuddy->alias) == NULL) + str = cbuddy->name; + g_string_append_printf(string, "[ %s ]", str); + } + + gaim_conversation_write(conv, NULL, string->str, + GAIM_MESSAGE_SYSTEM, time(NULL)); + g_string_free(string, TRUE); + } + + for (; users; users = users->next) + { + GaimConvChatBuddy *cbuddy = users->data; + gnt_entry_add_suggest(entry, cbuddy->name); + gnt_entry_add_suggest(entry, cbuddy->alias); + } +} + +static void +finch_chat_rename_user(GaimConversation *conv, const char *old, const char *new_n, const char *new_a) +{ + /* Update the name for string completion */ + FinchConv *ggc = conv->ui_data; + GntEntry *entry = GNT_ENTRY(ggc->entry); + gnt_entry_remove_suggest(entry, old); + gnt_entry_add_suggest(entry, new_n); + gnt_entry_add_suggest(entry, new_a); +} + +static void +finch_chat_remove_user(GaimConversation *conv, GList *list) +{ + /* Remove the name from string completion */ + FinchConv *ggc = conv->ui_data; + GntEntry *entry = GNT_ENTRY(ggc->entry); + for (; list; list = list->next) + gnt_entry_remove_suggest(entry, list->data); +} + +static void +finch_chat_update_user(GaimConversation *conv, const char *user) +{ +} + +static GaimConversationUiOps conv_ui_ops = +{ + .create_conversation = finch_create_conversation, + .destroy_conversation = finch_destroy_conversation, + .write_chat = finch_write_chat, + .write_im = finch_write_im, + .write_conv = finch_write_conv, + .chat_add_users = finch_chat_add_users, + .chat_rename_user = finch_chat_rename_user, + .chat_remove_users = finch_chat_remove_user, + .chat_update_user = finch_chat_update_user, + .present = NULL, + .has_focus = NULL, + .custom_smiley_add = NULL, + .custom_smiley_write = NULL, + .custom_smiley_close = NULL +}; + +GaimConversationUiOps *finch_conv_get_ui_ops() +{ + return &conv_ui_ops; +} + +/* Xerox */ +static GaimCmdRet +say_command_cb(GaimConversation *conv, + const char *cmd, char **args, char **error, void *data) +{ + if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM) + gaim_conv_im_send(GAIM_CONV_IM(conv), args[0]); + else if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT) + gaim_conv_chat_send(GAIM_CONV_CHAT(conv), args[0]); + + return GAIM_CMD_RET_OK; +} + +/* Xerox */ +static GaimCmdRet +me_command_cb(GaimConversation *conv, + const char *cmd, char **args, char **error, void *data) +{ + char *tmp; + + tmp = g_strdup_printf("/me %s", args[0]); + + if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM) + gaim_conv_im_send(GAIM_CONV_IM(conv), tmp); + else if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT) + gaim_conv_chat_send(GAIM_CONV_CHAT(conv), tmp); + + g_free(tmp); + return GAIM_CMD_RET_OK; +} + +/* Xerox */ +static GaimCmdRet +debug_command_cb(GaimConversation *conv, + const char *cmd, char **args, char **error, void *data) +{ + char *tmp, *markup; + GaimCmdStatus status; + + if (!g_ascii_strcasecmp(args[0], "version")) { + tmp = g_strdup_printf("me is using %s.", VERSION); + markup = g_markup_escape_text(tmp, -1); + + status = gaim_cmd_do_command(conv, tmp, markup, error); + + g_free(tmp); + g_free(markup); + return status; + } else { + gaim_conversation_write(conv, NULL, _("Supported debug options are: version"), + GAIM_MESSAGE_NO_LOG|GAIM_MESSAGE_ERROR, time(NULL)); + return GAIM_CMD_STATUS_OK; + } +} + +/* Xerox */ +static GaimCmdRet +clear_command_cb(GaimConversation *conv, + const char *cmd, char **args, char **error, void *data) +{ + FinchConv *ggconv = conv->ui_data; + gnt_text_view_clear(GNT_TEXT_VIEW(ggconv->tv)); + return GAIM_CMD_STATUS_OK; +} + +/* Xerox */ +static GaimCmdRet +help_command_cb(GaimConversation *conv, + const char *cmd, char **args, char **error, void *data) +{ + GList *l, *text; + GString *s; + + if (args[0] != NULL) { + s = g_string_new(""); + text = gaim_cmd_help(conv, args[0]); + + if (text) { + for (l = text; l; l = l->next) + if (l->next) + g_string_append_printf(s, "%s\n", (char *)l->data); + else + g_string_append_printf(s, "%s", (char *)l->data); + } else { + g_string_append(s, _("No such command (in this context).")); + } + } else { + s = g_string_new(_("Use \"/help <command>\" for help on a specific command.\n" + "The following commands are available in this context:\n")); + + text = gaim_cmd_list(conv); + for (l = text; l; l = l->next) + if (l->next) + g_string_append_printf(s, "%s, ", (char *)l->data); + else + g_string_append_printf(s, "%s.", (char *)l->data); + g_list_free(text); + } + + gaim_conversation_write(conv, NULL, s->str, GAIM_MESSAGE_NO_LOG, time(NULL)); + g_string_free(s, TRUE); + + return GAIM_CMD_STATUS_OK; +} + +static GaimCmdRet +cmd_show_window(GaimConversation *conv, const char *cmd, char **args, char **error, gpointer data) +{ + void (*callback)() = data; + callback(); + return GAIM_CMD_STATUS_OK; +} + +void finch_conversation_init() +{ + gaim_prefs_add_none(PREF_ROOT); + gaim_prefs_add_none(PREF_ROOT "/size"); + gaim_prefs_add_int(PREF_ROOT "/size/width", 70); + gaim_prefs_add_int(PREF_ROOT "/size/height", 20); + gaim_prefs_add_none(PREF_ROOT "/position"); + gaim_prefs_add_int(PREF_ROOT "/position/x", 0); + gaim_prefs_add_int(PREF_ROOT "/position/y", 0); + + /* Xerox the commands */ + gaim_cmd_register("say", "S", GAIM_CMD_P_DEFAULT, + GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_IM, NULL, + say_command_cb, _("say <message>: Send a message normally as if you weren't using a command."), NULL); + gaim_cmd_register("me", "S", GAIM_CMD_P_DEFAULT, + GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_IM, NULL, + me_command_cb, _("me <action>: Send an IRC style action to a buddy or chat."), NULL); + gaim_cmd_register("debug", "w", GAIM_CMD_P_DEFAULT, + GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_IM, NULL, + debug_command_cb, _("debug <option>: Send various debug information to the current conversation."), NULL); + gaim_cmd_register("clear", "", GAIM_CMD_P_DEFAULT, + GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_IM, NULL, + clear_command_cb, _("clear: Clears the conversation scrollback."), NULL); + gaim_cmd_register("help", "w", GAIM_CMD_P_DEFAULT, + GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, NULL, + help_command_cb, _("help <command>: Help on a specific command."), NULL); + + /* Now some commands to bring up some other windows */ + gaim_cmd_register("plugins", "", GAIM_CMD_P_DEFAULT, + GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_IM, NULL, + cmd_show_window, _("plugins: Show the plugins window."), finch_plugins_show_all); + gaim_cmd_register("buddylist", "", GAIM_CMD_P_DEFAULT, + GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_IM, NULL, + cmd_show_window, _("buddylist: Show the buddylist."), finch_blist_show); + gaim_cmd_register("accounts", "", GAIM_CMD_P_DEFAULT, + GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_IM, NULL, + cmd_show_window, _("accounts: Show the accounts window."), finch_accounts_show_all); + gaim_cmd_register("debugwin", "", GAIM_CMD_P_DEFAULT, + GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_IM, NULL, + cmd_show_window, _("debugwin: Show the debug window."), finch_debug_window_show); + gaim_cmd_register("prefs", "", GAIM_CMD_P_DEFAULT, + GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_IM, NULL, + cmd_show_window, _("prefs: Show the preference window."), finch_prefs_show_all); + gaim_cmd_register("status", "", GAIM_CMD_P_DEFAULT, + GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_IM, NULL, + cmd_show_window, _("statuses: Show the savedstatuses window."), finch_savedstatus_show_all); +} + +void finch_conversation_uninit() +{ +} + +void finch_conversation_set_active(GaimConversation *conv) +{ + FinchConv *ggconv = conv->ui_data; + GaimAccount *account; + char *title; + + g_return_if_fail(ggconv); + g_return_if_fail(g_list_find(ggconv->list, conv)); + + ggconv->active_conv = conv; + account = gaim_conversation_get_account(conv); + title = get_conversation_title(conv, account); + gnt_screen_rename_widget(ggconv->window, title); + g_free(title); +} + diff -r 317e7613e581 -r 0e3a8505ebbe finch/gntconv.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/gntconv.h Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,94 @@ +/** + * @file gntconv.h GNT Conversation API + * @ingroup gntui + * + * gaim + * + * Gaim is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _GNT_CONV_H +#define _GNT_CONV_H + +#include +#include + +#include "conversation.h" + +/*************************************************************************** + * @name GNT Conversations API + ***************************************************************************/ +/*@{*/ + +typedef struct _FinchConv FinchConv; +typedef struct _FinchConvChat FinchConvChat; +typedef struct _FinchConvIm FinchConvIm; + +struct _FinchConv +{ + GList *list; + GaimConversation *active_conv; + + GntWidget *window; /* the container */ + GntWidget *entry; /* entry */ + GntWidget *tv; /* text-view */ + + union + { + FinchConvChat *chat; + FinchConvIm *im; + } u; +}; + +struct _FinchConvChat +{ + GntWidget *userlist; /* the userlist */ +}; + +struct _FinchConvIm +{ + void *nothing_for_now; +}; + +/** + * Get the ui-functions. + * + * @return The GaimConversationUiOps populated with the appropriate functions. + */ +GaimConversationUiOps *finch_conv_get_ui_ops(void); + +/** + * Perform the necessary initializations. + */ +void finch_conversation_init(void); + +/** + * Perform the necessary uninitializations. + */ +void finch_conversation_uninit(void); + +/** + * Set a conversation as active in a contactized conversation + * + * @param conv The conversation to make active. + */ +void finch_conversation_set_active(GaimConversation *conv); + +/*@}*/ + +#endif diff -r 317e7613e581 -r 0e3a8505ebbe finch/gntdebug.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/gntdebug.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,304 @@ +/** + * @file gntdebug.c GNT Debug API + * @ingroup gntui + * + * gaim + * + * Gaim is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include + +#include "gntdebug.h" +#include "gntgaim.h" +#include "util.h" + +#include +#include + +#define PREF_ROOT "/gaim/gnt/debug" + +static struct +{ + GntWidget *window; + GntWidget *tview; + gboolean paused; + gboolean timestamps; +} debug; + +static gboolean +debug_window_kpress_cb(GntWidget *wid, const char *key, GntTextView *view) +{ + if (key[0] == 27) + { + if (strcmp(key, GNT_KEY_DOWN) == 0) + gnt_text_view_scroll(view, 1); + else if (strcmp(key, GNT_KEY_UP) == 0) + gnt_text_view_scroll(view, -1); + else if (strcmp(key, GNT_KEY_PGDOWN) == 0) + gnt_text_view_scroll(view, wid->priv.height - 2); + else if (strcmp(key, GNT_KEY_PGUP) == 0) + gnt_text_view_scroll(view, -(wid->priv.height - 2)); + else + return FALSE; + return TRUE; + } + return FALSE; +} + +static void +finch_debug_print(GaimDebugLevel level, const char *category, + const char *args) +{ + if (debug.window && !debug.paused) + { + int pos = gnt_text_view_get_lines_below(GNT_TEXT_VIEW(debug.tview)); + GntTextFormatFlags flag = GNT_TEXT_FLAG_NORMAL; + + if (debug.timestamps) { + const char *mdate; + time_t mtime = time(NULL); + mdate = gaim_utf8_strftime("%H:%M:%S ", localtime(&mtime)); + gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(debug.tview), + mdate, flag); + } + + gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(debug.tview), + category, GNT_TEXT_FLAG_BOLD); + gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(debug.tview), + ": ", GNT_TEXT_FLAG_BOLD); + + switch (level) + { + case GAIM_DEBUG_WARNING: + flag |= GNT_TEXT_FLAG_UNDERLINE; + case GAIM_DEBUG_ERROR: + case GAIM_DEBUG_FATAL: + flag |= GNT_TEXT_FLAG_BOLD; + break; + default: + break; + } + + gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(debug.tview), args, flag); + if (pos <= 1) + gnt_text_view_scroll(GNT_TEXT_VIEW(debug.tview), 0); + } +} + +static GaimDebugUiOps uiops = +{ + finch_debug_print, +}; + +GaimDebugUiOps *finch_debug_get_ui_ops() +{ + return &uiops; +} + +static void +reset_debug_win(GntWidget *w, gpointer null) +{ + debug.window = debug.tview = NULL; +} + +static void +clear_debug_win(GntWidget *w, GntTextView *tv) +{ + gnt_text_view_clear(tv); +} + +static void +print_stderr(const char *string) +{ + g_printerr("%s", string); +} + +static void +suppress_error_messages(const char *message) +{} + +static void +toggle_pause(GntWidget *w, gpointer n) +{ + debug.paused = !debug.paused; +} + +static void +toggle_timestamps(GntWidget *w, gpointer n) +{ + debug.timestamps = !debug.timestamps; + gaim_prefs_set_bool("/core/debug/timestamps", debug.timestamps); +} + +/* Xerox */ +static void +gaim_glib_log_handler(const gchar *domain, GLogLevelFlags flags, + const gchar *msg, gpointer user_data) +{ + GaimDebugLevel level; + char *new_msg = NULL; + char *new_domain = NULL; + + if ((flags & G_LOG_LEVEL_ERROR) == G_LOG_LEVEL_ERROR) + level = GAIM_DEBUG_ERROR; + else if ((flags & G_LOG_LEVEL_CRITICAL) == G_LOG_LEVEL_CRITICAL) + level = GAIM_DEBUG_FATAL; + else if ((flags & G_LOG_LEVEL_WARNING) == G_LOG_LEVEL_WARNING) + level = GAIM_DEBUG_WARNING; + else if ((flags & G_LOG_LEVEL_MESSAGE) == G_LOG_LEVEL_MESSAGE) + level = GAIM_DEBUG_INFO; + else if ((flags & G_LOG_LEVEL_INFO) == G_LOG_LEVEL_INFO) + level = GAIM_DEBUG_INFO; + else if ((flags & G_LOG_LEVEL_DEBUG) == G_LOG_LEVEL_DEBUG) + level = GAIM_DEBUG_MISC; + else + { + gaim_debug_warning("gntdebug", + "Unknown glib logging level in %d\n", flags); + + level = GAIM_DEBUG_MISC; /* This will never happen. */ + } + + if (msg != NULL) + new_msg = gaim_utf8_try_convert(msg); + + if (domain != NULL) + new_domain = gaim_utf8_try_convert(domain); + + if (new_msg != NULL) + { + gaim_debug(level, (new_domain != NULL ? new_domain : "g_log"), + "%s\n", new_msg); + + g_free(new_msg); + } + + g_free(new_domain); +} + +static void +size_changed_cb(GntWidget *widget, int oldw, int oldh) +{ + int w, h; + gnt_widget_get_size(widget, &w, &h); + gaim_prefs_set_int(PREF_ROOT "/size/width", w); + gaim_prefs_set_int(PREF_ROOT "/size/height", h); +} + +void finch_debug_window_show() +{ + debug.paused = FALSE; + debug.timestamps = gaim_prefs_get_bool("/core/debug/timestamps"); + if (debug.window == NULL) + { + GntWidget *wid, *box; + debug.window = gnt_vbox_new(FALSE); + gnt_box_set_toplevel(GNT_BOX(debug.window), TRUE); + gnt_box_set_title(GNT_BOX(debug.window), _("Debug Window")); + gnt_box_set_pad(GNT_BOX(debug.window), 0); + gnt_box_set_alignment(GNT_BOX(debug.window), GNT_ALIGN_MID); + + debug.tview = gnt_text_view_new(); + gnt_box_add_widget(GNT_BOX(debug.window), debug.tview); + gnt_widget_set_size(debug.tview, + gaim_prefs_get_int(PREF_ROOT "/size/width"), + gaim_prefs_get_int(PREF_ROOT "/size/height")); + g_signal_connect(G_OBJECT(debug.tview), "size_changed", G_CALLBACK(size_changed_cb), NULL); + + gnt_box_add_widget(GNT_BOX(debug.window), gnt_line_new(FALSE)); + + box = gnt_hbox_new(FALSE); + gnt_box_set_alignment(GNT_BOX(box), GNT_ALIGN_MID); + gnt_box_set_fill(GNT_BOX(box), FALSE); + + /* XXX: Setting the GROW_Y for the following widgets don't make sense. But right now + * it's necessary to make the width of the debug window resizable ... like I said, + * it doesn't make sense. The bug is likely in the packing in gntbox.c. + */ + wid = gnt_button_new(_("Clear")); + g_signal_connect(G_OBJECT(wid), "activate", G_CALLBACK(clear_debug_win), debug.tview); + GNT_WIDGET_SET_FLAGS(wid, GNT_WIDGET_GROW_Y); + gnt_box_add_widget(GNT_BOX(box), wid); + + wid = gnt_check_box_new(_("Pause")); + g_signal_connect(G_OBJECT(wid), "toggled", G_CALLBACK(toggle_pause), NULL); + GNT_WIDGET_SET_FLAGS(wid, GNT_WIDGET_GROW_Y); + gnt_box_add_widget(GNT_BOX(box), wid); + + wid = gnt_check_box_new(_("Timestamps")); + gnt_check_box_set_checked(GNT_CHECK_BOX(wid), debug.timestamps); + g_signal_connect(G_OBJECT(wid), "toggled", G_CALLBACK(toggle_timestamps), NULL); + GNT_WIDGET_SET_FLAGS(wid, GNT_WIDGET_GROW_Y); + gnt_box_add_widget(GNT_BOX(box), wid); + + gnt_box_add_widget(GNT_BOX(debug.window), box); + GNT_WIDGET_SET_FLAGS(box, GNT_WIDGET_GROW_Y); + + gnt_widget_set_name(debug.window, "debug-window"); + + g_signal_connect(G_OBJECT(debug.window), "destroy", G_CALLBACK(reset_debug_win), NULL); + g_signal_connect(G_OBJECT(debug.window), "key_pressed", G_CALLBACK(debug_window_kpress_cb), debug.tview); + } + + gnt_widget_show(debug.window); +} + +static gboolean +start_with_debugwin(gpointer null) +{ + finch_debug_window_show(); + return FALSE; +} + +void finch_debug_init() +{ +/* Xerox */ +#define REGISTER_G_LOG_HANDLER(name) \ + g_log_set_handler((name), G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL \ + | G_LOG_FLAG_RECURSION, \ + gaim_glib_log_handler, NULL) + + /* Register the glib log handlers. */ + REGISTER_G_LOG_HANDLER(NULL); + REGISTER_G_LOG_HANDLER("GLib"); + REGISTER_G_LOG_HANDLER("GModule"); + REGISTER_G_LOG_HANDLER("GLib-GObject"); + REGISTER_G_LOG_HANDLER("GThread"); + + g_set_print_handler(print_stderr); /* Redirect the debug messages to stderr */ + g_set_printerr_handler(suppress_error_messages); + + gaim_prefs_add_none(PREF_ROOT); + gaim_prefs_add_none(PREF_ROOT "/size"); + gaim_prefs_add_int(PREF_ROOT "/size/width", 60); + gaim_prefs_add_int(PREF_ROOT "/size/height", 15); + + if (gaim_debug_is_enabled()) + g_timeout_add(0, start_with_debugwin, NULL); +} + +void finch_debug_uninit() +{ +} + diff -r 317e7613e581 -r 0e3a8505ebbe finch/gntdebug.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/gntdebug.h Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,59 @@ +/** + * @file gntdebug.h GNT Debug API + * @ingroup gntui + * + * gaim + * + * Gaim is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _GNT_DEBUG_H +#define _GNT_DEBUG_H + +#include "debug.h" + +/********************************************************************** + * @name GNT Debug API + **********************************************************************/ +/*@{*/ + +/** + * Get the ui-functions. + * + * @return The GaimDebugUiOps structure populated with the appropriate functions. + */ +GaimDebugUiOps *finch_debug_get_ui_ops(void); + +/** + * Perform necessary initializations. + */ +void finch_debug_init(void); + +/** + * Perform necessary uninitializations. + */ +void finch_debug_uninit(void); + +/** + * Show the debug window. + */ +void finch_debug_window_show(void); + +/*@}*/ + +#endif diff -r 317e7613e581 -r 0e3a8505ebbe finch/gntft.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/gntft.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,532 @@ +/** + * @file gntft.c GNT File Transfer UI + * @ingroup gntui + * + * gaim + * + * Gaim is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include "internal.h" + +#include "debug.h" +#include "notify.h" +#include "ft.h" +#include "prpl.h" +#include "util.h" + +#include "gntft.h" +#include "prefs.h" + +#define GAIM_GNTXFER(xfer) \ + (GaimGntXferUiData *)(xfer)->ui_data + +typedef struct +{ + gboolean keep_open; + gboolean auto_clear; + gint num_transfers; + + GntWidget *window; + GntWidget *tree; + + GntWidget *remove_button; + GntWidget *stop_button; + GntWidget *close_button; +} GaimGntXferDialog; + +static GaimGntXferDialog *xfer_dialog = NULL; + +typedef struct +{ + time_t last_updated_time; + gboolean in_list; + + char *name; + +} GaimGntXferUiData; + +enum +{ + COLUMN_PROGRESS = 0, + COLUMN_FILENAME, + COLUMN_SIZE, + COLUMN_SPEED, + COLUMN_REMAINING, + COLUMN_STATUS, + NUM_COLUMNS +}; + + +/************************************************************************** + * Utility Functions + **************************************************************************/ + +static void +update_title_progress() +{ + const GList *list; + int num_active_xfers = 0; + guint64 total_bytes_xferred = 0; + guint64 total_file_size = 0; + + if (xfer_dialog == NULL || xfer_dialog->window == NULL) + return; + + /* Find all active transfers */ + for (list = gnt_tree_get_rows(GNT_TREE(xfer_dialog->tree)); list; list = list->next) { + GaimXfer *xfer = (GaimXfer *)list->data; + + if (gaim_xfer_get_status(xfer) == GAIM_XFER_STATUS_STARTED) { + num_active_xfers++; + total_bytes_xferred += gaim_xfer_get_bytes_sent(xfer); + total_file_size += gaim_xfer_get_size(xfer); + } + } + + /* Update the title */ + if (num_active_xfers > 0) { + gchar *title; + int total_pct = 0; + + if (total_file_size > 0) { + total_pct = 100 * total_bytes_xferred / total_file_size; + } + + title = g_strdup_printf(_("File Transfers - %d%% of %d files"), + total_pct, num_active_xfers); + gnt_screen_rename_widget((xfer_dialog->window), title); + g_free(title); + } else { + gnt_screen_rename_widget((xfer_dialog->window), _("File Transfers")); + } +} + + +/************************************************************************** + * Callbacks + **************************************************************************/ +static void +toggle_keep_open_cb(GntWidget *w) +{ + xfer_dialog->keep_open = !xfer_dialog->keep_open; + gaim_prefs_set_bool("/gaim/gnt/filetransfer/keep_open", + xfer_dialog->keep_open); +} + +static void +toggle_clear_finished_cb(GntWidget *w) +{ + xfer_dialog->auto_clear = !xfer_dialog->auto_clear; + gaim_prefs_set_bool("/gaim/gnt/filetransfer/clear_finished", + xfer_dialog->auto_clear); +} + +static void +remove_button_cb(GntButton *button) +{ + GaimXfer *selected_xfer = gnt_tree_get_selection_data(GNT_TREE(xfer_dialog->tree)); + if (selected_xfer && (selected_xfer->status == GAIM_XFER_STATUS_CANCEL_LOCAL || + selected_xfer->status == GAIM_XFER_STATUS_CANCEL_REMOTE || + selected_xfer->status == GAIM_XFER_STATUS_DONE)) { + finch_xfer_dialog_remove_xfer(selected_xfer); + } +} + +static void +stop_button_cb(GntButton *button) +{ + GaimXfer *selected_xfer = gnt_tree_get_selection_data(GNT_TREE(xfer_dialog->tree)); + if (selected_xfer && selected_xfer->status == GAIM_XFER_STATUS_STARTED) + gaim_xfer_cancel_local(selected_xfer); +} + +#if 0 +static void +tree_selection_changed_cb(GntTree *tree, GntTreeRow *old, GntTreeRow *current, gpointer n) +{ + xfer_dialog->selected_xfer = (GaimXfer *)gnt_tree_get_selection_data(tree); +} +#endif + +/************************************************************************** + * Dialog Building Functions + **************************************************************************/ + + +void +finch_xfer_dialog_new(void) +{ + const GList *iter; + GntWidget *window; + GntWidget *bbox; + GntWidget *button; + GntWidget *checkbox; + GntWidget *tree; + + if (!xfer_dialog) + xfer_dialog = g_new0(GaimGntXferDialog, 1); + + xfer_dialog->keep_open = + gaim_prefs_get_bool("/gaim/gnt/filetransfer/keep_open"); + xfer_dialog->auto_clear = + gaim_prefs_get_bool("/gaim/gnt/filetransfer/clear_finished"); + + /* Create the window. */ + xfer_dialog->window = window = gnt_vbox_new(FALSE); + g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(finch_xfer_dialog_destroy), NULL); + gnt_box_set_toplevel(GNT_BOX(window), TRUE); + gnt_box_set_title(GNT_BOX(window), _("File Transfers")); + + xfer_dialog->tree = tree = gnt_tree_new_with_columns(NUM_COLUMNS); + gnt_tree_set_column_titles(GNT_TREE(tree), _("Progress"), _("Filename"), _("Size"), _("Speed"), _("Remaining"), _("Status")); + gnt_tree_set_col_width(GNT_TREE(tree), COLUMN_PROGRESS, 8); + gnt_tree_set_col_width(GNT_TREE(tree), COLUMN_FILENAME, 8); + gnt_tree_set_col_width(GNT_TREE(tree), COLUMN_SIZE, 10); + gnt_tree_set_col_width(GNT_TREE(tree), COLUMN_SPEED, 10); + gnt_tree_set_col_width(GNT_TREE(tree), COLUMN_REMAINING, 10); + gnt_tree_set_col_width(GNT_TREE(tree), COLUMN_STATUS, 10); + gnt_tree_set_show_title(GNT_TREE(tree), TRUE); + gnt_box_add_widget(GNT_BOX(window), tree); + /*g_signal_connect(G_OBJECT(tree), "selection-changed",*/ + /*G_CALLBACK(tree_selection_changed_cb), NULL);*/ + checkbox = gnt_check_box_new( _("Close this window when all transfers finish")); + gnt_check_box_set_checked(GNT_CHECK_BOX(checkbox), + !xfer_dialog->keep_open); + g_signal_connect(G_OBJECT(checkbox), "toggled", + G_CALLBACK(toggle_keep_open_cb), NULL); + gnt_box_add_widget(GNT_BOX(window), checkbox); + + checkbox = gnt_check_box_new(_("Clear finished transfers")); + gnt_check_box_set_checked(GNT_CHECK_BOX(checkbox), + xfer_dialog->auto_clear); + g_signal_connect(G_OBJECT(checkbox), "toggled", + G_CALLBACK(toggle_clear_finished_cb), NULL); + gnt_box_add_widget(GNT_BOX(window), checkbox); + + bbox = gnt_hbox_new(TRUE); + + xfer_dialog->remove_button = button = gnt_button_new(_("Remove")); + g_signal_connect(G_OBJECT(button), "activate", + G_CALLBACK(remove_button_cb), NULL); + gnt_box_add_widget(GNT_BOX(bbox), button); + + xfer_dialog->stop_button = button = gnt_button_new(_("Stop")); + g_signal_connect(G_OBJECT(button), "activate", + G_CALLBACK(stop_button_cb), NULL); + gnt_box_add_widget(GNT_BOX(bbox), button); + + xfer_dialog->close_button = button = gnt_button_new(_("Close")); + g_signal_connect(G_OBJECT(button), "activate", + G_CALLBACK(finch_xfer_dialog_destroy), NULL); + gnt_box_add_widget(GNT_BOX(bbox), button); + + gnt_box_add_widget(GNT_BOX(window), bbox); + + for (iter = gaim_xfers_get_all(); iter; iter = iter->next) { + GaimXfer *xfer = (GaimXfer *)iter->data; + GaimGntXferUiData *data = GAIM_GNTXFER(xfer); + if (data->in_list) { + finch_xfer_dialog_add_xfer(xfer); + finch_xfer_dialog_update_xfer(xfer); + gnt_tree_set_selected(GNT_TREE(tree), xfer); + } + } + gnt_widget_show(xfer_dialog->window); +} + +void +finch_xfer_dialog_destroy() +{ + gnt_widget_destroy(xfer_dialog->window); + g_free(xfer_dialog); + xfer_dialog = NULL; +} + +void +finch_xfer_dialog_show() +{ + if (xfer_dialog == NULL) + finch_xfer_dialog_new(); +} + +void +finch_xfer_dialog_add_xfer(GaimXfer *xfer) +{ + GaimGntXferUiData *data; + GaimXferType type; + char *size_str, *remaining_str; + char *lfilename, *utf8; + + g_return_if_fail(xfer_dialog != NULL); + g_return_if_fail(xfer != NULL); + + gaim_xfer_ref(xfer); + + data = GAIM_GNTXFER(xfer); + data->in_list = TRUE; + + finch_xfer_dialog_show(); + + data->last_updated_time = 0; + + type = gaim_xfer_get_type(xfer); + + size_str = gaim_str_size_to_units(gaim_xfer_get_size(xfer)); + remaining_str = gaim_str_size_to_units(gaim_xfer_get_bytes_remaining(xfer)); + + lfilename = g_path_get_basename(gaim_xfer_get_local_filename(xfer)); + utf8 = g_filename_to_utf8(lfilename, -1, NULL, NULL, NULL); + g_free(lfilename); + lfilename = utf8; + gnt_tree_add_row_last(GNT_TREE(xfer_dialog->tree), xfer, + gnt_tree_create_row(GNT_TREE(xfer_dialog->tree), + "0.0", (type == GAIM_XFER_RECEIVE) ? gaim_xfer_get_filename(xfer) : lfilename, + size_str, "0.0", "",_("Waiting for transfer to begin")), NULL); + g_free(lfilename); + + g_free(size_str); + g_free(remaining_str); + + xfer_dialog->num_transfers++; + + update_title_progress(); +} + +void +finch_xfer_dialog_remove_xfer(GaimXfer *xfer) +{ + GaimGntXferUiData *data; + + g_return_if_fail(xfer_dialog != NULL); + g_return_if_fail(xfer != NULL); + + data = GAIM_GNTXFER(xfer); + + if (data == NULL) + return; + + if (!data->in_list) + return; + + data->in_list = FALSE; + + gnt_tree_remove(GNT_TREE(xfer_dialog->tree), xfer); + + xfer_dialog->num_transfers--; + + if (xfer_dialog->num_transfers == 0 && !xfer_dialog->keep_open) + finch_xfer_dialog_destroy(); + else + update_title_progress(); + gaim_xfer_unref(xfer); +} + +void +finch_xfer_dialog_cancel_xfer(GaimXfer *xfer) +{ + GaimGntXferUiData *data; + const gchar *status; + + g_return_if_fail(xfer_dialog != NULL); + g_return_if_fail(xfer != NULL); + + data = GAIM_GNTXFER(xfer); + + if (data == NULL) + return; + + if (!data->in_list) + return; + + if ((gaim_xfer_get_status(xfer) == GAIM_XFER_STATUS_CANCEL_LOCAL) && (xfer_dialog->auto_clear)) { + finch_xfer_dialog_remove_xfer(xfer); + return; + } + + data = GAIM_GNTXFER(xfer); + + update_title_progress(); + + if (gaim_xfer_is_canceled(xfer)) + status = _("Canceled"); + else + status = _("Failed"); + + gnt_tree_change_text(GNT_TREE(xfer_dialog->tree), xfer, COLUMN_STATUS, status); +} + +void +finch_xfer_dialog_update_xfer(GaimXfer *xfer) +{ + GaimGntXferUiData *data; + char *size_str, *remaining_str; + time_t current_time; + char prog_str[5]; + double kb_sent, kb_rem; + double kbps = 0.0; + time_t elapsed, now; + char *kbsec; + + if (xfer->end_time != 0) + now = xfer->end_time; + else + now = time(NULL); + + kb_sent = gaim_xfer_get_bytes_sent(xfer) / 1024.0; + kb_rem = gaim_xfer_get_bytes_remaining(xfer) / 1024.0; + elapsed = (xfer->start_time > 0 ? now - xfer->start_time : 0); + kbps = (elapsed > 0 ? (kb_sent / elapsed) : 0); + + kbsec = g_strdup_printf(_("%.2f KB/s"), kbps); + + g_return_if_fail(xfer_dialog != NULL); + g_return_if_fail(xfer != NULL); + + if ((data = GAIM_GNTXFER(xfer)) == NULL) + return; + + if (data->in_list == FALSE) + return; + + current_time = time(NULL); + if (((current_time - data->last_updated_time) == 0) && + (!gaim_xfer_is_completed(xfer))) { + /* Don't update the window more than once per second */ + return; + } + data->last_updated_time = current_time; + + size_str = gaim_str_size_to_units(gaim_xfer_get_size(xfer)); + remaining_str = gaim_str_size_to_units(gaim_xfer_get_bytes_remaining(xfer)); + + gnt_tree_change_text(GNT_TREE(xfer_dialog->tree), xfer, COLUMN_PROGRESS, + g_ascii_dtostr(prog_str, sizeof(prog_str), gaim_xfer_get_progress(xfer) * 100.)); + gnt_tree_change_text(GNT_TREE(xfer_dialog->tree), xfer, COLUMN_SIZE, size_str); + gnt_tree_change_text(GNT_TREE(xfer_dialog->tree), xfer, COLUMN_REMAINING, remaining_str); + gnt_tree_change_text(GNT_TREE(xfer_dialog->tree), xfer, COLUMN_SPEED, kbsec); + g_free(size_str); + g_free(remaining_str); + if (gaim_xfer_is_completed(xfer)) { + gnt_tree_change_text(GNT_TREE(xfer_dialog->tree), xfer, COLUMN_STATUS, _("Finished")); + } else { + gnt_tree_change_text(GNT_TREE(xfer_dialog->tree), xfer, COLUMN_STATUS, _("Transferring")); + } + + update_title_progress(); + + if (gaim_xfer_is_completed(xfer) && xfer_dialog->auto_clear) + finch_xfer_dialog_remove_xfer(xfer); +} + +/************************************************************************** + * File Transfer UI Ops + **************************************************************************/ +static void +finch_xfer_new_xfer(GaimXfer *xfer) +{ + GaimGntXferUiData *data; + + /* This is where we're setting xfer->ui_data for the first time. */ + data = g_new0(GaimGntXferUiData, 1); + xfer->ui_data = data; +} + +static void +finch_xfer_destroy(GaimXfer *xfer) +{ + GaimGntXferUiData *data; + + data = GAIM_GNTXFER(xfer); + if (data) { + g_free(data->name); + g_free(data); + xfer->ui_data = NULL; + } +} + +static void +finch_xfer_add_xfer(GaimXfer *xfer) +{ + if (!xfer_dialog) + finch_xfer_dialog_new(); + + finch_xfer_dialog_add_xfer(xfer); + gnt_tree_set_selected(GNT_TREE(xfer_dialog->tree), xfer); +} + +static void +finch_xfer_update_progress(GaimXfer *xfer, double percent) +{ + if (xfer_dialog) + finch_xfer_dialog_update_xfer(xfer); +} + +static void +finch_xfer_cancel_local(GaimXfer *xfer) +{ + if (xfer_dialog) + finch_xfer_dialog_cancel_xfer(xfer); +} + +static void +finch_xfer_cancel_remote(GaimXfer *xfer) +{ + if (xfer_dialog) + finch_xfer_dialog_cancel_xfer(xfer); +} + +static GaimXferUiOps ops = +{ + finch_xfer_new_xfer, + finch_xfer_destroy, + finch_xfer_add_xfer, + finch_xfer_update_progress, + finch_xfer_cancel_local, + finch_xfer_cancel_remote +}; + +/************************************************************************** + * GNT File Transfer API + **************************************************************************/ +void +finch_xfers_init(void) +{ + gaim_prefs_add_none("/gaim/gnt/filetransfer"); + gaim_prefs_add_bool("/gaim/gnt/filetransfer/clear_finished", TRUE); + gaim_prefs_add_bool("/gaim/gnt/filetransfer/keep_open", FALSE); +} + +void +finch_xfers_uninit(void) +{ + if (xfer_dialog != NULL) + finch_xfer_dialog_destroy(); +} + +GaimXferUiOps * +finch_xfers_get_ui_ops(void) +{ + return &ops; +} diff -r 317e7613e581 -r 0e3a8505ebbe finch/gntft.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/gntft.h Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,123 @@ +/** + * @file gntft.h GNT File Transfer UI + * @ingroup gntui + * + * gaim + * + * Gaim is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _GAIM_GNTFT_H_ +#define _GAIM_GNTFT_H_ + +#include "ft.h" + + +/**************************************************************************/ +/** @name GNT File Transfer Dialog API */ +/**************************************************************************/ +/*@{*/ + +/** + * Creates a new file transfer dialog. + * + * @return The new dialog. + */ +void finch_xfer_dialog_new(void); + +/** + * Destroys a file transfer dialog. + * + * @param dialog The file transfer dialog. + */ +void finch_xfer_dialog_destroy(void); + +/** + * Displays the file transfer dialog given. + * If dialog is @c NULL, displays the default dialog, creating one if necessary + * + * @param dialog The file transfer dialog to show. + */ +void finch_xfer_dialog_show(void); + +/** + * Hides the file transfer dialog. + * + * @param dialog The file transfer dialog to hide. + */ +void finch_xfer_dialog_hide(); + +/** + * Adds a file transfer to the dialog. + * + * @param dialog The file transfer dialog. + * @param xfer The file transfer. + */ +void finch_xfer_dialog_add_xfer(GaimXfer *xfer); + +/** + * Removes a file transfer from the dialog. + * + * @param dialog The file transfer dialog. + * @param xfer The file transfer. + */ +void finch_xfer_dialog_remove_xfer(GaimXfer *xfer); + +/** + * Indicate in a file transfer dialog that a transfer was canceled. + * + * @param dialog The file transfer dialog. + * @param xfer The file transfer that was canceled. + */ +void finch_xfer_dialog_cancel_xfer(GaimXfer *xfer); + +/** + * Updates the information for a transfer in the dialog. + * + * @param dialog The file transfer dialog. + * @param xfer The file transfer. + */ +void finch_xfer_dialog_update_xfer(GaimXfer *xfer); + +/*@}*/ + +/**************************************************************************/ +/** @name GNT File Transfer API */ +/**************************************************************************/ +/*@{*/ + +/** + * Initializes the GNT file transfer system. + */ +void finch_xfers_init(void); + +/** + * Uninitializes the GNT file transfer system. + */ +void finch_xfers_uninit(void); + +/** + * Returns the UI operations structure for the GNT file transfer UI. + * + * @return The GNT file transfer UI operations structure. + */ +GaimXferUiOps *finch_xfers_get_ui_ops(void); + +/*@}*/ + +#endif /* _GAIM_GNTFT_H_ */ diff -r 317e7613e581 -r 0e3a8505ebbe finch/gntgaim.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/gntgaim.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,417 @@ +/** + * gaim + * + * Gaim is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "account.h" +#include "conversation.h" +#include "core.h" +#include "debug.h" +#include "eventloop.h" +#include "ft.h" +#include "log.h" +#include "notify.h" +#include "prefix.h" +#include "prefs.h" +#include "prpl.h" +#include "pounce.h" +#include "savedstatuses.h" +#include "sound.h" +#include "status.h" +#include "util.h" +#include "whiteboard.h" + +#include "gntdebug.h" +#include "gntgaim.h" +#include "gntprefs.h" +#include "gntui.h" +#include "gntidle.h" + +#define _GNU_SOURCE +#include + +#include "config.h" + +static void +debug_init() +{ + finch_debug_init(); + gaim_debug_set_ui_ops(finch_debug_get_ui_ops()); +} + +static GaimCoreUiOps core_ops = +{ + finch_prefs_init, + debug_init, + gnt_ui_init, + gnt_ui_uninit +}; + +static GaimCoreUiOps * +gnt_core_get_ui_ops() +{ + return &core_ops; +} + +/* Anything IO-related is directly copied from gtkgaim's source tree */ + +#define GAIM_GNT_READ_COND (G_IO_IN | G_IO_HUP | G_IO_ERR) +#define GAIM_GNT_WRITE_COND (G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL) + +typedef struct _GaimGntIOClosure { + GaimInputFunction function; + guint result; + gpointer data; + +} GaimGntIOClosure; + +static void gaim_gnt_io_destroy(gpointer data) +{ + g_free(data); +} + +static gboolean gaim_gnt_io_invoke(GIOChannel *source, GIOCondition condition, gpointer data) +{ + GaimGntIOClosure *closure = data; + GaimInputCondition gaim_cond = 0; + + if (condition & GAIM_GNT_READ_COND) + gaim_cond |= GAIM_INPUT_READ; + if (condition & GAIM_GNT_WRITE_COND) + gaim_cond |= GAIM_INPUT_WRITE; + +#if 0 + gaim_debug(GAIM_DEBUG_MISC, "gtk_eventloop", + "CLOSURE: callback for %d, fd is %d\n", + closure->result, g_io_channel_unix_get_fd(source)); +#endif + +#ifdef _WIN32 + if(! gaim_cond) { +#if DEBUG + gaim_debug_misc("gnt_eventloop", + "CLOSURE received GIOCondition of 0x%x, which does not" + " match 0x%x (READ) or 0x%x (WRITE)\n", + condition, GAIM_GNT_READ_COND, GAIM_GNT_WRITE_COND); +#endif /* DEBUG */ + + return TRUE; + } +#endif /* _WIN32 */ + + closure->function(closure->data, g_io_channel_unix_get_fd(source), + gaim_cond); + + return TRUE; +} + +static guint gnt_input_add(gint fd, GaimInputCondition condition, GaimInputFunction function, + gpointer data) +{ + GaimGntIOClosure *closure = g_new0(GaimGntIOClosure, 1); + GIOChannel *channel; + GIOCondition cond = 0; + + closure->function = function; + closure->data = data; + + if (condition & GAIM_INPUT_READ) + cond |= GAIM_GNT_READ_COND; + if (condition & GAIM_INPUT_WRITE) + cond |= GAIM_GNT_WRITE_COND; + + channel = g_io_channel_unix_new(fd); + closure->result = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, cond, + gaim_gnt_io_invoke, closure, gaim_gnt_io_destroy); + + g_io_channel_unref(channel); + return closure->result; +} + +static GaimEventLoopUiOps eventloop_ops = +{ + g_timeout_add, + g_source_remove, + gnt_input_add, + g_source_remove, + NULL /* input_get_error */ +}; + +static GaimEventLoopUiOps * +gnt_eventloop_get_ui_ops(void) +{ + return &eventloop_ops; +} + +/* This is copied from gtkgaim */ +static char * +gnt_find_binary_location(void *symbol, void *data) +{ + static char *fullname = NULL; + static gboolean first = TRUE; + + char *argv0 = data; + struct stat st; + char *basebuf, *linkbuf, *fullbuf; + + if (!first) + /* We've already been through this. */ + return strdup(fullname); + + first = FALSE; + + if (!argv0) + return NULL; + + + basebuf = g_find_program_in_path(argv0); + + /* But we still need to deal with symbolic links */ + g_lstat(basebuf, &st); + while ((st.st_mode & S_IFLNK) == S_IFLNK) { + int written; + linkbuf = g_malloc(1024); + written = readlink(basebuf, linkbuf, 1024 - 1); + if (written == -1) + { + /* This really shouldn't happen, but do we + * need something better here? */ + g_free(linkbuf); + continue; + } + linkbuf[written] = '\0'; + if (linkbuf[0] == G_DIR_SEPARATOR) { + /* an absolute path */ + fullbuf = g_strdup(linkbuf); + } else { + char *dirbuf = g_path_get_dirname(basebuf); + /* a relative path */ + fullbuf = g_strdup_printf("%s%s%s", + dirbuf, G_DIR_SEPARATOR_S, + linkbuf); + g_free(dirbuf); + } + /* There's no memory leak here. Really! */ + g_free(linkbuf); + g_free(basebuf); + basebuf = fullbuf; + g_lstat(basebuf, &st); + } + + fullname = basebuf; + return strdup(fullname); +} + + +/* This is mostly copied from gtkgaim's source tree */ +static void +show_usage(const char *name, gboolean terse) +{ + char *text; + + if (terse) { + text = g_strdup_printf(_("%s. Try `%s -h' for more information.\n"), VERSION, name); + } else { + text = g_strdup_printf(_("%s\n" + "Usage: %s [OPTION]...\n\n" + " -c, --config=DIR use DIR for config files\n" + " -d, --debug print debugging messages to stdout\n" + " -h, --help display this help and exit\n" + " -n, --nologin don't automatically login\n" + " -v, --version display the current version and exit\n"), VERSION, name); + } + + gaim_print_utf8_to_console(stdout, text); + g_free(text); +} + +static int +init_libgaim(int argc, char **argv) +{ + char *path; + int opt; + gboolean opt_help = FALSE; + gboolean opt_nologin = FALSE; + gboolean opt_version = FALSE; + char *opt_config_dir_arg = NULL; + char *opt_session_arg = NULL; + gboolean debug_enabled = FALSE; + + struct option long_options[] = { + {"config", required_argument, NULL, 'c'}, + {"debug", no_argument, NULL, 'd'}, + {"help", no_argument, NULL, 'h'}, + {"nologin", no_argument, NULL, 'n'}, + {"session", required_argument, NULL, 's'}, + {"version", no_argument, NULL, 'v'}, + {0, 0, 0, 0} + }; + + gaim_br_set_locate_fallback_func(gnt_find_binary_location, argv[0]); + +#ifdef ENABLE_NLS + bindtextdomain(PACKAGE, LOCALEDIR); + bind_textdomain_codeset(PACKAGE, "UTF-8"); + textdomain(PACKAGE); +#endif + +#ifdef HAVE_SETLOCALE + setlocale(LC_ALL, ""); +#endif + + /* scan command-line options */ + opterr = 1; + while ((opt = getopt_long(argc, argv, +#ifndef _WIN32 + "c:dhn::s:v", +#else + "c:dhn::v", +#endif + long_options, NULL)) != -1) { + switch (opt) { + case 'c': /* config dir */ + g_free(opt_config_dir_arg); + opt_config_dir_arg = g_strdup(optarg); + break; + case 'd': /* debug */ + debug_enabled = TRUE; + break; + case 'h': /* help */ + opt_help = TRUE; + break; + case 'n': /* no autologin */ + opt_nologin = TRUE; + break; + case 's': /* use existing session ID */ + g_free(opt_session_arg); + opt_session_arg = g_strdup(optarg); + break; + case 'v': /* version */ + opt_version = TRUE; + break; + case '?': /* show terse help */ + default: + show_usage(argv[0], TRUE); + return 0; + break; + } + } + + /* show help message */ + if (opt_help) { + show_usage(argv[0], FALSE); + return 0; + } + /* show version message */ + if (opt_version) { + printf("gaim-text %s\n", VERSION); + return 0; + } + + /* set a user-specified config directory */ + if (opt_config_dir_arg != NULL) { + gaim_util_set_user_dir(opt_config_dir_arg); + g_free(opt_config_dir_arg); + } + + /* + * We're done piddling around with command line arguments. + * Fire up this baby. + */ + + /* Because we don't want debug-messages to show up and corrup the display */ + gaim_debug_set_enabled(debug_enabled); + + gaim_core_set_ui_ops(gnt_core_get_ui_ops()); + gaim_eventloop_set_ui_ops(gnt_eventloop_get_ui_ops()); + gaim_idle_set_ui_ops(finch_idle_get_ui_ops()); + + path = g_build_filename(gaim_user_dir(), "plugins", NULL); + gaim_plugins_add_search_path(path); + g_free(path); + + gaim_plugins_add_search_path(LIBDIR); + + if (!gaim_core_init(GAIM_GNT_UI)) + { + fprintf(stderr, + "Initialization of the Gaim core failed. Dumping core.\n" + "Please report this!\n"); + abort(); + } + + /* TODO: Move blist loading into gaim_blist_init() */ + gaim_set_blist(gaim_blist_new()); + gaim_blist_load(); + + /* TODO: Move prefs loading into gaim_prefs_init() */ + gaim_prefs_load(); + gaim_prefs_update_old(); + + /* load plugins we had when we quit */ + gaim_plugins_load_saved("/gaim/gnt/plugins/loaded"); + + /* TODO: Move pounces loading into gaim_pounces_init() */ + gaim_pounces_load(); + + if (opt_nologin) + { + /* Set all accounts to "offline" */ + GaimSavedStatus *saved_status; + + /* If we've used this type+message before, lookup the transient status */ + saved_status = gaim_savedstatus_find_transient_by_type_and_message( + GAIM_STATUS_OFFLINE, NULL); + + /* If this type+message is unique then create a new transient saved status */ + if (saved_status == NULL) + saved_status = gaim_savedstatus_new(NULL, GAIM_STATUS_OFFLINE); + + /* Set the status for each account */ + gaim_savedstatus_activate(saved_status); + } + else + { + /* Everything is good to go--sign on already */ + if (!gaim_prefs_get_bool("/core/savedstatus/startup_current_status")) + gaim_savedstatus_activate(gaim_savedstatus_get_startup()); + gaim_accounts_restore_current_statuses(); + } + + return 1; +} + +int main(int argc, char **argv) +{ + signal(SIGPIPE, SIG_IGN); + + /* Initialize the libgaim stuff */ + if (!init_libgaim(argc, argv)) + return 0; + + gaim_blist_show(); + gnt_main(); + +#ifdef STANDALONE + gaim_core_quit(); +#endif + + return 0; +} + diff -r 317e7613e581 -r 0e3a8505ebbe finch/gntgaim.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/gntgaim.h Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,27 @@ +/** + * gaim + * + * Gaim is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include + +#include "libpurple/internal.h" + +#define GAIM_GNT_UI "gnt-gaim" + diff -r 317e7613e581 -r 0e3a8505ebbe finch/gntidle.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/gntidle.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,45 @@ +/* + * gaim + * + * Gaim is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "internal.h" +#include "gntidle.h" +#include "gntwm.h" + +#include "idle.h" + +static time_t +finch_get_idle_time() +{ + return gnt_wm_get_idle_time(); +} + +static GaimIdleUiOps ui_ops = +{ + finch_get_idle_time +}; + +GaimIdleUiOps * +finch_idle_get_ui_ops() +{ + return &ui_ops; +} diff -r 317e7613e581 -r 0e3a8505ebbe finch/gntidle.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/gntidle.h Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,44 @@ +/** + * @file gntidle.h GNT Idle API + * @ingroup gntui + * + * gaim + * + * Pidgin is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _GNT_IDLE_H_ +#define _GNT_IDLE_H_ + +#include "idle.h" + +/**************************************************************************/ +/** @name GNT Idle API */ +/**************************************************************************/ +/*@{*/ + +/** + * Returns the GNT idle UI ops. + * + * @return The UI operations structure. + */ +GaimIdleUiOps *finch_idle_get_ui_ops(void); + +/*@}*/ + +#endif /* _Finch_IDLE_H_ */ diff -r 317e7613e581 -r 0e3a8505ebbe finch/gntnotify.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/gntnotify.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,374 @@ +/** + * @file gntnotify.c GNT Notify API + * @ingroup gntui + * + * gaim + * + * Gaim is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include + +#include + +#include "gntnotify.h" +#include "gntgaim.h" + +static struct +{ + GntWidget *window; + GntWidget *tree; +} emaildialog; + +static void +notify_msg_window_destroy_cb(GntWidget *window, GaimNotifyMsgType type) +{ + gaim_notify_close(type, window); +} + +static void * +finch_notify_message(GaimNotifyMsgType type, const char *title, + const char *primary, const char *secondary) +{ + GntWidget *window, *button; + GntTextFormatFlags pf = 0, sf = 0; + + switch (type) + { + case GAIM_NOTIFY_MSG_ERROR: + sf |= GNT_TEXT_FLAG_BOLD; + case GAIM_NOTIFY_MSG_WARNING: + pf |= GNT_TEXT_FLAG_UNDERLINE; + case GAIM_NOTIFY_MSG_INFO: + pf |= GNT_TEXT_FLAG_BOLD; + break; + } + + window = gnt_box_new(FALSE, TRUE); + gnt_box_set_toplevel(GNT_BOX(window), TRUE); + gnt_box_set_title(GNT_BOX(window), title); + gnt_box_set_fill(GNT_BOX(window), FALSE); + gnt_box_set_alignment(GNT_BOX(window), GNT_ALIGN_MID); + + if (primary) + gnt_box_add_widget(GNT_BOX(window), + gnt_label_new_with_format(primary, pf)); + if (secondary) + gnt_box_add_widget(GNT_BOX(window), + gnt_label_new_with_format(secondary, sf)); + + button = gnt_button_new(_("OK")); + gnt_box_add_widget(GNT_BOX(window), button); + g_signal_connect_swapped(G_OBJECT(button), "activate", + G_CALLBACK(gnt_widget_destroy), window); + g_signal_connect(G_OBJECT(window), "destroy", + G_CALLBACK(notify_msg_window_destroy_cb), GINT_TO_POINTER(type)); + + gnt_widget_show(window); + return window; +} + +/* handle is, in all/most occasions, a GntWidget * */ +static void finch_close_notify(GaimNotifyType type, void *handle) +{ + GntWidget *widget = handle; + + if (!widget) + return; + + while (widget->parent) + widget = widget->parent; + + if (type == GAIM_NOTIFY_SEARCHRESULTS) + gaim_notify_searchresults_free(g_object_get_data(handle, "notify-results")); +#if 1 + /* This did not seem to be necessary */ + g_signal_handlers_disconnect_by_func(G_OBJECT(widget), + G_CALLBACK(notify_msg_window_destroy_cb), GINT_TO_POINTER(type)); +#endif + gnt_widget_destroy(widget); +} + +static void *finch_notify_formatted(const char *title, const char *primary, + const char *secondary, const char *text) +{ + /* XXX: For now, simply strip the html and use _notify_message. For future use, + * there should be some way of parsing the makrups from GntTextView */ + char *unformat = gaim_markup_strip_html(text); + char *t = g_strdup_printf("%s%s%s", + secondary ? secondary : "", + secondary ? "\n" : "", + unformat ? unformat : ""); + + void *ret = finch_notify_message(GAIM_NOTIFY_FORMATTED, title, primary, t); + + g_free(t); + g_free(unformat); + + return ret; +} + +static void +reset_email_dialog() +{ + emaildialog.window = NULL; + emaildialog.tree = NULL; +} + +static void +setup_email_dialog() +{ + GntWidget *box, *tree, *button; + if (emaildialog.window) + return; + + emaildialog.window = box = gnt_vbox_new(FALSE); + gnt_box_set_toplevel(GNT_BOX(box), TRUE); + gnt_box_set_title(GNT_BOX(box), _("Emails")); + gnt_box_set_fill(GNT_BOX(box), FALSE); + gnt_box_set_alignment(GNT_BOX(box), GNT_ALIGN_MID); + gnt_box_set_pad(GNT_BOX(box), 0); + + gnt_box_add_widget(GNT_BOX(box), + gnt_label_new_with_format(_("You have mail!"), GNT_TEXT_FLAG_BOLD)); + + emaildialog.tree = tree = gnt_tree_new_with_columns(3); + gnt_tree_set_column_titles(GNT_TREE(tree), _("Account"), _("From"), _("Subject")); + gnt_tree_set_show_title(GNT_TREE(tree), TRUE); + gnt_tree_set_col_width(GNT_TREE(tree), 0, 15); + gnt_tree_set_col_width(GNT_TREE(tree), 1, 25); + gnt_tree_set_col_width(GNT_TREE(tree), 2, 25); + + gnt_box_add_widget(GNT_BOX(box), tree); + + button = gnt_button_new(_("Close")); + gnt_box_add_widget(GNT_BOX(box), button); + + g_signal_connect_swapped(G_OBJECT(button), "activate", G_CALLBACK(gnt_widget_destroy), box); + g_signal_connect(G_OBJECT(box), "destroy", G_CALLBACK(reset_email_dialog), NULL); +} + +static void * +finch_notify_emails(GaimConnection *gc, size_t count, gboolean detailed, + const char **subjects, const char **froms, const char **tos, + const char **urls) +{ + GaimAccount *account = gaim_connection_get_account(gc); + GString *message = g_string_new(NULL); + void *ret; + + if (!detailed) + { + g_string_append_printf(message, + ngettext("%s (%s) has %d new message.", + "%s (%s) has %d new messages.", + (int)count), + tos ? *tos : gaim_account_get_username(account), + gaim_account_get_protocol_name(account), (int)count); + } + else + { + char *to; + + setup_email_dialog(); + + to = g_strdup_printf("%s (%s)", tos ? *tos : gaim_account_get_username(account), + gaim_account_get_protocol_name(account)); + gnt_tree_add_row_after(GNT_TREE(emaildialog.tree), GINT_TO_POINTER(time(NULL)), + gnt_tree_create_row(GNT_TREE(emaildialog.tree), to, + froms ? *froms : "[Unknown sender]", + *subjects), + NULL, NULL); + g_free(to); + gnt_widget_show(emaildialog.window); + return NULL; + } + + ret = finch_notify_message(GAIM_NOTIFY_EMAIL, _("New Mail"), _("You have mail!"), message->str); + g_string_free(message, TRUE); + return ret; +} + +static void * +finch_notify_email(GaimConnection *gc, const char *subject, const char *from, + const char *to, const char *url) +{ + return finch_notify_emails(gc, 1, subject != NULL, + subject ? &subject : NULL, + from ? &from : NULL, + to ? &to : NULL, + url ? &url : NULL); +} + +static void * +finch_notify_userinfo(GaimConnection *gc, const char *who, GaimNotifyUserInfo *user_info) +{ + /* Xeroxed from gtknotify.c */ + char *primary; + char *info; + void *ui_handle; + + primary = g_strdup_printf(_("Info for %s"), who); + info = gaim_notify_user_info_get_text_with_newline(user_info, "
"); + ui_handle = finch_notify_formatted(_("Buddy Information"), primary, NULL, info); + g_free(info); + g_free(primary); + return ui_handle; +} + +static void +notify_button_activated(GntWidget *widget, GaimNotifySearchButton *b) +{ + GList *list = NULL; + GaimAccount *account = g_object_get_data(G_OBJECT(widget), "notify-account"); + gpointer data = g_object_get_data(G_OBJECT(widget), "notify-data"); + + list = gnt_tree_get_selection_text_list(GNT_TREE(widget)); + + b->callback(gaim_account_get_connection(account), list, data); + g_list_foreach(list, (GFunc)g_free, NULL); + g_list_free(list); +} + +static void +finch_notify_sr_new_rows(GaimConnection *gc, + GaimNotifySearchResults *results, void *data) +{ + GntTree *tree = GNT_TREE(data); + GList *o; + + /* XXX: Do I need to empty the tree here? */ + + for (o = results->rows; o; o = o->next) + { + gnt_tree_add_row_after(GNT_TREE(tree), o->data, + gnt_tree_create_row_from_list(GNT_TREE(tree), o->data), + NULL, NULL); + } +} + +static void * +finch_notify_searchresults(GaimConnection *gc, const char *title, + const char *primary, const char *secondary, + GaimNotifySearchResults *results, gpointer data) +{ + GntWidget *window, *tree, *box, *button; + GList *iter; + + window = gnt_vbox_new(FALSE); + gnt_box_set_toplevel(GNT_BOX(window), TRUE); + gnt_box_set_title(GNT_BOX(window), title); + gnt_box_set_fill(GNT_BOX(window), FALSE); + gnt_box_set_pad(GNT_BOX(window), 0); + gnt_box_set_alignment(GNT_BOX(window), GNT_ALIGN_MID); + + gnt_box_add_widget(GNT_BOX(window), + gnt_label_new_with_format(primary, GNT_TEXT_FLAG_BOLD)); + gnt_box_add_widget(GNT_BOX(window), + gnt_label_new_with_format(secondary, GNT_TEXT_FLAG_NORMAL)); + + tree = gnt_tree_new_with_columns(g_list_length(results->columns)); + gnt_tree_set_show_title(GNT_TREE(tree), TRUE); + gnt_box_add_widget(GNT_BOX(window), tree); + + box = gnt_hbox_new(TRUE); + + for (iter = results->buttons; iter; iter = iter->next) + { + GaimNotifySearchButton *b = iter->data; + const char *text; + + switch (b->type) + { + case GAIM_NOTIFY_BUTTON_LABELED: + text = b->label; + break; + case GAIM_NOTIFY_BUTTON_CONTINUE: + text = _("Continue"); + break; + case GAIM_NOTIFY_BUTTON_ADD: + text = _("Add"); + break; + case GAIM_NOTIFY_BUTTON_INFO: + text = _("Info"); + break; + case GAIM_NOTIFY_BUTTON_IM: + text = _("IM"); + break; + case GAIM_NOTIFY_BUTTON_JOIN: + text = _("Join"); + break; + case GAIM_NOTIFY_BUTTON_INVITE: + text = _("Invite"); + break; + default: + text = _("(none)"); + } + + button = gnt_button_new(text); + g_object_set_data(G_OBJECT(button), "notify-account", gaim_connection_get_account(gc)); + g_object_set_data(G_OBJECT(button), "notify-data", data); + g_signal_connect_swapped(G_OBJECT(button), "activate", + G_CALLBACK(notify_button_activated), b); + + gnt_box_add_widget(GNT_BOX(box), button); + } + + gnt_box_add_widget(GNT_BOX(window), box); + + finch_notify_sr_new_rows(gc, results, tree); + + gnt_widget_show(window); + g_object_set_data(G_OBJECT(window), "notify-results", results); + + return tree; +} + +static GaimNotifyUiOps ops = +{ + .notify_message = finch_notify_message, + .close_notify = finch_close_notify, /* The rest of the notify-uiops return a GntWidget. + These widgets should be destroyed from here. */ + .notify_formatted = finch_notify_formatted, + .notify_email = finch_notify_email, + .notify_emails = finch_notify_emails, + .notify_userinfo = finch_notify_userinfo, + + .notify_searchresults = finch_notify_searchresults, + .notify_searchresults_new_rows = finch_notify_sr_new_rows, + .notify_uri = NULL /* This is of low-priority to me */ +}; + +GaimNotifyUiOps *finch_notify_get_ui_ops() +{ + return &ops; +} + +void finch_notify_init() +{ +} + +void finch_notify_uninit() +{ +} + + diff -r 317e7613e581 -r 0e3a8505ebbe finch/gntnotify.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/gntnotify.h Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,55 @@ +/** + * @file gntnotify.h GNT Notify API + * @ingroup gntui + * + * gaim + * + * Gaim is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _GNT_NOTIFY_H +#define _GNT_NOTIFY_H + +#include "notify.h" + +/********************************************************************** + * @name GNT Notify API + **********************************************************************/ +/*@{*/ + +/** + * Get the ui-functions. + * + * @return The GaimNotifyUiOps structure populated with the appropriate functions. + */ +GaimNotifyUiOps *finch_notify_get_ui_ops(void); + +/** + * Perform necessary initializations. + */ +void finch_notify_init(void); + +/** + * Perform necessary uninitializations. + */ +void finch_notify_uninit(void); + +/*@}*/ + +#endif + diff -r 317e7613e581 -r 0e3a8505ebbe finch/gntplugin.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/gntplugin.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,274 @@ +/** + * @file gntplugin.c GNT Plugins API + * @ingroup gntui + * + * gaim + * + * Gaim is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include + +#include "notify.h" + +#include "gntgaim.h" +#include "gntplugin.h" + +static struct +{ + GntWidget *tree; + GntWidget *window; + GntWidget *aboot; + GntWidget *conf; +} plugins; + +static GHashTable *confwins; + +static void +decide_conf_button(GaimPlugin *plugin) +{ + if (gaim_plugin_is_loaded(plugin) && + ((GAIM_IS_GNT_PLUGIN(plugin) && + GAIM_GNT_PLUGIN_UI_INFO(plugin) != NULL) || + (plugin->info->prefs_info && + plugin->info->prefs_info->get_plugin_pref_frame))) + gnt_widget_set_visible(plugins.conf, TRUE); + else + gnt_widget_set_visible(plugins.conf, FALSE); + + gnt_box_readjust(GNT_BOX(plugins.window)); + gnt_widget_draw(plugins.window); +} + +static void +plugin_toggled_cb(GntWidget *tree, GaimPlugin *plugin, gpointer null) +{ + if (gnt_tree_get_choice(GNT_TREE(tree), plugin)) + { + if(!gaim_plugin_load(plugin)) + gaim_notify_error(NULL, "ERROR", "loading plugin failed", NULL); + } + else + { + GntWidget *win; + + if (!gaim_plugin_unload(plugin)) + gaim_notify_error(NULL, "ERROR", "unloading plugin failed", NULL); + + if ((win = g_hash_table_lookup(confwins, plugin)) != NULL) + { + gnt_widget_destroy(win); + } + } + decide_conf_button(plugin); + finch_plugins_save_loaded(); +} + +/* Xerox */ +void +finch_plugins_save_loaded(void) +{ + gaim_plugins_save_loaded("/gaim/gnt/plugins/loaded"); +} + +static void +selection_changed(GntWidget *widget, gpointer old, gpointer current, gpointer null) +{ + GaimPlugin *plugin = current; + char *text; + + /* XXX: Use formatting and stuff */ + gnt_text_view_clear(GNT_TEXT_VIEW(plugins.aboot)); + text = g_strdup_printf(_("Name: %s\nVersion: %s\nDescription: %s\nAuthor: %s\nWebsite: %s\nFilename: %s\n"), + SAFE(plugin->info->name), SAFE(plugin->info->version), SAFE(plugin->info->description), + SAFE(plugin->info->author), SAFE(plugin->info->homepage), SAFE(plugin->path)); + gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(plugins.aboot), + text, GNT_TEXT_FLAG_NORMAL); + gnt_text_view_scroll(GNT_TEXT_VIEW(plugins.aboot), 0); + g_free(text); + decide_conf_button(plugin); +} + +static void +reset_plugin_window(GntWidget *window, gpointer null) +{ + plugins.window = NULL; + plugins.tree = NULL; + plugins.aboot = NULL; +} + +static int +plugin_compare(GaimPlugin *p1, GaimPlugin *p2) +{ + char *s1 = g_utf8_strup(p1->info->name, -1); + char *s2 = g_utf8_strup(p2->info->name, -1); + int ret = g_utf8_collate(s1, s2); + g_free(s1); + g_free(s2); + return ret; +} + +static void +confwin_init() +{ + confwins = g_hash_table_new(g_direct_hash, g_direct_equal); +} + +static void +remove_confwin(GntWidget *window, gpointer plugin) +{ + g_hash_table_remove(confwins, plugin); +} + +static void +configure_plugin_cb(GntWidget *button, gpointer null) +{ + GaimPlugin *plugin; + FinchPluginFrame callback; + + g_return_if_fail(plugins.tree != NULL); + + plugin = gnt_tree_get_selection_data(GNT_TREE(plugins.tree)); + if (!gaim_plugin_is_loaded(plugin)) + { + gaim_notify_error(plugin, _("Error"), + _("Plugin need to be loaded before you can configure it."), NULL); + return; + } + + if (confwins && g_hash_table_lookup(confwins, plugin)) + return; + + if (GAIM_IS_GNT_PLUGIN(plugin) && + (callback = GAIM_GNT_PLUGIN_UI_INFO(plugin)) != NULL) + { + GntWidget *window = gnt_vbox_new(FALSE); + GntWidget *box, *button; + + gnt_box_set_toplevel(GNT_BOX(window), TRUE); + gnt_box_set_title(GNT_BOX(window), plugin->info->name); + gnt_box_set_alignment(GNT_BOX(window), GNT_ALIGN_MID); + + box = callback(); + gnt_box_add_widget(GNT_BOX(window), box); + + box = gnt_hbox_new(FALSE); + gnt_box_add_widget(GNT_BOX(window), box); + + button = gnt_button_new(_("Close")); + gnt_box_add_widget(GNT_BOX(box), button); + g_signal_connect_swapped(G_OBJECT(button), "activate", + G_CALLBACK(gnt_widget_destroy), window); + g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(remove_confwin), plugin); + + gnt_widget_show(window); + + if (confwins == NULL) + confwin_init(); + g_hash_table_insert(confwins, plugin, window); + } + else if (plugin->info->prefs_info && + plugin->info->prefs_info->get_plugin_pref_frame) + { + gaim_notify_info(plugin, _("..."), + _("Still need to do something about this."), NULL); + return; + } + else + { + gaim_notify_info(plugin, _("Error"), + _("No configuration options for this plugin."), NULL); + return; + } +} + +void finch_plugins_show_all() +{ + GntWidget *window, *tree, *box, *aboot, *button; + GList *iter; + if (plugins.window) + return; + + gaim_plugins_probe(G_MODULE_SUFFIX); + + plugins.window = window = gnt_vbox_new(FALSE); + gnt_box_set_toplevel(GNT_BOX(window), TRUE); + gnt_box_set_title(GNT_BOX(window), _("Plugins")); + gnt_box_set_pad(GNT_BOX(window), 0); + gnt_box_set_alignment(GNT_BOX(window), GNT_ALIGN_MID); + + gnt_box_add_widget(GNT_BOX(window), + gnt_label_new(_("You can (un)load plugins from the following list."))); + gnt_box_add_widget(GNT_BOX(window), gnt_hline_new()); + + box = gnt_hbox_new(FALSE); + gnt_box_add_widget(GNT_BOX(window), box); + gnt_box_add_widget(GNT_BOX(window), gnt_hline_new()); + + gnt_box_set_pad(GNT_BOX(box), 0); + plugins.tree = tree = gnt_tree_new(); + gnt_tree_set_compare_func(GNT_TREE(tree), (GCompareFunc)plugin_compare); + GNT_WIDGET_SET_FLAGS(tree, GNT_WIDGET_NO_BORDER); + gnt_box_add_widget(GNT_BOX(box), tree); + gnt_box_add_widget(GNT_BOX(box), gnt_vline_new()); + + plugins.aboot = aboot = gnt_text_view_new(); + gnt_widget_set_size(aboot, 40, 20); + gnt_box_add_widget(GNT_BOX(box), aboot); + + for (iter = gaim_plugins_get_all(); iter; iter = iter->next) + { + GaimPlugin *plug = iter->data; + + if (plug->info->type != GAIM_PLUGIN_STANDARD || + (plug->info->flags & GAIM_PLUGIN_FLAG_INVISIBLE) || + plug->error) + continue; + + gnt_tree_add_choice(GNT_TREE(tree), plug, + gnt_tree_create_row(GNT_TREE(tree), plug->info->name), NULL, NULL); + gnt_tree_set_choice(GNT_TREE(tree), plug, gaim_plugin_is_loaded(plug)); + } + gnt_tree_set_col_width(GNT_TREE(tree), 0, 30); + g_signal_connect(G_OBJECT(tree), "toggled", G_CALLBACK(plugin_toggled_cb), NULL); + g_signal_connect(G_OBJECT(tree), "selection_changed", G_CALLBACK(selection_changed), NULL); + + box = gnt_hbox_new(FALSE); + gnt_box_add_widget(GNT_BOX(window), box); + + button = gnt_button_new(_("Close")); + gnt_box_add_widget(GNT_BOX(box), button); + g_signal_connect_swapped(G_OBJECT(button), "activate", + G_CALLBACK(gnt_widget_destroy), window); + + plugins.conf = button = gnt_button_new(_("Configure Plugin")); + gnt_box_add_widget(GNT_BOX(box), button); + g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(configure_plugin_cb), NULL); + + g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(reset_plugin_window), NULL); + + gnt_widget_show(window); + + decide_conf_button(gnt_tree_get_selection_data(GNT_TREE(tree))); +} + diff -r 317e7613e581 -r 0e3a8505ebbe finch/gntplugin.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/gntplugin.h Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,71 @@ +/** + * @file gntplugin.h GNT Plugins API + * @ingroup gntui + * + * gaim + * + * Gaim is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _GNT_PLUGIN_H +#define _GNT_PLUGIN_H + +#include + +#include + +#include + +#include "gntgaim.h" + +/********************************************************************** + * @name GNT Plugins API + **********************************************************************/ +/*@{*/ + +typedef GntWidget* (*FinchPluginFrame) (); + +/* Guess where these came from */ +#define GAIM_GNT_PLUGIN_TYPE GAIM_GNT_UI + +/** + * Decide whether a plugin is a GNT-plugin. + */ +#define GAIM_IS_GNT_PLUGIN(plugin) \ + ((plugin)->info != NULL && (plugin)->info->ui_info != NULL && \ + !strcmp((plugin)->info->ui_requirement, GAIM_GNT_PLUGIN_TYPE)) + +/** + * Get the ui-info from GNT-plugins. + */ +#define GAIM_GNT_PLUGIN_UI_INFO(plugin) \ + (FinchPluginFrame)((plugin)->info->ui_info) + +/** + * Show a list of plugins. + */ +void finch_plugins_show_all(void); + +/** + * Save the list of loaded plugins. + */ +void finch_plugins_save_loaded(void); + +/*@}*/ + +#endif diff -r 317e7613e581 -r 0e3a8505ebbe finch/gntpounce.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/gntpounce.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,956 @@ +/** + * @file gntpounce.c GNT Buddy Pounce API + * @ingroup gntui + * + * gaim + * + * Gaim is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "internal.h" +#include "gntgaim.h" + +#include "account.h" +#include "conversation.h" +#include "debug.h" +#include "notify.h" +#include "prpl.h" +#include "request.h" +#include "server.h" +#include "util.h" + +#include "gntpounce.h" + + +typedef struct +{ + /* Pounce data */ + GaimPounce *pounce; + GaimAccount *account; + + /* The window */ + GntWidget *window; + + /* Pounce on Whom */ + GntWidget *account_menu; + GntWidget *buddy_entry; + + /* Pounce options */ + GntWidget *on_away; + + /* Pounce When Buddy... */ + GntWidget *signon; + GntWidget *signoff; + GntWidget *away; + GntWidget *away_return; + GntWidget *idle; + GntWidget *idle_return; + GntWidget *typing; + GntWidget *typed; + GntWidget *stop_typing; + GntWidget *message_recv; + + /* Action */ + GntWidget *open_win; + GntWidget *popup; + GntWidget *popup_entry; + GntWidget *send_msg; + GntWidget *send_msg_entry; + GntWidget *exec_cmd; + GntWidget *exec_cmd_entry; + GntWidget *play_sound; + + GntWidget *save_pounce; + + /* Buttons */ + GntWidget *save_button; + +} GaimGntPounceDialog; + +typedef struct +{ + GntWidget *window; + GntWidget *tree; + GntWidget *modify_button; + GntWidget *delete_button; +} PouncesManager; + +static PouncesManager *pounces_manager = NULL; + +/************************************************************************** + * Callbacks + **************************************************************************/ +static gint +delete_win_cb(GntWidget *w, GaimGntPounceDialog *dialog) +{ + gnt_widget_destroy(dialog->window); + g_free(dialog); + + return TRUE; +} + +static void +cancel_cb(GntWidget *w, GaimGntPounceDialog *dialog) +{ + gnt_widget_destroy(dialog->window); +} + +static void +add_pounce_to_treeview(GntTree *tree, GaimPounce *pounce) +{ + GaimAccount *account; + const char *pouncer; + const char *pouncee; + + account = gaim_pounce_get_pouncer(pounce); + pouncer = gaim_account_get_username(account); + pouncee = gaim_pounce_get_pouncee(pounce); + gnt_tree_add_row_last(tree, pounce, + gnt_tree_create_row(tree, pouncer, pouncee), NULL); +} + +static void +populate_pounces_list(PouncesManager *dialog) +{ + const GList *pounces; + + gnt_tree_remove_all(GNT_TREE(dialog->tree)); + + for (pounces = gaim_pounces_get_all(); pounces != NULL; + pounces = g_list_next(pounces)) + { + add_pounce_to_treeview(GNT_TREE(dialog->tree), pounces->data); + } +} + +static void +update_pounces(void) +{ + /* Rebuild the pounces list if the pounces manager is open */ + if (pounces_manager != NULL) + { + populate_pounces_list(pounces_manager); + } +} + +static void +signed_on_off_cb(GaimConnection *gc, gpointer user_data) +{ + update_pounces(); +} + +static void +save_pounce_cb(GntWidget *w, GaimGntPounceDialog *dialog) +{ + const char *name; + const char *message, *command, *reason; + GaimPounceEvent events = GAIM_POUNCE_NONE; + GaimPounceOption options = GAIM_POUNCE_OPTION_NONE; + + name = gnt_entry_get_text(GNT_ENTRY(dialog->buddy_entry)); + + if (*name == '\0') + { + gaim_notify_error(NULL, NULL, + _("Please enter a buddy to pounce."), NULL); + return; + } + + /* Options */ + if (gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->on_away))) + options |= GAIM_POUNCE_OPTION_AWAY; + + /* Events */ + if (gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->signon))) + events |= GAIM_POUNCE_SIGNON; + + if (gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->signoff))) + events |= GAIM_POUNCE_SIGNOFF; + + if (gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->away))) + events |= GAIM_POUNCE_AWAY; + + if (gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->away_return))) + events |= GAIM_POUNCE_AWAY_RETURN; + + if (gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->idle))) + events |= GAIM_POUNCE_IDLE; + + if (gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->idle_return))) + events |= GAIM_POUNCE_IDLE_RETURN; + + if (gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->typing))) + events |= GAIM_POUNCE_TYPING; + + if (gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->typed))) + events |= GAIM_POUNCE_TYPED; + + if (gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->stop_typing))) + events |= GAIM_POUNCE_TYPING_STOPPED; + + if (gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->message_recv))) + events |= GAIM_POUNCE_MESSAGE_RECEIVED; + + /* Data fields */ + message = gnt_entry_get_text(GNT_ENTRY(dialog->send_msg_entry)); + command = gnt_entry_get_text(GNT_ENTRY(dialog->exec_cmd_entry)); + reason = gnt_entry_get_text(GNT_ENTRY(dialog->popup_entry)); + + if (*reason == '\0') reason = NULL; + if (*message == '\0') message = NULL; + if (*command == '\0') command = NULL; + + if (dialog->pounce == NULL) { + dialog->pounce = gaim_pounce_new(GAIM_GNT_UI, dialog->account, + name, events, options); + } else { + gaim_pounce_set_events(dialog->pounce, events); + gaim_pounce_set_options(dialog->pounce, options); + gaim_pounce_set_pouncer(dialog->pounce, dialog->account); + gaim_pounce_set_pouncee(dialog->pounce, name); + } + + /* Actions */ + gaim_pounce_action_set_enabled(dialog->pounce, "open-window", + gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->open_win))); + gaim_pounce_action_set_enabled(dialog->pounce, "popup-notify", + gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->popup))); + gaim_pounce_action_set_enabled(dialog->pounce, "send-message", + gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->send_msg))); + gaim_pounce_action_set_enabled(dialog->pounce, "execute-command", + gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->exec_cmd))); + gaim_pounce_action_set_enabled(dialog->pounce, "play-beep", + gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->play_sound))); + + gaim_pounce_action_set_attribute(dialog->pounce, "send-message", + "message", message); + gaim_pounce_action_set_attribute(dialog->pounce, "execute-command", + "command", command); + gaim_pounce_action_set_attribute(dialog->pounce, "popup-notify", + "reason", reason); + + /* Set the defaults for next time. */ + gaim_prefs_set_bool("/gaim/gnt/pounces/default_actions/open-window", + gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->open_win))); + gaim_prefs_set_bool("/gaim/gnt/pounces/default_actions/popup-notify", + gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->popup))); + gaim_prefs_set_bool("/gaim/gnt/pounces/default_actions/send-message", + gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->send_msg))); + gaim_prefs_set_bool("/gaim/gnt/pounces/default_actions/execute-command", + gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->exec_cmd))); + gaim_prefs_set_bool("/gaim/gnt/pounces/default_actions/play-beep", + gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->play_sound))); + + gaim_pounce_set_save(dialog->pounce, + gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->save_pounce))); + + gaim_pounce_set_pouncer(dialog->pounce, + (GaimAccount *)gnt_combo_box_get_selected_data(GNT_COMBO_BOX(dialog->account_menu))); + + update_pounces(); + + gnt_widget_destroy(dialog->window); +} + + +void +finch_pounce_editor_show(GaimAccount *account, const char *name, + GaimPounce *cur_pounce) +{ + GaimGntPounceDialog *dialog; + GntWidget *window; + GntWidget *bbox; + GntWidget *hbox; + GntWidget *button; + GntWidget *combo; + GList *list; + + g_return_if_fail((cur_pounce != NULL) || + (account != NULL) || + (gaim_accounts_get_all() != NULL)); + + dialog = g_new0(GaimGntPounceDialog, 1); + + if (cur_pounce != NULL) { + dialog->pounce = cur_pounce; + dialog->account = gaim_pounce_get_pouncer(cur_pounce); + } else if (account != NULL) { + dialog->pounce = NULL; + dialog->account = account; + } else { + GList *connections = gaim_connections_get_all(); + GaimConnection *gc; + + if (connections != NULL) { + gc = (GaimConnection *)connections->data; + dialog->account = gaim_connection_get_account(gc); + } else + dialog->account = gaim_accounts_get_all()->data; + + dialog->pounce = NULL; + } + + /* Create the window. */ + dialog->window = window = gnt_vbox_new(FALSE); + gnt_box_set_pad(GNT_BOX(window), 0); + gnt_box_set_toplevel(GNT_BOX(window), TRUE); + gnt_box_set_alignment(GNT_BOX(window), GNT_ALIGN_LEFT); + gnt_box_set_title(GNT_BOX(window), + (cur_pounce == NULL + ? _("New Buddy Pounce") : _("Edit Buddy Pounce"))); + + g_signal_connect(G_OBJECT(window), "destroy", + G_CALLBACK(delete_win_cb), dialog); + + gnt_box_add_widget(GNT_BOX(window), gnt_label_new_with_format(_("Pounce Who"), GNT_TEXT_FLAG_BOLD)); + + /* Account: */ + gnt_box_add_widget(GNT_BOX(window), gnt_label_new(_("Account:"))); + dialog->account_menu = combo = gnt_combo_box_new(); + list = gaim_accounts_get_all(); + for (; list; list = list->next) + { + GaimAccount *account; + char *text; + + account = list->data; + text = g_strdup_printf("%s (%s)", + gaim_account_get_username(account), + gaim_account_get_protocol_name(account)); + gnt_combo_box_add_data(GNT_COMBO_BOX(combo), account, text); + g_free(text); + } + if (dialog->account) + gnt_combo_box_set_selected(GNT_COMBO_BOX(combo), dialog->account); + + gnt_box_add_widget(GNT_BOX(window), combo); + + /* Buddy: */ + hbox = gnt_hbox_new(FALSE); + gnt_box_add_widget(GNT_BOX(hbox), gnt_label_new(_("Buddy name:"))); + + dialog->buddy_entry = gnt_entry_new(NULL); + gnt_box_add_widget(GNT_BOX(hbox), dialog->buddy_entry); + + gnt_box_add_widget(GNT_BOX(window), hbox); + + if (cur_pounce != NULL) { + gnt_entry_set_text(GNT_ENTRY(dialog->buddy_entry), + gaim_pounce_get_pouncee(cur_pounce)); + } else if (name != NULL) { + gnt_entry_set_text(GNT_ENTRY(dialog->buddy_entry), name); + } + + gnt_box_add_widget(GNT_BOX(window), gnt_line_new(FALSE)); + gnt_box_add_widget(GNT_BOX(window), gnt_label_new_with_format(_("Pounce When Buddy..."), GNT_TEXT_FLAG_BOLD)); + + dialog->signon = gnt_check_box_new(_("Signs on")); + dialog->signoff = gnt_check_box_new(_("Signs off")); + dialog->away = gnt_check_box_new(_("Goes away")); + dialog->away_return = gnt_check_box_new(_("Returns from away")); + dialog->idle = gnt_check_box_new(_("Becomes idle")); + dialog->idle_return = gnt_check_box_new(_("Is no longer idle")); + dialog->typing = gnt_check_box_new(_("Starts typing")); + dialog->typed = gnt_check_box_new(_("Pauses while typing")); + dialog->stop_typing = gnt_check_box_new(_("Stops typing")); + dialog->message_recv = gnt_check_box_new(_("Sends a message")); + + hbox = gnt_hbox_new(FALSE); + gnt_box_set_pad(GNT_BOX(hbox), 2); + gnt_box_add_widget(GNT_BOX(hbox), dialog->signon); + gnt_box_add_widget(GNT_BOX(hbox), dialog->signoff); + gnt_box_add_widget(GNT_BOX(window), hbox); + hbox = gnt_hbox_new(FALSE); + gnt_box_set_pad(GNT_BOX(hbox), 2); + gnt_box_add_widget(GNT_BOX(hbox), dialog->away); + gnt_box_add_widget(GNT_BOX(hbox), dialog->away_return); + gnt_box_add_widget(GNT_BOX(window), hbox); + hbox = gnt_hbox_new(FALSE); + gnt_box_set_pad(GNT_BOX(hbox), 2); + gnt_box_add_widget(GNT_BOX(hbox), dialog->idle); + gnt_box_add_widget(GNT_BOX(hbox), dialog->idle_return); + gnt_box_add_widget(GNT_BOX(window), hbox); + hbox = gnt_hbox_new(FALSE); + gnt_box_set_pad(GNT_BOX(hbox), 2); + gnt_box_add_widget(GNT_BOX(hbox), dialog->typing); + gnt_box_add_widget(GNT_BOX(hbox), dialog->typed); + gnt_box_add_widget(GNT_BOX(window), hbox); + hbox = gnt_hbox_new(FALSE); + gnt_box_set_pad(GNT_BOX(hbox), 2); + gnt_box_add_widget(GNT_BOX(hbox), dialog->stop_typing); + gnt_box_add_widget(GNT_BOX(hbox), dialog->message_recv); + gnt_box_add_widget(GNT_BOX(window), hbox); + + /* Create the "Action" frame. */ + gnt_box_add_widget(GNT_BOX(window), gnt_line_new(FALSE)); + gnt_box_add_widget(GNT_BOX(window), gnt_label_new_with_format(_("Action"), GNT_TEXT_FLAG_BOLD)); + + dialog->open_win = gnt_check_box_new(_("Open an IM window")); + dialog->popup = gnt_check_box_new(_("Pop up a notification")); + dialog->send_msg = gnt_check_box_new(_("Send a message")); + dialog->exec_cmd = gnt_check_box_new(_("Execute a command")); + dialog->play_sound = gnt_check_box_new(_("Play a sound")); + + dialog->send_msg_entry = gnt_entry_new(NULL); + dialog->exec_cmd_entry = gnt_entry_new(NULL); + dialog->popup_entry = gnt_entry_new(NULL); + dialog->exec_cmd_entry = gnt_entry_new(NULL); + + hbox = gnt_hbox_new(FALSE); + gnt_box_add_widget(GNT_BOX(hbox), dialog->open_win); + gnt_box_add_widget(GNT_BOX(window), hbox); + hbox = gnt_hbox_new(FALSE); + gnt_box_add_widget(GNT_BOX(hbox), dialog->popup); + gnt_box_add_widget(GNT_BOX(hbox), dialog->popup_entry); + gnt_box_add_widget(GNT_BOX(window), hbox); + hbox = gnt_hbox_new(FALSE); + gnt_box_add_widget(GNT_BOX(hbox), dialog->send_msg); + gnt_box_add_widget(GNT_BOX(hbox), dialog->send_msg_entry); + gnt_box_add_widget(GNT_BOX(window), hbox); + hbox = gnt_hbox_new(FALSE); + gnt_box_add_widget(GNT_BOX(hbox), dialog->exec_cmd); + gnt_box_add_widget(GNT_BOX(hbox), dialog->exec_cmd_entry); + gnt_box_add_widget(GNT_BOX(window), hbox); + hbox = gnt_hbox_new(FALSE); + gnt_box_add_widget(GNT_BOX(hbox), dialog->play_sound); + gnt_box_add_widget(GNT_BOX(window), hbox); + + gnt_box_add_widget(GNT_BOX(window), gnt_line_new(FALSE)); + gnt_box_add_widget(GNT_BOX(window), gnt_label_new_with_format(_("Options"), GNT_TEXT_FLAG_BOLD)); + dialog->on_away = gnt_check_box_new(_("Pounce only when my status is not available")); + gnt_box_add_widget(GNT_BOX(window), dialog->on_away); + dialog->save_pounce = gnt_check_box_new(_("Recurring")); + gnt_box_add_widget(GNT_BOX(window), dialog->save_pounce); + + + gnt_box_add_widget(GNT_BOX(window), gnt_line_new(FALSE)); + /* Now the button box! */ + bbox = gnt_hbox_new(TRUE); + + /* Cancel button */ + button = gnt_button_new(_("Cancel")); + gnt_box_add_widget(GNT_BOX(bbox), button); + g_signal_connect(G_OBJECT(button), "activate", + G_CALLBACK(cancel_cb), dialog); + + /* Save button */ + dialog->save_button = button = gnt_button_new(_("Save")); + gnt_box_add_widget(GNT_BOX(bbox), button); + g_signal_connect(G_OBJECT(button), "activate", + G_CALLBACK(save_pounce_cb), dialog); + + gnt_box_add_widget(GNT_BOX(window), bbox); + + + /* Set the values of stuff. */ + if (cur_pounce != NULL) + { + GaimPounceEvent events = gaim_pounce_get_events(cur_pounce); + GaimPounceOption options = gaim_pounce_get_options(cur_pounce); + const char *value; + + /* Options */ + gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->on_away), + (options & GAIM_POUNCE_OPTION_AWAY)); + + /* Events */ + gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->signon), + (events & GAIM_POUNCE_SIGNON)); + gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->signoff), + (events & GAIM_POUNCE_SIGNOFF)); + gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->away), + (events & GAIM_POUNCE_AWAY)); + gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->away_return), + (events & GAIM_POUNCE_AWAY_RETURN)); + gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->idle), + (events & GAIM_POUNCE_IDLE)); + gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->idle_return), + (events & GAIM_POUNCE_IDLE_RETURN)); + gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->typing), + (events & GAIM_POUNCE_TYPING)); + gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->typed), + (events & GAIM_POUNCE_TYPED)); + gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->stop_typing), + (events & GAIM_POUNCE_TYPING_STOPPED)); + gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->message_recv), + (events & GAIM_POUNCE_MESSAGE_RECEIVED)); + + /* Actions */ + gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->open_win), + gaim_pounce_action_is_enabled(cur_pounce, "open-window")); + gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->popup), + gaim_pounce_action_is_enabled(cur_pounce, "popup-notify")); + gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->send_msg), + gaim_pounce_action_is_enabled(cur_pounce, "send-message")); + gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->exec_cmd), + gaim_pounce_action_is_enabled(cur_pounce, "execute-command")); + gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->play_sound), + gaim_pounce_action_is_enabled(cur_pounce, "play-beep")); + + gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->save_pounce), + gaim_pounce_get_save(cur_pounce)); + + if ((value = gaim_pounce_action_get_attribute(cur_pounce, + "send-message", + "message")) != NULL) + { + gnt_entry_set_text(GNT_ENTRY(dialog->send_msg_entry), value); + } + + if ((value = gaim_pounce_action_get_attribute(cur_pounce, + "popup-notify", + "reason")) != NULL) + { + gnt_entry_set_text(GNT_ENTRY(dialog->popup_entry), value); + } + + if ((value = gaim_pounce_action_get_attribute(cur_pounce, + "execute-command", + "command")) != NULL) + { + gnt_entry_set_text(GNT_ENTRY(dialog->exec_cmd_entry), value); + } + } + else + { + GaimBuddy *buddy = NULL; + + if (name != NULL) + buddy = gaim_find_buddy(account, name); + + /* Set some defaults */ + if (buddy == NULL) { + gnt_check_box_set_checked( + GNT_CHECK_BOX(dialog->signon), TRUE); + } else { + if (!GAIM_BUDDY_IS_ONLINE(buddy)) { + gnt_check_box_set_checked( + GNT_CHECK_BOX(dialog->signon), TRUE); + } else { + gboolean default_set = FALSE; + GaimPresence *presence = gaim_buddy_get_presence(buddy); + + if (gaim_presence_is_idle(presence)) + { + gnt_check_box_set_checked( + GNT_CHECK_BOX(dialog->idle_return), TRUE); + + default_set = TRUE; + } + + if (!gaim_presence_is_available(presence)) + { + gnt_check_box_set_checked( + GNT_CHECK_BOX(dialog->away_return), TRUE); + + default_set = TRUE; + } + + if (!default_set) + { + gnt_check_box_set_checked( + GNT_CHECK_BOX(dialog->signon), TRUE); + } + } + } + + gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->open_win), + gaim_prefs_get_bool("/gaim/gnt/pounces/default_actions/open-window")); + gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->popup), + gaim_prefs_get_bool("/gaim/gnt/pounces/default_actions/popup-notify")); + gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->send_msg), + gaim_prefs_get_bool("/gaim/gnt/pounces/default_actions/send-message")); + gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->exec_cmd), + gaim_prefs_get_bool("/gaim/gnt/pounces/default_actions/execute-command")); + gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->play_sound), + gaim_prefs_get_bool("/gaim/gnt/pounces/default_actions/play-beep")); + } + + gnt_widget_show(window); +} + + + +static gboolean +pounces_manager_destroy_cb(GntWidget *widget, gpointer user_data) +{ + PouncesManager *dialog = user_data; + + dialog->window = NULL; + finch_pounces_manager_hide(); + + return FALSE; +} + + +static void +pounces_manager_add_cb(GntButton *button, gpointer user_data) +{ + finch_pounce_editor_show(NULL, NULL, NULL); +} + + +static void +pounces_manager_modify_cb(GntButton *button, gpointer user_data) +{ + PouncesManager *dialog = user_data; + GaimPounce *pounce = gnt_tree_get_selection_data(GNT_TREE(dialog->tree)); + finch_pounce_editor_show(NULL, NULL, pounce); +} + +static void +pounces_manager_delete_confirm_cb(GaimPounce *pounce) +{ + gnt_tree_remove(GNT_TREE(pounces_manager->tree), pounce); + + gaim_request_close_with_handle(pounce); + gaim_pounce_destroy(pounce); +} + + +static void +pounces_manager_delete_cb(GntButton *button, gpointer user_data) +{ + PouncesManager *dialog = user_data; + GaimPounce *pounce; + GaimAccount *account; + const char *pouncer, *pouncee; + char *buf; + + pounce = (GaimPounce *)gnt_tree_get_selection_data(GNT_TREE(dialog->tree)); + account = gaim_pounce_get_pouncer(pounce); + pouncer = gaim_account_get_username(account); + pouncee = gaim_pounce_get_pouncee(pounce); + buf = g_strdup_printf(_("Are you sure you want to delete the pounce on %s for %s?"), pouncee, pouncer); + gaim_request_action(pounce, NULL, buf, NULL, 0, pounce, 2, + _("Delete"), pounces_manager_delete_confirm_cb, + _("Cancel"), NULL); + g_free(buf); +} + +static void +pounces_manager_close_cb(GntButton *button, gpointer user_data) +{ + finch_pounces_manager_hide(); +} + + +void +finch_pounces_manager_show(void) +{ + PouncesManager *dialog; + GntWidget *bbox; + GntWidget *button; + GntWidget *tree; + GntWidget *win; + + if (pounces_manager != NULL) { + return; + } + + pounces_manager = dialog = g_new0(PouncesManager, 1); + + dialog->window = win = gnt_vbox_new(FALSE); + gnt_box_set_toplevel(GNT_BOX(win), TRUE); + gnt_box_set_title(GNT_BOX(win), _("Buddy Pounces")); + gnt_box_set_pad(GNT_BOX(win), 0); + + g_signal_connect(G_OBJECT(win), "destroy", + G_CALLBACK(pounces_manager_destroy_cb), dialog); + + /* List of saved buddy pounces */ + dialog->tree = tree = GNT_WIDGET(gnt_tree_new_with_columns(2)); + gnt_tree_set_column_titles(GNT_TREE(tree), "Account", "Pouncee", NULL); + gnt_tree_set_show_title(GNT_TREE(tree), TRUE); + + gnt_box_add_widget(GNT_BOX(win), tree); + + /* Button box. */ + bbox = gnt_hbox_new(TRUE); + + /* Add button */ + button = gnt_button_new(_("Add")); + gnt_box_add_widget(GNT_BOX(bbox), button); + + g_signal_connect(G_OBJECT(button), "activate", + G_CALLBACK(pounces_manager_add_cb), dialog); + + /* Modify button */ + button = gnt_button_new(_("Modify")); + dialog->modify_button = button; + gnt_box_add_widget(GNT_BOX(bbox), button); + + g_signal_connect(G_OBJECT(button), "activate", + G_CALLBACK(pounces_manager_modify_cb), dialog); + + /* Delete button */ + button = gnt_button_new(_("Delete")); + dialog->delete_button = button; + gnt_box_add_widget(GNT_BOX(bbox), button); + + g_signal_connect(G_OBJECT(button), "activate", + G_CALLBACK(pounces_manager_delete_cb), dialog); + + /* Close button */ + button = gnt_button_new(_("Close")); + gnt_box_add_widget(GNT_BOX(bbox), button); + gnt_widget_show(button); + + g_signal_connect(G_OBJECT(button), "activate", + G_CALLBACK(pounces_manager_close_cb), dialog); + + gnt_box_add_widget(GNT_BOX(win), bbox); + + gnt_widget_show(win); + populate_pounces_list(pounces_manager); +} + +void +finch_pounces_manager_hide(void) +{ + if (pounces_manager == NULL) + return; + + if (pounces_manager->window != NULL) + gnt_widget_destroy(pounces_manager->window); + + gaim_signals_disconnect_by_handle(pounces_manager); + + g_free(pounces_manager); + pounces_manager = NULL; +} + +static void +pounce_cb(GaimPounce *pounce, GaimPounceEvent events, void *data) +{ + GaimConversation *conv; + GaimAccount *account; + GaimBuddy *buddy; + const char *pouncee; + const char *alias; + + pouncee = gaim_pounce_get_pouncee(pounce); + account = gaim_pounce_get_pouncer(pounce); + + buddy = gaim_find_buddy(account, pouncee); + if (buddy != NULL) + { + alias = gaim_buddy_get_alias(buddy); + if (alias == NULL) + alias = pouncee; + } + else + alias = pouncee; + + if (gaim_pounce_action_is_enabled(pounce, "open-window")) + { + conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, pouncee, account); + + if (conv == NULL) + conv = gaim_conversation_new(GAIM_CONV_TYPE_IM, account, pouncee); + } + + if (gaim_pounce_action_is_enabled(pounce, "popup-notify")) + { + char *tmp; + const char *name_shown; + const char *reason; + reason = gaim_pounce_action_get_attribute(pounce, "popup-notify", + "reason"); + + /* + * Here we place the protocol name in the pounce dialog to lessen + * confusion about what protocol a pounce is for. + */ + tmp = g_strdup_printf( + (events & GAIM_POUNCE_TYPING) ? + _("%s has started typing to you (%s)") : + (events & GAIM_POUNCE_TYPED) ? + _("%s has paused while typing to you (%s)") : + (events & GAIM_POUNCE_SIGNON) ? + _("%s has signed on (%s)") : + (events & GAIM_POUNCE_IDLE_RETURN) ? + _("%s has returned from being idle (%s)") : + (events & GAIM_POUNCE_AWAY_RETURN) ? + _("%s has returned from being away (%s)") : + (events & GAIM_POUNCE_TYPING_STOPPED) ? + _("%s has stopped typing to you (%s)") : + (events & GAIM_POUNCE_SIGNOFF) ? + _("%s has signed off (%s)") : + (events & GAIM_POUNCE_IDLE) ? + _("%s has become idle (%s)") : + (events & GAIM_POUNCE_AWAY) ? + _("%s has gone away. (%s)") : + (events & GAIM_POUNCE_MESSAGE_RECEIVED) ? + _("%s has sent you a message. (%s)") : + _("Unknown pounce event. Please report this!"), + alias, gaim_account_get_protocol_name(account)); + + /* + * Ok here is where I change the second argument, title, from + * NULL to the account alias if we have it or the account + * name if that's all we have + */ + if ((name_shown = gaim_account_get_alias(account)) == NULL) + name_shown = gaim_account_get_username(account); + + if (reason == NULL) + { + gaim_notify_info(NULL, name_shown, tmp, gaim_date_format_full(NULL)); + } + else + { + char *tmp2 = g_strdup_printf("%s\n\n%s", reason, gaim_date_format_full(NULL)); + gaim_notify_info(NULL, name_shown, tmp, tmp2); + g_free(tmp2); + } + g_free(tmp); + } + + if (gaim_pounce_action_is_enabled(pounce, "send-message")) + { + const char *message; + + message = gaim_pounce_action_get_attribute(pounce, "send-message", + "message"); + + if (message != NULL) + { + conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, pouncee, account); + + if (conv == NULL) + conv = gaim_conversation_new(GAIM_CONV_TYPE_IM, account, pouncee); + + gaim_conversation_write(conv, NULL, message, + GAIM_MESSAGE_SEND, time(NULL)); + + serv_send_im(account->gc, (char *)pouncee, (char *)message, 0); + } + } + + if (gaim_pounce_action_is_enabled(pounce, "execute-command")) + { + const char *command; + + command = gaim_pounce_action_get_attribute(pounce, + "execute-command", "command"); + + if (command != NULL) + { + char *localecmd = g_locale_from_utf8(command, -1, NULL, + NULL, NULL); + + if (localecmd != NULL) + { + int pid = fork(); + + if (pid == 0) { + char *args[4]; + + args[0] = "sh"; + args[1] = "-c"; + args[2] = (char *)localecmd; + args[3] = NULL; + + execvp(args[0], args); + + _exit(0); + } + g_free(localecmd); + } + } + } + + if (gaim_pounce_action_is_enabled(pounce, "play-beep")) + { + beep(); + } +} + +static void +free_pounce(GaimPounce *pounce) +{ + update_pounces(); +} + +static void +new_pounce(GaimPounce *pounce) +{ + gaim_pounce_action_register(pounce, "open-window"); + gaim_pounce_action_register(pounce, "popup-notify"); + gaim_pounce_action_register(pounce, "send-message"); + gaim_pounce_action_register(pounce, "execute-command"); + gaim_pounce_action_register(pounce, "play-beep"); + + update_pounces(); +} + +void * +finch_pounces_get_handle() +{ + static int handle; + + return &handle; +} + +void +finch_pounces_init(void) +{ + gaim_pounces_register_handler(GAIM_GNT_UI, pounce_cb, new_pounce, + free_pounce); + + gaim_prefs_add_none("/gaim/gnt/pounces"); + gaim_prefs_add_none("/gaim/gnt/pounces/default_actions"); + gaim_prefs_add_bool("/gaim/gnt/pounces/default_actions/open-window", + FALSE); + gaim_prefs_add_bool("/gaim/gnt/pounces/default_actions/popup-notify", + TRUE); + gaim_prefs_add_bool("/gaim/gnt/pounces/default_actions/send-message", + FALSE); + gaim_prefs_add_bool("/gaim/gnt/pounces/default_actions/execute-command", + FALSE); + gaim_prefs_add_bool("/gaim/gnt/pounces/default_actions/play-beep", + FALSE); + gaim_prefs_add_none("/gaim/gnt/pounces/dialog"); + + gaim_signal_connect(gaim_connections_get_handle(), "signed-on", + finch_pounces_get_handle(), + GAIM_CALLBACK(signed_on_off_cb), NULL); + gaim_signal_connect(gaim_connections_get_handle(), "signed-off", + finch_pounces_get_handle(), + GAIM_CALLBACK(signed_on_off_cb), NULL); +} + +/* XXX: There's no such thing in pidgin. Perhaps there should be? */ +void finch_pounces_uninit() +{ + gaim_pounces_register_handler(GAIM_GNT_UI, NULL, NULL, NULL); + + gaim_signals_disconnect_by_handle(finch_pounces_get_handle()); +} + diff -r 317e7613e581 -r 0e3a8505ebbe finch/gntpounce.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/gntpounce.h Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,67 @@ +/** + * @file gntpounce.h GNT Buddy Pounce API + * @ingroup gntui + * + * gaim + * + * Gaim is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _GAIM_GNTPOUNCE_H_ +#define _GAIM_GNTPOUNCE_H_ + +#include "pounce.h" + +/** + * Displays a New Buddy Pounce or Edit Buddy Pounce dialog. + * + * @param account The optional account to use. + * @param name The optional name to pounce on. + * @param cur_pounce The current buddy pounce, if editing an existing one. + */ +void finch_pounce_editor_show(GaimAccount *account, const char *name, + GaimPounce *cur_pounce); + +/** + * Shows the pounces manager window. + */ +void finch_pounces_manager_show(void); + +/** + * Hides the pounces manager window. + */ +void finch_pounces_manager_hide(void); + +/** + * Returns the gtkpounces handle + * + * @return The handle to the GTK+ pounces system + */ +void *finch_pounces_get_handle(void); + +/** + * Initializes the GNT pounces subsystem. + */ +void finch_pounces_init(void); + +/** + * Uninitializes the GNT pounces subsystem. + */ +void finch_pounces_uninit(void); + +#endif /* _GAIM_GTKPOUNCE_H_ */ diff -r 317e7613e581 -r 0e3a8505ebbe finch/gntprefs.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/gntprefs.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,286 @@ +/** + * @file gntprefs.c GNT Preferences API + * @ingroup gntui + * + * gaim + * + * Gaim is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include + +#include "gntgaim.h" +#include "gntprefs.h" +#include "gntrequest.h" + +#include + +static GList *freestrings; /* strings to be freed when the pref-window is closed */ + +void finch_prefs_init() +{ + gaim_prefs_add_none("/gaim"); + gaim_prefs_add_none("/gaim/gnt"); + + gaim_prefs_add_none("/gaim/gnt/plugins"); + gaim_prefs_add_path_list("/gaim/gnt/plugins/loaded", NULL); + + gaim_prefs_add_none("/gaim/gnt/conversations"); + gaim_prefs_add_bool("/gaim/gnt/conversations/timestamps", TRUE); + gaim_prefs_add_bool("/gaim/gnt/conversations/notify_typing", FALSE); /* XXX: Not functional yet */ +} + +typedef struct +{ + GaimPrefType type; + const char *pref; + const char *label; + GList *(*lv)(); /* If the value is to be selected from a number of choices */ +} Prefs; + +static GList * +get_log_options() +{ + return gaim_log_logger_get_options(); +} + +static GList * +get_idle_options() +{ + GList *list = NULL; + list = g_list_append(list, "Based on keyboard use"); /* XXX: string freeze */ + list = g_list_append(list, "system"); + list = g_list_append(list, (char*)_("From last sent message")); + list = g_list_append(list, "gaim"); + list = g_list_append(list, (char*)_("Never")); + list = g_list_append(list, "never"); + return list; +} + +static GList * +get_status_titles() +{ + GList *list = NULL; + const GList *iter; + for (iter = gaim_savedstatuses_get_all(); iter; iter = iter->next) { + char *str; + if (gaim_savedstatus_is_transient(iter->data)) + continue; + str = g_strdup_printf("%ld", gaim_savedstatus_get_creation_time(iter->data)); + list = g_list_append(list, (char*)gaim_savedstatus_get_title(iter->data)); + list = g_list_append(list, str); + freestrings = g_list_prepend(freestrings, str); + } + return list; +} + +static GaimRequestField * +get_pref_field(Prefs *prefs) +{ + GaimRequestField *field = NULL; + + if (prefs->lv == NULL) + { + switch (prefs->type) + { + case GAIM_PREF_BOOLEAN: + field = gaim_request_field_bool_new(prefs->pref, _(prefs->label), + gaim_prefs_get_bool(prefs->pref)); + break; + case GAIM_PREF_INT: + field = gaim_request_field_int_new(prefs->pref, _(prefs->label), + gaim_prefs_get_int(prefs->pref)); + break; + case GAIM_PREF_STRING: + field = gaim_request_field_string_new(prefs->pref, _(prefs->label), + gaim_prefs_get_string(prefs->pref), FALSE); + break; + default: + break; + } + } + else + { + GList *list = prefs->lv(), *iter; + if (list) + field = gaim_request_field_list_new(prefs->pref, _(prefs->label)); + for (iter = list; iter; iter = iter->next) + { + gboolean select = FALSE; + const char *data = iter->data; + int idata; + iter = iter->next; + switch (prefs->type) + { + case GAIM_PREF_BOOLEAN: + sscanf(iter->data, "%d", &idata); + if (gaim_prefs_get_bool(prefs->pref) == idata) + select = TRUE; + break; + case GAIM_PREF_INT: + sscanf(iter->data, "%d", &idata); + if (gaim_prefs_get_int(prefs->pref) == idata) + select = TRUE; + break; + case GAIM_PREF_STRING: + if (strcmp(gaim_prefs_get_string(prefs->pref), iter->data) == 0) + select = TRUE; + break; + default: + break; + } + gaim_request_field_list_add(field, data, iter->data); + if (select) + gaim_request_field_list_add_selected(field, data); + } + g_list_free(list); + } + return field; +} + +static Prefs blist[] = +{ + {GAIM_PREF_BOOLEAN, "/gaim/gnt/blist/idletime", N_("Show Idle Time"), NULL}, + {GAIM_PREF_BOOLEAN, "/gaim/gnt/blist/showoffline", N_("Show Offline Buddies"), NULL}, + {GAIM_PREF_NONE, NULL, NULL, NULL} +}; + +static Prefs convs[] = +{ + {GAIM_PREF_BOOLEAN, "/gaim/gnt/conversations/timestamps", N_("Show Timestamps"), NULL}, + {GAIM_PREF_BOOLEAN, "/gaim/gnt/conversations/notify_typing", N_("Notify buddies when you are typing"), NULL}, + {GAIM_PREF_NONE, NULL, NULL, NULL} +}; + +static Prefs logging[] = +{ + {GAIM_PREF_STRING, "/core/logging/format", N_("Log format"), get_log_options}, + {GAIM_PREF_BOOLEAN, "/core/logging/log_ims", N_("Log IMs"), NULL}, + {GAIM_PREF_BOOLEAN, "/core/logging/log_chats", N_("Log chats"), NULL}, + {GAIM_PREF_BOOLEAN, "/core/logging/log_system", N_("Log status change events"), NULL}, + {GAIM_PREF_NONE, NULL, NULL, NULL}, +}; + +/* XXX: Translate after the freeze */ +static Prefs idle[] = +{ + {GAIM_PREF_STRING, "/core/away/idle_reporting", "Report Idle time", get_idle_options}, + {GAIM_PREF_BOOLEAN, "/core/away/away_when_idle", "Change status when idle", NULL}, + {GAIM_PREF_INT, "/core/away/mins_before_away", "Minutes before changing status", NULL}, + {GAIM_PREF_INT, "/core/savedstatus/idleaway", "Change status to", get_status_titles}, + {GAIM_PREF_NONE, NULL, NULL, NULL}, +}; + +static void +free_strings() +{ + g_list_foreach(freestrings, (GFunc)g_free, NULL); + g_list_free(freestrings); + freestrings = NULL; +} + +static void +save_cb(void *data, GaimRequestFields *allfields) +{ + GList *list; + for (list = gaim_request_fields_get_groups(allfields); list; list = list->next) + { + GaimRequestFieldGroup *group = list->data; + GList *fields = gaim_request_field_group_get_fields(group); + + for (; fields ; fields = fields->next) + { + GaimRequestField *field = fields->data; + GaimRequestFieldType type = gaim_request_field_get_type(field); + GaimPrefType pt; + gpointer val = NULL; + const char *id = gaim_request_field_get_id(field); + + switch (type) + { + case GAIM_REQUEST_FIELD_LIST: + val = gaim_request_field_list_get_selected(field)->data; + break; + case GAIM_REQUEST_FIELD_BOOLEAN: + val = GINT_TO_POINTER(gaim_request_field_bool_get_value(field)); + break; + case GAIM_REQUEST_FIELD_INTEGER: + val = GINT_TO_POINTER(gaim_request_field_int_get_value(field)); + break; + case GAIM_REQUEST_FIELD_STRING: + val = (gpointer)gaim_request_field_string_get_value(field); + break; + default: + break; + } + + pt = gaim_prefs_get_type(id); + switch (pt) + { + case GAIM_PREF_INT: + if (type == GAIM_REQUEST_FIELD_LIST) /* Lists always return string */ + sscanf(val, "%ld", (long int *)&val); + gaim_prefs_set_int(id, GPOINTER_TO_INT(val)); + break; + case GAIM_PREF_BOOLEAN: + gaim_prefs_set_bool(id, GPOINTER_TO_INT(val)); + break; + case GAIM_PREF_STRING: + gaim_prefs_set_string(id, val); + break; + default: + break; + } + } + } + free_strings(); +} + +static void +add_pref_group(GaimRequestFields *fields, const char *title, Prefs *prefs) +{ + GaimRequestField *field; + GaimRequestFieldGroup *group; + int i; + + group = gaim_request_field_group_new(title); + gaim_request_fields_add_group(fields, group); + for (i = 0; prefs[i].pref; i++) + { + field = get_pref_field(prefs + i); + if (field) + gaim_request_field_group_add_field(group, field); + } +} + +void finch_prefs_show_all() +{ + GaimRequestFields *fields; + + fields = gaim_request_fields_new(); + + add_pref_group(fields, _("Buddy List"), blist); + add_pref_group(fields, _("Conversations"), convs); + add_pref_group(fields, _("Logging"), logging); + add_pref_group(fields, _("Idle"), idle); + + gaim_request_fields(NULL, _("Preferences"), NULL, NULL, fields, + _("Save"), G_CALLBACK(save_cb), _("Cancel"), free_strings, NULL); +} + diff -r 317e7613e581 -r 0e3a8505ebbe finch/gntprefs.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/gntprefs.h Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,45 @@ +/** + * @file gntprefs.h GNT Preferences API + * @ingroup gntui + * + * gaim + * + * Gaim is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _GNT_PREFS_H +#define _GNT_PREFS_H + +/********************************************************************** + * @name GNT Preferences API + **********************************************************************/ +/*@{*/ + +/** + * Perform necessary initializations. + */ +void finch_prefs_init(void); + +/** + * Show the preferences dialog. + */ +void finch_prefs_show_all(void); + +/*@}*/ + +#endif diff -r 317e7613e581 -r 0e3a8505ebbe finch/gntrequest.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/gntrequest.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,619 @@ +/** + * @file gntrequest.c GNT Request API + * @ingroup gntui + * + * gaim + * + * Gaim is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gntgaim.h" +#include "gntrequest.h" +#include "util.c" + +typedef struct +{ + void *user_data; + GntWidget *entry, *dialog; + GCallback *cbs; +} GaimGntFileRequest; + +static GntWidget * +setup_request_window(const char *title, const char *primary, + const char *secondary, GaimRequestType type) +{ + GntWidget *window; + + window = gnt_vbox_new(FALSE); + gnt_box_set_toplevel(GNT_BOX(window), TRUE); + gnt_box_set_title(GNT_BOX(window), title); + gnt_box_set_alignment(GNT_BOX(window), GNT_ALIGN_MID); + + if (primary) + gnt_box_add_widget(GNT_BOX(window), + gnt_label_new_with_format(primary, GNT_TEXT_FLAG_BOLD)); + if (secondary) + gnt_box_add_widget(GNT_BOX(window), gnt_label_new(secondary)); + + g_signal_connect_swapped(G_OBJECT(window), "destroy", G_CALLBACK(gaim_request_close), + GINT_TO_POINTER(type)); + + return window; +} + +static GntWidget * +setup_button_box(gpointer userdata, gpointer cb, gpointer data, ...) +{ + GntWidget *box, *button; + va_list list; + const char *text; + gpointer callback; + + box = gnt_hbox_new(FALSE); + + va_start(list, data); + + while ((text = va_arg(list, const char *))) + { + callback = va_arg(list, gpointer); + button = gnt_button_new(text); + gnt_box_add_widget(GNT_BOX(box), button); + g_object_set_data(G_OBJECT(button), "activate-callback", callback); + g_object_set_data(G_OBJECT(button), "activate-userdata", userdata); + g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(cb), data); + } + + va_end(list); + return box; +} + +static void +notify_input_cb(GntWidget *button, GntWidget *entry) +{ + GaimRequestInputCb callback = g_object_get_data(G_OBJECT(button), "activate-callback"); + gpointer data = g_object_get_data(G_OBJECT(button), "activate-userdata"); + const char *text = gnt_entry_get_text(GNT_ENTRY(entry)); + + if (callback) + callback(data, text); + + while (button->parent) + button = button->parent; + + gaim_request_close(GAIM_REQUEST_INPUT, button); +} + +static void * +finch_request_input(const char *title, const char *primary, + const char *secondary, const char *default_value, + gboolean multiline, gboolean masked, gchar *hint, + const char *ok_text, GCallback ok_cb, + const char *cancel_text, GCallback cancel_cb, + void *user_data) +{ + GntWidget *window, *box, *entry; + + window = setup_request_window(title, primary, secondary, GAIM_REQUEST_INPUT); + + entry = gnt_entry_new(default_value); + if (masked) + gnt_entry_set_masked(GNT_ENTRY(entry), TRUE); + gnt_box_add_widget(GNT_BOX(window), entry); + + box = setup_button_box(user_data, notify_input_cb, entry, + ok_text, ok_cb, cancel_text, cancel_cb, NULL); + gnt_box_add_widget(GNT_BOX(window), box); + + gnt_widget_show(window); + + return window; +} + +static void +finch_close_request(GaimRequestType type, gpointer ui_handle) +{ + GntWidget *widget = GNT_WIDGET(ui_handle); + while (widget->parent) + widget = widget->parent; + gnt_widget_destroy(widget); +} + +static void +request_choice_cb(GntWidget *button, GntComboBox *combo) +{ + GaimRequestChoiceCb callback = g_object_get_data(G_OBJECT(button), "activate-callback"); + gpointer data = g_object_get_data(G_OBJECT(button), "activate-userdata"); + int choice = GPOINTER_TO_INT(gnt_combo_box_get_selected_data(GNT_COMBO_BOX(combo))) - 1; + + if (callback) + callback(data, choice); + + while (button->parent) + button = button->parent; + + gaim_request_close(GAIM_REQUEST_INPUT, button); +} + +static void * +finch_request_choice(const char *title, const char *primary, + const char *secondary, unsigned int default_value, + const char *ok_text, GCallback ok_cb, + const char *cancel_text, GCallback cancel_cb, + void *user_data, va_list choices) +{ + GntWidget *window, *combo, *box; + const char *text; + int val; + + window = setup_request_window(title, primary, secondary, GAIM_REQUEST_CHOICE); + + combo = gnt_combo_box_new(); + gnt_box_add_widget(GNT_BOX(window), combo); + while ((text = va_arg(choices, const char *))) + { + val = va_arg(choices, int); + gnt_combo_box_add_data(GNT_COMBO_BOX(combo), GINT_TO_POINTER(val + 1), text); + } + gnt_combo_box_set_selected(GNT_COMBO_BOX(combo), GINT_TO_POINTER(default_value + 1)); + + box = setup_button_box(user_data, request_choice_cb, combo, + ok_text, ok_cb, cancel_text, cancel_cb, NULL); + gnt_box_add_widget(GNT_BOX(window), box); + + gnt_widget_show(window); + + return window; +} + +static void +request_action_cb(GntWidget *button, GntWidget *window) +{ + GaimRequestActionCb callback = g_object_get_data(G_OBJECT(button), "activate-callback"); + gpointer data = g_object_get_data(G_OBJECT(button), "activate-userdata"); + int id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(button), "activate-id")); + + if (callback) + callback(data, id); + + gaim_request_close(GAIM_REQUEST_ACTION, window); +} + +static void* +finch_request_action(const char *title, const char *primary, + const char *secondary, unsigned int default_value, + void *user_data, size_t actioncount, + va_list actions) +{ + GntWidget *window, *box, *button; + int i; + + window = setup_request_window(title, primary, secondary, GAIM_REQUEST_ACTION); + + box = gnt_hbox_new(FALSE); + gnt_box_add_widget(GNT_BOX(window), box); + for (i = 0; i < actioncount; i++) + { + const char *text = va_arg(actions, const char *); + GaimRequestActionCb callback = va_arg(actions, GaimRequestActionCb); + + button = gnt_button_new(text); + gnt_box_add_widget(GNT_BOX(box), button); + + g_object_set_data(G_OBJECT(button), "activate-callback", callback); + g_object_set_data(G_OBJECT(button), "activate-userdata", user_data); + g_object_set_data(G_OBJECT(button), "activate-id", GINT_TO_POINTER(i)); + g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(request_action_cb), window); + } + + gnt_widget_show(window); + + return window; +} + +static void +request_fields_cb(GntWidget *button, GaimRequestFields *fields) +{ + GaimRequestFieldsCb callback = g_object_get_data(G_OBJECT(button), "activate-callback"); + gpointer data = g_object_get_data(G_OBJECT(button), "activate-userdata"); + GList *list; + + /* Update the data of the fields. GtkGaim does this differently. Instead of + * updating the fields at the end like here, it updates the appropriate field + * instantly whenever a change is made. That allows it to make sure the + * 'required' fields are entered before the user can hit OK. It's not the case + * here, althought it can be done. I am not honouring the 'required' fields + * for the moment. */ + for (list = gaim_request_fields_get_groups(fields); list; list = list->next) + { + GaimRequestFieldGroup *group = list->data; + GList *fields = gaim_request_field_group_get_fields(group); + + for (; fields ; fields = fields->next) + { + GaimRequestField *field = fields->data; + GaimRequestFieldType type = gaim_request_field_get_type(field); + if (type == GAIM_REQUEST_FIELD_BOOLEAN) + { + GntWidget *check = field->ui_data; + gboolean value = gnt_check_box_get_checked(GNT_CHECK_BOX(check)); + gaim_request_field_bool_set_value(field, value); + } + else if (type == GAIM_REQUEST_FIELD_STRING) + { + GntWidget *entry = field->ui_data; + const char *text = gnt_entry_get_text(GNT_ENTRY(entry)); + gaim_request_field_string_set_value(field, (text && *text) ? text : NULL); + } + else if (type == GAIM_REQUEST_FIELD_INTEGER) + { + GntWidget *entry = field->ui_data; + const char *text = gnt_entry_get_text(GNT_ENTRY(entry)); + int value = (text && *text) ? atoi(text) : 0; + gaim_request_field_int_set_value(field, value); + } + else if (type == GAIM_REQUEST_FIELD_CHOICE) + { + GntWidget *combo = field->ui_data; + int id; + id = GPOINTER_TO_INT(gnt_combo_box_get_selected_data(GNT_COMBO_BOX(combo))); + gaim_request_field_choice_set_value(field, id); + } + else if (type == GAIM_REQUEST_FIELD_LIST) + { + GList *list = NULL; + if (gaim_request_field_list_get_multi_select(field)) + { + const GList *iter; + GntWidget *tree = field->ui_data; + + iter = gaim_request_field_list_get_items(field); + for (; iter; iter = iter->next) + { + const char *text = iter->data; + gpointer key = gaim_request_field_list_get_data(field, text); + if (gnt_tree_get_choice(GNT_TREE(tree), key)) + list = g_list_prepend(list, key); + } + } + else + { + GntWidget *combo = field->ui_data; + gpointer data = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(combo)); + list = g_list_append(list, data); + } + + gaim_request_field_list_set_selected(field, list); + g_list_free(list); + } + else if (type == GAIM_REQUEST_FIELD_ACCOUNT) + { + GntWidget *combo = field->ui_data; + GaimAccount *acc = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(combo)); + gaim_request_field_account_set_value(field, acc); + } + } + } + + if (callback) + callback(data, fields); + + while (button->parent) + button = button->parent; + + gaim_request_close(GAIM_REQUEST_FIELDS, button); +} + +static void * +finch_request_fields(const char *title, const char *primary, + const char *secondary, GaimRequestFields *allfields, + const char *ok, GCallback ok_cb, + const char *cancel, GCallback cancel_cb, + void *userdata) +{ + GntWidget *window, *box; + GList *grlist; + + window = setup_request_window(title, primary, secondary, GAIM_REQUEST_FIELDS); + + /* This is how it's going to work: the request-groups are going to be + * stacked vertically one after the other. A GntLine will be separating + * the groups. */ + box = gnt_vbox_new(FALSE); + gnt_box_set_pad(GNT_BOX(box), 0); + gnt_box_set_fill(GNT_BOX(box), TRUE); + for (grlist = gaim_request_fields_get_groups(allfields); grlist; grlist = grlist->next) + { + GaimRequestFieldGroup *group = grlist->data; + GList *fields = gaim_request_field_group_get_fields(group); + GntWidget *hbox; + const char *title = gaim_request_field_group_get_title(group); + + if (title) + gnt_box_add_widget(GNT_BOX(box), + gnt_label_new_with_format(title, GNT_TEXT_FLAG_BOLD)); + + for (; fields ; fields = fields->next) + { + /* XXX: Break each of the fields into a separate function? */ + GaimRequestField *field = fields->data; + GaimRequestFieldType type = gaim_request_field_get_type(field); + const char *label = gaim_request_field_get_label(field); + + hbox = gnt_hbox_new(TRUE); /* hrm */ + gnt_box_add_widget(GNT_BOX(box), hbox); + + if (type != GAIM_REQUEST_FIELD_BOOLEAN && label) + { + GntWidget *l = gnt_label_new(label); + gnt_widget_set_size(l, 0, 1); + gnt_box_add_widget(GNT_BOX(hbox), l); + } + + if (type == GAIM_REQUEST_FIELD_BOOLEAN) + { + GntWidget *check = gnt_check_box_new(label); + gnt_check_box_set_checked(GNT_CHECK_BOX(check), + gaim_request_field_bool_get_default_value(field)); + gnt_box_add_widget(GNT_BOX(hbox), check); + field->ui_data = check; + } + else if (type == GAIM_REQUEST_FIELD_STRING) + { + GntWidget *entry = gnt_entry_new( + gaim_request_field_string_get_default_value(field)); + gnt_entry_set_masked(GNT_ENTRY(entry), + gaim_request_field_string_is_masked(field)); + gnt_box_add_widget(GNT_BOX(hbox), entry); + field->ui_data = entry; + } + else if (type == GAIM_REQUEST_FIELD_INTEGER) + { + char str[256]; + int val = gaim_request_field_int_get_default_value(field); + GntWidget *entry; + + snprintf(str, sizeof(str), "%d", val); + entry = gnt_entry_new(str); + gnt_entry_set_flag(GNT_ENTRY(entry), GNT_ENTRY_FLAG_INT); + gnt_box_add_widget(GNT_BOX(hbox), entry); + field->ui_data = entry; + } + else if (type == GAIM_REQUEST_FIELD_CHOICE) + { + int id; + const GList *list; + GntWidget *combo = gnt_combo_box_new(); + gnt_box_add_widget(GNT_BOX(hbox), combo); + field->ui_data = combo; + + list = gaim_request_field_choice_get_labels(field); + for (id = 1; list; list = list->next, id++) + { + gnt_combo_box_add_data(GNT_COMBO_BOX(combo), + GINT_TO_POINTER(id), list->data); + } + gnt_combo_box_set_selected(GNT_COMBO_BOX(combo), + GINT_TO_POINTER(gaim_request_field_choice_get_default_value(field))); + } + else if (type == GAIM_REQUEST_FIELD_LIST) + { + const GList *list; + gboolean multi = gaim_request_field_list_get_multi_select(field); + if (multi) + { + GntWidget *tree = gnt_tree_new(); + gnt_box_add_widget(GNT_BOX(hbox), tree); + field->ui_data = tree; + + list = gaim_request_field_list_get_items(field); + for (; list; list = list->next) + { + const char *text = list->data; + gpointer key = gaim_request_field_list_get_data(field, text); + gnt_tree_add_choice(GNT_TREE(tree), key, + gnt_tree_create_row(GNT_TREE(tree), text), NULL, NULL); + if (gaim_request_field_list_is_selected(field, text)) + gnt_tree_set_choice(GNT_TREE(tree), key, TRUE); + } + } + else + { + GntWidget *combo = gnt_combo_box_new(); + gnt_box_set_alignment(GNT_BOX(hbox), GNT_ALIGN_MID); + gnt_box_add_widget(GNT_BOX(hbox), combo); + field->ui_data = combo; + + list = gaim_request_field_list_get_items(field); + for (; list; list = list->next) + { + const char *text = list->data; + gpointer key = gaim_request_field_list_get_data(field, text); + gnt_combo_box_add_data(GNT_COMBO_BOX(combo), key, text); + if (gaim_request_field_list_is_selected(field, text)) + gnt_combo_box_set_selected(GNT_COMBO_BOX(combo), key); + } + } + } + else if (type == GAIM_REQUEST_FIELD_ACCOUNT) + { + gboolean all; + GaimAccount *def; + GList *list; + GntWidget *combo = gnt_combo_box_new(); + gnt_box_set_alignment(GNT_BOX(hbox), GNT_ALIGN_MID); + gnt_box_add_widget(GNT_BOX(hbox), combo); + field->ui_data = combo; + + all = gaim_request_field_account_get_show_all(field); + def = gaim_request_field_account_get_default_value(field); + + if (all) + list = gaim_accounts_get_all(); + else + list = gaim_connections_get_all(); + + for (; list; list = list->next) + { + GaimAccount *account; + char *text; + + if (all) + account = list->data; + else + account = gaim_connection_get_account(list->data); + + text = g_strdup_printf("%s (%s)", + gaim_account_get_username(account), + gaim_account_get_protocol_name(account)); + gnt_combo_box_add_data(GNT_COMBO_BOX(combo), account, text); + g_free(text); + if (account == def) + gnt_combo_box_set_selected(GNT_COMBO_BOX(combo), account); + } + gnt_widget_set_size(combo, 20, 3); /* ew */ + } + else + { + gnt_box_add_widget(GNT_BOX(hbox), + gnt_label_new_with_format(_("Not implemented yet."), + GNT_TEXT_FLAG_BOLD)); + } + } + if (grlist->next) + gnt_box_add_widget(GNT_BOX(box), gnt_hline_new()); + } + gnt_box_add_widget(GNT_BOX(window), box); + + box = setup_button_box(userdata, request_fields_cb, allfields, + ok, ok_cb, cancel, cancel_cb, NULL); + gnt_box_add_widget(GNT_BOX(window), box); + + gnt_widget_show(window); + + return window; +} + +static void +file_cancel_cb(GntWidget *wid, gpointer fq) +{ + GaimGntFileRequest *data = fq; + if (data->cbs[1] != NULL) + ((GaimRequestFileCb)data->cbs[1])(data->user_data, NULL); + + gaim_request_close(GAIM_REQUEST_FILE, data->dialog); +} + +static void +file_ok_cb(GntWidget *wid, gpointer fq) +{ + GaimGntFileRequest *data = fq; + if (data->cbs[0] != NULL) + ((GaimRequestFileCb)data->cbs[0])(data->user_data, gnt_entry_get_text(GNT_ENTRY(data->entry))); + + gaim_request_close(GAIM_REQUEST_FILE, data->dialog); +} + +static void +file_request_destroy(GaimGntFileRequest *data) +{ + g_free(data->cbs); + g_free(data); +} + +static void * +finch_request_file(const char *title, const char *filename, + gboolean savedialog, + GCallback ok_cb, GCallback cancel_cb, + void *user_data) +{ + GntWidget *window = gnt_vbox_new(FALSE); + GntWidget *entry, *hbox, *button; + GaimGntFileRequest *data = g_new0(GaimGntFileRequest, 1); + + data->user_data = user_data; + data->cbs = g_new0(GCallback, 2); + data->cbs[0] = ok_cb; + data->cbs[1] = cancel_cb; + data->dialog = window; + data->entry = entry = gnt_entry_new(g_strconcat(gaim_home_dir(), G_DIR_SEPARATOR_S, filename, NULL)); + gnt_widget_set_size(entry, 30, 1); + gnt_box_set_toplevel(GNT_BOX(window), TRUE); + gnt_box_set_title(GNT_BOX(window), title ? title : (savedialog ? _("Save File...") : _("Open File..."))); +#if 0 + /* After the string freeze */ + gnt_box_add_widget(GNT_BOX(window), gnt_label_new(_("Please enter a full path for a file"))); +#endif + gnt_box_add_widget(GNT_BOX(window), entry); + + hbox = gnt_hbox_new(TRUE); + gnt_box_set_alignment(GNT_BOX(hbox), GNT_ALIGN_MID); + + button = gnt_button_new(_("Cancel")); + g_signal_connect(G_OBJECT(button), "activate", + G_CALLBACK(file_cancel_cb), data); + gnt_box_add_widget(GNT_BOX(hbox), button); + + button = gnt_button_new(_("OK")); + g_signal_connect(G_OBJECT(button), "activate", + G_CALLBACK(file_ok_cb), data); + gnt_box_add_widget(GNT_BOX(hbox), button); + + gnt_box_add_widget(GNT_BOX(window), hbox); + + g_signal_connect_swapped(G_OBJECT(window), "destroy", + G_CALLBACK(file_request_destroy), data); + + gnt_widget_show(window); + + return window; +} + +static GaimRequestUiOps uiops = +{ + .request_input = finch_request_input, + .close_request = finch_close_request, + .request_choice = finch_request_choice, + .request_action = finch_request_action, + .request_fields = finch_request_fields, + .request_file = finch_request_file, + .request_folder = NULL /* No plans for this */ +}; + +GaimRequestUiOps *finch_request_get_ui_ops() +{ + return &uiops; +} + +void finch_request_init() +{ +} + +void finch_request_uninit() +{ +} + diff -r 317e7613e581 -r 0e3a8505ebbe finch/gntrequest.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/gntrequest.h Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,54 @@ +/** + * @file gntrequest.h GNT Request API + * @ingroup gntui + * + * gaim + * + * Gaim is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _GNT_REQUEST_H +#define _GNT_REQUEST_H + +#include "request.h" + +/********************************************************************** + * @name GNT Request API + **********************************************************************/ +/*@{*/ + +/** + * Get the ui-functions. + * + * @return The GaimRequestUiOps structure populated with the appropriate functions. + */ +GaimRequestUiOps *finch_request_get_ui_ops(void); + +/** + * Perform necessary initializations. + */ +void finch_request_init(void); + +/** + * Perform necessary uninitializations. + */ +void finch_request_uninit(void); + +/*@}*/ + +#endif diff -r 317e7613e581 -r 0e3a8505ebbe finch/gntstatus.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/gntstatus.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,606 @@ +/** + * @file gntstatus.c GNT Status API + * @ingroup gntui + * + * gaim + * + * Gaim is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "gntgaim.h" +#include "gntstatus.h" + +static struct +{ + GntWidget *window; + GntWidget *tree; +} statuses; + +typedef struct +{ + GaimSavedStatus *saved; + GntWidget *window; + GntWidget *title; + GntWidget *type; + GntWidget *message; + GntWidget *tree; + GHashTable *hash; /* list of windows for substatuses */ +} EditStatus; + +typedef struct +{ + GaimAccount *account; + const GaimStatusType *type; + char *message; +} RowInfo; + +typedef struct +{ + GntWidget *window; + GntWidget *type; + GntWidget *message; + + EditStatus *parent; + RowInfo *key; +} EditSubStatus; + +static GList *edits; /* List of opened edit-status dialogs */ + +static void +reset_status_window(GntWidget *widget, gpointer null) +{ + statuses.window = NULL; + statuses.tree = NULL; +} + +static void +populate_statuses(GntTree *tree) +{ + const GList *list; + + for (list = gaim_savedstatuses_get_all(); list; list = list->next) + { + GaimSavedStatus *saved = list->data; + const char *title, *type, *message; + + if (gaim_savedstatus_is_transient(saved)) + continue; + + title = gaim_savedstatus_get_title(saved); + type = gaim_primitive_get_name_from_type(gaim_savedstatus_get_type(saved)); + message = gaim_savedstatus_get_message(saved); /* XXX: Strip possible markups */ + + gnt_tree_add_row_last(tree, saved, + gnt_tree_create_row(tree, title, type, message), NULL); + } +} + +static void +really_delete_status(GaimSavedStatus *saved) +{ + GList *iter; + + for (iter = edits; iter; iter = iter->next) + { + EditStatus *edit = iter->data; + if (edit->saved == saved) + { + gnt_widget_destroy(edit->window); + break; + } + } + + if (statuses.tree) + gnt_tree_remove(GNT_TREE(statuses.tree), saved); + + gaim_savedstatus_delete(gaim_savedstatus_get_title(saved)); +} + +static void +ask_before_delete(GntWidget *button, gpointer null) +{ + char *ask; + GaimSavedStatus *saved; + + g_return_if_fail(statuses.tree != NULL); + + saved = gnt_tree_get_selection_data(GNT_TREE(statuses.tree)); + ask = g_strdup_printf(_("Are you sure you want to delete \"%s\""), + gaim_savedstatus_get_title(saved)); + + gaim_request_action(saved, _("Delete Status"), ask, NULL, 0, saved, 2, + _("Delete"), really_delete_status, _("Cancel"), NULL); + g_free(ask); +} + +static void +use_savedstatus_cb(GntWidget *widget, gpointer null) +{ + g_return_if_fail(statuses.tree != NULL); + + gaim_savedstatus_activate(gnt_tree_get_selection_data(GNT_TREE(statuses.tree))); +} + +static void +edit_savedstatus_cb(GntWidget *widget, gpointer null) +{ + g_return_if_fail(statuses.tree != NULL); + + finch_savedstatus_edit(gnt_tree_get_selection_data(GNT_TREE(statuses.tree))); +} + +void finch_savedstatus_show_all() +{ + GntWidget *window, *tree, *box, *button; + if (statuses.window) + return; + + statuses.window = window = gnt_vbox_new(FALSE); + gnt_box_set_toplevel(GNT_BOX(window), TRUE); + gnt_box_set_title(GNT_BOX(window), _("Saved Statuses")); + gnt_box_set_fill(GNT_BOX(window), FALSE); + gnt_box_set_alignment(GNT_BOX(window), GNT_ALIGN_MID); + gnt_box_set_pad(GNT_BOX(window), 0); + + /* XXX: Add some sorting function to sort alphabetically, perhaps */ + statuses.tree = tree = gnt_tree_new_with_columns(3); + gnt_tree_set_column_titles(GNT_TREE(tree), _("Title"), _("Type"), _("Message")); + gnt_tree_set_show_title(GNT_TREE(tree), TRUE); + gnt_tree_set_col_width(GNT_TREE(tree), 0, 25); + gnt_tree_set_col_width(GNT_TREE(tree), 1, 12); + gnt_tree_set_col_width(GNT_TREE(tree), 2, 35); + gnt_box_add_widget(GNT_BOX(window), tree); + + populate_statuses(GNT_TREE(tree)); + + box = gnt_hbox_new(FALSE); + gnt_box_add_widget(GNT_BOX(window), box); + + button = gnt_button_new(_("Use")); + gnt_box_add_widget(GNT_BOX(box), button); + g_signal_connect(G_OBJECT(button), "activate", + G_CALLBACK(use_savedstatus_cb), NULL); + + button = gnt_button_new(_("Add")); + gnt_box_add_widget(GNT_BOX(box), button); + g_signal_connect_swapped(G_OBJECT(button), "activate", + G_CALLBACK(finch_savedstatus_edit), NULL); + + button = gnt_button_new(_("Edit")); + gnt_box_add_widget(GNT_BOX(box), button); + g_signal_connect(G_OBJECT(button), "activate", + G_CALLBACK(edit_savedstatus_cb), NULL); + + button = gnt_button_new(_("Delete")); + gnt_box_add_widget(GNT_BOX(box), button); + g_signal_connect(G_OBJECT(button), "activate", + G_CALLBACK(ask_before_delete), NULL); + + button = gnt_button_new(_("Close")); + gnt_box_add_widget(GNT_BOX(box), button); + g_signal_connect_swapped(G_OBJECT(button), "activate", + G_CALLBACK(gnt_widget_destroy), window); + + g_signal_connect(G_OBJECT(window), "destroy", + G_CALLBACK(reset_status_window), NULL); + gnt_widget_show(window); +} + +static void +destroy_substatus_win(GaimAccount *account, EditSubStatus *sub, gpointer null) +{ + gnt_widget_destroy(sub->window); /* the "destroy" callback will remove entry from the hashtable */ +} + +static void +free_key(gpointer key, gpointer n) +{ + RowInfo *row = key; + g_free(row->message); + g_free(key); +} + + +static void +update_edit_list(GntWidget *widget, EditStatus *edit) +{ + edits = g_list_remove(edits, edit); + gaim_notify_close_with_handle(edit); + g_hash_table_foreach(edit->hash, (GHFunc)destroy_substatus_win, NULL); + g_list_foreach((GList*)gnt_tree_get_rows(GNT_TREE(edit->tree)), free_key, NULL); + g_free(edit); +} + +static void +set_substatuses(EditStatus *edit) +{ + const GList *iter; + for (iter = gnt_tree_get_rows(GNT_TREE(edit->tree)); iter; iter = iter->next) { + RowInfo *key = iter->data; + if (gnt_tree_get_choice(GNT_TREE(edit->tree), key)) { + gaim_savedstatus_set_substatus(edit->saved, key->account, key->type, key->message); + } + } +} + + +static void +use_trans_status_cb(GntWidget *button, EditStatus *edit) +{ + const char *message; + GaimStatusPrimitive prim; + GaimSavedStatus *saved; + + message = gnt_entry_get_text(GNT_ENTRY(edit->message)); + prim = GPOINTER_TO_INT(gnt_combo_box_get_selected_data(GNT_COMBO_BOX(edit->type))); + + saved = gaim_savedstatus_find_transient_by_type_and_message(prim, message); + if (saved == NULL) { + saved = gaim_savedstatus_new(NULL, prim); + edit->saved = saved; + set_substatuses(edit); + } + gaim_savedstatus_set_message(saved, message); + gaim_savedstatus_activate(saved); + gnt_widget_destroy(edit->window); +} + +static void +save_savedstatus_cb(GntWidget *button, EditStatus *edit) +{ + const char *title, *message; + GaimStatusPrimitive prim; + GaimSavedStatus *find; + + title = gnt_entry_get_text(GNT_ENTRY(edit->title)); + message = gnt_entry_get_text(GNT_ENTRY(edit->message)); + if (!message || !*message) + message = NULL; + + prim = GPOINTER_TO_INT(gnt_combo_box_get_selected_data(GNT_COMBO_BOX(edit->type))); + + if (!title || !*title) + { + gaim_notify_error(edit, _("Error"), _("Invalid title"), + _("Please enter a non-empty title for the status.")); + return; + } + + find = gaim_savedstatus_find(title); + if (find && find != edit->saved) + { + gaim_notify_error(edit, _("Error"), _("Duplicate title"), + _("Please enter a different title for the status.")); + return; + } + + if (edit->saved == NULL) + { + edit->saved = gaim_savedstatus_new(title, prim); + gaim_savedstatus_set_message(edit->saved, message); + set_substatuses(edit); + if (statuses.tree) + gnt_tree_add_row_last(GNT_TREE(statuses.tree), edit->saved, + gnt_tree_create_row(GNT_TREE(statuses.tree), title, + gaim_primitive_get_name_from_type(prim), message), NULL); + } + else + { + gaim_savedstatus_set_title(edit->saved, title); + gaim_savedstatus_set_type(edit->saved, prim); + gaim_savedstatus_set_message(edit->saved, message); + if (statuses.tree) + { + gnt_tree_change_text(GNT_TREE(statuses.tree), edit->saved, 0, title); + gnt_tree_change_text(GNT_TREE(statuses.tree), edit->saved, 1, + gaim_primitive_get_name_from_type(prim)); + gnt_tree_change_text(GNT_TREE(statuses.tree), edit->saved, 2, message); + } + } + + if (g_object_get_data(G_OBJECT(button), "use")) + gaim_savedstatus_activate(edit->saved); + + gnt_widget_destroy(edit->window); +} + +static void +add_substatus(EditStatus *edit, GaimAccount *account) +{ + char *name; + const char *type = NULL, *message = NULL; + GaimSavedStatusSub *sub = NULL; + RowInfo *key; + + if (!edit || !edit->tree) + return; + + if (edit->saved) + sub = gaim_savedstatus_get_substatus(edit->saved, account); + + key = g_new0(RowInfo, 1); + key->account = account; + + if (sub) + { + key->type = gaim_savedstatus_substatus_get_type(sub); + type = gaim_status_type_get_name(key->type); + message = gaim_savedstatus_substatus_get_message(sub); + key->message = g_strdup(message); + } + + name = g_strdup_printf("%s (%s)", gaim_account_get_username(account), + gaim_account_get_protocol_name(account)); + gnt_tree_add_choice(GNT_TREE(edit->tree), key, + gnt_tree_create_row(GNT_TREE(edit->tree), + name, type ? type : "", message ? message : ""), NULL, NULL); + + if (sub) + gnt_tree_set_choice(GNT_TREE(edit->tree), key, TRUE); + g_free(name); +} + +static void +substatus_window_destroy_cb(GntWidget *window, EditSubStatus *sub) +{ + g_hash_table_remove(sub->parent->hash, sub->key->account); + g_free(sub); +} + +static void +save_substatus_cb(GntWidget *widget, EditSubStatus *sub) +{ + GaimSavedStatus *saved = sub->parent->saved; + RowInfo *row = sub->key; + const char *message; + GaimStatusType *type; + + type = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(sub->type)); + message = gnt_entry_get_text(GNT_ENTRY(sub->message)); + + row->type = type; + row->message = g_strdup(message); + + if (saved) /* Save the substatus if the savedstatus actually exists. */ + gaim_savedstatus_set_substatus(saved, row->account, type, message); + + gnt_tree_set_choice(GNT_TREE(sub->parent->tree), row, TRUE); + gnt_tree_change_text(GNT_TREE(sub->parent->tree), row, 1, + gaim_status_type_get_name(type)); + gnt_tree_change_text(GNT_TREE(sub->parent->tree), row, 2, message); + + gnt_widget_destroy(sub->window); +} + +static gboolean +popup_substatus(GntTree *tree, const char *key, EditStatus *edit) +{ + if (key[0] == ' ' && key[1] == 0) + { + EditSubStatus *sub; + GntWidget *window, *combo, *entry, *box, *button, *l; + GaimSavedStatusSub *substatus = NULL; + const GList *iter; + char *name; + RowInfo *selected = gnt_tree_get_selection_data(tree); + GaimAccount *account = selected->account; + + if (gnt_tree_get_choice(tree, selected)) + { + /* There was a savedstatus for this account. Now remove it. */ + g_free(selected->message); + selected->type = NULL; + selected->message = NULL; + /* XXX: should we really be saving it right now? */ + gaim_savedstatus_unset_substatus(edit->saved, account); + gnt_tree_change_text(tree, account, 1, NULL); + gnt_tree_change_text(tree, account, 2, NULL); + return FALSE; + } + + if (g_hash_table_lookup(edit->hash, account)) + return TRUE; + + if (edit->saved) + substatus = gaim_savedstatus_get_substatus(edit->saved, account); + + sub = g_new0(EditSubStatus, 1); + sub->parent = edit; + sub->key = selected; + + sub->window = window = gnt_vbox_new(FALSE); + gnt_box_set_toplevel(GNT_BOX(window), TRUE); + gnt_box_set_title(GNT_BOX(window), _("Substatus")); /* XXX: a better title */ + + box = gnt_hbox_new(FALSE); + gnt_box_add_widget(GNT_BOX(box), gnt_label_new(_("Account:"))); + name = g_strdup_printf("%s (%s)", gaim_account_get_username(account), + gaim_account_get_protocol_name(account)); + gnt_box_add_widget(GNT_BOX(box), gnt_label_new(name)); + g_free(name); + gnt_box_add_widget(GNT_BOX(window), box); + + box = gnt_hbox_new(FALSE); + gnt_box_add_widget(GNT_BOX(box), (l = gnt_label_new(_("Status:")))); + gnt_widget_set_size(l, 0, 1); /* I don't like having to do this */ + sub->type = combo = gnt_combo_box_new(); + gnt_box_add_widget(GNT_BOX(box), combo); + gnt_box_add_widget(GNT_BOX(window), box); + + for (iter = gaim_account_get_status_types(account); iter; iter = iter->next) + { + GaimStatusType *type = iter->data; + if (!gaim_status_type_is_user_settable(type)) + continue; + gnt_combo_box_add_data(GNT_COMBO_BOX(combo), type, gaim_status_type_get_name(type)); + } + + box = gnt_hbox_new(FALSE); + gnt_box_add_widget(GNT_BOX(box), gnt_label_new(_("Message:"))); + sub->message = entry = gnt_entry_new(substatus ? gaim_savedstatus_substatus_get_message(substatus) : NULL); + gnt_box_add_widget(GNT_BOX(box), entry); + gnt_box_add_widget(GNT_BOX(window), box); + + box = gnt_hbox_new(FALSE); + button = gnt_button_new(_("Cancel")); + g_signal_connect_swapped(G_OBJECT(button), "activate", G_CALLBACK(gnt_widget_destroy), window); + gnt_box_add_widget(GNT_BOX(box), button); + button = gnt_button_new(_("Save")); + g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(save_substatus_cb), sub); + gnt_box_add_widget(GNT_BOX(box), button); + gnt_box_add_widget(GNT_BOX(window), box); + + gnt_widget_show(window); + + g_hash_table_insert(edit->hash, account, sub); + + g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(substatus_window_destroy_cb), sub); + + return TRUE; + } + return FALSE; +} + +void finch_savedstatus_edit(GaimSavedStatus *saved) +{ + EditStatus *edit; + GntWidget *window, *box, *button, *entry, *combo, *label, *tree; + GaimStatusPrimitive prims[] = {GAIM_STATUS_AVAILABLE, GAIM_STATUS_AWAY, + GAIM_STATUS_INVISIBLE, GAIM_STATUS_OFFLINE, GAIM_STATUS_UNSET}, current; + GList *iter; + int i; + + if (saved) + { + GList *iter; + for (iter = edits; iter; iter = iter->next) + { + edit = iter->data; + if (edit->saved == saved) + return; + } + } + + edit = g_new0(EditStatus, 1); + edit->saved = saved; + edit->window = window = gnt_vbox_new(FALSE); + gnt_box_set_toplevel(GNT_BOX(window), TRUE); + gnt_box_set_title(GNT_BOX(window), _("Edit Status")); + gnt_box_set_fill(GNT_BOX(window), TRUE); + gnt_box_set_alignment(GNT_BOX(window), GNT_ALIGN_LEFT); + gnt_box_set_pad(GNT_BOX(window), 0); + + edits = g_list_append(edits, edit); + + /* Title */ + box = gnt_hbox_new(FALSE); + gnt_box_set_alignment(GNT_BOX(box), GNT_ALIGN_LEFT); + gnt_box_add_widget(GNT_BOX(window), box); + gnt_box_add_widget(GNT_BOX(box), gnt_label_new(_("Title"))); + + edit->title = entry = gnt_entry_new(saved ? gaim_savedstatus_get_title(saved) : NULL); + gnt_box_add_widget(GNT_BOX(box), entry); + + /* Type */ + box = gnt_hbox_new(FALSE); + gnt_box_add_widget(GNT_BOX(window), box); + gnt_box_add_widget(GNT_BOX(box), label = gnt_label_new(_("Status"))); + gnt_widget_set_size(label, 0, 1); + + edit->type = combo = gnt_combo_box_new(); + gnt_box_add_widget(GNT_BOX(box), combo); + current = saved ? gaim_savedstatus_get_type(saved) : GAIM_STATUS_UNSET; + for (i = 0; prims[i] != GAIM_STATUS_UNSET; i++) + { + gnt_combo_box_add_data(GNT_COMBO_BOX(combo), GINT_TO_POINTER(prims[i]), + gaim_primitive_get_name_from_type(prims[i])); + if (prims[i] == current) + gnt_combo_box_set_selected(GNT_COMBO_BOX(combo), GINT_TO_POINTER(current)); + } + + /* Message */ + box = gnt_hbox_new(FALSE); + gnt_box_add_widget(GNT_BOX(window), box); + gnt_box_add_widget(GNT_BOX(box), gnt_label_new(_("Message"))); + + edit->message = entry = gnt_entry_new(saved ? gaim_savedstatus_get_message(saved) : NULL); + gnt_box_add_widget(GNT_BOX(window), entry); + + gnt_box_add_widget(GNT_BOX(window), gnt_hline_new()); + gnt_box_add_widget(GNT_BOX(window), gnt_label_new(_("Use different status for following accounts"))); + + edit->hash = g_hash_table_new(g_direct_hash, g_direct_equal); + edit->tree = tree = gnt_tree_new_with_columns(3); + gnt_box_add_widget(GNT_BOX(window), tree); + gnt_tree_set_show_title(GNT_TREE(tree), TRUE); + gnt_tree_set_column_titles(GNT_TREE(tree), _("Account"), _("Status"), _("Message")); + gnt_tree_set_col_width(GNT_TREE(tree), 0, 30); + gnt_tree_set_col_width(GNT_TREE(tree), 1, 10); + gnt_tree_set_col_width(GNT_TREE(tree), 2, 30); + + for (iter = gaim_accounts_get_all(); iter; iter = iter->next) + { + add_substatus(edit, iter->data); + } + + g_signal_connect(G_OBJECT(tree), "key_pressed", G_CALLBACK(popup_substatus), edit); + + /* The buttons */ + box = gnt_hbox_new(FALSE); + gnt_box_add_widget(GNT_BOX(window), box); + + /* Use */ + button = gnt_button_new(_("Use")); + gnt_box_add_widget(GNT_BOX(box), button); + g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(use_trans_status_cb), edit); + + /* Save */ + button = gnt_button_new(_("Save")); + gnt_box_add_widget(GNT_BOX(box), button); + g_object_set_data(G_OBJECT(button), "use", NULL); + g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(save_savedstatus_cb), edit); + + /* Save & Use */ + button = gnt_button_new(_("Save & Use")); + gnt_box_add_widget(GNT_BOX(box), button); + g_object_set_data(G_OBJECT(button), "use", GINT_TO_POINTER(TRUE)); + g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(save_savedstatus_cb), edit); + + /* Cancel */ + button = gnt_button_new(_("Cancel")); + gnt_box_add_widget(GNT_BOX(box), button); + g_signal_connect_swapped(G_OBJECT(button), "activate", + G_CALLBACK(gnt_widget_destroy), window); + + g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(update_edit_list), edit); + + gnt_widget_show(window); +} + diff -r 317e7613e581 -r 0e3a8505ebbe finch/gntstatus.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/gntstatus.h Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,50 @@ +/** + * @file gntstatus.h GNT Status API + * @ingroup gntui + * + * gaim + * + * Gaim is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _GNT_STATUS_H +#define _GNT_STATUS_H + +#include +#include + +/********************************************************************** + * @name GNT BuddyList API + **********************************************************************/ +/*@{*/ + +/** + * Show a dialog with all the saved statuses. + */ +void finch_savedstatus_show_all(void); + +/** + * Show a dialog to edit a status. + * + * @param saved The saved status to edit. Set it to @c NULL to create a new status. + */ +void finch_savedstatus_edit(GaimSavedStatus *saved); + +/*@}*/ + +#endif diff -r 317e7613e581 -r 0e3a8505ebbe finch/gntui.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/gntui.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,118 @@ +/** + * gaim + * + * Gaim is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "gntui.h" + +#include "gntaccount.h" +#include "gntblist.h" +#include "gntconn.h" +#include "gntconv.h" +#include "gntdebug.h" +#include "gntft.h" +#include "gntnotify.h" +#include "gntplugin.h" +#include "gntpounce.h" +#include "gntprefs.h" +#include "gntrequest.h" +#include "gntstatus.h" +#include "internal.h" + +#include + +void gnt_ui_init() +{ +#ifdef STANDALONE + gnt_init(); +#endif + + gaim_prefs_add_none("/gaim/gnt"); + + /* Accounts */ + finch_accounts_init(); + gaim_accounts_set_ui_ops(finch_accounts_get_ui_ops()); + + /* Connections */ + finch_connections_init(); + gaim_connections_set_ui_ops(finch_connections_get_ui_ops()); + + /* Initialize the buddy list */ + finch_blist_init(); + gaim_blist_set_ui_ops(finch_blist_get_ui_ops()); + + /* Now the conversations */ + finch_conversation_init(); + gaim_conversations_set_ui_ops(finch_conv_get_ui_ops()); + + /* Notify */ + finch_notify_init(); + gaim_notify_set_ui_ops(finch_notify_get_ui_ops()); + + finch_request_init(); + gaim_request_set_ui_ops(finch_request_get_ui_ops()); + + finch_pounces_init(); + + finch_xfers_init(); + gaim_xfers_set_ui_ops(finch_xfers_get_ui_ops()); + + gnt_register_action(_("Accounts"), finch_accounts_show_all); + gnt_register_action(_("Buddy List"), finch_blist_show); + gnt_register_action(_("Buddy Pounces"), finch_pounces_manager_show); + gnt_register_action(_("Debug Window"), finch_debug_window_show); + gnt_register_action(_("File Transfers"), finch_xfer_dialog_show); + gnt_register_action(_("Plugins"), finch_plugins_show_all); + gnt_register_action(_("Preferences"), finch_prefs_show_all); + gnt_register_action(_("Statuses"), finch_savedstatus_show_all); + +#ifdef STANDALONE + + finch_plugins_save_loaded(); +} + +void gnt_ui_uninit() +{ + gaim_accounts_set_ui_ops(NULL); + finch_accounts_uninit(); + + gaim_connections_set_ui_ops(NULL); + finch_connections_uninit(); + + gaim_blist_set_ui_ops(NULL); + finch_blist_uninit(); + + gaim_conversations_set_ui_ops(NULL); + finch_conversation_uninit(); + + gaim_notify_set_ui_ops(NULL); + finch_notify_uninit(); + + gaim_request_set_ui_ops(NULL); + finch_request_uninit(); + + finch_pounces_uninit(); + + finch_xfers_uninit(); + gaim_xfers_set_ui_ops(NULL); + + gnt_quit(); +#endif +} + diff -r 317e7613e581 -r 0e3a8505ebbe finch/gntui.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/gntui.h Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,30 @@ +/** + * gaim + * + * Gaim is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _GNT_UI_H +#define _GNT_UI_H + +#include "gnt.h" + +void gnt_ui_init(void); +void gnt_ui_uninit(void); + +#endif diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/AUTHORS diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/COPYING --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/COPYING Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/ChangeLog diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/INSTALL --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/INSTALL Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,229 @@ +Copyright 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software +Foundation, Inc. + + This file is free documentation; the Free Software Foundation gives +unlimited permission to copy, distribute and modify it. + +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. (Caching is +disabled by default to prevent problems with accidental use of stale +cache files.) + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You only need +`configure.ac' if you want to change it or regenerate `configure' using +a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. Run `./configure --help' +for details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not support the `VPATH' +variable, you have to compile the package for one architecture at a +time in the source code directory. After you have installed the +package for one architecture, use `make distclean' before reconfiguring +for another architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PATH'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=PATH' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' cannot figure out +automatically, but needs to determine by the type of machine the package +will run on. Usually, assuming the package is built to be run on the +_same_ architectures, `configure' can figure that out, but if it prints +a message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the `--target=TYPE' option to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + + Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +will cause the specified gcc to be used as the C compiler (unless it is +overridden in the site shell script). + +`configure' Invocation +====================== + + `configure' recognizes the following options to control how it +operates. + +`--help' +`-h' + Print a summary of the options to `configure', and exit. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/Makefile.am --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/Makefile.am Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,83 @@ +EXTRA_DIST=genmarshal + +SUBDIRS = . wms +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = gnt.pc + +lib_LTLIBRARIES = libgnt.la + +libgnt_la_SOURCES = \ + gntmarshal.c \ + gntwidget.c \ + gntbindable.c \ + gntbox.c \ + gntbutton.c \ + gntcheckbox.c \ + gntclipboard.c \ + gntcolors.c \ + gntcombobox.c \ + gntentry.c \ + gntkeys.c \ + gntlabel.c \ + gntline.c \ + gntmenu.c \ + gntmenuitem.c \ + gntmenuitemcheck.c \ + gntstyle.c \ + gnttextview.c \ + gnttree.c \ + gntutils.c \ + gntwindow.c \ + gntwm.c \ + gntmain.c + +libgnt_la_headers = \ + gntwidget.h \ + gntbindable.h \ + gntbox.h \ + gntbutton.h \ + gntcheckbox.h \ + gntclipboard.h \ + gntcolors.h \ + gntcombobox.h \ + gntentry.h \ + gntkeys.h \ + gntlabel.h \ + gntline.h \ + gntmarshal.h \ + gntmenu.h \ + gntmenuitem.h \ + gntmenuitemcheck.h \ + gntstyle.h \ + gnttextview.h \ + gnttree.h \ + gntutils.h \ + gntwindow.h \ + gntwm.h \ + gnt.h + +CLEANFILES = \ + gntmarshal.h \ + gntmarshal.c + +gntmarshal.c: genmarshal gntmarshal.h + echo "#include \"gntmarshal.h\"" > $@ + cat genmarshal | glib-genmarshal --prefix=gnt_closure_marshal --body >> $@ + +gntmarshal.h: genmarshal + cat genmarshal | glib-genmarshal --prefix=gnt_closure_marshal --header > $@ + +libgnt_laincludedir=$(includedir)/gnt +libgnt_lainclude_HEADERS = \ + $(libgnt_la_headers) + +libgnt_la_DEPENDENCIES = +libgnt_la_LDFLAGS = -export-dynamic +libgnt_la_LIBADD = \ + $(GLIB_LIBS) \ + $(GNT_LIBS) + +AM_CPPFLAGS = \ + $(GLIB_CFLAGS) \ + $(GNT_CFLAGS) \ + $(DEBUG_CFLAGS) diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/NEWS diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/README diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/autogen.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/autogen.sh Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,48 @@ +#!/bin/sh + +(libtoolize --version) < /dev/null > /dev/null 2>&1 || { + echo; + echo "You must have libtool installed to compile LibGNT"; + echo; + exit; +} + +(automake --version) < /dev/null > /dev/null 2>&1 || { + echo; + echo "You must have automake installed to compile LibGNT"; + echo; + exit; +} + +(autoconf --version) < /dev/null > /dev/null 2>&1 || { + echo; + echo "You must have autoconf installed to compile LibGNT"; + echo; + exit; +} + +echo "Generating configuration files for LibGNT, please wait...." +echo; + +echo "Running libtoolize, please ignore non-fatal messages...." +echo n | libtoolize --copy --force || exit; + +# Add other directories to this list if people continue to experience +# brokennesses ... Obviously the real answer is for them to fix it +# themselves, but for Luke's sake we have this. +for dir in "/usr/local/share/aclocal" \ + "/opt/gnome-1.4/share/aclocal" +do + if test -d $dir ; then + ACLOCAL_FLAGS="$ACLOCAL_FLAGS -I $dir" + fi +done + +libtoolize -c -f --automake +aclocal $ACLOCAL_FLAGS || exit; +autoheader || exit; +automake --add-missing --copy; +autoconf || exit; +automake || exit; +./configure $@ + diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/configure.ac --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/configure.ac Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,257 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT([libgnt], [0.0.0dev], [gaim-devel@lists.sourceforge.net]) +AC_CANONICAL_SYSTEM +AM_CONFIG_HEADER(config.h) +AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION) + +AC_PREREQ([2.50]) + +AC_PATH_PROG(sedpath, sed) + +dnl Storing configure arguments +AC_DEFINE_UNQUOTED(CONFIG_ARGS, "$ac_configure_args", [configure arguments]) + +dnl Checks for programs. +AC_PROG_CC +AC_DISABLE_STATIC +AM_PROG_LIBTOOL +LIBTOOL="$LIBTOOL --silent" +AC_PROG_INSTALL + +dnl we don't use autobreak on cygwin!! +dnl AC_CYGWIN + +dnl Checks for header files. +AC_HEADER_STDC +AC_HEADER_SYS_WAIT +AC_CHECK_HEADERS(arpa/nameser_compat.h fcntl.h sys/time.h unistd.h locale.h signal.h stdint.h regex.h) + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_STRUCT_TM + +AC_C_BIGENDIAN + +dnl Checks for library functions. +AC_TYPE_SIGNAL +AC_FUNC_STRFTIME +AC_CHECK_FUNCS(strdup strstr atexit setlocale) + +dnl to prevent the g_stat()/g_unlink() crash, +dnl (09:50:07) Robot101: LSchiere2: it's easy. +LC_SYS_LARGEFILE somewhere in configure.ac +AC_SYS_LARGEFILE + +dnl FreeBSD doesn't have libdl, dlopen is provided by libc +AC_CHECK_FUNC(dlopen, LIBDL="", [AC_CHECK_LIB(dl, dlopen, LIBDL="-ldl")]) + +AC_MSG_CHECKING(for the %z format string in strftime()) +AC_TRY_RUN([ +#ifdef HAVE_SYS_TIME_H +#include +#endif +#include +#include + +int main() +{ + char buf[6]; + time_t t = time(NULL); + + if (strftime(buf, sizeof(buf), "%z", localtime(&t)) != 5) + return 1; + + fprintf(stderr, "strftime(\"%%z\") yields: \"%s\"\n", buf); + + return !((buf[0] == '-' || buf[0] == '+') && + (buf[1] >= '0' && buf[1] <= '9') && + (buf[2] >= '0' && buf[2] <= '9') && + (buf[3] >= '0' && buf[3] <= '9') && + (buf[4] >= '0' && buf[4] <= '9') + ); +} +], +[ + AC_MSG_RESULT(yes) + AC_DEFINE([HAVE_STRFTIME_Z_FORMAT], [1], + [Define to 1 if you have a strftime() that supports the %z format string.]) +], +[ + AC_MSG_RESULT(no) +], +[ + # Fallback for Cross Compiling... + # This will enable the compatibility code. + AC_MSG_RESULT(no) +] +) + + +AC_CHECK_HEADER(sys/utsname.h) +AC_CHECK_FUNC(uname) + +if test "x$enable_debug" = "xyes" ; then + AC_DEFINE(DEBUG, 1, [Define if debugging is enabled.]) + enable_fatal_asserts="yes" +fi + +if test "x$enable_fatal_asserts" = "xyes" ; then + AC_DEFINE(GAIM_FATAL_ASSERTS, 1, [Define to make assertions fatal (useful for debugging).]) +fi + +if test "x$enable_deprecated" = "xno"; then + DEBUG_CFLAGS="$DEBUG_CFLAGS -DG_DISABLE_DEPRECATED -DGDK_DISABLE_DEPRECATED -DGDK_PIXBUF_DISABLE_DEPRECATED -DGTK_DISABLE_DEPRECATED" +fi + +if test "x$GCC" = "xyes"; then + dnl We enable -Wall later. + dnl If it's set after the warning CFLAGS in the compiler invocation, it counteracts the -Wno... flags. + dnl This leads to warnings we don't want. + CFLAGS=`echo $CFLAGS |$sedpath 's/-Wall//'` + + dnl ENABLE WARNINGS SUPPORTED BY THE VERSION OF GCC IN USE + dnl + dnl Future Possibilities + dnl + dnl Consider adding -Wbad-function-cast. + dnl This leads to spurious warnings using GPOINTER_TO_INT(), et al. directly on a function call. + dnl We'd need an intermediate variable. + dnl + dnl Consider adding -Wfloat-equal. + dnl This leads to warnings with Perl. + dnl Perhaps we could write ugly configure magic and pass -Wno-float-equal down to that subdirectory. + dnl On the other hand, it's probably actually broken, so maybe the Perl folks should fix that? + dnl + dnl Consider removing -Wno-sign-compare (from the -Wextra set) and fixing all those cases. + dnl This is likely non-trivial. + dnl + for newflag in \ + "-Waggregate-return" \ + "-Wcast-align" \ + "-Wdeclaration-after-statement" \ + "-Werror-implicit-function-declaration" \ + "-Wextra -Wno-sign-compare -Wno-unused-parameter" \ + "-Winit-self" \ + "-Wmissing-declarations" \ + "-Wmissing-prototypes" \ + "-Wnested-externs" \ + "-Wpointer-arith" \ + "-Wundef" \ + ; do + orig_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $newflag" + AC_MSG_CHECKING(for $newflag option to gcc) + AC_TRY_COMPILE([], [ + int main() {return 0;} + ], [ + AC_MSG_RESULT(yes) + CFLAGS="$orig_CFLAGS" + DEBUG_CFLAGS="$DEBUG_CFLAGS $newflag" + ], [ + AC_MSG_RESULT(no) + CFLAGS="$orig_CFLAGS" + ]) + done + + if test "x$enable_fortify" = "xyes"; then + AC_MSG_CHECKING(for FORTIFY_SOURCE support) + AC_TRY_COMPILE([#include ], [ + int main() { + #if !(__GNUC_PREREQ (4, 1) \ + || (defined __GNUC_RH_RELEASE__ && __GNUC_PREREQ (4, 0)) \ + || (defined __GNUC_RH_RELEASE__ && __GNUC_PREREQ (3, 4) \ + && __GNUC_MINOR__ == 4 \ + && (__GNUC_PATCHLEVEL__ > 2 \ + || (__GNUC_PATCHLEVEL__ == 2 && __GNUC_RH_RELEASE__ >= 8)))) + #error No FORTIFY_SOURCE support + #endif + return 0; + } + ], [ + AC_MSG_RESULT(yes) + DEBUG_CFLAGS="$DEBUG_CFLAGS -D_FORTIFY_SOURCE=2" + ], [ + AC_MSG_RESULT(no) + ]) + fi + + DEBUG_CFLAGS="-Wall $DEBUG_CFLAGS" + CFLAGS="-g $CFLAGS" +fi +AC_SUBST(CFLAGS) + +PKG_CHECK_MODULES(GLIB, [glib-2.0 >= 2.0.0 gobject-2.0 gmodule-2.0],, + [ + AC_MSG_ERROR([ +*** GLib 2.0 is required to build LibGNT; please make sure you have the GLib +*** development headers installed. The latest version of GLib is +*** always available at http://www.gtk.org/.]) + ]) +AC_SUBST(GLIB_CFLAGS) +AC_SUBST(GLIB_LIBS) + + +AC_MSG_CHECKING(for me pot o' gold) +AC_MSG_RESULT(no) +AC_CHECK_FUNCS(gethostid lrand48) +AC_CHECK_FUNCS(memcpy memmove random strchr strerror vprintf) +AC_CHECK_HEADERS(malloc.h paths.h sgtty.h stdarg.h sys/cdefs.h) +AC_CHECK_HEADERS(sys/file.h sys/filio.h sys/ioctl.h sys/msgbuf.h) +AC_CHECK_HEADERS(sys/select.h sys/uio.h sys/utsname.h sys/wait.h) +AC_CHECK_HEADERS(termios.h) +#AC_CHECK_FUNC(wcwidth, [AC_DEFINE([HAVE_WCWIDTH], [1], [Define to 1 if you have wcwidth function.])]) +#AC_VAR_TIMEZONE_EXTERNALS + +GNT_CFLAGS= +GNT_LIBS= +AC_CHECK_LIB(ncursesw, initscr, [GNT_LIBS="-lncursesw"], [enable_gnt=no]) +AC_CHECK_LIB(panelw, update_panels, [GNT_LIBS="$GNT_LIBS -lpanelw"], [enable_gnt=no]) + +# If ncursesw is not found, look for plain old ncurses +if test "x$enable_gnt" = "xno"; then + AC_CHECK_LIB(ncurses, initscr, [[GNT_LIBS="-lncurses"] [enable_gnt=yes]], [enable_gnt=no]) + AC_CHECK_LIB(panel, update_panels, [[GNT_LIBS="$GNT_LIBS -lpanel"] [enable_gnt=yes]], [enable_gnt=no]) + AC_DEFINE(NO_WIDECHAR, [1], [Define to 1 if you do not have ncursesw.]) +else + dnl # Some distros put the headers in ncursesw/, some don't + found_ncurses_h=no + for f in /usr/include/ncursesw/ncurses.h /usr/include/ncurses.h + do + AC_CHECK_HEADER($f,[ + AC_MSG_CHECKING([if $f supports wide characters]) + AC_TRY_COMPILE([ + #define _XOPEN_SOURCE_EXTENDED + #include <$f> + ], [ + #ifndef get_wch + # error get_wch not found! + #endif + ], [ + dir=`dirname $f` + if test x"$dir" != x"." ; then + GNT_CFLAGS="-I$dir/" + else + GNT_CFLAGS="" + fi + + found_ncurses_h=yes + AC_MSG_RESULT([yes]) + break + ], [ + AC_MSG_RESULT([no]) + ]) + ]) + done +fi +AC_SUBST(GNT_CFLAGS) +AC_SUBST(GNT_LIBS) + +if test "x$enable_gnt" = "xno"; then + AC_MSG_ERROR([ +*** You need ncursesw or ncurses.]) +fi + +AC_OUTPUT([Makefile + gnt.pc + wms/Makefile + ]) + diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/genmarshal --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/genmarshal Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,10 @@ +BOOLEAN:VOID +BOOLEAN:STRING +VOID:INT,INT,INT,INT +VOID:INT,INT +VOID:POINTER,POINTER +BOOLEAN:INT,INT +BOOLEAN:INT,INT,INT +BOOLEAN:POINTER,POINTER,POINTER +BOOLEAN:INT,INT,INT,POINTER +VOID:STRING,STRING diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gnt-skel.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gnt-skel.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,106 @@ +#include "gnt-skel.h" + +enum +{ + SIGS = 1, +}; + +static GntWidgetClass *parent_class = NULL; +static guint signals[SIGS] = { 0 }; + +static void +gnt_skel_draw(GntWidget *widget) +{ + GNTDEBUG; +} + +static void +gnt_skel_size_request(GntWidget *widget) +{ +} + +static void +gnt_skel_map(GntWidget *widget) +{ + if (widget->priv.width == 0 || widget->priv.height == 0) + gnt_widget_size_request(widget); + GNTDEBUG; +} + +static gboolean +gnt_skel_key_pressed(GntWidget *widget, const char *text) +{ + return FALSE; +} + +static void +gnt_skel_destroy(GntWidget *widget) +{ +} + +static void +gnt_skel_class_init(GntSkelClass *klass) +{ + GObjectClass *obj_class = G_OBJECT_CLASS(klass); + + parent_class = GNT_WIDGET_CLASS(klass); + parent_class->destroy = gnt_skel_destroy; + parent_class->draw = gnt_skel_draw; + parent_class->map = gnt_skel_map; + parent_class->size_request = gnt_skel_size_request; + parent_class->key_pressed = gnt_skel_key_pressed; + + parent_class->actions = g_hash_table_duplicate(parent_class->actions, g_str_hash, + g_str_equal, NULL, (GDestroyNotify)gnt_widget_action_free); + parent_class->bindings = g_hash_table_duplicate(parent_class->bindings, g_str_hash, + g_str_equal, NULL, (GDestroyNotify)gnt_widget_action_param_free); + + gnt_widget_actions_read(G_OBJECT_CLASS_TYPE(klass), klass); + + GNTDEBUG; +} + +static void +gnt_skel_init(GTypeInstance *instance, gpointer class) +{ + GNTDEBUG; +} + +/****************************************************************************** + * GntSkel API + *****************************************************************************/ +GType +gnt_skel_get_gtype(void) +{ + static GType type = 0; + + if(type == 0) + { + static const GTypeInfo info = { + sizeof(GntSkelClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc)gnt_skel_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof(GntSkel), + 0, /* n_preallocs */ + gnt_skel_init, /* instance_init */ + }; + + type = g_type_register_static(GNT_TYPE_WIDGET, + "GntSkel", + &info, 0); + } + + return type; +} + +GntWidget *gnt_skel_new() +{ + GntWidget *widget = g_object_new(GNT_TYPE_SKEL, NULL); + GntSkel *skel = GNT_SKEL(widget); + + return widget; +} + diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gnt-skel.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gnt-skel.h Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,47 @@ +#ifndef GNT_SKEL_H +#define GNT_SKEL_H + +#include "gntwidget.h" +#include "gnt.h" +#include "gntcolors.h" +#include "gntkeys.h" + +#define GNT_TYPE_SKEL (gnt_skel_get_gtype()) +#define GNT_SKEL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNT_TYPE_SKEL, GntSkel)) +#define GNT_SKEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GNT_TYPE_SKEL, GntSkelClass)) +#define GNT_IS_SKEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GNT_TYPE_SKEL)) +#define GNT_IS_SKEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GNT_TYPE_SKEL)) +#define GNT_SKEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GNT_TYPE_SKEL, GntSkelClass)) + +#define GNT_SKEL_FLAGS(obj) (GNT_SKEL(obj)->priv.flags) +#define GNT_SKEL_SET_FLAGS(obj, flags) (GNT_SKEL_FLAGS(obj) |= flags) +#define GNT_SKEL_UNSET_FLAGS(obj, flags) (GNT_SKEL_FLAGS(obj) &= ~(flags)) + +typedef struct _GnSkel GntSkel; +typedef struct _GnSkelPriv GntSkelPriv; +typedef struct _GnSkelClass GntSkelClass; + +struct _GnSkel +{ + GntWidget parent; +}; + +struct _GnSkelClass +{ + GntWidgetClass parent; + + void (*gnt_reserved1)(void); + void (*gnt_reserved2)(void); + void (*gnt_reserved3)(void); + void (*gnt_reserved4)(void); +}; + +G_BEGIN_DECLS + +GType gnt_skel_get_gtype(void); + +GntWidget *gnt_skel_new(); + +G_END_DECLS + +#endif /* GNT_SKEL_H */ diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gnt.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gnt.h Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,41 @@ +#include +#include "gntwidget.h" +#include "gntclipboard.h" +#include "gntcolors.h" +#include "gntkeys.h" + +void gnt_init(void); + +void gnt_main(void); + +gboolean gnt_ascii_only(void); + +void gnt_screen_occupy(GntWidget *widget); + +void gnt_screen_release(GntWidget *widget); + +void gnt_screen_update(GntWidget *widget); + +void gnt_screen_take_focus(GntWidget *widget); + +void gnt_screen_resize_widget(GntWidget *widget, int width, int height); + +void gnt_screen_move_widget(GntWidget *widget, int x, int y); + +void gnt_screen_rename_widget(GntWidget *widget, const char *text); + +gboolean gnt_widget_has_focus(GntWidget *widget); + +void gnt_widget_set_urgent(GntWidget *widget); + +void gnt_register_action(const char *label, void (*callback)()); + +gboolean gnt_screen_menu_show(gpointer menu); + +void gnt_quit(void); + +GntClipboard *gnt_get_clipboard(void); + +gchar *gnt_get_clipboard_string(void); + +void gnt_set_clipboard_string(gchar *); diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gnt.pc.in --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gnt.pc.in Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,14 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ +datarootdir=@datarootdir@ +datadir=@datadir@ +sysconfdir=@sysconfdir@ + +Name: LibGNT +Description: Glib Ncurses Toolkit is a collection of curses-widgets. +Version: @VERSION@ +Requires: glib-2.0 +Cflags: -I${includedir}/gnt +Libs: -L${libdir} -lgnt diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gntbindable.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gntbindable.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,232 @@ +#include "gntbindable.h" +#include "gntstyle.h" +#include "gnt.h" +#include "gntutils.h" + +static GObjectClass *parent_class = NULL; + +static void +gnt_bindable_class_init(GntBindableClass *klass) +{ + parent_class = g_type_class_peek_parent(klass); + + klass->actions = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, + (GDestroyNotify)gnt_bindable_action_free); + klass->bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, + (GDestroyNotify)gnt_bindable_action_param_free); + + gnt_style_read_actions(G_OBJECT_CLASS_TYPE(klass), GNT_BINDABLE_CLASS(klass)); + GNTDEBUG; +} + +static gpointer +bindable_clone(GntBindableAction *action) +{ + GntBindableAction *ret = g_new0(GntBindableAction, 1); + ret->name = g_strdup(action->name); + ret->u = action->u; + return ret; +} + +static gpointer +binding_clone(GntBindableActionParam *param) +{ + GntBindableActionParam *p = g_new0(GntBindableActionParam, 1); + p->list = g_list_copy(param->list); + p->action = param->action; + return p; +} + +static void +duplicate_hashes(GntBindableClass *klass) +{ + /* Duplicate the bindings from parent class */ + if (klass->actions) { + klass->actions = g_hash_table_duplicate(klass->actions, g_str_hash, + g_str_equal, g_free, (GDestroyNotify)gnt_bindable_action_free, + (GDupFunc)g_strdup, (GDupFunc)bindable_clone); + klass->bindings = g_hash_table_duplicate(klass->bindings, g_str_hash, + g_str_equal, g_free, (GDestroyNotify)gnt_bindable_action_param_free, + (GDupFunc)g_strdup, (GDupFunc)binding_clone); + } else { + klass->actions = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, + (GDestroyNotify)gnt_bindable_action_free); + klass->bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, + (GDestroyNotify)gnt_bindable_action_param_free); + } + + GNTDEBUG; +} + +/****************************************************************************** + * GntBindable API + *****************************************************************************/ +GType +gnt_bindable_get_gtype(void) +{ + static GType type = 0; + + if(type == 0) { + static const GTypeInfo info = { + sizeof(GntBindableClass), + (GBaseInitFunc)duplicate_hashes, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc)gnt_bindable_class_init, + NULL, + NULL, /* class_data */ + sizeof(GntBindable), + 0, /* n_preallocs */ + NULL, /* instance_init */ + NULL /* value_table */ + }; + + type = g_type_register_static(G_TYPE_OBJECT, + "GntBindable", + &info, G_TYPE_FLAG_ABSTRACT); + } + + return type; +} + +/** + * Key Remaps + */ +const char * +gnt_bindable_remap_keys(GntBindable *bindable, const char *text) +{ + const char *remap = NULL; + GType type = G_OBJECT_TYPE(bindable); + GntBindableClass *klass = GNT_BINDABLE_CLASS(GNT_BINDABLE_GET_CLASS(bindable)); + + if (klass->remaps == NULL) + { + klass->remaps = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + gnt_styles_get_keyremaps(type, klass->remaps); + } + + remap = g_hash_table_lookup(klass->remaps, text); + + return (remap ? remap : text); +} + +/** + * Actions and Bindings + */ +gboolean +gnt_bindable_perform_action_named(GntBindable *bindable, const char *name, ...) +{ + GntBindableClass *klass = GNT_BINDABLE_CLASS(GNT_BINDABLE_GET_CLASS(bindable)); + GList *list = NULL; + va_list args; + GntBindableAction *action; + void *p; + + va_start(args, name); + while ((p = va_arg(args, void *)) != NULL) + list = g_list_append(list, p); + va_end(args); + + action = g_hash_table_lookup(klass->actions, name); + if (action && action->u.action) { + return action->u.action(bindable, list); + } + return FALSE; +} + +gboolean +gnt_bindable_perform_action_key(GntBindable *bindable, const char *keys) +{ + GntBindableClass *klass = GNT_BINDABLE_CLASS(GNT_BINDABLE_GET_CLASS(bindable)); + GntBindableActionParam *param = g_hash_table_lookup(klass->bindings, keys); + + if (param && param->action) { + if (param->list) + return param->action->u.action(bindable, param->list); + else + return param->action->u.action_noparam(bindable); + } + return FALSE; +} + +static void +register_binding(GntBindableClass *klass, const char *name, const char *trigger, GList *list) +{ + GntBindableActionParam *param; + GntBindableAction *action; + + if (name == NULL || *name == '\0') { + g_hash_table_remove(klass->bindings, (char*)trigger); + gnt_keys_del_combination(trigger); + return; + } + + action = g_hash_table_lookup(klass->actions, name); + if (!action) { + g_printerr("GntWidget: Invalid action name %s for %s\n", + name, g_type_name(G_OBJECT_CLASS_TYPE(klass))); + if (list) + g_list_free(list); + return; + } + + param = g_new0(GntBindableActionParam, 1); + param->action = action; + param->list = list; + g_hash_table_replace(klass->bindings, g_strdup(trigger), param); + gnt_keys_add_combination(trigger); +} + +void gnt_bindable_register_binding(GntBindableClass *klass, const char *name, + const char *trigger, ...) +{ + GList *list = NULL; + va_list args; + void *data; + + va_start(args, trigger); + while ((data = va_arg(args, void *))) { + list = g_list_append(list, data); + } + va_end(args); + + register_binding(klass, name, trigger, list); +} + +void gnt_bindable_class_register_action(GntBindableClass *klass, const char *name, + GntBindableActionCallback callback, const char *trigger, ...) +{ + void *data; + va_list args; + GntBindableAction *action = g_new0(GntBindableAction, 1); + GList *list; + + action->name = g_strdup(name); + action->u.action = callback; + + g_hash_table_replace(klass->actions, g_strdup(name), action); + + if (trigger && *trigger) { + list = NULL; + va_start(args, trigger); + while ((data = va_arg(args, void *))) { + list = g_list_append(list, data); + } + va_end(args); + + register_binding(klass, name, trigger, list); + } +} + +void gnt_bindable_action_free(GntBindableAction *action) +{ + g_free(action->name); + g_free(action); +} + +void gnt_bindable_action_param_free(GntBindableActionParam *param) +{ + g_list_free(param->list); /* XXX: There may be a leak here for string parameters */ + g_free(param); +} + + diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gntbindable.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gntbindable.h Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,90 @@ +#ifndef GNT_BINDABLE_H +#define GNT_BINDABLE_H + +#include +#include +#include +#include + +#define GNT_TYPE_BINDABLE (gnt_bindable_get_gtype()) +#define GNT_BINDABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNT_TYPE_BINDABLE, GntBindable)) +#define GNT_BINDABLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GNT_TYPE_BINDABLE, GntBindableClass)) +#define GNT_IS_BINDABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GNT_TYPE_BINDABLE)) +#define GNT_IS_BINDABLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GNT_TYPE_BINDABLE)) +#define GNT_BINDABLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GNT_TYPE_BINDABLE, GntBindableClass)) + +#define GNTDEBUG g_printerr("%s\n", __FUNCTION__) + +typedef struct _GnBindable GntBindable; +typedef struct _GnBindableClass GntBindableClass; + +struct _GnBindable +{ + GObject inherit; +}; + +struct _GnBindableClass +{ + GObjectClass parent; + + GHashTable *remaps; /* Key remaps */ + GHashTable *actions; /* name -> Action */ + GHashTable *bindings; /* key -> ActionParam */ + + void (*gnt_reserved1)(void); + void (*gnt_reserved2)(void); + void (*gnt_reserved3)(void); + void (*gnt_reserved4)(void); +}; + +G_BEGIN_DECLS + +GType gnt_bindable_get_gtype(void); + +/******************/ +/* Key Remaps */ +/******************/ +const char * gnt_bindable_remap_keys(GntBindable *bindable, const char *text); + +/******************/ +/* Bindable Actions */ +/******************/ +typedef gboolean (*GntBindableActionCallback) (GntBindable *bindable, GList *params); +typedef gboolean (*GntBindableActionCallbackNoParam)(GntBindable *bindable); + +typedef struct _GnBindableAction GntBindableAction; +typedef struct _GnBindableActionParam GntBindableActionParam; + +struct _GnBindableAction +{ + char *name; /* The name of the action */ + union { + gboolean (*action)(GntBindable *bindable, GList *params); + gboolean (*action_noparam)(GntBindable *bindable); + } u; +}; + +struct _GnBindableActionParam +{ + GntBindableAction *action; + GList *list; +}; + + +/*GntBindableAction *gnt_bindable_action_parse(const char *name);*/ + +void gnt_bindable_action_free(GntBindableAction *action); +void gnt_bindable_action_param_free(GntBindableActionParam *param); + +void gnt_bindable_class_register_action(GntBindableClass *klass, const char *name, + GntBindableActionCallback callback, const char *trigger, ...); +void gnt_bindable_register_binding(GntBindableClass *klass, const char *name, + const char *trigger, ...); + +gboolean gnt_bindable_perform_action_key(GntBindable *bindable, const char *keys); +gboolean gnt_bindable_perform_action_named(GntBindable *bindable, const char *name, ...); + +G_END_DECLS + +#endif /* GNT_BINDABLE_H */ + diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gntbox.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gntbox.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,788 @@ +#include "gntbox.h" +#include "gntutils.h" + +#include + +enum +{ + SIGS = 1, +}; + +static GntWidgetClass *parent_class = NULL; + +static GntWidget * find_focusable_widget(GntBox *box); + +static void +add_to_focus(gpointer value, gpointer data) +{ + GntBox *box = GNT_BOX(data); + GntWidget *w = GNT_WIDGET(value); + + if (GNT_IS_BOX(w)) + g_list_foreach(GNT_BOX(w)->list, add_to_focus, box); + else if (GNT_WIDGET_IS_FLAG_SET(w, GNT_WIDGET_CAN_TAKE_FOCUS)) + box->focus = g_list_append(box->focus, w); +} + +static void +get_title_thingies(GntBox *box, char *title, int *p, int *r) +{ + GntWidget *widget = GNT_WIDGET(box); + int len; + char *end = (char*)gnt_util_onscreen_width_to_pointer(title, widget->priv.width - 4, &len); + + if (p) + *p = (widget->priv.width - len) / 2; + if (r) + *r = (widget->priv.width + len) / 2; + *end = '\0'; +} + +static void +gnt_box_draw(GntWidget *widget) +{ + GntBox *box = GNT_BOX(widget); + + if (box->focus == NULL && widget->parent == NULL) + g_list_foreach(box->list, add_to_focus, box); + + g_list_foreach(box->list, (GFunc)gnt_widget_draw, NULL); + + gnt_box_sync_children(box); + + if (box->title && !GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER)) + { + int pos, right; + char *title = g_strdup(box->title); + + get_title_thingies(box, title, &pos, &right); + + if (gnt_widget_has_focus(widget)) + wbkgdset(widget->window, '\0' | COLOR_PAIR(GNT_COLOR_TITLE)); + else + wbkgdset(widget->window, '\0' | COLOR_PAIR(GNT_COLOR_TITLE_D)); + mvwaddch(widget->window, 0, pos-1, ACS_RTEE | COLOR_PAIR(GNT_COLOR_NORMAL)); + mvwaddstr(widget->window, 0, pos, title); + mvwaddch(widget->window, 0, right, ACS_LTEE | COLOR_PAIR(GNT_COLOR_NORMAL)); + g_free(title); + } + + GNTDEBUG; +} + +static void +reposition_children(GntWidget *widget) +{ + GList *iter; + GntBox *box = GNT_BOX(widget); + int w, h, curx, cury, max; + gboolean has_border = FALSE; + + w = h = 0; + max = 0; + curx = widget->priv.x; + cury = widget->priv.y; + if (!(GNT_WIDGET_FLAGS(widget) & GNT_WIDGET_NO_BORDER)) + { + has_border = TRUE; + curx += 1; + cury += 1; + } + + for (iter = box->list; iter; iter = iter->next) + { + if (GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(iter->data), GNT_WIDGET_INVISIBLE)) + continue; + gnt_widget_set_position(GNT_WIDGET(iter->data), curx, cury); + gnt_widget_get_size(GNT_WIDGET(iter->data), &w, &h); + if (box->vertical) + { + if (h) + { + cury += h + box->pad; + if (max < w) + max = w; + } + } + else + { + if (w) + { + curx += w + box->pad; + if (max < h) + max = h; + } + } + } + + if (has_border) + { + curx += 1; + cury += 1; + max += 2; + } + + if (box->list) + { + if (box->vertical) + cury -= box->pad; + else + curx -= box->pad; + } + + if (box->vertical) + { + widget->priv.width = max; + widget->priv.height = cury - widget->priv.y; + } + else + { + widget->priv.width = curx - widget->priv.x; + widget->priv.height = max; + } +} + +static void +gnt_box_set_position(GntWidget *widget, int x, int y) +{ + GList *iter; + int changex, changey; + + changex = widget->priv.x - x; + changey = widget->priv.y - y; + + for (iter = GNT_BOX(widget)->list; iter; iter = iter->next) + { + GntWidget *w = GNT_WIDGET(iter->data); + gnt_widget_set_position(w, w->priv.x - changex, + w->priv.y - changey); + } +} + +static void +gnt_box_size_request(GntWidget *widget) +{ + GntBox *box = GNT_BOX(widget); + GList *iter; + int maxw = 0, maxh = 0; + + g_list_foreach(box->list, (GFunc)gnt_widget_size_request, NULL); + + for (iter = box->list; iter; iter = iter->next) + { + int w, h; + gnt_widget_get_size(GNT_WIDGET(iter->data), &w, &h); + if (maxh < h) + maxh = h; + if (maxw < w) + maxw = w; + } + + for (iter = box->list; iter; iter = iter->next) + { + int w, h; + GntWidget *wid = GNT_WIDGET(iter->data); + + gnt_widget_get_size(wid, &w, &h); + + if (box->homogeneous) + { + if (box->vertical) + h = maxh; + else + w = maxw; + } + if (box->fill) + { + if (box->vertical) + w = maxw; + else + h = maxh; + } + + gnt_widget_set_size(wid, w, h); + } + + reposition_children(widget); +} + +static void +gnt_box_map(GntWidget *widget) +{ + if (widget->priv.width == 0 || widget->priv.height == 0) + { + gnt_widget_size_request(widget); + find_focusable_widget(GNT_BOX(widget)); + } + GNTDEBUG; +} + +/* Ensures that the current widget can take focus */ +static GntWidget * +find_focusable_widget(GntBox *box) +{ + /* XXX: Make sure the widget is visible? */ + if (box->focus == NULL && GNT_WIDGET(box)->parent == NULL) + g_list_foreach(box->list, add_to_focus, box); + + if (box->active == NULL && box->focus) + box->active = box->focus->data; + + return box->active; +} + +static void +find_next_focus(GntBox *box) +{ + gpointer last = box->active; + do + { + GList *iter = g_list_find(box->focus, box->active); + if (iter && iter->next) + box->active = iter->next->data; + else if (box->focus) + box->active = box->focus->data; + if (!GNT_WIDGET_IS_FLAG_SET(box->active, GNT_WIDGET_INVISIBLE)) + break; + } while (box->active != last); +} + +static void +find_prev_focus(GntBox *box) +{ + gpointer last = box->active; + + if (!box->focus) + return; + + do + { + GList *iter = g_list_find(box->focus, box->active); + if (!iter) + box->active = box->focus->data; + else if (!iter->prev) + box->active = g_list_last(box->focus)->data; + else + box->active = iter->prev->data; + if (!GNT_WIDGET_IS_FLAG_SET(box->active, GNT_WIDGET_INVISIBLE)) + break; + } while (box->active != last); +} + +static gboolean +gnt_box_key_pressed(GntWidget *widget, const char *text) +{ + GntBox *box = GNT_BOX(widget); + GntWidget *now; + + if (box->active == NULL && !find_focusable_widget(box)) + return FALSE; + + if (gnt_widget_key_pressed(box->active, text)) + return TRUE; + + now = box->active; + + if (text[0] == 27) + { + if (strcmp(text, GNT_KEY_LEFT) == 0) + { + find_prev_focus(box); + } + else if (strcmp(text, GNT_KEY_RIGHT) == 0) + { + find_next_focus(box); + } + } + else if (text[0] == '\t') + { + find_next_focus(box); + } + + if (now && now != box->active) + { + gnt_widget_set_focus(now, FALSE); + gnt_widget_set_focus(box->active, TRUE); + return TRUE; + } + + return FALSE; +} + +static void +gnt_box_lost_focus(GntWidget *widget) +{ + GntWidget *w = GNT_BOX(widget)->active; + if (w) + gnt_widget_set_focus(w, FALSE); + gnt_widget_draw(widget); +} + +static void +gnt_box_gained_focus(GntWidget *widget) +{ + GntWidget *w = GNT_BOX(widget)->active; + if (w) + gnt_widget_set_focus(w, TRUE); + gnt_widget_draw(widget); +} + +static void +gnt_box_destroy(GntWidget *w) +{ + GntBox *box = GNT_BOX(w); + + gnt_box_remove_all(box); + gnt_screen_release(w); +} + +static void +gnt_box_expose(GntWidget *widget, int x, int y, int width, int height) +{ + WINDOW *win = newwin(height, width, widget->priv.y + y, widget->priv.x + x); + copywin(widget->window, win, y, x, 0, 0, height - 1, width - 1, FALSE); + wrefresh(win); + delwin(win); +} + +static gboolean +gnt_box_confirm_size(GntWidget *widget, int width, int height) +{ + GList *iter; + GntBox *box = GNT_BOX(widget); + int wchange, hchange; + + if (widget->priv.width != width && !GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_GROW_X)) + return FALSE; + if (widget->priv.height != height && !GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_GROW_Y)) + return FALSE; + + if (!box->list) + return TRUE; + + wchange = widget->priv.width - width; + hchange = widget->priv.height - height; + + if (wchange == 0 && hchange == 0) + return TRUE; /* Quit playing games */ + + /* XXX: Right now, I am trying to just apply all the changes to + * just one widget. It should be possible to distribute the + * changes to all the widgets in the box. */ + for (iter = box->list; iter; iter = iter->next) + { + GntWidget *wid = iter->data; + int w, h; + + gnt_widget_get_size(wid, &w, &h); + + if (gnt_widget_confirm_size(wid, w - wchange, h - hchange)) + { + GList *i; + + for (i = box->list; i; i = i->next) + { + int tw, th; + if (i == iter) continue; + gnt_widget_get_size(GNT_WIDGET(i->data), &tw, &th); + if (box->vertical) + { + if (!gnt_widget_confirm_size(i->data, tw - wchange, th)) + return FALSE; + } + else + { + if (!gnt_widget_confirm_size(i->data, tw, th - hchange)) + return FALSE; + } + } +#if 0 + gnt_widget_set_size(wid, w - wchange, h - hchange); + if (box->vertical) + hchange = 0; + else + wchange = 0; + + for (i = box->list; i; i = i->next) + { + int tw, th; + if (i == iter) continue; + gnt_widget_get_size(GNT_WIDGET(i->data), &tw, &th); + gnt_widget_set_size(i->data, tw - wchange, th - hchange); + } +#endif + g_object_set_data(G_OBJECT(box), "size-queued", wid); + return TRUE; + } + } + + return FALSE; +} + +static void +gnt_box_size_changed(GntWidget *widget, int oldw, int oldh) +{ + int wchange, hchange; + GList *i; + GntBox *box = GNT_BOX(widget); + GntWidget *wid; + int tw, th; + + wchange = widget->priv.width - oldw; + hchange = widget->priv.height - oldh; + + wid = g_object_get_data(G_OBJECT(box), "size-queued"); + if (wid) + { + gnt_widget_get_size(wid, &tw, &th); + gnt_widget_set_size(wid, tw + wchange, th + hchange); + g_object_set_data(G_OBJECT(box), "size-queued", NULL); + } + + if (box->vertical) + hchange = 0; + else + wchange = 0; + + for (i = box->list; i; i = i->next) + { + if (wid != i->data) + { + gnt_widget_get_size(GNT_WIDGET(i->data), &tw, &th); + gnt_widget_set_size(i->data, tw + wchange, th + hchange); + } + } + + reposition_children(widget); +} + +static gboolean +gnt_box_clicked(GntWidget *widget, GntMouseEvent event, int cx, int cy) +{ + GList *iter; + for (iter = GNT_BOX(widget)->list; iter; iter = iter->next) { + int x, y, w, h; + GntWidget *wid = iter->data; + + gnt_widget_get_position(wid, &x, &y); + gnt_widget_get_size(wid, &w, &h); + + if (cx >= x && cx < x + w && cy >= y && cy < y + h) { + if (event <= GNT_MIDDLE_MOUSE_DOWN && + GNT_WIDGET_IS_FLAG_SET(wid, GNT_WIDGET_CAN_TAKE_FOCUS)) { + while (widget->parent) + widget = widget->parent; + gnt_box_give_focus_to_child(GNT_BOX(widget), wid); + } + return gnt_widget_clicked(wid, event, cx, cy); + } + } + return FALSE; +} + +static void +gnt_box_class_init(GntBoxClass *klass) +{ + parent_class = GNT_WIDGET_CLASS(klass); + parent_class->destroy = gnt_box_destroy; + parent_class->draw = gnt_box_draw; + parent_class->expose = gnt_box_expose; + parent_class->map = gnt_box_map; + parent_class->size_request = gnt_box_size_request; + parent_class->set_position = gnt_box_set_position; + parent_class->key_pressed = gnt_box_key_pressed; + parent_class->clicked = gnt_box_clicked; + parent_class->lost_focus = gnt_box_lost_focus; + parent_class->gained_focus = gnt_box_gained_focus; + parent_class->confirm_size = gnt_box_confirm_size; + parent_class->size_changed = gnt_box_size_changed; + + GNTDEBUG; +} + +static void +gnt_box_init(GTypeInstance *instance, gpointer class) +{ + GntWidget *widget = GNT_WIDGET(instance); + GntBox *box = GNT_BOX(widget); + /* Initially make both the height and width resizable. + * Update the flags as necessary when widgets are added to it. */ + GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_GROW_X | GNT_WIDGET_GROW_Y); + GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_CAN_TAKE_FOCUS); + GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW); + box->pad = 1; + box->fill = TRUE; + GNTDEBUG; +} + +/****************************************************************************** + * GntBox API + *****************************************************************************/ +GType +gnt_box_get_gtype(void) +{ + static GType type = 0; + + if(type == 0) + { + static const GTypeInfo info = { + sizeof(GntBoxClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc)gnt_box_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof(GntBox), + 0, /* n_preallocs */ + gnt_box_init, /* instance_init */ + NULL /* value_table */ + }; + + type = g_type_register_static(GNT_TYPE_WIDGET, + "GntBox", + &info, 0); + } + + return type; +} + +GntWidget *gnt_box_new(gboolean homo, gboolean vert) +{ + GntWidget *widget = g_object_new(GNT_TYPE_BOX, NULL); + GntBox *box = GNT_BOX(widget); + + box->homogeneous = homo; + box->vertical = vert; + box->alignment = vert ? GNT_ALIGN_LEFT : GNT_ALIGN_MID; + + return widget; +} + +void gnt_box_add_widget(GntBox *b, GntWidget *widget) +{ + b->list = g_list_append(b->list, widget); + widget->parent = GNT_WIDGET(b); + + if (b->vertical) + { + if (!GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_GROW_X)) + GNT_WIDGET_UNSET_FLAGS(GNT_WIDGET(b), GNT_WIDGET_GROW_X); + } + else + { + if (!GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_GROW_Y)) + GNT_WIDGET_UNSET_FLAGS(GNT_WIDGET(b), GNT_WIDGET_GROW_Y); + } +} + +void gnt_box_set_title(GntBox *b, const char *title) +{ + char *prev = b->title; + GntWidget *w = GNT_WIDGET(b); + b->title = g_strdup(title); + if (w->window && !GNT_WIDGET_IS_FLAG_SET(w, GNT_WIDGET_NO_BORDER)) { + /* Erase the old title */ + int pos, right; + get_title_thingies(b, prev, &pos, &right); + mvwhline(w->window, 0, pos - 1, ACS_HLINE | COLOR_PAIR(GNT_COLOR_NORMAL), + right - pos + 2); + g_free(prev); + } +} + +void gnt_box_set_pad(GntBox *box, int pad) +{ + box->pad = pad; + /* XXX: Perhaps redraw if already showing? */ +} + +void gnt_box_set_toplevel(GntBox *box, gboolean set) +{ + GntWidget *widget = GNT_WIDGET(box); + if (set) + { + GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW); + GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_CAN_TAKE_FOCUS); + } + else + { + GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW); + GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_CAN_TAKE_FOCUS); + } +} + +void gnt_box_sync_children(GntBox *box) +{ + GList *iter; + GntWidget *widget = GNT_WIDGET(box); + int pos = 1; + + if (GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER)) + pos = 0; + + for (iter = box->list; iter; iter = iter->next) + { + GntWidget *w = GNT_WIDGET(iter->data); + int height, width; + int x, y; + + if (GNT_WIDGET_IS_FLAG_SET(w, GNT_WIDGET_INVISIBLE)) + continue; + + if (GNT_IS_BOX(w)) + gnt_box_sync_children(GNT_BOX(w)); + + gnt_widget_get_size(w, &width, &height); + + x = w->priv.x - widget->priv.x; + y = w->priv.y - widget->priv.y; + + if (box->vertical) + { + x = pos; + if (box->alignment == GNT_ALIGN_RIGHT) + x += widget->priv.width - width; + else if (box->alignment == GNT_ALIGN_MID) + x += (widget->priv.width - width)/2; + if (x + width > widget->priv.width - pos) + x -= x + width - (widget->priv.width - pos); + } + else + { + y = pos; + if (box->alignment == GNT_ALIGN_BOTTOM) + y += widget->priv.height - height; + else if (box->alignment == GNT_ALIGN_MID) + y += (widget->priv.height - height)/2; + if (y + height >= widget->priv.height - pos) + y = widget->priv.height - height - pos; + } + + copywin(w->window, widget->window, 0, 0, + y, x, y + height - 1, x + width - 1, FALSE); + gnt_widget_set_position(w, x + widget->priv.x, y + widget->priv.y); + } +} + +void gnt_box_set_alignment(GntBox *box, GntAlignment alignment) +{ + box->alignment = alignment; +} + +void gnt_box_remove(GntBox *box, GntWidget *widget) +{ + box->list = g_list_remove(box->list, widget); + if (GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_CAN_TAKE_FOCUS) + && GNT_WIDGET(box)->parent == NULL && box->focus) + { + if (widget == box->active) + { + find_next_focus(box); + if (box->active == widget) /* There's only one widget */ + box->active = NULL; + } + box->focus = g_list_remove(box->focus, widget); + } + + if (GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(box), GNT_WIDGET_MAPPED)) + gnt_widget_draw(GNT_WIDGET(box)); +} + +void gnt_box_remove_all(GntBox *box) +{ + g_list_foreach(box->list, (GFunc)gnt_widget_destroy, NULL); + g_list_free(box->list); + g_list_free(box->focus); + box->list = NULL; + box->focus = NULL; + GNT_WIDGET(box)->priv.width = 0; + GNT_WIDGET(box)->priv.height = 0; +} + +void gnt_box_readjust(GntBox *box) +{ + GList *iter; + GntWidget *wid; + int width, height; + + if (GNT_WIDGET(box)->parent != NULL) + return; + + for (iter = box->list; iter; iter = iter->next) + { + GntWidget *w = iter->data; + if (GNT_IS_BOX(w)) + gnt_box_readjust(GNT_BOX(w)); + else + { + GNT_WIDGET_UNSET_FLAGS(w, GNT_WIDGET_MAPPED); + w->priv.width = 0; + w->priv.height = 0; + } + } + + wid = GNT_WIDGET(box); + GNT_WIDGET_UNSET_FLAGS(wid, GNT_WIDGET_MAPPED); + wid->priv.width = 0; + wid->priv.height = 0; + + if (wid->parent == NULL) + { + g_list_free(box->focus); + box->focus = NULL; + box->active = NULL; + gnt_widget_size_request(wid); + gnt_widget_get_size(wid, &width, &height); + gnt_screen_resize_widget(wid, width, height); + find_focusable_widget(box); + } +} + +void gnt_box_set_fill(GntBox *box, gboolean fill) +{ + box->fill = fill; +} + +void gnt_box_move_focus(GntBox *box, int dir) +{ + GntWidget *now; + + if (box->active == NULL) + { + find_focusable_widget(box); + return; + } + + now = box->active; + + if (dir == 1) + find_next_focus(box); + else if (dir == -1) + find_prev_focus(box); + + if (now && now != box->active) + { + gnt_widget_set_focus(now, FALSE); + gnt_widget_set_focus(box->active, TRUE); + } + + if (GNT_WIDGET(box)->window) + gnt_widget_draw(GNT_WIDGET(box)); +} + +void gnt_box_give_focus_to_child(GntBox *box, GntWidget *widget) +{ + GList *find = g_list_find(box->focus, widget); + gpointer now = box->active; + if (find) + box->active = widget; + if (now && now != box->active) + { + gnt_widget_set_focus(now, FALSE); + gnt_widget_set_focus(box->active, TRUE); + } + + if (GNT_WIDGET(box)->window) + gnt_widget_draw(GNT_WIDGET(box)); +} + diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gntbox.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gntbox.h Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,98 @@ +#ifndef GNT_BOX_H +#define GNT_BOX_H + +#include "gnt.h" +#include "gntwidget.h" + +#define GNT_TYPE_BOX (gnt_box_get_gtype()) +#define GNT_BOX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNT_TYPE_BOX, GntBox)) +#define GNT_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GNT_TYPE_BOX, GntBoxClass)) +#define GNT_IS_BOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GNT_TYPE_BOX)) +#define GNT_IS_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GNT_TYPE_BOX)) +#define GNT_BOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GNT_TYPE_BOX, GntBoxClass)) + +typedef struct _GnBox GntBox; +typedef struct _GnBoxClass GntBoxClass; + +typedef enum +{ + /* These for vertical boxes */ + GNT_ALIGN_LEFT, + GNT_ALIGN_RIGHT, + + GNT_ALIGN_MID, + + /* These for horizontal boxes */ + GNT_ALIGN_TOP, + GNT_ALIGN_BOTTOM +} GntAlignment; + +struct _GnBox +{ + GntWidget parent; + + gboolean vertical; + gboolean homogeneous; + gboolean fill; + GList *list; /* List of widgets */ + + GntWidget *active; + int pad; /* Number of spaces to use between widgets */ + GntAlignment alignment; /* How are the widgets going to be aligned? */ + + char *title; + GList *focus; /* List of widgets to cycle focus (only valid for parent boxes) */ + + void (*gnt_reserved1)(void); + void (*gnt_reserved2)(void); + void (*gnt_reserved3)(void); + void (*gnt_reserved4)(void); +}; + +struct _GnBoxClass +{ + GntWidgetClass parent; + + void (*gnt_reserved1)(void); + void (*gnt_reserved2)(void); + void (*gnt_reserved3)(void); + void (*gnt_reserved4)(void); +}; + +G_BEGIN_DECLS + +GType gnt_box_get_gtype(void); + +#define gnt_vbox_new(homo) gnt_box_new(homo, TRUE) +#define gnt_hbox_new(homo) gnt_box_new(homo, FALSE) + +GntWidget *gnt_box_new(gboolean homo, gboolean vert); + +void gnt_box_add_widget(GntBox *box, GntWidget *widget); + +void gnt_box_set_title(GntBox *box, const char *title); + +void gnt_box_set_pad(GntBox *box, int pad); + +void gnt_box_set_toplevel(GntBox *box, gboolean set); + +void gnt_box_sync_children(GntBox *box); + +void gnt_box_set_alignment(GntBox *box, GntAlignment alignment); + +void gnt_box_remove(GntBox *box, GntWidget *widget); /* XXX: does NOT destroy widget */ + +void gnt_box_remove_all(GntBox *box); /* Removes AND destroys all the widgets in it */ + +void gnt_box_readjust(GntBox *box); + +void gnt_box_set_fill(GntBox *box, gboolean fill); + +void gnt_box_move_focus(GntBox *box, int dir); /* +1 to move forward, -1 for backward */ + +void gnt_box_give_focus_to_child(GntBox *box, GntWidget *widget); + +G_END_DECLS + +#endif /* GNT_BOX_H */ + diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gntbutton.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gntbutton.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,136 @@ +#include + +#include "gntbutton.h" +#include "gntutils.h" + +enum +{ + SIGS = 1, +}; + +static GntWidgetClass *parent_class = NULL; + +static void +gnt_button_draw(GntWidget *widget) +{ + GntButton *button = GNT_BUTTON(widget); + GntColorType type; + + if (gnt_widget_has_focus(widget)) + type = GNT_COLOR_HIGHLIGHT; + else + type = GNT_COLOR_NORMAL; + + wbkgdset(widget->window, '\0' | COLOR_PAIR(type)); + mvwaddstr(widget->window, 1, 2, button->priv->text); + + GNTDEBUG; +} + +static void +gnt_button_size_request(GntWidget *widget) +{ + GntButton *button = GNT_BUTTON(widget); + gnt_util_get_text_bound(button->priv->text, + &widget->priv.width, &widget->priv.height); + widget->priv.width += 4; + if (!GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER)) + widget->priv.height += 2; +} + +static void +gnt_button_map(GntWidget *widget) +{ + if (widget->priv.width == 0 || widget->priv.height == 0) + gnt_widget_size_request(widget); + GNTDEBUG; +} + +static gboolean +gnt_button_key_pressed(GntWidget *widget, const char *key) +{ + if (strcmp(key, GNT_KEY_ENTER) == 0) + { + gnt_widget_activate(widget); + return TRUE; + } + return FALSE; +} + +static gboolean +gnt_button_clicked(GntWidget *widget, GntMouseEvent event, int x, int y) +{ + if (event == GNT_LEFT_MOUSE_DOWN) { + gnt_widget_activate(widget); + return TRUE; + } + return FALSE; +} + +static void +gnt_button_class_init(GntWidgetClass *klass) +{ + parent_class = GNT_WIDGET_CLASS(klass); + parent_class->draw = gnt_button_draw; + parent_class->map = gnt_button_map; + parent_class->size_request = gnt_button_size_request; + parent_class->key_pressed = gnt_button_key_pressed; + parent_class->clicked = gnt_button_clicked; + + GNTDEBUG; +} + +static void +gnt_button_init(GTypeInstance *instance, gpointer class) +{ + GntWidget *widget = GNT_WIDGET(instance); + GntButton *button = GNT_BUTTON(instance); + button->priv = g_new0(GntButtonPriv, 1); + + GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_GROW_X); + + widget->priv.minw = 4; + widget->priv.minh = 3; + GNTDEBUG; +} + +/****************************************************************************** + * GntButton API + *****************************************************************************/ +GType +gnt_button_get_gtype(void) { + static GType type = 0; + + if(type == 0) { + static const GTypeInfo info = { + sizeof(GntButtonClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc)gnt_button_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof(GntButton), + 0, /* n_preallocs */ + gnt_button_init, /* instance_init */ + NULL /* value_table */ + }; + + type = g_type_register_static(GNT_TYPE_WIDGET, + "GntButton", + &info, 0); + } + + return type; +} + +GntWidget *gnt_button_new(const char *text) +{ + GntWidget *widget = g_object_new(GNT_TYPE_BUTTON, NULL); + GntButton *button = GNT_BUTTON(widget); + + button->priv->text = gnt_util_onscreen_fit_string(text, -1); + gnt_widget_set_take_focus(widget, TRUE); + + return widget; +} + diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gntbutton.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gntbutton.h Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,55 @@ +#ifndef GNT_BUTTON_H +#define GNT_BUTTON_H + +#include +#include +#include "gnt.h" +#include "gntwidget.h" + +#define GNT_TYPE_BUTTON (gnt_button_get_gtype()) +#define GNT_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNT_TYPE_BUTTON, GntButton)) +#define GNT_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GNT_TYPE_BUTTON, GntButtonClass)) +#define GNT_IS_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GNT_TYPE_BUTTON)) +#define GNT_IS_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GNT_TYPE_BUTTON)) +#define GNT_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GNT_TYPE_BUTTON, GntButtonClass)) + +typedef struct _GnButton GntButton; +typedef struct _GnButtonPriv GntButtonPriv; +typedef struct _GnButtonClass GntButtonClass; + +struct _GnButtonPriv +{ + char *text; +}; + +struct _GnButton +{ + GntWidget parent; + + GntButtonPriv *priv; + + void (*gnt_reserved1)(void); + void (*gnt_reserved2)(void); + void (*gnt_reserved3)(void); + void (*gnt_reserved4)(void); +}; + +struct _GnButtonClass +{ + GntWidgetClass parent; + + void (*gnt_reserved1)(void); + void (*gnt_reserved2)(void); + void (*gnt_reserved3)(void); + void (*gnt_reserved4)(void); +}; + +G_BEGIN_DECLS + +GType gnt_button_get_gtype(void); + +GntWidget *gnt_button_new(const char *text); + +G_END_DECLS + +#endif /* GNT_BUTTON_H */ diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gntcheckbox.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gntcheckbox.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,156 @@ +#include "gntcheckbox.h" + +enum +{ + SIG_TOGGLED = 1, + SIGS, +}; + +static GntButtonClass *parent_class = NULL; +static guint signals[SIGS] = { 0 }; + +static void +gnt_check_box_draw(GntWidget *widget) +{ + GntCheckBox *cb = GNT_CHECK_BOX(widget); + GntColorType type; + char *text; + + if (gnt_widget_has_focus(widget)) + type = GNT_COLOR_HIGHLIGHT; + else + type = GNT_COLOR_NORMAL; + + wbkgdset(widget->window, '\0' | COLOR_PAIR(type)); + + text = g_strdup_printf("[%c]", cb->checked ? 'X' : ' '); + mvwaddstr(widget->window, 0, 0, text); + g_free(text); + + wbkgdset(widget->window, '\0' | COLOR_PAIR(GNT_COLOR_NORMAL)); + mvwaddstr(widget->window, 0, 4, GNT_BUTTON(cb)->priv->text); + + GNTDEBUG; +} + +static void +toggle_selection(GntWidget *widget) +{ + GNT_CHECK_BOX(widget)->checked = !GNT_CHECK_BOX(widget)->checked; + g_signal_emit(widget, signals[SIG_TOGGLED], 0); + gnt_widget_draw(widget); +} + +static gboolean +gnt_check_box_key_pressed(GntWidget *widget, const char *text) +{ + if (text[0] == ' ' && text[1] == '\0') + { + toggle_selection(widget); + return TRUE; + } + + return FALSE; +} + +static gboolean +gnt_check_box_clicked(GntWidget *widget, GntMouseEvent event, int x, int y) +{ + if (event == GNT_LEFT_MOUSE_DOWN) { + toggle_selection(widget); + return TRUE; + } + return FALSE; +} + +static void +gnt_check_box_class_init(GntCheckBoxClass *klass) +{ + GntWidgetClass *wclass = GNT_WIDGET_CLASS(klass); + + parent_class = GNT_BUTTON_CLASS(klass); + /*parent_class->destroy = gnt_check_box_destroy;*/ + wclass->draw = gnt_check_box_draw; + /*parent_class->map = gnt_check_box_map;*/ + /*parent_class->size_request = gnt_check_box_size_request;*/ + wclass->key_pressed = gnt_check_box_key_pressed; + wclass->clicked = gnt_check_box_clicked; + + signals[SIG_TOGGLED] = + g_signal_new("toggled", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GntCheckBoxClass, toggled), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + GNTDEBUG; +} + +static void +gnt_check_box_init(GTypeInstance *instance, gpointer class) +{ + GntWidget *widget = GNT_WIDGET(instance); + widget->priv.minh = 1; + widget->priv.minw = 4; + GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW); + GNTDEBUG; +} + +/****************************************************************************** + * GntCheckBox API + *****************************************************************************/ +GType +gnt_check_box_get_gtype(void) +{ + static GType type = 0; + + if(type == 0) + { + static const GTypeInfo info = { + sizeof(GntCheckBoxClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc)gnt_check_box_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof(GntCheckBox), + 0, /* n_preallocs */ + gnt_check_box_init, /* instance_init */ + NULL /* value_table */ + }; + + type = g_type_register_static(GNT_TYPE_BUTTON, + "GntCheckBox", + &info, 0); + } + + return type; +} + +GntWidget *gnt_check_box_new(const char *text) +{ + GntWidget *widget = g_object_new(GNT_TYPE_CHECK_BOX, NULL); + + GNT_BUTTON(widget)->priv->text = g_strdup(text); + gnt_widget_set_take_focus(widget, TRUE); + + return widget; +} + +void gnt_check_box_set_checked(GntCheckBox *box, gboolean set) +{ + if (set != box->checked) + { + box->checked = set; + g_signal_emit(box, signals[SIG_TOGGLED], 0); + } +} + +gboolean gnt_check_box_get_checked(GntCheckBox *box) +{ + return box->checked; +} + + + diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gntcheckbox.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gntcheckbox.h Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,54 @@ +#ifndef GNT_CHECK_BOX_H +#define GNT_CHECK_BOX_H + +#include "gntbutton.h" +#include "gnt.h" +#include "gntcolors.h" +#include "gntkeys.h" + +#define GNT_TYPE_CHECK_BOX (gnt_check_box_get_gtype()) +#define GNT_CHECK_BOX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNT_TYPE_CHECK_BOX, GntCheckBox)) +#define GNT_CHECK_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GNT_TYPE_CHECK_BOX, GntCheckBoxClass)) +#define GNT_IS_CHECK_BOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GNT_TYPE_CHECK_BOX)) +#define GNT_IS_CHECK_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GNT_TYPE_CHECK_BOX)) +#define GNT_CHECK_BOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GNT_TYPE_CHECK_BOX, GntCheckBoxClass)) + +#define GNT_CHECK_BOX_FLAGS(obj) (GNT_CHECK_BOX(obj)->priv.flags) +#define GNT_CHECK_BOX_SET_FLAGS(obj, flags) (GNT_CHECK_BOX_FLAGS(obj) |= flags) +#define GNT_CHECK_BOX_UNSET_FLAGS(obj, flags) (GNT_CHECK_BOX_FLAGS(obj) &= ~(flags)) + +typedef struct _GnCheckBox GntCheckBox; +typedef struct _GnCheckBoxPriv GntCheckBoxPriv; +typedef struct _GnCheckBoxClass GntCheckBoxClass; + +struct _GnCheckBox +{ + GntButton parent; + gboolean checked; +}; + +struct _GnCheckBoxClass +{ + GntButtonClass parent; + + void (*toggled)(void); + + void (*gnt_reserved1)(void); + void (*gnt_reserved2)(void); + void (*gnt_reserved3)(void); + void (*gnt_reserved4)(void); +}; + +G_BEGIN_DECLS + +GType gnt_check_box_get_gtype(void); + +GntWidget *gnt_check_box_new(const char *text); + +void gnt_check_box_set_checked(GntCheckBox *box, gboolean set); + +gboolean gnt_check_box_get_checked(GntCheckBox *box); + +G_END_DECLS + +#endif /* GNT_CHECK_BOX_H */ diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gntclipboard.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gntclipboard.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,74 @@ +#include "gntclipboard.h" + +gchar *string; + +enum { + SIG_CLIPBOARD = 0, + SIGS +}; + +static guint signals[SIGS] = { 0 }; + +static void +gnt_clipboard_class_init(GntClipboardClass *klass) +{ + signals[SIG_CLIPBOARD] = + g_signal_new("clipboard_changed", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, 1, G_TYPE_POINTER); + +} + +/****************************************************************************** + * GntClipboard API + *****************************************************************************/ + +void +gnt_clipboard_set_string(GntClipboard *clipboard, gchar *string) +{ + g_free(clipboard->string); + clipboard->string = g_strdup(string); + g_signal_emit(clipboard, signals[SIG_CLIPBOARD], 0, clipboard->string); +} + +gchar * +gnt_clipboard_get_string(GntClipboard *clipboard) +{ + return g_strdup(clipboard->string); +} + +static void gnt_clipboard_init(GTypeInstance *instance, gpointer class) { + GntClipboard *clipboard = GNT_CLIPBOARD(instance); + clipboard->string = g_strdup(""); +} + +GType +gnt_clipboard_get_gtype(void) +{ + static GType type = 0; + + if (type == 0) { + static const GTypeInfo info = { + sizeof(GntClipboardClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc)gnt_clipboard_class_init, + NULL, + NULL, /* class_data */ + sizeof(GntClipboard), + 0, /* n_preallocs */ + gnt_clipboard_init, /* instance_init */ + NULL /* value_table */ + }; + + type = g_type_register_static(G_TYPE_OBJECT, + "GntClipboard", + &info, 0); + } + + return type; +} diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gntclipboard.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gntclipboard.h Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,46 @@ +#ifndef GNT_CLIPBOARD_H +#define GNT_CLIPBOARD_H + +#include +#include +#include + +#define GNT_TYPE_CLIPBOARD (gnt_clipboard_get_gtype()) +#define GNT_CLIPBOARD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNT_TYPE_CLIPBOARD, GntClipboard)) +#define GNT_CLIPBOARD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GNT_TYPE_CLIPBOARD, GntClipboardClass)) +#define GNT_IS_CLIPBOARD(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GNT_TYPE_CLIPBOARD)) +#define GNT_IS_CLIPBOARD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GNT_TYPE_CLIPBOARD)) +#define GNT_CLIPBOARD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GNT_TYPE_CLIPBOARD, GntClipboardClass)) + +#define GNTDEBUG g_printerr("%s\n", __FUNCTION__) + +typedef struct _GnClipboard GntClipboard; +typedef struct _GnClipboardClass GntClipboardClass; + +struct _GnClipboard +{ + GObject inherit; + gchar *string; +}; + +struct _GnClipboardClass +{ + GObjectClass parent; + + void (*gnt_reserved1)(void); + void (*gnt_reserved2)(void); + void (*gnt_reserved3)(void); + void (*gnt_reserved4)(void); +}; + +G_BEGIN_DECLS + +GType gnt_clipboard_get_gtype(void); + +gchar *gnt_clipboard_get_string(GntClipboard *); + +void gnt_clipboard_set_string(GntClipboard *, gchar *); + +G_END_DECLS + +#endif diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gntcolors.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gntcolors.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,256 @@ +#include "config.h" + +#include + +#include "gntcolors.h" +#include "gntstyle.h" + +#include + +#include +#include + +static struct +{ + short r, g, b; +} colors[GNT_TOTAL_COLORS]; + +static void +backup_colors() +{ + short i; + for (i = 0; i < GNT_TOTAL_COLORS; i++) + { + color_content(i, &colors[i].r, + &colors[i].g, &colors[i].b); + } +} + +static gboolean +can_use_custom_color() +{ + return (gnt_style_get_bool(GNT_STYLE_COLOR, FALSE) && can_change_color()); +} + +static void +restore_colors() +{ + short i; + for (i = 0; i < GNT_TOTAL_COLORS; i++) + { + init_color(i, colors[i].r, + colors[i].g, colors[i].b); + } +} + +void gnt_init_colors() +{ + static gboolean init = FALSE; + int defaults; + + if (init) + return; + init = TRUE; + + start_color(); + defaults = use_default_colors(); + + if (can_use_custom_color()) + { + backup_colors(); + + /* Do some init_color()s */ + init_color(GNT_COLOR_BLACK, 0, 0, 0); + init_color(GNT_COLOR_RED, 1000, 0, 0); + init_color(GNT_COLOR_GREEN, 0, 1000, 0); + init_color(GNT_COLOR_BLUE, 250, 250, 700); + init_color(GNT_COLOR_WHITE, 1000, 1000, 1000); + init_color(GNT_COLOR_GRAY, 699, 699, 699); + init_color(GNT_COLOR_DARK_GRAY, 256, 256, 256); + + /* Now some init_pair()s */ + init_pair(GNT_COLOR_NORMAL, GNT_COLOR_BLACK, GNT_COLOR_WHITE); + init_pair(GNT_COLOR_HIGHLIGHT, GNT_COLOR_WHITE, GNT_COLOR_BLUE); + init_pair(GNT_COLOR_SHADOW, GNT_COLOR_BLACK, GNT_COLOR_DARK_GRAY); + + init_pair(GNT_COLOR_TITLE, GNT_COLOR_WHITE, GNT_COLOR_BLUE); + init_pair(GNT_COLOR_TITLE_D, GNT_COLOR_WHITE, GNT_COLOR_GRAY); + + init_pair(GNT_COLOR_TEXT_NORMAL, GNT_COLOR_WHITE, GNT_COLOR_BLUE); + init_pair(GNT_COLOR_HIGHLIGHT_D, GNT_COLOR_BLACK, GNT_COLOR_GRAY); + init_pair(GNT_COLOR_DISABLED, GNT_COLOR_GRAY, GNT_COLOR_WHITE); + init_pair(GNT_COLOR_URGENT, GNT_COLOR_WHITE, GNT_COLOR_RED); + } + else + { + int bg; + + if (defaults == OK) { + init_pair(GNT_COLOR_NORMAL, -1, -1); + bg = -1; + } else { + init_pair(GNT_COLOR_NORMAL, COLOR_BLACK, COLOR_WHITE); + bg = COLOR_WHITE; + } + init_pair(GNT_COLOR_DISABLED, COLOR_YELLOW, bg); + init_pair(GNT_COLOR_URGENT, COLOR_GREEN, bg); + + init_pair(GNT_COLOR_HIGHLIGHT, COLOR_WHITE, COLOR_BLUE); + init_pair(GNT_COLOR_SHADOW, COLOR_BLACK, COLOR_BLACK); + init_pair(GNT_COLOR_TITLE, COLOR_WHITE, COLOR_BLUE); + init_pair(GNT_COLOR_TITLE_D, COLOR_WHITE, COLOR_BLACK); + init_pair(GNT_COLOR_TEXT_NORMAL, COLOR_WHITE, COLOR_BLUE); + init_pair(GNT_COLOR_HIGHLIGHT_D, COLOR_CYAN, COLOR_BLACK); + } +} + +void +gnt_uninit_colors() +{ + if (can_use_custom_color()) + restore_colors(); +} + +static int +get_color(char *key) +{ + int color; + gboolean custom = can_use_custom_color(); + + key = g_strstrip(key); + + if (strcmp(key, "black") == 0) + color = custom ? GNT_COLOR_BLACK : COLOR_BLACK; + else if (strcmp(key, "red") == 0) + color = custom ? GNT_COLOR_RED : COLOR_RED; + else if (strcmp(key, "green") == 0) + color = custom ? GNT_COLOR_GREEN : COLOR_GREEN; + else if (strcmp(key, "blue") == 0) + color = custom ? GNT_COLOR_BLUE : COLOR_BLUE; + else if (strcmp(key, "white") == 0) + color = custom ? GNT_COLOR_WHITE : COLOR_WHITE; + else if (strcmp(key, "gray") == 0) + color = custom ? GNT_COLOR_GRAY : COLOR_YELLOW; /* eh? */ + else if (strcmp(key, "darkgray") == 0) + color = custom ? GNT_COLOR_DARK_GRAY : COLOR_BLACK; + else if (strcmp(key, "magenta") == 0) + color = COLOR_MAGENTA; + else if (strcmp(key, "cyan") == 0) + color = COLOR_CYAN; + else + color = -1; + return color; +} + +#if GLIB_CHECK_VERSION(2,6,0) +void gnt_colors_parse(GKeyFile *kfile) +{ + GError *error = NULL; + gsize nkeys; + char **keys = g_key_file_get_keys(kfile, "colors", &nkeys, &error); + + if (error) + { + g_printerr("GntColors: %s\n", error->message); + g_error_free(error); + error = NULL; + } + else if (nkeys) + { + gnt_init_colors(); + while (nkeys--) + { + gsize len; + gchar *key = keys[nkeys]; + char **list = g_key_file_get_string_list(kfile, "colors", key, &len, NULL); + if (len == 3) + { + int r = atoi(list[0]); + int g = atoi(list[1]); + int b = atoi(list[2]); + int color = -1; + + key = g_ascii_strdown(key, -1); + color = get_color(key); + g_free(key); + if (color == -1) + continue; + + init_color(color, r, g, b); + } + g_strfreev(list); + } + + g_strfreev(keys); + } + + gnt_color_pairs_parse(kfile); +} + +void gnt_color_pairs_parse(GKeyFile *kfile) +{ + GError *error = NULL; + gsize nkeys; + char **keys = g_key_file_get_keys(kfile, "colorpairs", &nkeys, &error); + + if (error) + { + g_printerr("GntColors: %s\n", error->message); + g_error_free(error); + return; + } + else if (nkeys) + gnt_init_colors(); + + while (nkeys--) + { + gsize len; + gchar *key = keys[nkeys]; + char **list = g_key_file_get_string_list(kfile, "colorpairs", key, &len, NULL); + if (len == 2) + { + GntColorType type = 0; + gchar *fgc = g_ascii_strdown(list[0], -1); + gchar *bgc = g_ascii_strdown(list[1], -1); + int fg = get_color(fgc); + int bg = get_color(bgc); + g_free(fgc); + g_free(bgc); + if (fg == -1 || bg == -1) + continue; + + key = g_ascii_strdown(key, -1); + + if (strcmp(key, "normal") == 0) + type = GNT_COLOR_NORMAL; + else if (strcmp(key, "highlight") == 0) + type = GNT_COLOR_HIGHLIGHT; + else if (strcmp(key, "highlightd") == 0) + type = GNT_COLOR_HIGHLIGHT_D; + else if (strcmp(key, "shadow") == 0) + type = GNT_COLOR_SHADOW; + else if (strcmp(key, "title") == 0) + type = GNT_COLOR_TITLE; + else if (strcmp(key, "titled") == 0) + type = GNT_COLOR_TITLE_D; + else if (strcmp(key, "text") == 0) + type = GNT_COLOR_TEXT_NORMAL; + else if (strcmp(key, "disabled") == 0) + type = GNT_COLOR_DISABLED; + else if (strcmp(key, "urgent") == 0) + type = GNT_COLOR_URGENT; + else { + g_free(key); + continue; + } + g_free(key); + + init_pair(type, fg, bg); + } + g_strfreev(list); + } + + g_strfreev(keys); +} + +#endif /* GKeyFile */ diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gntcolors.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gntcolors.h Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,46 @@ +#ifndef GNT_COLORS_H +#define GNT_COLORS_H + +#include + +typedef enum +{ + GNT_COLOR_NORMAL = 1, + GNT_COLOR_HIGHLIGHT, /* eg. when a button is selected */ + GNT_COLOR_DISABLED, /* eg. when a button is disabled */ + GNT_COLOR_HIGHLIGHT_D, /* eg. when a button is selected, but some other window is in focus */ + GNT_COLOR_TEXT_NORMAL, + GNT_COLOR_TEXT_INACTIVE, /* when the entry is out of focus */ + GNT_COLOR_MNEMONIC, + GNT_COLOR_MNEMONIC_D, + GNT_COLOR_SHADOW, + GNT_COLOR_TITLE, + GNT_COLOR_TITLE_D, + GNT_COLOR_URGENT, /* this is for the 'urgent' windows */ + GNT_COLORS +} GntColorType; + +enum +{ + GNT_COLOR_BLACK = 0, + GNT_COLOR_RED, + GNT_COLOR_GREEN, + GNT_COLOR_BLUE, + GNT_COLOR_WHITE, + GNT_COLOR_GRAY, + GNT_COLOR_DARK_GRAY, + GNT_TOTAL_COLORS +}; + +/* populate some default colors */ +void gnt_init_colors(void); + +void gnt_uninit_colors(void); + +#if GLIB_CHECK_VERSION(2,6,0) +void gnt_colors_parse(GKeyFile *kfile); + +void gnt_color_pairs_parse(GKeyFile *kfile); +#endif + +#endif diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gntcombobox.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gntcombobox.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,324 @@ +#include "gntbox.h" +#include "gntcombobox.h" +#include "gnttree.h" +#include "gntmarshal.h" +#include "gntutils.h" + +#include + +enum +{ + SIG_SELECTION_CHANGED, + SIGS, +}; + +static GntWidgetClass *parent_class = NULL; +static guint signals[SIGS] = { 0 }; +static void (*widget_lost_focus)(GntWidget *widget); + +static void +set_selection(GntComboBox *box, gpointer key) +{ + if (box->selected != key) + { + /* XXX: make sure the key actually does exist */ + gpointer old = box->selected; + box->selected = key; + if (GNT_WIDGET(box)->window) + gnt_widget_draw(GNT_WIDGET(box)); + if (box->dropdown) + gnt_tree_set_selected(GNT_TREE(box->dropdown), key); + g_signal_emit(box, signals[SIG_SELECTION_CHANGED], 0, old, key); + } +} + +static void +hide_popup(GntComboBox *box, gboolean set) +{ + gnt_widget_set_size(box->dropdown, + box->dropdown->priv.width - 1, box->dropdown->priv.height); + if (set) + set_selection(box, gnt_tree_get_selection_data(GNT_TREE(box->dropdown))); + else + gnt_tree_set_selected(GNT_TREE(box->dropdown), box->selected); + gnt_widget_hide(box->dropdown->parent); +} + +static void +gnt_combo_box_draw(GntWidget *widget) +{ + GntComboBox *box = GNT_COMBO_BOX(widget); + char *text = NULL, *s; + GntColorType type; + int len; + + if (box->dropdown && box->selected) + text = gnt_tree_get_selection_text(GNT_TREE(box->dropdown)); + + if (text == NULL) + text = g_strdup(""); + + if (gnt_widget_has_focus(widget)) + type = GNT_COLOR_HIGHLIGHT; + else + type = GNT_COLOR_NORMAL; + + wbkgdset(widget->window, '\0' | COLOR_PAIR(type)); + + s = (char*)gnt_util_onscreen_width_to_pointer(text, widget->priv.width - 4, &len); + *s = '\0'; + + mvwaddstr(widget->window, 1, 1, text); + whline(widget->window, ' ' | COLOR_PAIR(type), widget->priv.width - 4 - len); + mvwaddch(widget->window, 1, widget->priv.width - 3, ACS_VLINE | COLOR_PAIR(GNT_COLOR_NORMAL)); + mvwaddch(widget->window, 1, widget->priv.width - 2, ACS_DARROW | COLOR_PAIR(GNT_COLOR_NORMAL)); + + g_free(text); + GNTDEBUG; +} + +static void +gnt_combo_box_size_request(GntWidget *widget) +{ + if (!GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_MAPPED)) + { + GntWidget *dd = GNT_COMBO_BOX(widget)->dropdown; + gnt_widget_size_request(dd); + widget->priv.height = 3; /* For now, a combobox will have border */ + widget->priv.width = MAX(10, dd->priv.width + 4); + } +} + +static void +gnt_combo_box_map(GntWidget *widget) +{ + if (widget->priv.width == 0 || widget->priv.height == 0) + gnt_widget_size_request(widget); + GNTDEBUG; +} + +static void +popup_dropdown(GntComboBox *box) +{ + GntWidget *widget = GNT_WIDGET(box); + GntWidget *parent = box->dropdown->parent; + int height = g_list_length(GNT_TREE(box->dropdown)->list); + int y = widget->priv.y + widget->priv.height - 1; + gnt_widget_set_size(box->dropdown, widget->priv.width, height + 2); + + if (y + height + 2 >= getmaxy(stdscr)) + y = widget->priv.y - height - 1; + gnt_widget_set_position(parent, widget->priv.x, y); + if (parent->window) + { + mvwin(parent->window, y, widget->priv.x); + wresize(parent->window, height+2, widget->priv.width); + } + parent->priv.width = widget->priv.width; + parent->priv.height = height + 2; + + GNT_WIDGET_UNSET_FLAGS(parent, GNT_WIDGET_INVISIBLE); + gnt_widget_draw(parent); +} + +static gboolean +gnt_combo_box_key_pressed(GntWidget *widget, const char *text) +{ + GntComboBox *box = GNT_COMBO_BOX(widget); + if (GNT_WIDGET_IS_FLAG_SET(box->dropdown->parent, GNT_WIDGET_MAPPED)) + { + if (text[1] == 0) + { + switch (text[0]) + { + case '\r': + case '\t': + hide_popup(box, TRUE); + return TRUE; + case 27: + hide_popup(box, FALSE); + return TRUE; + } + } + if (gnt_widget_key_pressed(box->dropdown, text)) + return TRUE; + } + else + { + if (text[0] == 27) + { + if (strcmp(text, GNT_KEY_UP) == 0 || + strcmp(text, GNT_KEY_DOWN) == 0) + { + popup_dropdown(box); + return TRUE; + } + } + } + + return FALSE; +} + +static void +gnt_combo_box_destroy(GntWidget *widget) +{ + gnt_widget_destroy(GNT_COMBO_BOX(widget)->dropdown->parent); +} + +static void +gnt_combo_box_lost_focus(GntWidget *widget) +{ + GntComboBox *combo = GNT_COMBO_BOX(widget); + if (GNT_WIDGET_IS_FLAG_SET(combo->dropdown->parent, GNT_WIDGET_MAPPED)) + hide_popup(combo, FALSE); + widget_lost_focus(widget); +} + +static gboolean +gnt_combo_box_clicked(GntWidget *widget, GntMouseEvent event, int x, int y) +{ + GntComboBox *box = GNT_COMBO_BOX(widget); + gboolean dshowing = GNT_WIDGET_IS_FLAG_SET(box->dropdown->parent, GNT_WIDGET_MAPPED); + + if (event == GNT_MOUSE_SCROLL_UP) { + if (dshowing) + gnt_widget_key_pressed(box->dropdown, GNT_KEY_UP); + } else if (event == GNT_MOUSE_SCROLL_DOWN) { + if (dshowing) + gnt_widget_key_pressed(box->dropdown, GNT_KEY_DOWN); + } else if (event == GNT_LEFT_MOUSE_DOWN) { + if (dshowing) { + hide_popup(box, TRUE); + } else { + popup_dropdown(GNT_COMBO_BOX(widget)); + } + } else + return FALSE; + return TRUE; +} + +static void +gnt_combo_box_size_changed(GntWidget *widget, int oldw, int oldh) +{ + GntComboBox *box = GNT_COMBO_BOX(widget); + gnt_widget_set_size(box->dropdown, widget->priv.width - 1, box->dropdown->priv.height); +} + +static void +gnt_combo_box_class_init(GntComboBoxClass *klass) +{ + parent_class = GNT_WIDGET_CLASS(klass); + + parent_class->destroy = gnt_combo_box_destroy; + parent_class->draw = gnt_combo_box_draw; + parent_class->map = gnt_combo_box_map; + parent_class->size_request = gnt_combo_box_size_request; + parent_class->key_pressed = gnt_combo_box_key_pressed; + parent_class->clicked = gnt_combo_box_clicked; + parent_class->size_changed = gnt_combo_box_size_changed; + + widget_lost_focus = parent_class->lost_focus; + parent_class->lost_focus = gnt_combo_box_lost_focus; + + signals[SIG_SELECTION_CHANGED] = + g_signal_new("selection-changed", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + gnt_closure_marshal_VOID__POINTER_POINTER, + G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER); + + GNTDEBUG; +} + +static void +gnt_combo_box_init(GTypeInstance *instance, gpointer class) +{ + GntWidget *box; + GntWidget *widget = GNT_WIDGET(instance); + GntComboBox *combo = GNT_COMBO_BOX(instance); + + GNT_WIDGET_SET_FLAGS(GNT_WIDGET(instance), + GNT_WIDGET_GROW_X | GNT_WIDGET_CAN_TAKE_FOCUS | GNT_WIDGET_NO_SHADOW); + combo->dropdown = gnt_tree_new(); + + box = gnt_box_new(FALSE, FALSE); + GNT_WIDGET_SET_FLAGS(box, GNT_WIDGET_NO_SHADOW | GNT_WIDGET_NO_BORDER | GNT_WIDGET_TRANSIENT); + gnt_box_set_pad(GNT_BOX(box), 0); + gnt_box_add_widget(GNT_BOX(box), combo->dropdown); + + widget->priv.minw = 4; + widget->priv.minh = 3; + GNTDEBUG; +} + +/****************************************************************************** + * GntComboBox API + *****************************************************************************/ +GType +gnt_combo_box_get_gtype(void) +{ + static GType type = 0; + + if(type == 0) + { + static const GTypeInfo info = { + sizeof(GntComboBoxClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc)gnt_combo_box_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof(GntComboBox), + 0, /* n_preallocs */ + gnt_combo_box_init, /* instance_init */ + NULL /* value_table */ + }; + + type = g_type_register_static(GNT_TYPE_WIDGET, + "GntComboBox", + &info, 0); + } + + return type; +} + +GntWidget *gnt_combo_box_new() +{ + GntWidget *widget = g_object_new(GNT_TYPE_COMBO_BOX, NULL); + + return widget; +} + +void gnt_combo_box_add_data(GntComboBox *box, gpointer key, const char *text) +{ + gnt_tree_add_row_last(GNT_TREE(box->dropdown), key, + gnt_tree_create_row(GNT_TREE(box->dropdown), text), NULL); + if (box->selected == NULL) + set_selection(box, key); +} + +gpointer gnt_combo_box_get_selected_data(GntComboBox *box) +{ + return box->selected; +} + +void gnt_combo_box_set_selected(GntComboBox *box, gpointer key) +{ + set_selection(box, key); +} + +void gnt_combo_box_remove(GntComboBox *box, gpointer key) +{ + gnt_tree_remove(GNT_TREE(box->dropdown), key); + if (box->selected == key) + set_selection(box, NULL); +} + +void gnt_combo_box_remove_all(GntComboBox *box) +{ + gnt_tree_remove_all(GNT_TREE(box->dropdown)); + set_selection(box, NULL); +} + diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gntcombobox.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gntcombobox.h Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,61 @@ +#ifndef GNT_COMBO_BOX_H +#define GNT_COMBO_BOX_H + +#include "gnt.h" +#include "gntcolors.h" +#include "gntkeys.h" +#include "gntwidget.h" + +#define GNT_TYPE_COMBO_BOX (gnt_combo_box_get_gtype()) +#define GNT_COMBO_BOX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNT_TYPE_COMBO_BOX, GntComboBox)) +#define GNT_COMBO_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GNT_TYPE_COMBO_BOX, GntComboBoxClass)) +#define GNT_IS_COMBO_BOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GNT_TYPE_COMBO_BOX)) +#define GNT_IS_COMBO_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GNT_TYPE_COMBO_BOX)) +#define GNT_COMBO_BOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GNT_TYPE_COMBO_BOX, GntComboBoxClass)) + +#define GNT_COMBO_BOX_FLAGS(obj) (GNT_COMBO_BOX(obj)->priv.flags) +#define GNT_COMBO_BOX_SET_FLAGS(obj, flags) (GNT_COMBO_BOX_FLAGS(obj) |= flags) +#define GNT_COMBO_BOX_UNSET_FLAGS(obj, flags) (GNT_COMBO_BOX_FLAGS(obj) &= ~(flags)) + +typedef struct _GnComboBox GntComboBox; +typedef struct _GnComboBoxPriv GntComboBoxPriv; +typedef struct _GnComboBoxClass GntComboBoxClass; + +struct _GnComboBox +{ + GntWidget parent; + + GntWidget *dropdown; /* This is a GntTree */ + + void *selected; /* Currently selected key */ +}; + +struct _GnComboBoxClass +{ + GntWidgetClass parent; + + void (*gnt_reserved1)(void); + void (*gnt_reserved2)(void); + void (*gnt_reserved3)(void); + void (*gnt_reserved4)(void); +}; + +G_BEGIN_DECLS + +GType gnt_combo_box_get_gtype(void); + +GntWidget *gnt_combo_box_new(void); + +void gnt_combo_box_add_data(GntComboBox *box, gpointer key, const char *text); + +void gnt_combo_box_remove(GntComboBox *box, gpointer key); + +void gnt_combo_box_remove_all(GntComboBox *box); + +gpointer gnt_combo_box_get_selected_data(GntComboBox *box); + +void gnt_combo_box_set_selected(GntComboBox *box, gpointer key); + +G_END_DECLS + +#endif /* GNT_COMBO_BOX_H */ diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gntentry.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gntentry.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,932 @@ +#include +#include + +#include "gntbox.h" +#include "gntentry.h" +#include "gntstyle.h" +#include "gnttree.h" +#include "gntutils.h" + +enum +{ + SIG_TEXT_CHANGED, + SIGS, +}; +static guint signals[SIGS] = { 0 }; + +static GntWidgetClass *parent_class = NULL; + +static void gnt_entry_set_text_internal(GntEntry *entry, const char *text); + +static void +destroy_suggest(GntEntry *entry) +{ + if (entry->ddown) + { + gnt_widget_destroy(entry->ddown->parent); + entry->ddown = NULL; + } +} + +static char * +get_beginning_of_word(GntEntry *entry) +{ + char *s = entry->cursor; + while (s > entry->start) + { + char *t = g_utf8_find_prev_char(entry->start, s); + if (isspace(*t)) + break; + s = t; + } + return s; +} + +static gboolean +show_suggest_dropdown(GntEntry *entry) +{ + char *suggest = NULL; + int len; + int offset = 0, x, y; + int count = 0; + GList *iter; + + if (entry->word) + { + char *s = get_beginning_of_word(entry); + suggest = g_strndup(s, entry->cursor - s); + if (entry->scroll < s) + offset = gnt_util_onscreen_width(entry->scroll, s); + } + else + suggest = g_strdup(entry->start); + len = strlen(suggest); /* Don't need to use the utf8-function here */ + + if (entry->ddown == NULL) + { + GntWidget *box = gnt_vbox_new(FALSE); + entry->ddown = gnt_tree_new(); + gnt_tree_set_compare_func(GNT_TREE(entry->ddown), (GCompareFunc)g_utf8_collate); + gnt_box_add_widget(GNT_BOX(box), entry->ddown); + /* XXX: Connect to the "activate" signal for the dropdown tree */ + + GNT_WIDGET_SET_FLAGS(box, GNT_WIDGET_TRANSIENT); + + gnt_widget_get_position(GNT_WIDGET(entry), &x, &y); + x += offset; + y++; + if (y + 10 >= getmaxy(stdscr)) + y -= 11; + gnt_widget_set_position(box, x, y); + } + else + gnt_tree_remove_all(GNT_TREE(entry->ddown)); + + for (count = 0, iter = entry->suggests; iter; iter = iter->next) + { + const char *text = iter->data; + if (g_ascii_strncasecmp(suggest, text, len) == 0 && strlen(text) >= len) + { + gnt_tree_add_row_after(GNT_TREE(entry->ddown), (gpointer)text, + gnt_tree_create_row(GNT_TREE(entry->ddown), text), + NULL, NULL); + count++; + } + } + g_free(suggest); + + if (count == 0) + { + destroy_suggest(entry); + return FALSE; + } + + gnt_widget_draw(entry->ddown->parent); + return TRUE; +} + +static void +gnt_entry_draw(GntWidget *widget) +{ + GntEntry *entry = GNT_ENTRY(widget); + int stop; + gboolean focus; + + if ((focus = gnt_widget_has_focus(widget))) + wbkgdset(widget->window, '\0' | COLOR_PAIR(GNT_COLOR_TEXT_NORMAL)); + else + wbkgdset(widget->window, '\0' | COLOR_PAIR(GNT_COLOR_HIGHLIGHT_D)); + + if (entry->masked) + { + mvwhline(widget->window, 0, 0, gnt_ascii_only() ? '*' : ACS_BULLET, + g_utf8_pointer_to_offset(entry->scroll, entry->end)); + } + else + mvwprintw(widget->window, 0, 0, "%s", entry->scroll); + + stop = gnt_util_onscreen_width(entry->scroll, entry->end); + if (stop < widget->priv.width) + whline(widget->window, ENTRY_CHAR, widget->priv.width - stop); + + if (focus) + mvwchgat(widget->window, 0, gnt_util_onscreen_width(entry->scroll, entry->cursor), + 1, A_REVERSE, GNT_COLOR_TEXT_NORMAL, NULL); + + GNTDEBUG; +} + +static void +gnt_entry_size_request(GntWidget *widget) +{ + if (!GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_MAPPED)) + { + widget->priv.height = 1; + widget->priv.width = 20; + } +} + +static void +gnt_entry_map(GntWidget *widget) +{ + if (widget->priv.width == 0 || widget->priv.height == 0) + gnt_widget_size_request(widget); + GNTDEBUG; +} + +static void +entry_redraw(GntWidget *widget) +{ + gnt_entry_draw(widget); + gnt_widget_queue_update(widget); +} + +static void +entry_text_changed(GntEntry *entry) +{ + g_signal_emit(entry, signals[SIG_TEXT_CHANGED], 0); +} + +static gboolean +move_back(GntBindable *bind, GList *null) +{ + GntEntry *entry = GNT_ENTRY(bind); + if (entry->cursor <= entry->start) + return FALSE; + entry->cursor = g_utf8_find_prev_char(entry->start, entry->cursor); + if (entry->cursor < entry->scroll) + entry->scroll = entry->cursor; + entry_redraw(GNT_WIDGET(entry)); + return TRUE; +} + +static gboolean +move_forward(GntBindable *bind, GList *list) +{ + GntEntry *entry = GNT_ENTRY(bind); + if (entry->cursor >= entry->end) + return FALSE; + entry->cursor = g_utf8_find_next_char(entry->cursor, NULL); + while (gnt_util_onscreen_width(entry->scroll, entry->cursor) >= GNT_WIDGET(entry)->priv.width) + entry->scroll = g_utf8_find_next_char(entry->scroll, NULL); + entry_redraw(GNT_WIDGET(entry)); + return TRUE; +} + +static gboolean +backspace(GntBindable *bind, GList *null) +{ + int len; + GntEntry *entry = GNT_ENTRY(bind); + + if (entry->cursor <= entry->start) + return TRUE; + + len = entry->cursor - g_utf8_find_prev_char(entry->start, entry->cursor); + entry->cursor -= len; + memmove(entry->cursor, entry->cursor + len, entry->end - entry->cursor); + entry->end -= len; + + if (entry->scroll > entry->start) + entry->scroll = g_utf8_find_prev_char(entry->start, entry->scroll); + + entry_redraw(GNT_WIDGET(entry)); + if (entry->ddown) + show_suggest_dropdown(entry); + entry_text_changed(entry); + return TRUE; +} + +static gboolean +delkey(GntBindable *bind, GList *null) +{ + int len; + GntEntry *entry = GNT_ENTRY(bind); + + if (entry->cursor >= entry->end) + return FALSE; + + len = g_utf8_find_next_char(entry->cursor, NULL) - entry->cursor; + memmove(entry->cursor, entry->cursor + len, entry->end - entry->cursor - len + 1); + entry->end -= len; + entry_redraw(GNT_WIDGET(entry)); + + if (entry->ddown) + show_suggest_dropdown(entry); + entry_text_changed(entry); + return TRUE; +} + +static gboolean +move_start(GntBindable *bind, GList *null) +{ + GntEntry *entry = GNT_ENTRY(bind); + entry->scroll = entry->cursor = entry->start; + entry_redraw(GNT_WIDGET(entry)); + return TRUE; +} + +static gboolean +move_end(GntBindable *bind, GList *null) +{ + GntEntry *entry = GNT_ENTRY(bind); + entry->cursor = entry->end; + /* This should be better than this */ + while (gnt_util_onscreen_width(entry->scroll, entry->cursor) >= GNT_WIDGET(entry)->priv.width) + entry->scroll = g_utf8_find_next_char(entry->scroll, NULL); + entry_redraw(GNT_WIDGET(entry)); + return TRUE; +} + +static gboolean +history_prev(GntBindable *bind, GList *null) +{ + GntEntry *entry = GNT_ENTRY(bind); + if (entry->histlength && entry->history->prev) + { + entry->history = entry->history->prev; + gnt_entry_set_text_internal(entry, entry->history->data); + destroy_suggest(entry); + entry_text_changed(entry); + + return TRUE; + } + return FALSE; +} + +static gboolean +history_next(GntBindable *bind, GList *null) +{ + GntEntry *entry = GNT_ENTRY(bind); + if (entry->histlength && entry->history->next) + { + if (entry->history->prev == NULL) + { + /* Save the current contents */ + char *text = g_strdup(gnt_entry_get_text(entry)); + g_free(entry->history->data); + entry->history->data = text; + } + + entry->history = entry->history->next; + gnt_entry_set_text_internal(entry, entry->history->data); + destroy_suggest(entry); + entry_text_changed(entry); + + return TRUE; + } + return FALSE; +} + +static gboolean +clipboard_paste(GntBindable *bind, GList *n) +{ + GntEntry *entry = GNT_ENTRY(bind); + gchar *i, *text, *a, *all; + text = i = gnt_get_clipboard_string(); + while (*i != '\0') { + i = g_utf8_next_char(i); + if (*i == '\r' || *i == '\n') + *i = ' '; + } + a = g_strndup(entry->start, entry->cursor - entry->start); + all = g_strconcat(a, text, entry->cursor, NULL); + gnt_entry_set_text_internal(entry, all); + g_free(a); + g_free(text); + g_free(all); + return TRUE; +} + +static gboolean +suggest_show(GntBindable *bind, GList *null) +{ + return show_suggest_dropdown(GNT_ENTRY(bind)); +} + +static gboolean +suggest_next(GntBindable *bind, GList *null) +{ + GntEntry *entry = GNT_ENTRY(bind); + if (entry->ddown) { + gnt_bindable_perform_action_named(GNT_BINDABLE(entry->ddown), "move-down", NULL); + return TRUE; + } + return FALSE; +} + +static gboolean +suggest_prev(GntBindable *bind, GList *null) +{ + GntEntry *entry = GNT_ENTRY(bind); + if (entry->ddown) { + gnt_bindable_perform_action_named(GNT_BINDABLE(entry->ddown), "move-up", NULL); + return TRUE; + } + return FALSE; +} + +static gboolean +del_to_home(GntBindable *bind, GList *null) +{ + GntEntry *entry = GNT_ENTRY(bind); + if (entry->cursor <= entry->start) + return TRUE; + memmove(entry->start, entry->cursor, entry->end - entry->cursor); + entry->end -= (entry->cursor - entry->start); + entry->cursor = entry->scroll = entry->start; + memset(entry->end, '\0', entry->buffer - (entry->end - entry->start)); + entry_redraw(GNT_WIDGET(bind)); + entry_text_changed(entry); + return TRUE; +} + +static gboolean +del_to_end(GntBindable *bind, GList *null) +{ + GntEntry *entry = GNT_ENTRY(bind); + if (entry->end <= entry->cursor) + return TRUE; + entry->end = entry->cursor; + memset(entry->end, '\0', entry->buffer - (entry->end - entry->start)); + entry_redraw(GNT_WIDGET(bind)); + entry_text_changed(entry); + return TRUE; +} + +#define SAME(a,b) ((g_unichar_isalpha(a) && g_unichar_isalpha(b)) || \ + (g_unichar_isdigit(a) && g_unichar_isdigit(b)) || \ + (g_unichar_isspace(a) && g_unichar_isspace(b)) || \ + (g_unichar_iswide(a) && g_unichar_iswide(b))) + +static const char * +begin_word(const char *text, const char *begin) +{ + gunichar ch = 0; + while (text > begin && (!*text || g_unichar_isspace(g_utf8_get_char(text)))) + text = g_utf8_find_prev_char(begin, text); + ch = g_utf8_get_char(text); + while ((text = g_utf8_find_prev_char(begin, text)) >= begin) { + gunichar cur = g_utf8_get_char(text); + if (!SAME(ch, cur)) + break; + } + + return (text ? g_utf8_find_next_char(text, NULL) : begin); +} + +static const char * +next_begin_word(const char *text, const char *end) +{ + gunichar ch = 0; + ch = g_utf8_get_char(text); + while ((text = g_utf8_find_next_char(text, end)) != NULL && text <= end) { + gunichar cur = g_utf8_get_char(text); + if (!SAME(ch, cur)) + break; + } + + while (text && text < end && g_unichar_isspace(g_utf8_get_char(text))) + text = g_utf8_find_next_char(text, end); + return (text ? text : end); +} + +#undef SAME +static gboolean +move_back_word(GntBindable *bind, GList *null) +{ + GntEntry *entry = GNT_ENTRY(bind); + const char *iter = g_utf8_find_prev_char(entry->start, entry->cursor); + + if (iter < entry->start) + return TRUE; + iter = begin_word(iter, entry->start); + entry->cursor = (char*)iter; + if (entry->cursor < entry->scroll) + entry->scroll = entry->cursor; + entry_redraw(GNT_WIDGET(bind)); + return TRUE; +} + +static gboolean +del_prev_word(GntBindable *bind, GList *null) +{ + GntWidget *widget = GNT_WIDGET(bind); + GntEntry *entry = GNT_ENTRY(bind); + char *iter = g_utf8_find_prev_char(entry->start, entry->cursor); + int count; + + if (iter < entry->start) + return TRUE; + iter = (char*)begin_word(iter, entry->start); + count = entry->cursor - iter; + memmove(iter, entry->cursor, entry->end - entry->cursor); + entry->end -= count; + entry->cursor = iter; + if (entry->cursor <= entry->scroll) { + entry->scroll = entry->cursor - widget->priv.width + 2; + if (entry->scroll < entry->start) + entry->scroll = entry->start; + } + memset(entry->end, '\0', entry->buffer - (entry->end - entry->start)); + entry_redraw(widget); + entry_text_changed(entry); + + return TRUE; +} + +static gboolean +move_forward_word(GntBindable *bind, GList *list) +{ + GntEntry *entry = GNT_ENTRY(bind); + GntWidget *widget = GNT_WIDGET(bind); + entry->cursor = (char *)next_begin_word(entry->cursor, entry->end); + while (gnt_util_onscreen_width(entry->scroll, entry->cursor) >= widget->priv.width) { + entry->scroll = g_utf8_find_next_char(entry->scroll, NULL); + } + entry_redraw(widget); + return TRUE; +} + +static gboolean +delete_forward_word(GntBindable *bind, GList *list) +{ + GntEntry *entry = GNT_ENTRY(bind); + GntWidget *widget = GNT_WIDGET(bind); + char *iter = (char *)next_begin_word(entry->cursor, entry->end); + int len = entry->end - iter + 1; + if (len <= 0) + return TRUE; + memmove(entry->cursor, iter, len); + len = iter - entry->cursor; + entry->end -= len; + memset(entry->end, '\0', len); + entry_redraw(widget); + entry_text_changed(entry); + return TRUE; +} + +static gboolean +gnt_entry_key_pressed(GntWidget *widget, const char *text) +{ + GntEntry *entry = GNT_ENTRY(widget); + + if (text[0] == 27) + { + if (text[1] == 0) + { + destroy_suggest(entry); + return TRUE; + } + + return FALSE; + } + else + { + if (text[0] == '\t') + { + if (entry->ddown) + destroy_suggest(entry); + else if (entry->suggests) + return show_suggest_dropdown(entry); + + return FALSE; + } + else if (text[0] == '\r' && entry->ddown) + { + char *text = g_strdup(gnt_tree_get_selection_data(GNT_TREE(entry->ddown))); + destroy_suggest(entry); + if (entry->word) + { + char *s = get_beginning_of_word(entry); + char *iter = text; + while (*iter && toupper(*s) == toupper(*iter)) + { + *s++ = *iter++; + } + gnt_entry_key_pressed(widget, iter); + } + else + { + gnt_entry_set_text_internal(entry, text); + } + g_free(text); + entry_text_changed(entry); + return TRUE; + } + + if (!iscntrl(text[0])) + { + const char *str, *next; + + for (str = text; *str; str = next) + { + int len; + next = g_utf8_find_next_char(str, NULL); + len = next - str; + + /* Valid input? */ + /* XXX: Is it necessary to use _unichar_ variants here? */ + if (ispunct(*str) && (entry->flag & GNT_ENTRY_FLAG_NO_PUNCT)) + continue; + if (isspace(*str) && (entry->flag & GNT_ENTRY_FLAG_NO_SPACE)) + continue; + if (isalpha(*str) && !(entry->flag & GNT_ENTRY_FLAG_ALPHA)) + continue; + if (isdigit(*str) && !(entry->flag & GNT_ENTRY_FLAG_INT)) + continue; + + /* Reached the max? */ + if (entry->max && g_utf8_pointer_to_offset(entry->start, entry->end) >= entry->max) + continue; + + if (entry->end + len - entry->start >= entry->buffer) + { + /* This will cause the buffer to grow */ + char *tmp = g_strdup(entry->start); + gnt_entry_set_text_internal(entry, tmp); + g_free(tmp); + } + + memmove(entry->cursor + len, entry->cursor, entry->end - entry->cursor + 1); + entry->end += len; + + while (str < next) + { + if (*str == '\r' || *str == '\n') + *entry->cursor = ' '; + else + *entry->cursor = *str; + entry->cursor++; + str++; + } + + while (gnt_util_onscreen_width(entry->scroll, entry->cursor) >= widget->priv.width) + entry->scroll = g_utf8_find_next_char(entry->scroll, NULL); + + if (entry->ddown) + show_suggest_dropdown(entry); + } + entry_redraw(widget); + entry_text_changed(entry); + return TRUE; + } + } + + return FALSE; +} + +static void +gnt_entry_destroy(GntWidget *widget) +{ + GntEntry *entry = GNT_ENTRY(widget); + g_free(entry->start); + + if (entry->history) + { + entry->history = g_list_first(entry->history); + g_list_foreach(entry->history, (GFunc)g_free, NULL); + g_list_free(entry->history); + } + + if (entry->suggests) + { + g_list_foreach(entry->suggests, (GFunc)g_free, NULL); + g_list_free(entry->suggests); + } + + if (entry->ddown) + { + gnt_widget_destroy(entry->ddown->parent); + } +} + +static void +gnt_entry_lost_focus(GntWidget *widget) +{ + GntEntry *entry = GNT_ENTRY(widget); + destroy_suggest(entry); + entry_redraw(widget); +} + +static void +gnt_entry_class_init(GntEntryClass *klass) +{ + GntBindableClass *bindable = GNT_BINDABLE_CLASS(klass); + char s[2] = {erasechar(), 0}; + + parent_class = GNT_WIDGET_CLASS(klass); + parent_class->destroy = gnt_entry_destroy; + parent_class->draw = gnt_entry_draw; + parent_class->map = gnt_entry_map; + parent_class->size_request = gnt_entry_size_request; + parent_class->key_pressed = gnt_entry_key_pressed; + parent_class->lost_focus = gnt_entry_lost_focus; + + signals[SIG_TEXT_CHANGED] = + g_signal_new("text_changed", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GntEntryClass, text_changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + gnt_bindable_class_register_action(bindable, "cursor-home", move_start, + GNT_KEY_CTRL_A, NULL); + gnt_bindable_register_binding(bindable, "cursor-home", GNT_KEY_HOME, NULL); + gnt_bindable_class_register_action(bindable, "cursor-end", move_end, + GNT_KEY_CTRL_E, NULL); + gnt_bindable_register_binding(bindable, "cursor-end", GNT_KEY_END, NULL); + gnt_bindable_class_register_action(bindable, "delete-prev", backspace, + GNT_KEY_BACKSPACE, NULL); + gnt_bindable_register_binding(bindable, "delete-prev", s, NULL); + gnt_bindable_register_binding(bindable, "delete-prev", GNT_KEY_CTRL_H, NULL); + gnt_bindable_class_register_action(bindable, "delete-next", delkey, + GNT_KEY_DEL, NULL); + gnt_bindable_register_binding(bindable, "delete-next", GNT_KEY_CTRL_D, NULL); + gnt_bindable_class_register_action(bindable, "delete-start", del_to_home, + GNT_KEY_CTRL_U, NULL); + gnt_bindable_class_register_action(bindable, "delete-end", del_to_end, + GNT_KEY_CTRL_K, NULL); + gnt_bindable_class_register_action(bindable, "delete-prev-word", del_prev_word, + GNT_KEY_CTRL_W, NULL); + gnt_bindable_class_register_action(bindable, "cursor-prev-word", move_back_word, + "\033" "b", NULL); + gnt_bindable_class_register_action(bindable, "cursor-prev", move_back, + GNT_KEY_LEFT, NULL); + gnt_bindable_register_binding(bindable, "cursor-prev", GNT_KEY_CTRL_B, NULL); + gnt_bindable_class_register_action(bindable, "cursor-next", move_forward, + GNT_KEY_RIGHT, NULL); + gnt_bindable_register_binding(bindable, "cursor-next", GNT_KEY_CTRL_F, NULL); + gnt_bindable_class_register_action(bindable, "cursor-next-word", move_forward_word, + "\033" "f", NULL); + gnt_bindable_class_register_action(bindable, "delete-next-word", delete_forward_word, + "\033" "d", NULL); + gnt_bindable_class_register_action(bindable, "suggest-show", suggest_show, + "\t", NULL); + gnt_bindable_class_register_action(bindable, "suggest-next", suggest_next, + GNT_KEY_DOWN, NULL); + gnt_bindable_class_register_action(bindable, "suggest-prev", suggest_prev, + GNT_KEY_UP, NULL); + gnt_bindable_class_register_action(bindable, "history-prev", history_prev, + GNT_KEY_CTRL_DOWN, NULL); + gnt_bindable_class_register_action(bindable, "history-next", history_next, + GNT_KEY_CTRL_UP, NULL); + gnt_bindable_class_register_action(bindable, "clipboard-paste", clipboard_paste, + GNT_KEY_CTRL_V, NULL); + + gnt_style_read_actions(G_OBJECT_CLASS_TYPE(klass), GNT_BINDABLE_CLASS(klass)); + GNTDEBUG; +} + +static void +gnt_entry_init(GTypeInstance *instance, gpointer class) +{ + GntWidget *widget = GNT_WIDGET(instance); + GntEntry *entry = GNT_ENTRY(instance); + + entry->flag = GNT_ENTRY_FLAG_ALL; + entry->max = 0; + + entry->histlength = 0; + entry->history = NULL; + + entry->word = TRUE; + entry->always = FALSE; + entry->suggests = NULL; + + GNT_WIDGET_SET_FLAGS(GNT_WIDGET(entry), + GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW | GNT_WIDGET_CAN_TAKE_FOCUS); + GNT_WIDGET_SET_FLAGS(GNT_WIDGET(entry), GNT_WIDGET_GROW_X); + + widget->priv.minw = 3; + widget->priv.minh = 1; + + GNTDEBUG; +} + +/****************************************************************************** + * GntEntry API + *****************************************************************************/ +GType +gnt_entry_get_gtype(void) +{ + static GType type = 0; + + if(type == 0) + { + static const GTypeInfo info = { + sizeof(GntEntryClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc)gnt_entry_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof(GntEntry), + 0, /* n_preallocs */ + gnt_entry_init, /* instance_init */ + NULL /* value_table */ + }; + + type = g_type_register_static(GNT_TYPE_WIDGET, + "GntEntry", + &info, 0); + } + + return type; +} + +GntWidget *gnt_entry_new(const char *text) +{ + GntWidget *widget = g_object_new(GNT_TYPE_ENTRY, NULL); + GntEntry *entry = GNT_ENTRY(widget); + + gnt_entry_set_text_internal(entry, text); + + return widget; +} + +static void +gnt_entry_set_text_internal(GntEntry *entry, const char *text) +{ + int len; + int scroll, cursor; + + g_free(entry->start); + + if (text && text[0]) + { + len = strlen(text); + } + else + { + len = 0; + } + + entry->buffer = len + 128; + + scroll = entry->scroll - entry->start; + cursor = entry->end - entry->cursor; + + entry->start = g_new0(char, entry->buffer); + if (text) + snprintf(entry->start, len + 1, "%s", text); + entry->end = entry->start + len; + + entry->scroll = entry->start + scroll; + entry->cursor = entry->end - cursor; + + if (GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(entry), GNT_WIDGET_MAPPED)) + entry_redraw(GNT_WIDGET(entry)); +} + +void gnt_entry_set_text(GntEntry *entry, const char *text) +{ + gboolean changed = TRUE; + if (text == NULL && entry->start == NULL) + changed = FALSE; + if (text && entry->start && g_utf8_collate(text, entry->start) == 0) + changed = FALSE; + gnt_entry_set_text_internal(entry, text); + if (changed) + entry_text_changed(entry); +} + +void gnt_entry_set_max(GntEntry *entry, int max) +{ + entry->max = max; +} + +void gnt_entry_set_flag(GntEntry *entry, GntEntryFlag flag) +{ + entry->flag = flag; + /* XXX: Check the existing string to make sure the flags are respected? */ +} + +const char *gnt_entry_get_text(GntEntry *entry) +{ + return entry->start; +} + +void gnt_entry_clear(GntEntry *entry) +{ + gnt_entry_set_text_internal(entry, NULL); + entry->scroll = entry->cursor = entry->end = entry->start; + entry_redraw(GNT_WIDGET(entry)); + destroy_suggest(entry); + entry_text_changed(entry); +} + +void gnt_entry_set_masked(GntEntry *entry, gboolean set) +{ + entry->masked = set; +} + +void gnt_entry_add_to_history(GntEntry *entry, const char *text) +{ + g_return_if_fail(entry->history != NULL); /* Need to set_history_length first */ + + if (g_list_length(entry->history) >= entry->histlength) + return; + + entry->history = g_list_first(entry->history); + g_free(entry->history->data); + entry->history->data = g_strdup(text); + entry->history = g_list_prepend(entry->history, NULL); +} + +void gnt_entry_set_history_length(GntEntry *entry, int num) +{ + if (num == 0) + { + entry->histlength = num; + if (entry->history) + { + entry->history = g_list_first(entry->history); + g_list_foreach(entry->history, (GFunc)g_free, NULL); + g_list_free(entry->history); + entry->history = NULL; + } + return; + } + + if (entry->histlength == 0) + { + entry->histlength = num; + entry->history = g_list_append(NULL, NULL); + return; + } + + if (num > 0 && num < entry->histlength) + { + GList *first, *iter; + int index = 0; + for (first = entry->history, index = 0; first->prev; first = first->prev, index++); + while ((iter = g_list_nth(first, num)) != NULL) + { + g_free(iter->data); + first = g_list_delete_link(first, iter); + } + entry->histlength = num; + if (index >= num) + entry->history = g_list_last(first); + return; + } + + entry->histlength = num; +} + +void gnt_entry_set_word_suggest(GntEntry *entry, gboolean word) +{ + entry->word = word; +} + +void gnt_entry_set_always_suggest(GntEntry *entry, gboolean always) +{ + entry->always = always; +} + +void gnt_entry_add_suggest(GntEntry *entry, const char *text) +{ + GList *find; + + if (!text || !*text) + return; + + find = g_list_find_custom(entry->suggests, text, (GCompareFunc)g_utf8_collate); + if (find) + return; + entry->suggests = g_list_append(entry->suggests, g_strdup(text)); +} + +void gnt_entry_remove_suggest(GntEntry *entry, const char *text) +{ + GList *find = g_list_find_custom(entry->suggests, text, (GCompareFunc)g_utf8_collate); + if (find) + { + g_free(find->data); + entry->suggests = g_list_delete_link(entry->suggests, find); + } +} + diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gntentry.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gntentry.h Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,106 @@ +#ifndef GNT_ENTRY_H +#define GNT_ENTRY_H + +#include "gntwidget.h" +#include "gnt.h" +#include "gntcolors.h" +#include "gntkeys.h" + +#define GNT_TYPE_ENTRY (gnt_entry_get_gtype()) +#define GNT_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNT_TYPE_ENTRY, GntEntry)) +#define GNT_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GNT_TYPE_ENTRY, GntEntryClass)) +#define GNT_IS_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GNT_TYPE_ENTRY)) +#define GNT_IS_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GNT_TYPE_ENTRY)) +#define GNT_ENTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GNT_TYPE_ENTRY, GntEntryClass)) + +#define GNT_ENTRY_FLAGS(obj) (GNT_ENTRY(obj)->priv.flags) +#define GNT_ENTRY_SET_FLAGS(obj, flags) (GNT_ENTRY_FLAGS(obj) |= flags) +#define GNT_ENTRY_UNSET_FLAGS(obj, flags) (GNT_ENTRY_FLAGS(obj) &= ~(flags)) + +#define ENTRY_CHAR '_' /* The character to use to fill in the blank places */ + +typedef struct _GnEntry GntEntry; +typedef struct _GnEntryPriv GntEntryPriv; +typedef struct _GnEntryClass GntEntryClass; + +typedef enum +{ + GNT_ENTRY_FLAG_ALPHA = 1 << 0, /* Only alpha */ + GNT_ENTRY_FLAG_INT = 1 << 1, /* Only integer */ + GNT_ENTRY_FLAG_NO_SPACE = 1 << 2, /* No blank space is allowed */ + GNT_ENTRY_FLAG_NO_PUNCT = 1 << 3, /* No punctuations */ + GNT_ENTRY_FLAG_MASK = 1 << 4, /* Mask the inputs */ +} GntEntryFlag; + +#define GNT_ENTRY_FLAG_ALL (GNT_ENTRY_FLAG_ALPHA | GNT_ENTRY_FLAG_INT) + +struct _GnEntry +{ + GntWidget parent; + + GntEntryFlag flag; + + char *start; + char *end; + char *scroll; /* Current scrolling position */ + char *cursor; /* Cursor location */ + /* 0 <= cursor - scroll < widget-width */ + + size_t buffer; /* Size of the buffer */ + + int max; /* 0 means infinite */ + gboolean masked; + + GList *history; /* History of the strings. User can use this by pressing ctrl+up/down */ + int histlength; /* How long can the history be? */ + + GList *suggests; /* List of suggestions */ + gboolean word; /* Are the suggestions for only a word, or for the whole thing? */ + gboolean always; /* Should the list of suggestions show at all times, or only on tab-press? */ + GntWidget *ddown; /* The dropdown with the suggested list */ +}; + +struct _GnEntryClass +{ + GntWidgetClass parent; + + void (*text_changed)(GntEntry *entry); + void (*gnt_reserved1)(void); + void (*gnt_reserved2)(void); + void (*gnt_reserved3)(void); + void (*gnt_reserved4)(void); +}; + +G_BEGIN_DECLS + +GType gnt_entry_get_gtype(void); + +GntWidget *gnt_entry_new(const char *text); + +void gnt_entry_set_max(GntEntry *entry, int max); + +void gnt_entry_set_text(GntEntry *entry, const char *text); + +void gnt_entry_set_flag(GntEntry *entry, GntEntryFlag flag); + +const char *gnt_entry_get_text(GntEntry *entry); + +void gnt_entry_clear(GntEntry *entry); + +void gnt_entry_set_masked(GntEntry *entry, gboolean set); + +void gnt_entry_add_to_history(GntEntry *entry, const char *text); + +void gnt_entry_set_history_length(GntEntry *entry, int num); + +void gnt_entry_set_word_suggest(GntEntry *entry, gboolean word); + +void gnt_entry_set_always_suggest(GntEntry *entry, gboolean always); + +void gnt_entry_add_suggest(GntEntry *entry, const char *text); + +void gnt_entry_remove_suggest(GntEntry *entry, const char *text); + +G_END_DECLS + +#endif /* GNT_ENTRY_H */ diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gntkeys.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gntkeys.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,243 @@ +#include "gntkeys.h" + +#include +#include +#include + +char *gnt_key_cup; +char *gnt_key_cdown; +char *gnt_key_cleft; +char *gnt_key_cright; + +static const char *term; +static GHashTable *specials; + +void gnt_init_keys() +{ + const char *controls[] = {"", "c-", "ctrl-", "ctr-", "ctl-", NULL}; + const char *alts[] = {"", "alt-", "a-", "m-", "meta-", NULL}; + int c, a, ch; + char key[32]; + + if (term == NULL) { + term = getenv("TERM"); + if (!term) + term = ""; /* Just in case */ + } + + if (strcmp(term, "xterm") == 0 || strcmp(term, "rxvt") == 0) { + gnt_key_cup = "\033" "[1;5A"; + gnt_key_cdown = "\033" "[1;5B"; + gnt_key_cright = "\033" "[1;5C"; + gnt_key_cleft = "\033" "[1;5D"; + } else if (strcmp(term, "screen") == 0 || strcmp(term, "rxvt-unicode") == 0) { + gnt_key_cup = "\033" "Oa"; + gnt_key_cdown = "\033" "Ob"; + gnt_key_cright = "\033" "Oc"; + gnt_key_cleft = "\033" "Od"; + } + + specials = g_hash_table_new(g_str_hash, g_str_equal); + +#define INSERT_KEY(k, code) do { \ + g_hash_table_insert(specials, g_strdup(k), g_strdup(code)); \ + gnt_keys_add_combination(code); \ + } while (0) + + INSERT_KEY("home", GNT_KEY_HOME); + INSERT_KEY("end", GNT_KEY_END); + INSERT_KEY("pageup", GNT_KEY_PGUP); + INSERT_KEY("pagedown", GNT_KEY_PGDOWN); + INSERT_KEY("insert", GNT_KEY_INS); + INSERT_KEY("delete", GNT_KEY_DEL); + + INSERT_KEY("left", GNT_KEY_LEFT); + INSERT_KEY("right", GNT_KEY_RIGHT); + INSERT_KEY("up", GNT_KEY_UP); + INSERT_KEY("down", GNT_KEY_DOWN); + + INSERT_KEY("tab", "\t"); + INSERT_KEY("menu", GNT_KEY_POPUP); + + INSERT_KEY("f1", GNT_KEY_F1); + INSERT_KEY("f2", GNT_KEY_F2); + INSERT_KEY("f3", GNT_KEY_F3); + INSERT_KEY("f4", GNT_KEY_F4); + INSERT_KEY("f5", GNT_KEY_F5); + INSERT_KEY("f6", GNT_KEY_F6); + INSERT_KEY("f7", GNT_KEY_F7); + INSERT_KEY("f8", GNT_KEY_F8); + INSERT_KEY("f9", GNT_KEY_F9); + INSERT_KEY("f10", GNT_KEY_F10); + INSERT_KEY("f11", GNT_KEY_F11); + INSERT_KEY("f12", GNT_KEY_F12); + +#define REM_LENGTH (sizeof(key) - (cur - key)) +#define INSERT_COMB(k, code) do { \ + snprintf(key, sizeof(key), "%s%s%s", controls[c], alts[a], k); \ + INSERT_KEY(key, code); \ + } while (0); + + /* Lower-case alphabets */ + for (a = 0, c = 0; controls[c]; c++, a = 0) { + if (c) { + INSERT_COMB("up", gnt_key_cup); + INSERT_COMB("down", gnt_key_cdown); + INSERT_COMB("left", gnt_key_cleft); + INSERT_COMB("right", gnt_key_cright); + } + + for (a = 0; alts[a]; a++) { + for (ch = 0; ch < 26; ch++) { + char str[2] = {'a' + ch, 0}, code[4] = "\0\0\0\0"; + int ind = 0; + if (a) + code[ind++] = '\033'; + code[ind] = (c ? 1 : 'a') + ch; + INSERT_COMB(str, code); + } + } + } + c = 0; + for (a = 0; alts[a]; a++) { + /* Upper-case alphabets */ + for (ch = 0; ch < 26; ch++) { + char str[2] = {'A' + ch, 0}, code[] = {'\033', 'A' + ch, 0}; + INSERT_COMB(str, code); + } + /* Digits */ + for (ch = 0; ch < 10; ch++) { + char str[2] = {'0' + ch, 0}, code[] = {'\033', '0' + ch, 0}; + INSERT_COMB(str, code); + } + } +} + +void gnt_keys_refine(char *text) +{ + if (*text == 27 && *(text + 1) == '[' && + (*(text + 2) >= 'A' && *(text + 2) <= 'D')) { + /* Apparently this is necessary for urxvt and screen and xterm */ + if (strcmp(term, "screen") == 0 || strcmp(term, "rxvt-unicode") == 0 || + strcmp(term, "xterm") == 0) + *(text + 1) = 'O'; + } else if (*(unsigned char*)text == 195) { + if (*(text + 2) == 0 && strcmp(term, "xterm") == 0) { + *(text) = 27; + *(text + 1) -= 64; /* Say wha? */ + } + } +} + +const char *gnt_key_translate(const char *name) +{ + return g_hash_table_lookup(specials, name); +} + +/** + * The key-bindings will be saved in a tree. When a keystroke happens, GNT will + * find the sequence that matches a binding and return the length. + * A sequence should not be a prefix of another sequence. If it is, then only + * the shortest one will be processed. If we want to change that, we will need + * to allow getting the k-th prefix that matches the input, and pay attention + * to the return value of gnt_wm_process_input in gntmain.c. + */ +#define SIZE 256 + +#define IS_END 1 << 0 +struct _node +{ + struct _node *next[SIZE]; + int ref; + int flags; +}; + +static struct _node root = {.ref = 1, .flags = 0}; + +static void add_path(struct _node *node, const char *path) +{ + struct _node *n = NULL; + if (!path || !*path) { + node->flags |= IS_END; + return; + } + while (*path && node->next[*path]) { + node = node->next[*path]; + node->ref++; + path++; + } + if (!*path) + return; + n = g_new0(struct _node, 1); + n->ref = 1; + node->next[*path++] = n; + add_path(n, path); +} + +void gnt_keys_add_combination(const char *path) +{ + add_path(&root, path); +} + +static void del_path(struct _node *node, const char *path) +{ + struct _node *next = NULL; + + if (!*path) + return; + next = node->next[*path]; + if (!next) + return; + del_path(next, path + 1); + next->ref--; + if (next->ref == 0) { + node->next[*path] = NULL; + g_free(next); + } +} + +void gnt_keys_del_combination(const char *path) +{ + del_path(&root, path); +} + +int gnt_keys_find_combination(const char *path) +{ + int depth = 0; + struct _node *n = &root; + + root.flags &= ~IS_END; + while (*path && n->next[*path] && !(n->flags & IS_END)) { + if (g_utf8_find_next_char(path, NULL) - path > 1) + return 0; + n = n->next[*path++]; + depth++; + } + + if (!(n->flags & IS_END)) + depth = 0; + return depth; +} + +static void +print_path(struct _node *node, int depth) +{ + int i; + for (i = 0; i < SIZE; i++) { + if (node->next[i]) { + g_printerr("%*c (%d:%d)\n", depth * 4, i, node->next[i]->ref, + node->next[i]->flags); + print_path(node->next[i], depth + 1); + } + } +} + +/* this is purely for debugging purposes. */ +void gnt_keys_print_combinations(void); +void gnt_keys_print_combinations() +{ + g_printerr("--------\n"); + print_path(&root, 1); + g_printerr("--------\n"); +} + diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gntkeys.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gntkeys.h Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,99 @@ +#ifndef GNT_KEYS_H +#define GNT_KEYS_H + +#include +#include + +/** + * terminfo/termcap doesn't provide all the information that I want to use, eg. + * ctrl-up, ctrl-down etc. So I am going to hard-code some of the information + * for some popular $TERMs + */ +extern char *gnt_key_cup; +extern char *gnt_key_cdown; +extern char *gnt_key_cleft; +extern char *gnt_key_cright; + +#define SAFE(x) ((x) ? (x) : "") + +#define GNT_KEY_POPUP SAFE(key_f16) /* Apparently */ + +/* Arrow keys */ +#define GNT_KEY_LEFT SAFE(key_left) +#define GNT_KEY_RIGHT SAFE(key_right) +#define GNT_KEY_UP SAFE(key_up) +#define GNT_KEY_DOWN SAFE(key_down) + +#define GNT_KEY_CTRL_UP SAFE(gnt_key_cup) +#define GNT_KEY_CTRL_DOWN SAFE(gnt_key_cdown) +#define GNT_KEY_CTRL_RIGHT SAFE(gnt_key_cright) +#define GNT_KEY_CTRL_LEFT SAFE(gnt_key_cleft) + +#define GNT_KEY_PGUP SAFE(key_ppage) +#define GNT_KEY_PGDOWN SAFE(key_npage) +#define GNT_KEY_HOME SAFE(key_home) +#define GNT_KEY_END SAFE(key_end) + +#define GNT_KEY_ENTER carriage_return + +#define GNT_KEY_BACKSPACE SAFE(key_backspace) +#define GNT_KEY_DEL SAFE(key_dc) +#define GNT_KEY_INS SAFE(key_ic) + +#define GNT_KEY_CTRL_A "\001" +#define GNT_KEY_CTRL_B "\002" +#define GNT_KEY_CTRL_D "\004" +#define GNT_KEY_CTRL_E "\005" +#define GNT_KEY_CTRL_F "\006" +#define GNT_KEY_CTRL_G "\007" +#define GNT_KEY_CTRL_H "\010" +#define GNT_KEY_CTRL_I "\011" +#define GNT_KEY_CTRL_J "\012" +#define GNT_KEY_CTRL_K "\013" +#define GNT_KEY_CTRL_L "\014" +#define GNT_KEY_CTRL_M "\012" +#define GNT_KEY_CTRL_N "\016" +#define GNT_KEY_CTRL_O "\017" +#define GNT_KEY_CTRL_P "\020" +#define GNT_KEY_CTRL_R "\022" +#define GNT_KEY_CTRL_T "\024" +#define GNT_KEY_CTRL_U "\025" +#define GNT_KEY_CTRL_V "\026" +#define GNT_KEY_CTRL_W "\027" +#define GNT_KEY_CTRL_X "\030" +#define GNT_KEY_CTRL_Y "\031" + +#define GNT_KEY_F1 SAFE(key_f1) +#define GNT_KEY_F2 SAFE(key_f2) +#define GNT_KEY_F3 SAFE(key_f3) +#define GNT_KEY_F4 SAFE(key_f4) +#define GNT_KEY_F5 SAFE(key_f5) +#define GNT_KEY_F6 SAFE(key_f6) +#define GNT_KEY_F7 SAFE(key_f7) +#define GNT_KEY_F8 SAFE(key_f8) +#define GNT_KEY_F9 SAFE(key_f9) +#define GNT_KEY_F10 SAFE(key_f10) +#define GNT_KEY_F11 SAFE(key_f11) +#define GNT_KEY_F12 SAFE(key_f12) + +/** + * This will do stuff with the terminal settings and stuff. + */ +void gnt_init_keys(void); +void gnt_keys_refine(char *text); +const char *gnt_key_translate(const char *name); + +void gnt_keys_add_combination(const char *path); +void gnt_keys_del_combination(const char *path); +int gnt_keys_find_combination(const char *path); + + +/* A lot of commonly used variable names are defined in . + * #undef them to make life easier for everyone. */ + +#undef columns +#undef lines +#undef buttons +#undef newline + +#endif diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gntlabel.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gntlabel.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,124 @@ +#include "gntlabel.h" +#include "gntutils.h" + +#include + +enum +{ + SIGS = 1, +}; + +static GntWidgetClass *parent_class = NULL; + +static void +gnt_label_destroy(GntWidget *widget) +{ + GntLabel *label = GNT_LABEL(widget); + g_free(label->text); +} + +static void +gnt_label_draw(GntWidget *widget) +{ + GntLabel *label = GNT_LABEL(widget); + chtype flag = gnt_text_format_flag_to_chtype(label->flags); + + wbkgdset(widget->window, '\0' | flag); + mvwaddstr(widget->window, 0, 0, label->text); + + GNTDEBUG; +} + +static void +gnt_label_size_request(GntWidget *widget) +{ + GntLabel *label = GNT_LABEL(widget); + + gnt_util_get_text_bound(label->text, + &widget->priv.width, &widget->priv.height); +} + +static void +gnt_label_class_init(GntLabelClass *klass) +{ + parent_class = GNT_WIDGET_CLASS(klass); + parent_class->destroy = gnt_label_destroy; + parent_class->draw = gnt_label_draw; + parent_class->map = NULL; + parent_class->size_request = gnt_label_size_request; + + GNTDEBUG; +} + +static void +gnt_label_init(GTypeInstance *instance, gpointer class) +{ + GntWidget *widget = GNT_WIDGET(instance); + GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_GROW_X); + widget->priv.minw = 3; + widget->priv.minh = 1; + GNTDEBUG; +} + +/****************************************************************************** + * GntLabel API + *****************************************************************************/ +GType +gnt_label_get_gtype(void) +{ + static GType type = 0; + + if(type == 0) + { + static const GTypeInfo info = { + sizeof(GntLabelClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc)gnt_label_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof(GntLabel), + 0, /* n_preallocs */ + gnt_label_init, /* instance_init */ + NULL /* value_table */ + }; + + type = g_type_register_static(GNT_TYPE_WIDGET, + "GntLabel", + &info, 0); + } + + return type; +} + +GntWidget *gnt_label_new(const char *text) +{ + return gnt_label_new_with_format(text, 0); +} + +GntWidget *gnt_label_new_with_format(const char *text, GntTextFormatFlags flags) +{ + GntWidget *widget = g_object_new(GNT_TYPE_LABEL, NULL); + GntLabel *label = GNT_LABEL(widget); + + label->text = gnt_util_onscreen_fit_string(text, -1); + label->flags = flags; + gnt_widget_set_take_focus(widget, FALSE); + GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW); + + return widget; +} + +void gnt_label_set_text(GntLabel *label, const char *text) +{ + g_free(label->text); + label->text = gnt_util_onscreen_fit_string(text, -1); + + if (GNT_WIDGET(label)->window) + { + gnt_widget_hide(GNT_WIDGET(label)); + gnt_label_size_request(GNT_WIDGET(label)); + gnt_widget_draw(GNT_WIDGET(label)); + } +} + diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gntlabel.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gntlabel.h Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,54 @@ +#ifndef GNT_LABEL_H +#define GNT_LABEL_H + +#include "gnt.h" +#include "gntwidget.h" +#include "gnttextview.h" + +#define GNT_TYPE_LABEL (gnt_label_get_gtype()) +#define GNT_LABEL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNT_TYPE_LABEL, GntLabel)) +#define GNT_LABEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GNT_TYPE_LABEL, GntLabelClass)) +#define GNT_IS_LABEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GNT_TYPE_LABEL)) +#define GNT_IS_LABEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GNT_TYPE_LABEL)) +#define GNT_LABEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GNT_TYPE_LABEL, GntLabelClass)) + +typedef struct _GnLabel GntLabel; +typedef struct _GnLabelClass GntLabelClass; + +struct _GnLabel +{ + GntWidget parent; + + char *text; + GntTextFormatFlags flags; + + void (*gnt_reserved1)(void); + void (*gnt_reserved2)(void); + void (*gnt_reserved3)(void); + void (*gnt_reserved4)(void); +}; + +struct _GnLabelClass +{ + GntWidgetClass parent; + + void (*gnt_reserved1)(void); + void (*gnt_reserved2)(void); + void (*gnt_reserved3)(void); + void (*gnt_reserved4)(void); +}; + +G_BEGIN_DECLS + +GType gnt_label_get_gtype(void); + +GntWidget *gnt_label_new(const char *text); + +GntWidget *gnt_label_new_with_format(const char *text, GntTextFormatFlags flags); + +void gnt_label_set_text(GntLabel *label, const char *text); + +G_END_DECLS + +#endif /* GNT_LABEL_H */ + diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gntline.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gntline.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,115 @@ +#include "gntline.h" + +enum +{ + SIGS = 1, +}; + +static GntWidgetClass *parent_class = NULL; + +static void +gnt_line_draw(GntWidget *widget) +{ + GntLine *line = GNT_LINE(widget); + if (line->vertical) + mvwvline(widget->window, 1, 0, ACS_VLINE | COLOR_PAIR(GNT_COLOR_NORMAL), + widget->priv.height - 2); + else + mvwhline(widget->window, 0, 1, ACS_HLINE | COLOR_PAIR(GNT_COLOR_NORMAL), + widget->priv.width - 2); +} + +static void +gnt_line_size_request(GntWidget *widget) +{ + if (GNT_LINE(widget)->vertical) + { + widget->priv.width = 1; + widget->priv.height = 5; + } + else + { + widget->priv.width = 5; + widget->priv.height = 1; + } +} + +static void +gnt_line_map(GntWidget *widget) +{ + if (widget->priv.width == 0 || widget->priv.height == 0) + gnt_widget_size_request(widget); + GNTDEBUG; +} + +static void +gnt_line_class_init(GntLineClass *klass) +{ + parent_class = GNT_WIDGET_CLASS(klass); + parent_class->draw = gnt_line_draw; + parent_class->map = gnt_line_map; + parent_class->size_request = gnt_line_size_request; + + GNTDEBUG; +} + +static void +gnt_line_init(GTypeInstance *instance, gpointer class) +{ + GntWidget *widget = GNT_WIDGET(instance); + GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_NO_SHADOW | GNT_WIDGET_NO_BORDER); + widget->priv.minw = 1; + widget->priv.minh = 1; + GNTDEBUG; +} + +/****************************************************************************** + * GntLine API + *****************************************************************************/ +GType +gnt_line_get_gtype(void) +{ + static GType type = 0; + + if(type == 0) + { + static const GTypeInfo info = { + sizeof(GntLineClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc)gnt_line_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof(GntLine), + 0, /* n_preallocs */ + gnt_line_init, /* instance_init */ + NULL /* value_table */ + }; + + type = g_type_register_static(GNT_TYPE_WIDGET, + "GntLine", + &info, 0); + } + + return type; +} + +GntWidget *gnt_line_new(gboolean vertical) +{ + GntWidget *widget = g_object_new(GNT_TYPE_LINE, NULL); + GntLine *line = GNT_LINE(widget); + + line->vertical = vertical; + + if (vertical) + { + GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_GROW_Y); + } + else + { + GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_GROW_X); + } + + return widget; +} + diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gntline.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gntline.h Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,52 @@ +#ifndef GNT_LINE_H +#define GNT_LINE_H + +#include "gntwidget.h" +#include "gnt.h" +#include "gntcolors.h" +#include "gntkeys.h" + +#define GNT_TYPE_LINE (gnt_line_get_gtype()) +#define GNT_LINE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNT_TYPE_LINE, GntLine)) +#define GNT_LINE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GNT_TYPE_LINE, GntLineClass)) +#define GNT_IS_LINE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GNT_TYPE_LINE)) +#define GNT_IS_LINE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GNT_TYPE_LINE)) +#define GNT_LINE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GNT_TYPE_LINE, GntLineClass)) + +#define GNT_LINE_FLAGS(obj) (GNT_LINE(obj)->priv.flags) +#define GNT_LINE_SET_FLAGS(obj, flags) (GNT_LINE_FLAGS(obj) |= flags) +#define GNT_LINE_UNSET_FLAGS(obj, flags) (GNT_LINE_FLAGS(obj) &= ~(flags)) + +typedef struct _GnLine GntLine; +typedef struct _GnLinePriv GntLinePriv; +typedef struct _GnLineClass GntLineClass; + +struct _GnLine +{ + GntWidget parent; + + gboolean vertical; +}; + +struct _GnLineClass +{ + GntWidgetClass parent; + + void (*gnt_reserved1)(void); + void (*gnt_reserved2)(void); + void (*gnt_reserved3)(void); + void (*gnt_reserved4)(void); +}; + +G_BEGIN_DECLS + +GType gnt_line_get_gtype(void); + +#define gnt_hline_new() gnt_line_new(FALSE) +#define gnt_vline_new() gnt_line_new(TRUE) + +GntWidget *gnt_line_new(gboolean vertical); + +G_END_DECLS + +#endif /* GNT_LINE_H */ diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gntmain.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gntmain.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,535 @@ +#define _GNU_SOURCE +#if defined(__APPLE__) +#define _XOPEN_SOURCE_EXTENDED +#endif + +#include "config.h" + +#include + +#include +#include + +#include "gnt.h" +#include "gntbox.h" +#include "gntcolors.h" +#include "gntclipboard.h" +#include "gntkeys.h" +#include "gntmenu.h" +#include "gntstyle.h" +#include "gnttree.h" +#include "gntutils.h" +#include "gntwm.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * Notes: Interesting functions to look at: + * scr_dump, scr_init, scr_restore: for workspaces + * + * Need to wattrset for colors to use with PDCurses. + */ + +static GIOChannel *channel = NULL; + +static gboolean ascii_only; +static gboolean mouse_enabled; + +static void setup_io(void); + +static gboolean refresh_screen(); + +GntWM *wm; +static GntClipboard *clipboard; + +#define HOLDING_ESCAPE (escape_stuff.timer != 0) + +static struct { + int timer; +} escape_stuff; + +static gboolean +escape_timeout(gpointer data) +{ + gnt_wm_process_input(wm, "\033"); + escape_stuff.timer = 0; + return FALSE; +} + +/** + * Mouse support: + * - bring a window on top if you click on its taskbar + * - click on the top-bar of the active window and drag+drop to move a window + * - click on a window to bring it to focus + * - allow scrolling in tree/textview on wheel-scroll event + * - click to activate button or select a row in tree + * wishlist: + * - have a little [X] on the windows, and clicking it will close that window. + */ +static gboolean +detect_mouse_action(const char *buffer) +{ + int x, y; + static enum { + MOUSE_NONE, + MOUSE_LEFT, + MOUSE_RIGHT, + MOUSE_MIDDLE + } button = MOUSE_NONE; + static GntWidget *remember = NULL; + static int offset = 0; + GntMouseEvent event; + GntWidget *widget = NULL; + PANEL *p = NULL; + + if (!wm->ordered || buffer[0] != 27) + return FALSE; + + buffer++; + if (strlen(buffer) < 5) + return FALSE; + + x = buffer[3]; + y = buffer[4]; + if (x < 0) x += 256; + if (y < 0) y += 256; + x -= 33; + y -= 33; + + while ((p = panel_below(p)) != NULL) { + const GntNode *node = panel_userptr(p); + GntWidget *wid; + if (!node) + continue; + wid = node->me; + if (x >= wid->priv.x && x < wid->priv.x + wid->priv.width) { + if (y >= wid->priv.y && y < wid->priv.y + wid->priv.height) { + widget = wid; + break; + } + } + } + + if (strncmp(buffer, "[M ", 3) == 0) { + /* left button down */ + /* Bring the window you clicked on to front */ + /* If you click on the topbar, then you can drag to move the window */ + event = GNT_LEFT_MOUSE_DOWN; + } else if (strncmp(buffer, "[M\"", 3) == 0) { + /* right button down */ + event = GNT_RIGHT_MOUSE_DOWN; + } else if (strncmp(buffer, "[M!", 3) == 0) { + /* middle button down */ + event = GNT_MIDDLE_MOUSE_DOWN; + } else if (strncmp(buffer, "[M`", 3) == 0) { + /* wheel up*/ + event = GNT_MOUSE_SCROLL_UP; + } else if (strncmp(buffer, "[Ma", 3) == 0) { + /* wheel down */ + event = GNT_MOUSE_SCROLL_DOWN; + } else if (strncmp(buffer, "[M#", 3) == 0) { + /* button up */ + event = GNT_MOUSE_UP; + } else + return FALSE; + + if (gnt_wm_process_click(wm, event, x, y, widget)) + return TRUE; + + if (event == GNT_LEFT_MOUSE_DOWN && widget && widget != wm->_list.window && + !GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_TRANSIENT)) { + if (widget != wm->ordered->data) { + gnt_wm_raise_window(wm, widget); + } + if (y == widget->priv.y) { + offset = x - widget->priv.x; + remember = widget; + button = MOUSE_LEFT; + } + } else if (event == GNT_MOUSE_UP) { + if (button == MOUSE_NONE && y == getmaxy(stdscr) - 1) { + /* Clicked on the taskbar */ + int n = g_list_length(wm->list); + if (n) { + int width = getmaxx(stdscr) / n; + gnt_bindable_perform_action_named(GNT_BINDABLE(wm), "switch-window-n", x/width, NULL); + } + } else if (button == MOUSE_LEFT && remember) { + x -= offset; + if (x < 0) x = 0; + if (y < 0) y = 0; + gnt_screen_move_widget(remember, x, y); + } + button = MOUSE_NONE; + remember = NULL; + offset = 0; + } + + gnt_widget_clicked(widget, event, x, y); + return TRUE; +} + +static gboolean +io_invoke_error(GIOChannel *source, GIOCondition cond, gpointer data) +{ + int id = GPOINTER_TO_INT(data); + g_source_remove(id); + g_io_channel_unref(source); + + channel = NULL; + setup_io(); + return TRUE; +} + +static gboolean +io_invoke(GIOChannel *source, GIOCondition cond, gpointer null) +{ + char keys[256]; + int rd = read(STDIN_FILENO, keys + HOLDING_ESCAPE, sizeof(keys) - 1 - HOLDING_ESCAPE); + char *k; + if (rd < 0) + { + int ch = getch(); /* This should return ERR, but let's see what it really returns */ + endwin(); + printf("ERROR: %s\n", strerror(errno)); + printf("File descriptor is: %d\n\nGIOChannel is: %p\ngetch() = %d\n", STDIN_FILENO, source, ch); + raise(SIGABRT); + } + else if (rd == 0) + { + endwin(); + printf("EOF\n"); + raise(SIGABRT); + } + + rd += HOLDING_ESCAPE; + keys[rd] = 0; + if (mouse_enabled && detect_mouse_action(keys)) + return TRUE; + + if (HOLDING_ESCAPE) + keys[0] = '\033'; + k = keys; + while (rd) { + char back; + int p; + + if (k[0] == '\033' && rd == 1) { + if (escape_stuff.timer) { + gnt_wm_process_input(wm, "\033\033"); + g_source_remove(escape_stuff.timer); + escape_stuff.timer = 0; + break; + } + escape_stuff.timer = g_timeout_add(250, escape_timeout, NULL); + break; + } + + gnt_keys_refine(k); + p = MAX(1, gnt_keys_find_combination(k)); + back = k[p]; + k[p] = '\0'; + gnt_wm_process_input(wm, k); /* XXX: */ + k[p] = back; + rd -= p; + k += p; + } + + return TRUE; +} + +static void +setup_io() +{ + int result; + channel = g_io_channel_unix_new(STDIN_FILENO); + g_io_channel_set_close_on_unref(channel, TRUE); + +#if 0 + g_io_channel_set_encoding(channel, NULL, NULL); + g_io_channel_set_buffered(channel, FALSE); + g_io_channel_set_flags(channel, G_IO_FLAG_NONBLOCK, NULL ); +#endif + + result = g_io_add_watch_full(channel, G_PRIORITY_HIGH, + (G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI), + io_invoke, NULL, NULL); + + g_io_add_watch_full(channel, G_PRIORITY_HIGH, + (G_IO_NVAL), + io_invoke_error, GINT_TO_POINTER(result), NULL); + + g_io_channel_unref(channel); /* Apparently this caused crashes for some people. + But irssi does this, so I am going to assume the + crashes were caused by some other stuff. */ + + g_printerr("gntmain: setting up IO\n"); +} + +static gboolean +refresh_screen() +{ + gnt_bindable_perform_action_named(GNT_BINDABLE(wm), "refresh-screen", NULL); + return FALSE; +} + +/* Xerox */ +static void +clean_pid(void) +{ + int status; + pid_t pid; + + do { + pid = waitpid(-1, &status, WNOHANG); + } while (pid != 0 && pid != (pid_t)-1); + + if ((pid == (pid_t) - 1) && (errno != ECHILD)) { + char errmsg[BUFSIZ]; + g_snprintf(errmsg, BUFSIZ, "Warning: waitpid() returned %d", pid); + perror(errmsg); + } +} + +static void +sighandler(int sig) +{ + switch (sig) { +#ifdef SIGWINCH + case SIGWINCH: + werase(stdscr); + wrefresh(stdscr); + g_idle_add(refresh_screen, NULL); + signal(SIGWINCH, sighandler); + break; +#endif + case SIGCHLD: + clean_pid(); + signal(SIGCHLD, sighandler); + break; + } +} + +static void +init_wm() +{ + const char *name = gnt_style_get(GNT_STYLE_WM); + gpointer handle; + + if (name && *name) { + handle = g_module_open(name, G_MODULE_BIND_LAZY); + if (handle) { + gboolean (*init)(GntWM **); + if (g_module_symbol(handle, "gntwm_init", (gpointer)&init)) { + init(&wm); + } + } + } + if (wm == NULL) + wm = g_object_new(GNT_TYPE_WM, NULL); +} + +void gnt_init() +{ + char *filename; + const char *locale; + + if (channel) + return; + + locale = setlocale(LC_ALL, ""); + + setup_io(); + + if (locale && (strstr(locale, "UTF") || strstr(locale, "utf"))) + ascii_only = FALSE; + else + ascii_only = TRUE; + + initscr(); + typeahead(-1); + noecho(); + curs_set(0); + + gnt_init_keys(); + gnt_init_styles(); + + filename = g_build_filename(g_get_home_dir(), ".gntrc", NULL); + gnt_style_read_configure_file(filename); + g_free(filename); + + gnt_init_colors(); + + wbkgdset(stdscr, '\0' | COLOR_PAIR(GNT_COLOR_NORMAL)); + refresh(); + +#ifdef ALL_MOUSE_EVENTS + if ((mouse_enabled = gnt_style_get_bool(GNT_STYLE_MOUSE, FALSE))) + mousemask(ALL_MOUSE_EVENTS | REPORT_MOUSE_POSITION, NULL); +#endif + + wbkgdset(stdscr, '\0' | COLOR_PAIR(GNT_COLOR_NORMAL)); + werase(stdscr); + wrefresh(stdscr); + +#ifdef SIGWINCH + signal(SIGWINCH, sighandler); +#endif + signal(SIGCHLD, sighandler); + signal(SIGPIPE, SIG_IGN); + + g_type_init(); + + init_wm(); + + clipboard = g_object_new(GNT_TYPE_CLIPBOARD, NULL); +} + +void gnt_main() +{ + wm->loop = g_main_loop_new(NULL, FALSE); + g_main_loop_run(wm->loop); +} + +/********************************* + * Stuff for 'window management' * + *********************************/ + +void gnt_screen_occupy(GntWidget *widget) +{ + gnt_wm_new_window(wm, widget); +} + +void gnt_screen_release(GntWidget *widget) +{ + gnt_wm_window_close(wm, widget); +} + +void gnt_screen_update(GntWidget *widget) +{ + gnt_wm_update_window(wm, widget); +} + +gboolean gnt_widget_has_focus(GntWidget *widget) +{ + GntWidget *w; + if (!widget) + return FALSE; + + if (GNT_IS_MENU(widget)) + return TRUE; + + w = widget; + + while (widget->parent) + widget = widget->parent; + + if (widget == wm->_list.window) + return TRUE; + if (wm->ordered && wm->ordered->data == widget) { + if (GNT_IS_BOX(widget) && + (GNT_BOX(widget)->active == w || widget == w)) + return TRUE; + } + return FALSE; +} + +void gnt_widget_set_urgent(GntWidget *widget) +{ + while (widget->parent) + widget = widget->parent; + + if (wm->ordered && wm->ordered->data == widget) + return; + + GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_URGENT); + + gnt_wm_update_window(wm, widget); +} + +void gnt_quit() +{ + g_hash_table_destroy(wm->nodes); /* XXX: */ + update_panels(); + doupdate(); + gnt_uninit_colors(); + gnt_uninit_styles(); + endwin(); +} + +gboolean gnt_ascii_only() +{ + return ascii_only; +} + +void gnt_screen_resize_widget(GntWidget *widget, int width, int height) +{ + gnt_wm_resize_window(wm, widget, width, height); +} + +void gnt_screen_move_widget(GntWidget *widget, int x, int y) +{ + gnt_wm_move_window(wm, widget, x, y); +} + +void gnt_screen_rename_widget(GntWidget *widget, const char *text) +{ + gnt_box_set_title(GNT_BOX(widget), text); + gnt_widget_draw(widget); + gnt_wm_update_window(wm, widget); +} + +void gnt_register_action(const char *label, void (*callback)()) +{ + GntAction *action = g_new0(GntAction, 1); + action->label = g_strdup(label); + action->callback = callback; + + wm->acts = g_list_append(wm->acts, action); +} + +static void +reset_menu(GntWidget *widget, gpointer null) +{ + wm->menu = NULL; +} + +gboolean gnt_screen_menu_show(gpointer newmenu) +{ + if (wm->menu) { + /* For now, if a menu is being displayed, then another menu + * can NOT take over. */ + return FALSE; + } + + wm->menu = newmenu; + GNT_WIDGET_UNSET_FLAGS(GNT_WIDGET(wm->menu), GNT_WIDGET_INVISIBLE); + gnt_widget_draw(GNT_WIDGET(wm->menu)); + + g_signal_connect(G_OBJECT(wm->menu), "hide", G_CALLBACK(reset_menu), NULL); + + return TRUE; +} + +void gnt_set_clipboard_string(gchar *string) +{ + gnt_clipboard_set_string(clipboard, string); +} + +GntClipboard *gnt_get_clipboard() +{ + return clipboard; +} +gchar *gnt_get_clipboard_string() +{ + return gnt_clipboard_get_string(clipboard); +} diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gntmenu.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gntmenu.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,317 @@ +#include "gntmenu.h" +#include "gntmenuitemcheck.h" + +#include + +enum +{ + SIGS = 1, +}; + +static GntTreeClass *parent_class = NULL; + +static void (*org_draw)(GntWidget *wid); +static void (*org_destroy)(GntWidget *wid); +static void (*org_map)(GntWidget *wid); +static gboolean (*org_key_pressed)(GntWidget *w, const char *t); + +static void +gnt_menu_draw(GntWidget *widget) +{ + GntMenu *menu = GNT_MENU(widget); + GList *iter; + chtype type; + int i; + + if (menu->type == GNT_MENU_TOPLEVEL) { + wbkgdset(widget->window, '\0' | COLOR_PAIR(GNT_COLOR_HIGHLIGHT)); + werase(widget->window); + + for (i = 0, iter = menu->list; iter; iter = iter->next, i++) { + GntMenuItem *item = GNT_MENUITEM(iter->data); + type = ' ' | COLOR_PAIR(GNT_COLOR_HIGHLIGHT); + if (i == menu->selected) + type |= A_REVERSE; + item->priv.x = getcurx(widget->window) + widget->priv.x; + item->priv.y = getcury(widget->window) + widget->priv.y + 1; + wbkgdset(widget->window, type); + wprintw(widget->window, " %s ", item->text); + } + } else { + org_draw(widget); + } + + GNTDEBUG; +} + +static void +gnt_menu_size_request(GntWidget *widget) +{ + GntMenu *menu = GNT_MENU(widget); + + if (menu->type == GNT_MENU_TOPLEVEL) { + widget->priv.height = 1; + widget->priv.width = getmaxx(stdscr); + } else { + widget->priv.height = g_list_length(menu->list) + 2; + widget->priv.width = 25; /* XXX: */ + } +} + +static void +menu_tree_add(GntMenu *menu, GntMenuItem *item, GntMenuItem *parent) +{ + if (GNT_IS_MENUITEM_CHECK(item)) { + gnt_tree_add_choice(GNT_TREE(menu), item, + gnt_tree_create_row(GNT_TREE(menu), item->text, " "), parent, NULL); + gnt_tree_set_choice(GNT_TREE(menu), item, gnt_menuitem_check_get_checked(GNT_MENUITEM_CHECK(item))); + } else + gnt_tree_add_row_last(GNT_TREE(menu), item, + gnt_tree_create_row(GNT_TREE(menu), item->text, item->submenu ? ">" : " "), parent); + + if (0 && item->submenu) { + GntMenu *sub = GNT_MENU(item->submenu); + GList *iter; + for (iter = sub->list; iter; iter = iter->next) { + GntMenuItem *it = GNT_MENUITEM(iter->data); + menu_tree_add(menu, it, item); + } + } +} + +static void +gnt_menu_map(GntWidget *widget) +{ + GntMenu *menu = GNT_MENU(widget); + + if (menu->type == GNT_MENU_TOPLEVEL) { + gnt_widget_size_request(widget); + } else { + /* Populate the tree */ + GList *iter; + gnt_tree_remove_all(GNT_TREE(widget)); + for (iter = menu->list; iter; iter = iter->next) { + GntMenuItem *item = GNT_MENUITEM(iter->data); + menu_tree_add(menu, item, NULL); + } + org_map(widget); + gnt_tree_adjust_columns(GNT_TREE(widget)); + } + GNTDEBUG; +} + +static void +menuitem_activate(GntMenu *menu, GntMenuItem *item) +{ + if (item) { + if (item->submenu) { + GntMenu *sub = GNT_MENU(item->submenu); + menu->submenu = sub; + sub->type = GNT_MENU_POPUP; /* Submenus are *never* toplevel */ + sub->parentmenu = menu; + if (menu->type != GNT_MENU_TOPLEVEL) { + GntWidget *widget = GNT_WIDGET(menu); + item->priv.x = widget->priv.x + widget->priv.width - 1; + item->priv.y = widget->priv.y + gnt_tree_get_selection_visible_line(GNT_TREE(menu)); + } + gnt_widget_set_position(GNT_WIDGET(sub), item->priv.x, item->priv.y); + GNT_WIDGET_UNSET_FLAGS(GNT_WIDGET(sub), GNT_WIDGET_INVISIBLE); + gnt_widget_draw(GNT_WIDGET(sub)); + } else if (item->callback) { + item->callback(item, item->callbackdata); + while (menu) { + gnt_widget_hide(GNT_WIDGET(menu)); + menu = menu->parentmenu; + } + } + } +} + +static gboolean +gnt_menu_key_pressed(GntWidget *widget, const char *text) +{ + GntMenu *menu = GNT_MENU(widget); + int current = menu->selected; + + if (menu->submenu) { + do menu = menu->submenu; while (menu->submenu); + return (gnt_widget_key_pressed(GNT_WIDGET(menu), text)); + } + + if (text[0] == 27 && text[1] == 0) { + /* Escape closes menu */ + GntMenu *par = menu->parentmenu; + if (par != NULL) { + par->submenu = NULL; + gnt_widget_hide(widget); + } else + gnt_widget_hide(widget); + return TRUE; + } + + if (menu->type == GNT_MENU_TOPLEVEL) { + if (strcmp(text, GNT_KEY_LEFT) == 0) { + menu->selected--; + if (menu->selected < 0) + menu->selected = g_list_length(menu->list) - 1; + } else if (strcmp(text, GNT_KEY_RIGHT) == 0) { + menu->selected++; + if (menu->selected >= g_list_length(menu->list)) + menu->selected = 0; + } else if (strcmp(text, GNT_KEY_ENTER) == 0) { + gnt_widget_activate(widget); + } + + if (current != menu->selected) { + gnt_widget_draw(widget); + return TRUE; + } + } else { + return org_key_pressed(widget, text); + } + + return FALSE; +} + +static void +gnt_menu_destroy(GntWidget *widget) +{ + GntMenu *menu = GNT_MENU(widget); + g_list_foreach(menu->list, (GFunc)g_object_unref, NULL); + g_list_free(menu->list); + org_destroy(widget); +} + +static void +gnt_menu_toggled(GntTree *tree, gpointer key) +{ + GntMenuItem *item = GNT_MENUITEM(key); + GntMenu *menu = GNT_MENU(tree); + gboolean check = gnt_menuitem_check_get_checked(GNT_MENUITEM_CHECK(item)); + gnt_menuitem_check_set_checked(GNT_MENUITEM_CHECK(item), !check); + if (item->callback) + item->callback(item, item->callbackdata); + while (menu) { + gnt_widget_hide(GNT_WIDGET(menu)); + menu = menu->parentmenu; + } +} + +static void +gnt_menu_activate(GntWidget *widget) +{ + GntMenu *menu = GNT_MENU(widget); + GntMenuItem *item; + + if (menu->type == GNT_MENU_TOPLEVEL) { + item = g_list_nth_data(menu->list, menu->selected); + } else { + item = gnt_tree_get_selection_data(GNT_TREE(menu)); + } + + if (item) { + if (GNT_IS_MENUITEM_CHECK(item)) + gnt_menu_toggled(GNT_TREE(widget), item); + else + menuitem_activate(menu, item); + } +} + +static void +gnt_menu_hide(GntWidget *widget) +{ + GntMenu *menu = GNT_MENU(widget); + if (menu->parentmenu) + menu->parentmenu->submenu = NULL; +} + +static void +gnt_menu_class_init(GntMenuClass *klass) +{ + GntWidgetClass *wid_class = GNT_WIDGET_CLASS(klass); + parent_class = GNT_TREE_CLASS(klass); + + org_destroy = wid_class->destroy; + org_map = wid_class->map; + org_draw = wid_class->draw; + org_key_pressed = wid_class->key_pressed; + + wid_class->destroy = gnt_menu_destroy; + wid_class->draw = gnt_menu_draw; + wid_class->map = gnt_menu_map; + wid_class->size_request = gnt_menu_size_request; + wid_class->key_pressed = gnt_menu_key_pressed; + wid_class->activate = gnt_menu_activate; + wid_class->hide = gnt_menu_hide; + + parent_class->toggled = gnt_menu_toggled; + + GNTDEBUG; +} + +static void +gnt_menu_init(GTypeInstance *instance, gpointer class) +{ + GntWidget *widget = GNT_WIDGET(instance); + GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_NO_SHADOW | GNT_WIDGET_NO_BORDER | + GNT_WIDGET_CAN_TAKE_FOCUS | GNT_WIDGET_TRANSIENT); + GNTDEBUG; +} + +/****************************************************************************** + * GntMenu API + *****************************************************************************/ +GType +gnt_menu_get_gtype(void) +{ + static GType type = 0; + + if(type == 0) + { + static const GTypeInfo info = { + sizeof(GntMenuClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc)gnt_menu_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof(GntMenu), + 0, /* n_preallocs */ + gnt_menu_init, /* instance_init */ + NULL /* value_table */ + }; + + type = g_type_register_static(GNT_TYPE_TREE, + "GntMenu", + &info, 0); + } + + return type; +} + +GntWidget *gnt_menu_new(GntMenuType type) +{ + GntWidget *widget = g_object_new(GNT_TYPE_MENU, NULL); + GntMenu *menu = GNT_MENU(widget); + menu->list = NULL; + menu->selected = 0; + menu->type = type; + + if (type == GNT_MENU_TOPLEVEL) { + widget->priv.x = 0; + widget->priv.y = 0; + } else { + GNT_TREE(widget)->show_separator = FALSE; + _gnt_tree_init_internals(GNT_TREE(widget), 2); + gnt_tree_set_col_width(GNT_TREE(widget), 1, 1); /* The second column is to indicate that it has a submenu */ + GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_NO_BORDER); + } + + return widget; +} + +void gnt_menu_add_item(GntMenu *menu, GntMenuItem *item) +{ + menu->list = g_list_append(menu->list, item); +} + diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gntmenu.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gntmenu.h Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,70 @@ +#ifndef GNT_MENU_H +#define GNT_MENU_H + +#include "gnttree.h" +#include "gntcolors.h" +#include "gntkeys.h" + +#define GNT_TYPE_MENU (gnt_menu_get_gtype()) +#define GNT_MENU(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNT_TYPE_MENU, GntMenu)) +#define GNT_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GNT_TYPE_MENU, GntMenuClass)) +#define GNT_IS_MENU(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GNT_TYPE_MENU)) +#define GNT_IS_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GNT_TYPE_MENU)) +#define GNT_MENU_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GNT_TYPE_MENU, GntMenuClass)) + +#define GNT_MENU_FLAGS(obj) (GNT_MENU(obj)->priv.flags) +#define GNT_MENU_SET_FLAGS(obj, flags) (GNT_MENU_FLAGS(obj) |= flags) +#define GNT_MENU_UNSET_FLAGS(obj, flags) (GNT_MENU_FLAGS(obj) &= ~(flags)) + +typedef struct _GnMenu GntMenu; +typedef struct _GnMenuPriv GntMenuPriv; +typedef struct _GnMenuClass GntMenuClass; + +#include "gntmenuitem.h" + +/** + * A toplevel-menu is displayed at the top of the screen, and it spans accross + * the entire width of the screen. + * A popup-menu could be displayed, for example, as a context menu for widgets. + */ +typedef enum +{ + GNT_MENU_TOPLEVEL = 1, /* Menu for a toplevel window */ + GNT_MENU_POPUP, /* A popup menu */ +} GntMenuType; + +struct _GnMenu +{ + GntTree parent; + GntMenuType type; + + GList *list; + int selected; + + /* This will keep track of its immediate submenu which is visible so that + * keystrokes can be passed to it. */ + GntMenu *submenu; + GntMenu *parentmenu; +}; + +struct _GnMenuClass +{ + GntTreeClass parent; + + void (*gnt_reserved1)(void); + void (*gnt_reserved2)(void); + void (*gnt_reserved3)(void); + void (*gnt_reserved4)(void); +}; + +G_BEGIN_DECLS + +GType gnt_menu_get_gtype(void); + +GntWidget *gnt_menu_new(GntMenuType type); + +void gnt_menu_add_item(GntMenu *menu, GntMenuItem *item); + +G_END_DECLS + +#endif /* GNT_MENU_H */ diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gntmenuitem.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gntmenuitem.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,84 @@ +#include "gntmenu.h" +#include "gntmenuitem.h" + +static GObjectClass *parent_class = NULL; + +static void +gnt_menuitem_destroy(GObject *obj) +{ + GntMenuItem *item = GNT_MENUITEM(obj); + g_free(item->text); + item->text = NULL; + if (item->submenu) + gnt_widget_destroy(GNT_WIDGET(item->submenu)); + parent_class->dispose(obj); +} + +static void +gnt_menuitem_class_init(GntMenuItemClass *klass) +{ + GObjectClass *obj_class = G_OBJECT_CLASS(klass); + parent_class = g_type_class_peek_parent(klass); + + obj_class->dispose = gnt_menuitem_destroy; +} + +static void +gnt_menuitem_init(GTypeInstance *instance, gpointer class) +{ +} + +/****************************************************************************** + * GntMenuItem API + *****************************************************************************/ +GType +gnt_menuitem_get_gtype(void) +{ + static GType type = 0; + + if(type == 0) + { + static const GTypeInfo info = { + sizeof(GntMenuItemClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc)gnt_menuitem_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof(GntMenuItem), + 0, /* n_preallocs */ + gnt_menuitem_init, /* instance_init */ + NULL /* value_table */ + }; + + type = g_type_register_static(G_TYPE_OBJECT, + "GntMenuItem", + &info, 0); + } + + return type; +} + +GntMenuItem *gnt_menuitem_new(const char *text) +{ + GObject *item = g_object_new(GNT_TYPE_MENUITEM, NULL); + GntMenuItem *menuitem = GNT_MENUITEM(item); + + menuitem->text = g_strdup(text); + + return menuitem; +} + +void gnt_menuitem_set_callback(GntMenuItem *item, GntMenuItemCallback callback, gpointer data) +{ + item->callback = callback; + item->callbackdata = data; +} + +void gnt_menuitem_set_submenu(GntMenuItem *item, GntMenu *menu) +{ + if (item->submenu) + gnt_widget_destroy(GNT_WIDGET(item->submenu)); + item->submenu = menu; +} + diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gntmenuitem.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gntmenuitem.h Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,71 @@ +#ifndef GNT_MENUITEM_H +#define GNT_MENUITEM_H + +#include +#include + +#define GNT_TYPE_MENUITEM (gnt_menuitem_get_gtype()) +#define GNT_MENUITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNT_TYPE_MENUITEM, GntMenuItem)) +#define GNT_MENUITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GNT_TYPE_MENUITEM, GntMenuItemClass)) +#define GNT_IS_MENUITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GNT_TYPE_MENUITEM)) +#define GNT_IS_MENUITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GNT_TYPE_MENUITEM)) +#define GNT_MENUITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GNT_TYPE_MENUITEM, GntMenuItemClass)) + +#define GNT_MENUITEM_FLAGS(obj) (GNT_MENUITEM(obj)->priv.flags) +#define GNT_MENUITEM_SET_FLAGS(obj, flags) (GNT_MENUITEM_FLAGS(obj) |= flags) +#define GNT_MENUITEM_UNSET_FLAGS(obj, flags) (GNT_MENUITEM_FLAGS(obj) &= ~(flags)) + +typedef struct _GnMenuItem GntMenuItem; +typedef struct _GnMenuItemPriv GntMenuItemPriv; +typedef struct _GnMenuItemClass GntMenuItemClass; + +#include "gntmenu.h" + +struct _GnMenuItemPriv +{ + /* These will be used to determine the position of the submenu */ + int x; + int y; +}; + +typedef void (*GntMenuItemCallback)(GntMenuItem *item, gpointer data); + +struct _GnMenuItem +{ + GObject parent; + GntMenuItemPriv priv; + + char *text; + + /* A GntMenuItem can have a callback associated with it. + * The callback will be activated whenever the suer selects it and presses enter (or clicks). + * However, if the GntMenuItem has some child, then the callback and callbackdata will be ignored. */ + gpointer callbackdata; + GntMenuItemCallback callback; + + GntMenu *submenu; +}; + +struct _GnMenuItemClass +{ + GObjectClass parent; + + void (*gnt_reserved1)(void); + void (*gnt_reserved2)(void); + void (*gnt_reserved3)(void); + void (*gnt_reserved4)(void); +}; + +G_BEGIN_DECLS + +GType gnt_menuitem_get_gtype(void); + +GntMenuItem *gnt_menuitem_new(const char *text); + +void gnt_menuitem_set_callback(GntMenuItem *item, GntMenuItemCallback callback, gpointer data); + +void gnt_menuitem_set_submenu(GntMenuItem *item, GntMenu *menu); + +G_END_DECLS + +#endif /* GNT_MENUITEM_H */ diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gntmenuitemcheck.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gntmenuitemcheck.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,68 @@ +#include "gntmenuitemcheck.h" + +static GntMenuItemClass *parent_class = NULL; + +static void +gnt_menuitem_check_class_init(GntMenuItemCheckClass *klass) +{ + parent_class = GNT_MENUITEM_CLASS(klass); + + GNTDEBUG; +} + +static void +gnt_menuitem_check_init(GTypeInstance *instance, gpointer class) +{ + GNTDEBUG; +} + +/****************************************************************************** + * GntMenuItemCheck API + *****************************************************************************/ +GType +gnt_menuitem_check_get_gtype(void) +{ + static GType type = 0; + + if(type == 0) + { + static const GTypeInfo info = { + sizeof(GntMenuItemCheckClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc)gnt_menuitem_check_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof(GntMenuItemCheck), + 0, /* n_preallocs */ + gnt_menuitem_check_init, /* instance_init */ + NULL /* value_table */ + }; + + type = g_type_register_static(GNT_TYPE_MENUITEM, + "GntMenuItemCheck", + &info, 0); + } + + return type; +} + +GntMenuItem *gnt_menuitem_check_new(const char *text) +{ + GntMenuItem *item = g_object_new(GNT_TYPE_MENUITEM_CHECK, NULL); + GntMenuItem *menuitem = GNT_MENUITEM(item); + + menuitem->text = g_strdup(text); + return item; +} + +gboolean gnt_menuitem_check_get_checked(GntMenuItemCheck *item) +{ + return item->checked; +} + +void gnt_menuitem_check_set_checked(GntMenuItemCheck *item, gboolean set) +{ + item->checked = set; +} + diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gntmenuitemcheck.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gntmenuitemcheck.h Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,52 @@ +#ifndef GNT_MENUITEM_CHECK_H +#define GNT_MENUITEM_CHECK_H + +#include "gnt.h" +#include "gntcolors.h" +#include "gntkeys.h" +#include "gntmenuitem.h" + +#define GNT_TYPE_MENUITEM_CHECK (gnt_menuitem_check_get_gtype()) +#define GNT_MENUITEM_CHECK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNT_TYPE_MENUITEM_CHECK, GntMenuItemCheck)) +#define GNT_MENUITEM_CHECK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GNT_TYPE_MENUITEM_CHECK, GntMenuItemCheckClass)) +#define GNT_IS_MENUITEM_CHECK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GNT_TYPE_MENUITEM_CHECK)) +#define GNT_IS_MENUITEM_CHECK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GNT_TYPE_MENUITEM_CHECK)) +#define GNT_MENUITEM_CHECK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GNT_TYPE_MENUITEM_CHECK, GntMenuItemCheckClass)) + +#define GNT_MENUITEM_CHECK_FLAGS(obj) (GNT_MENUITEM_CHECK(obj)->priv.flags) +#define GNT_MENUITEM_CHECK_SET_FLAGS(obj, flags) (GNT_MENUITEM_CHECK_FLAGS(obj) |= flags) +#define GNT_MENUITEM_CHECK_UNSET_FLAGS(obj, flags) (GNT_MENUITEM_CHECK_FLAGS(obj) &= ~(flags)) + +typedef struct _GnMenuItemCheck GntMenuItemCheck; +typedef struct _GnMenuItemCheckPriv GntMenuItemCheckPriv; +typedef struct _GnMenuItemCheckClass GntMenuItemCheckClass; + +struct _GnMenuItemCheck +{ + GntMenuItem parent; + gboolean checked; +}; + +struct _GnMenuItemCheckClass +{ + GntMenuItemClass parent; + + void (*gnt_reserved1)(void); + void (*gnt_reserved2)(void); + void (*gnt_reserved3)(void); + void (*gnt_reserved4)(void); +}; + +G_BEGIN_DECLS + +GType gnt_menuitem_check_get_gtype(void); + +GntMenuItem *gnt_menuitem_check_new(const char *text); + +gboolean gnt_menuitem_check_get_checked(GntMenuItemCheck *item); + +void gnt_menuitem_check_set_checked(GntMenuItemCheck *item, gboolean set); + +G_END_DECLS + +#endif /* GNT_MENUITEM_CHECK_H */ diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gntrc.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gntrc.sample Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,21 @@ +[general] +shadow = 0 + +[colors] +black = 0; 0; 0 +red = 1000; 0; 0 +green = 0; 1000; 0 +blue = 250; 250; 700 +white = 1000; 1000; 1000 +gray = 700; 700; 700 +darkgray = 256; 256; 256 + +[colorpairs] +normal = black; white +highlight = white; blue +highlightd = black; gray +shadow = black; darkgray +title = white; blue +titled = white; gray +text = white; blue +disabled = gray; white diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gntstyle.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gntstyle.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,268 @@ +#include "gntstyle.h" +#include "gntcolors.h" + +#include +#include + +#if GLIB_CHECK_VERSION(2,6,0) +static GKeyFile *gkfile; +#endif + +static char * str_styles[GNT_STYLES]; +static int int_styles[GNT_STYLES]; +static int bool_styles[GNT_STYLES]; + +const char *gnt_style_get(GntStyle style) +{ + return str_styles[style]; +} + +gboolean gnt_style_get_bool(GntStyle style, gboolean def) +{ + int i; + const char * str; + + if (bool_styles[style] != -1) + return bool_styles[style]; + + str = gnt_style_get(style); + + if (str) + { + if (strcmp(str, "false") == 0) + def = FALSE; + else if (strcmp(str, "true") == 0) + def = TRUE; + else if (sscanf(str, "%d", &i) == 1) + { + if (i) + def = TRUE; + else + def = FALSE; + } + } + + bool_styles[style] = def; + return bool_styles[style]; +} + +static void +refine(char *text) +{ + char *s = text, *t = text; + + while (*s) + { + if (*s == '^' && *(s + 1) == '[') + { + *t = '\033'; /* escape */ + s++; + } + else if (*s == '\\') + { + if (*(s + 1) == '\0') + *t = ' '; + else + { + s++; + if (*s == 'r' || *s == 'n') + *t = '\r'; + else if (*s == 't') + *t = '\t'; + else + *t = *s; + } + } + else + *t = *s; + t++; + s++; + } + *t = '\0'; +} + +static char * +parse_key(const char *key) +{ + return (char *)gnt_key_translate(key); +} + +void gnt_style_read_actions(GType type, GntBindableClass *klass) +{ +#if GLIB_CHECK_VERSION(2,6,0) + char *name; + GError *error = NULL; + + name = g_strdup_printf("%s::binding", g_type_name(type)); + + if (g_key_file_has_group(gkfile, name)) + { + gsize len = 0; + char **keys; + + keys = g_key_file_get_keys(gkfile, name, &len, &error); + if (error) + { + g_printerr("GntStyle: %s\n", error->message); + g_error_free(error); + g_free(name); + return; + } + + while (len--) + { + char *key, *action; + + key = g_strdup(keys[len]); + action = g_key_file_get_string(gkfile, name, keys[len], &error); + + if (error) + { + g_printerr("GntStyle: %s\n", error->message); + g_error_free(error); + error = NULL; + } + else + { + const char *keycode = parse_key(key); + if (keycode == NULL) { + g_printerr("GntStyle: Invalid key-binding %s\n", key); + } else { + gnt_bindable_register_binding(klass, action, keycode, NULL); + } + } + g_free(key); + g_free(action); + } + g_strfreev(keys); + } + g_free(name); +#endif +} + +void gnt_styles_get_keyremaps(GType type, GHashTable *hash) +{ +#if GLIB_CHECK_VERSION(2,6,0) + char *name; + GError *error = NULL; + + name = g_strdup_printf("%s::remap", g_type_name(type)); + + if (g_key_file_has_group(gkfile, name)) + { + gsize len = 0; + char **keys; + + keys = g_key_file_get_keys(gkfile, name, &len, &error); + if (error) + { + g_printerr("GntStyle: %s\n", error->message); + g_error_free(error); + g_free(name); + return; + } + + while (len--) + { + char *key, *replace; + + key = g_strdup(keys[len]); + replace = g_key_file_get_string(gkfile, name, keys[len], &error); + + if (error) + { + g_printerr("GntStyle: %s\n", error->message); + g_error_free(error); + error = NULL; + g_free(key); + } + else + { + refine(key); + refine(replace); + g_hash_table_insert(hash, key, replace); + } + } + g_strfreev(keys); + } + + g_free(name); +#endif +} + +#if GLIB_CHECK_VERSION(2,6,0) +static void +read_general_style(GKeyFile *kfile) +{ + GError *error = NULL; + gsize nkeys; + char **keys = g_key_file_get_keys(kfile, "general", &nkeys, &error); + int i; + struct + { + const char *style; + GntStyle en; + } styles[] = {{"shadow", GNT_STYLE_SHADOW}, + {"customcolor", GNT_STYLE_COLOR}, + {"mouse", GNT_STYLE_MOUSE}, + {"wm", GNT_STYLE_WM}, + {"remember_position", GNT_STYLE_REMPOS}, + {NULL, 0}}; + + if (error) + { + g_printerr("GntStyle: %s\n", error->message); + g_error_free(error); + } + else + { + for (i = 0; styles[i].style; i++) + { + error = NULL; + str_styles[styles[i].en] = + g_key_file_get_string(kfile, "general", styles[i].style, &error); + } + } + g_strfreev(keys); +} +#endif + +void gnt_style_read_configure_file(const char *filename) +{ +#if GLIB_CHECK_VERSION(2,6,0) + GError *error = NULL; + gkfile = g_key_file_new(); + + if (!g_key_file_load_from_file(gkfile, filename, G_KEY_FILE_NONE, &error)) + { + g_printerr("GntStyle: %s\n", error->message); + g_error_free(error); + return; + } + gnt_colors_parse(gkfile); + read_general_style(gkfile); +#endif +} + +void gnt_init_styles() +{ + int i; + for (i = 0; i < GNT_STYLES; i++) + { + str_styles[i] = NULL; + int_styles[i] = -1; + bool_styles[i] = -1; + } +} + +void gnt_uninit_styles() +{ + int i; + for (i = 0; i < GNT_STYLES; i++) + g_free(str_styles[i]); + +#if GLIB_CHECK_VERSION(2,6,0) + g_key_file_free(gkfile); +#endif +} + diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gntstyle.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gntstyle.h Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,27 @@ +#include "gnt.h" + +typedef enum +{ + GNT_STYLE_SHADOW = 0, + GNT_STYLE_COLOR = 1, + GNT_STYLE_MOUSE = 2, + GNT_STYLE_WM = 3, + GNT_STYLE_REMPOS = 4, + GNT_STYLES +} GntStyle; + +void gnt_style_read_configure_file(const char *filename); + +const char *gnt_style_get(GntStyle style); + +gboolean gnt_style_get_bool(GntStyle style, gboolean def); + +/* This should be called only once for the each type */ +void gnt_styles_get_keyremaps(GType type, GHashTable *hash); + +void gnt_style_read_actions(GType type, GntBindableClass *klass); + +void gnt_init_styles(void); + +void gnt_uninit_styles(void); + diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gnttextview.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gnttextview.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,727 @@ +#include "gnttextview.h" +#include "gntutils.h" + +#include + +enum +{ + SIGS = 1, +}; + +typedef struct +{ + GntTextFormatFlags tvflag; + chtype flags; + int start; + int end; /* This is the next byte of the last character of this segment */ +} GntTextSegment; + +typedef struct +{ + GList *segments; /* A list of GntTextSegments */ + int length; /* The current length of the line so far (ie. onscreen width) */ + gboolean soft; /* TRUE if it's an overflow from prev. line */ +} GntTextLine; + +typedef struct +{ + char *name; + int start; + int end; +} GntTextTag; + +static GntWidgetClass *parent_class = NULL; + +static gchar *select_start; +static gchar *select_end; +static gboolean double_click; + +static void +gnt_text_view_draw(GntWidget *widget) +{ + GntTextView *view = GNT_TEXT_VIEW(widget); + int i = 0; + GList *lines; + int rows, scrcol; + + werase(widget->window); + + for (i = 0, lines = view->list; i < widget->priv.height && lines; i++, lines = lines->next) + { + GList *iter; + GntTextLine *line = lines->data; + + wmove(widget->window, widget->priv.height - 1 - i, 0); + + for (iter = line->segments; iter; iter = iter->next) + { + GntTextSegment *seg = iter->data; + char *end = view->string->str + seg->end; + char back = *end; + chtype fl = seg->flags; + *end = '\0'; + if (select_start < view->string->str + seg->start && select_end > view->string->str + seg->end) { + fl |= A_REVERSE; + wattrset(widget->window, fl); + wprintw(widget->window, "%s", (view->string->str + seg->start)); + } else if (select_start && select_end && + ((select_start >= view->string->str + seg->start && select_start <= view->string->str + seg->end) || + (select_end <= view->string->str + seg->end && select_start <= view->string->str + seg->start))) { + char *cur = view->string->str + seg->start; + while (*cur != '\0') { + gchar *last = g_utf8_next_char(cur); + gchar *str; + if (cur >= select_start && cur <= select_end) + fl |= A_REVERSE; + else + fl = seg->flags; + str = g_strndup(cur, last - cur); + wattrset(widget->window, fl); + waddstr(widget->window, str); + g_free(str); + cur = g_utf8_next_char(cur); + } + } else { + wattrset(widget->window, fl); + wprintw(widget->window, "%s", (view->string->str + seg->start)); + } + *end = back; + } + wattroff(widget->window, A_UNDERLINE | A_BLINK | A_REVERSE); + whline(widget->window, ' ', widget->priv.width - line->length - 1); + } + + scrcol = widget->priv.width - 1; + rows = widget->priv.height - 2; + if (rows > 0) + { + int total = g_list_length(g_list_first(view->list)); + int showing, position, up, down; + + showing = rows * rows / total + 1; + showing = MIN(rows, showing); + + total -= rows; + up = g_list_length(lines); + down = total - up; + + position = (rows - showing) * up / MAX(1, up + down); + position = MAX((lines != NULL), position); + + if (showing + position > rows) + position = rows - showing; + + if (showing + position == rows && view->list && view->list->prev) + position = MAX(1, rows - 1 - showing); + else if (showing + position < rows && view->list && !view->list->prev) + position = rows - showing; + + mvwvline(widget->window, position + 1, scrcol, + ACS_CKBOARD | COLOR_PAIR(GNT_COLOR_HIGHLIGHT_D), showing); + } + + mvwaddch(widget->window, 0, scrcol, + (lines ? ACS_UARROW : ' ') | COLOR_PAIR(GNT_COLOR_HIGHLIGHT_D)); + mvwaddch(widget->window, widget->priv.height - 1, scrcol, + ((view->list && view->list->prev) ? ACS_DARROW : ' ') | + COLOR_PAIR(GNT_COLOR_HIGHLIGHT_D)); + + GNTDEBUG; +} + +static void +gnt_text_view_size_request(GntWidget *widget) +{ + if (!GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_MAPPED)) + { + gnt_widget_set_size(widget, 64, 20); + } +} + +static void +gnt_text_view_map(GntWidget *widget) +{ + if (widget->priv.width == 0 || widget->priv.height == 0) + gnt_widget_size_request(widget); + GNTDEBUG; +} + +static gboolean +gnt_text_view_key_pressed(GntWidget *widget, const char *text) +{ + return FALSE; +} + +static void +free_text_segment(gpointer data, gpointer null) +{ + GntTextSegment *seg = data; + g_free(seg); +} + +static void +free_text_line(gpointer data, gpointer null) +{ + GntTextLine *line = data; + g_list_foreach(line->segments, free_text_segment, NULL); + g_list_free(line->segments); + g_free(line); +} + +static void +free_tag(gpointer data, gpointer null) +{ + GntTextTag *tag = data; + g_free(tag->name); + g_free(tag); +} + +static void +gnt_text_view_destroy(GntWidget *widget) +{ + GntTextView *view = GNT_TEXT_VIEW(widget); + view->list = g_list_first(view->list); + g_list_foreach(view->list, free_text_line, NULL); + g_list_free(view->list); + g_list_foreach(view->tags, free_tag, NULL); + g_list_free(view->tags); + g_string_free(view->string, TRUE); +} + +static char * +gnt_text_view_get_p(GntTextView *view, int x, int y) +{ + int i = 0; + GntWidget *wid = GNT_WIDGET(view); + GntTextLine *line; + GList *lines; + GList *segs; + GntTextSegment *seg; + gchar *pos; + + y = wid->priv.height - y; + if (g_list_length(view->list) < y) { + x = 0; + y = g_list_length(view->list) - 1; + } + + lines = g_list_nth(view->list, y - 1); + if (!lines) + return NULL; + do { + line = lines->data; + lines = lines->next; + } while (line && !line->segments && lines); + + if (!line || !line->segments) /* no valid line */ + return NULL; + segs = line->segments; + seg = (GntTextSegment *)segs->data; + pos = view->string->str + seg->start; + x = MIN(x, line->length); + while (++i <= x) { + gunichar *u; + pos = g_utf8_next_char(pos); + u = g_utf8_to_ucs4(pos, -1, NULL, NULL, NULL); + if (u && g_unichar_iswide(*u)) + i++; + g_free(u); + } + return pos; +} + +static GString * +select_word_text(GntTextView *view, gchar *c) +{ + gchar *start = c; + gchar *end = c; + gchar *t, *endsize; + while ((t = g_utf8_prev_char(start))) { + if (!g_ascii_isspace(*t)) { + if (start == view->string->str) + break; + start = t; + } else + break; + } + while ((t = g_utf8_next_char(end))) { + if (!g_ascii_isspace(*t)) + end = t; + else + break; + } + select_start = start; + select_end = end; + endsize = g_utf8_next_char(select_end); /* End at the correct byte */ + return g_string_new_len(start, endsize - start); +} + +static gboolean too_slow(gpointer n) +{ + double_click = FALSE; + return FALSE; +} + +static gboolean +gnt_text_view_clicked(GntWidget *widget, GntMouseEvent event, int x, int y) +{ + if (event == GNT_MOUSE_SCROLL_UP) { + gnt_text_view_scroll(GNT_TEXT_VIEW(widget), -1); + } else if (event == GNT_MOUSE_SCROLL_DOWN) { + gnt_text_view_scroll(GNT_TEXT_VIEW(widget), 1); + } else if (event == GNT_LEFT_MOUSE_DOWN) { + select_start = gnt_text_view_get_p(GNT_TEXT_VIEW(widget), x - widget->priv.x, y - widget->priv.y); + g_timeout_add(500, too_slow, NULL); + } else if (event == GNT_MOUSE_UP) { + if (select_start) { + GString *clip; + select_end = gnt_text_view_get_p(GNT_TEXT_VIEW(widget), x - widget->priv.x, y - widget->priv.y); + if (select_end < select_start) { + gchar *t = select_start; + select_start = select_end; + select_end = t; + } + if (select_start == select_end) { + if (double_click) { + clip = select_word_text(GNT_TEXT_VIEW(widget), select_start); + double_click = FALSE; + } else { + double_click = TRUE; + select_start = 0; + select_end = 0; + gnt_widget_draw(widget); + return TRUE; + } + } else { + gchar *endsize = g_utf8_next_char(select_end); /* End at the correct byte */ + clip = g_string_new_len(select_start, endsize - select_start); + } + gnt_widget_draw(widget); + gnt_set_clipboard_string(clip->str); + g_string_free(clip, TRUE); + } + } else + return FALSE; + return TRUE; +} + +static void +gnt_text_view_reflow(GntTextView *view) +{ + /* This is pretty ugly, and inefficient. Someone do something about it. */ + GntTextLine *line; + GList *back, *iter, *list; + GString *string; + int pos = 0; /* no. of 'real' lines */ + + list = view->list; + while (list->prev) { + line = list->data; + if (!line->soft) + pos++; + list = list->prev; + } + + back = g_list_last(view->list); + view->list = NULL; + + string = view->string; + view->string = NULL; + gnt_text_view_clear(view); + + view->string = g_string_set_size(view->string, string->len); + view->string->len = 0; + GNT_WIDGET_SET_FLAGS(GNT_WIDGET(view), GNT_WIDGET_DRAWING); + + for (; back; back = back->prev) { + line = back->data; + if (back->next && !line->soft) { + gnt_text_view_append_text_with_flags(view, "\n", GNT_TEXT_FLAG_NORMAL); + } + + for (iter = line->segments; iter; iter = iter->next) { + GntTextSegment *seg = iter->data; + char *start = string->str + seg->start; + char *end = string->str + seg->end; + char back = *end; + *end = '\0'; + gnt_text_view_append_text_with_flags(view, start, seg->tvflag); + *end = back; + } + free_text_line(line, NULL); + } + g_list_free(list); + + list = view->list = g_list_first(view->list); + /* Go back to the line that was in view before resizing started */ + while (pos--) { + while (((GntTextLine*)list->data)->soft) + list = list->next; + list = list->next; + } + view->list = list; + GNT_WIDGET_UNSET_FLAGS(GNT_WIDGET(view), GNT_WIDGET_DRAWING); + if (GNT_WIDGET(view)->window) + gnt_widget_draw(GNT_WIDGET(view)); + g_string_free(string, TRUE); +} + +static void +gnt_text_view_size_changed(GntWidget *widget, int w, int h) +{ + if (w != widget->priv.width) { + gnt_text_view_reflow(GNT_TEXT_VIEW(widget)); + } +} + +static void +gnt_text_view_class_init(GntTextViewClass *klass) +{ + parent_class = GNT_WIDGET_CLASS(klass); + parent_class->destroy = gnt_text_view_destroy; + parent_class->draw = gnt_text_view_draw; + parent_class->map = gnt_text_view_map; + parent_class->size_request = gnt_text_view_size_request; + parent_class->key_pressed = gnt_text_view_key_pressed; + parent_class->clicked = gnt_text_view_clicked; + parent_class->size_changed = gnt_text_view_size_changed; + + GNTDEBUG; +} + +static void +gnt_text_view_init(GTypeInstance *instance, gpointer class) +{ + GntWidget *widget = GNT_WIDGET(instance); + + GNT_WIDGET_SET_FLAGS(GNT_WIDGET(instance), GNT_WIDGET_GROW_Y | GNT_WIDGET_GROW_X); + + widget->priv.minw = 5; + widget->priv.minh = 2; + GNTDEBUG; +} + +/****************************************************************************** + * GntTextView API + *****************************************************************************/ +GType +gnt_text_view_get_gtype(void) +{ + static GType type = 0; + + if(type == 0) + { + static const GTypeInfo info = { + sizeof(GntTextViewClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc)gnt_text_view_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof(GntTextView), + 0, /* n_preallocs */ + gnt_text_view_init, /* instance_init */ + NULL /* value_table */ + }; + + type = g_type_register_static(GNT_TYPE_WIDGET, + "GntTextView", + &info, 0); + } + + return type; +} + +GntWidget *gnt_text_view_new() +{ + GntWidget *widget = g_object_new(GNT_TYPE_TEXTVIEW, NULL); + GntTextView *view = GNT_TEXT_VIEW(widget); + GntTextLine *line = g_new0(GntTextLine, 1); + + GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW); + + view->string = g_string_new(NULL); + view->list = g_list_append(view->list, line); + + return widget; +} + +void gnt_text_view_append_text_with_flags(GntTextView *view, const char *text, GntTextFormatFlags flags) +{ + gnt_text_view_append_text_with_tag(view, text, flags, NULL); +} + +void gnt_text_view_append_text_with_tag(GntTextView *view, const char *text, + GntTextFormatFlags flags, const char *tagname) +{ + GntWidget *widget = GNT_WIDGET(view); + int fl = 0; + const char *start, *end; + GList *list = view->list; + GntTextLine *line; + int len; + + if (text == NULL || *text == '\0') + return; + + fl = gnt_text_format_flag_to_chtype(flags); + + len = view->string->len; + view->string = g_string_append(view->string, text); + + if (tagname) { + GntTextTag *tag = g_new0(GntTextTag, 1); + tag->name = g_strdup(tagname); + tag->start = len; + tag->end = view->string->len; + view->tags = g_list_append(view->tags, tag); + } + + view->list = g_list_first(view->list); + + start = end = view->string->str + len; + + while (*start) { + GntTextSegment *seg = NULL; + + if (*end == '\n' || *end == '\r') { + end++; + start = end; + gnt_text_view_next_line(view); + view->list = g_list_first(view->list); + continue; + } + + line = view->list->data; + if (line->length == widget->priv.width - 1) { + /* The last added line was exactly the same width as the widget */ + line = g_new0(GntTextLine, 1); + line->soft = TRUE; + view->list = g_list_prepend(view->list, line); + } + + if ((end = strchr(start, '\n')) != NULL || + (end = strchr(start, '\r')) != NULL) { + len = gnt_util_onscreen_width(start, end - 1); + if (len >= widget->priv.width - line->length - 1) { + end = NULL; + } + } + + if (end == NULL) + end = gnt_util_onscreen_width_to_pointer(start, + widget->priv.width - line->length - 1, &len); + + /* Try to append to the previous segment if possible */ + if (line->segments) { + seg = g_list_last(line->segments)->data; + if (seg->flags != fl) + seg = NULL; + } + + if (seg == NULL) { + seg = g_new0(GntTextSegment, 1); + seg->start = start - view->string->str; + seg->tvflag = flags; + seg->flags = fl; + line->segments = g_list_append(line->segments, seg); + } + seg->end = end - view->string->str; + line->length += len; + + start = end; + if (*end && *end != '\n' && *end != '\r') { + line = g_new0(GntTextLine, 1); + line->soft = TRUE; + view->list = g_list_prepend(view->list, line); + } + } + + view->list = list; + + gnt_widget_draw(widget); +} + +void gnt_text_view_scroll(GntTextView *view, int scroll) +{ + if (scroll == 0) + { + view->list = g_list_first(view->list); + } + else if (scroll > 0) + { + GList *list = g_list_nth_prev(view->list, scroll); + if (list == NULL) + list = g_list_first(view->list); + view->list = list; + } + else if (scroll < 0) + { + GList *list = g_list_nth(view->list, -scroll); + if (list == NULL) + list = g_list_last(view->list); + view->list = list; + } + + gnt_widget_draw(GNT_WIDGET(view)); +} + +void gnt_text_view_next_line(GntTextView *view) +{ + GntTextLine *line = g_new0(GntTextLine, 1); + GList *list = view->list; + + view->list = g_list_prepend(g_list_first(view->list), line); + view->list = list; + gnt_widget_draw(GNT_WIDGET(view)); +} + +chtype gnt_text_format_flag_to_chtype(GntTextFormatFlags flags) +{ + chtype fl = 0; + + if (flags & GNT_TEXT_FLAG_BOLD) + fl |= A_BOLD; + if (flags & GNT_TEXT_FLAG_UNDERLINE) + fl |= A_UNDERLINE; + if (flags & GNT_TEXT_FLAG_BLINK) + fl |= A_BLINK; + + if (flags & GNT_TEXT_FLAG_DIM) + fl |= (A_DIM | COLOR_PAIR(GNT_COLOR_DISABLED)); + else if (flags & GNT_TEXT_FLAG_HIGHLIGHT) + fl |= (A_DIM | COLOR_PAIR(GNT_COLOR_HIGHLIGHT)); + else + fl |= COLOR_PAIR(GNT_COLOR_NORMAL); + + return fl; +} + +void gnt_text_view_clear(GntTextView *view) +{ + GntTextLine *line; + + g_list_foreach(view->list, free_text_line, NULL); + g_list_free(view->list); + view->list = NULL; + + line = g_new0(GntTextLine, 1); + view->list = g_list_append(view->list, line); + if (view->string) + g_string_free(view->string, TRUE); + view->string = g_string_new(NULL); + + if (GNT_WIDGET(view)->window) + gnt_widget_draw(GNT_WIDGET(view)); +} + +int gnt_text_view_get_lines_below(GntTextView *view) +{ + int below = 0; + GList *list = view->list; + while ((list = list->prev)) + ++below; + return below; +} + +int gnt_text_view_get_lines_above(GntTextView *view) +{ + int above = 0; + GList *list = view->list; + list = g_list_nth(view->list, GNT_WIDGET(view)->priv.height); + if (!list) + return 0; + while ((list = list->next)) + ++above; + return above; +} + +/** + * XXX: There are quite possibly more than a few bugs here. + */ +int gnt_text_view_tag_change(GntTextView *view, const char *name, const char *text, gboolean all) +{ + GList *alllines = g_list_first(view->list); + GList *list, *next, *iter, *inext; + const int text_length = text ? strlen(text) : 0; + int count = 0; + for (list = view->tags; list; list = next) { + GntTextTag *tag = list->data; + next = list->next; + if (strcmp(tag->name, name) == 0) { + int change; + char *before, *after; + + count++; + + before = g_strndup(view->string->str, tag->start); + after = g_strdup(view->string->str + tag->end); + change = (tag->end - tag->start) - text_length; + + g_string_printf(view->string, "%s%s%s", before, text ? text : "", after); + g_free(before); + g_free(after); + + /* Update the offsets of the next tags */ + for (iter = next; iter; iter = iter->next) { + GntTextTag *t = iter->data; + t->start -= change; + t->end -= change; + } + + /* Update the offsets of the segments */ + for (iter = alllines; iter; iter = inext) { + GList *segs, *snext; + GntTextLine *line = iter->data; + inext = iter->next; + for (segs = line->segments; segs; segs = snext) { + GntTextSegment *seg = segs->data; + snext = segs->next; + if (seg->start >= tag->end) { + /* The segment is somewhere after the tag */ + seg->start -= change; + seg->end -= change; + } else if (seg->end <= tag->start) { + /* This segment is somewhere in front of the tag */ + } else if (seg->start >= tag->start) { + /* This segment starts in the middle of the tag */ + if (text == NULL) { + free_text_segment(seg, NULL); + line->segments = g_list_delete_link(line->segments, segs); + if (line->segments == NULL) { + free_text_line(line, NULL); + if (view->list == iter) { + if (inext) + view->list = inext; + else + view->list = iter->prev; + } + alllines = g_list_delete_link(alllines, iter); + } + } else { + /* XXX: (null) */ + seg->start = tag->start; + seg->end = tag->end - change; + } + line->length -= change; + /* XXX: Make things work if the tagged text spans over several lines. */ + } else { + /* XXX: handle the rest of the conditions */ + g_printerr("WTF! This needs to be handled properly!!\n"); + } + } + } + if (text == NULL) { + /* Remove the tag */ + view->tags = g_list_delete_link(view->tags, list); + free_tag(tag, NULL); + } else { + tag->end -= change; + } + if (!all) + break; + } + } + return count; +} + diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gnttextview.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gnttextview.h Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,86 @@ +#ifndef GNT_TEXT_VIEW_H +#define GNT_TEXT_VIEW_H + +#include "gntwidget.h" +#include "gnt.h" +#include "gntcolors.h" +#include "gntkeys.h" + +#define GNT_TYPE_TEXTVIEW (gnt_text_view_get_gtype()) +#define GNT_TEXT_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNT_TYPE_TEXTVIEW, GntTextView)) +#define GNT_TEXT_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GNT_TYPE_TEXTVIEW, GntTextViewClass)) +#define GNT_IS_TEXTVIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GNT_TYPE_TEXTVIEW)) +#define GNT_IS_TEXTVIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GNT_TYPE_TEXTVIEW)) +#define GNT_TEXT_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GNT_TYPE_TEXTVIEW, GntTextViewClass)) + +#define GNT_TEXT_VIEW_FLAGS(obj) (GNT_TEXT_VIEW(obj)->priv.flags) +#define GNT_TEXT_VIEW_SET_FLAGS(obj, flags) (GNT_TEXT_VIEW_FLAGS(obj) |= flags) +#define GNT_TEXT_VIEW_UNSET_FLAGS(obj, flags) (GNT_TEXT_VIEW_FLAGS(obj) &= ~(flags)) + +typedef struct _GnTextView GntTextView; +typedef struct _GnTextViewPriv GntTextViewPriv; +typedef struct _GnTextViewClass GntTextViewClass; + +struct _GnTextView +{ + GntWidget parent; + + GString *string; + GList *list; /* List of GntTextLine */ + + GList *tags; /* A list of tags */ +}; + +typedef enum +{ + GNT_TEXT_FLAG_NORMAL = 0, + GNT_TEXT_FLAG_BOLD = 1 << 0, + GNT_TEXT_FLAG_UNDERLINE = 1 << 1, + GNT_TEXT_FLAG_BLINK = 1 << 2, + GNT_TEXT_FLAG_DIM = 1 << 3, + GNT_TEXT_FLAG_HIGHLIGHT = 1 << 4, +} GntTextFormatFlags; + +struct _GnTextViewClass +{ + GntWidgetClass parent; + + void (*gnt_reserved1)(void); + void (*gnt_reserved2)(void); + void (*gnt_reserved3)(void); + void (*gnt_reserved4)(void); +}; + +G_BEGIN_DECLS + +GType gnt_text_view_get_gtype(void); + +/* XXX: For now, don't set a textview to have any border. + * If you want borders real bad, put it in a box. */ +GntWidget *gnt_text_view_new(void); + +/* scroll > 0 means scroll up, < 0 means scroll down, == 0 means scroll to the end */ +void gnt_text_view_scroll(GntTextView *view, int scroll); + +void gnt_text_view_append_text_with_flags(GntTextView *view, const char *text, GntTextFormatFlags flags); + +void gnt_text_view_append_text_with_tag(GntTextView *view, const char *text, GntTextFormatFlags flags, const char *tag); + +/* Move the cursor to the beginning of the next line and resets text-attributes. + * It first completes the current line with the current text-attributes. */ +void gnt_text_view_next_line(GntTextView *view); + +chtype gnt_text_format_flag_to_chtype(GntTextFormatFlags flags); + +void gnt_text_view_clear(GntTextView *view); + +int gnt_text_view_get_lines_below(GntTextView *view); + +int gnt_text_view_get_lines_above(GntTextView *view); + +/* If text is NULL, then the tag is removed. */ +int gnt_text_view_tag_change(GntTextView *view, const char *name, const char *text, gboolean all); + +G_END_DECLS + +#endif /* GNT_TEXT_VIEW_H */ diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gnttree.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gnttree.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,1499 @@ +#include "gntmarshal.h" +#include "gntstyle.h" +#include "gnttree.h" +#include "gntutils.h" + +#include +#include + +#define SEARCH_TIMEOUT 4000 /* 4 secs */ + +enum +{ + SIG_SELECTION_CHANGED, + SIG_SCROLLED, + SIG_TOGGLED, + SIGS, +}; + +#define TAB_SIZE 3 + +/* XXX: Make this one into a GObject? + * ... Probably not */ +struct _GnTreeRow +{ + void *key; + void *data; /* XXX: unused */ + + gboolean collapsed; + gboolean choice; /* Is this a choice-box? + If choice is true, then child will be NULL */ + gboolean isselected; + GntTextFormatFlags flags; + + GntTreeRow *parent; + GntTreeRow *child; + GntTreeRow *next; + GntTreeRow *prev; + + GList *columns; + GntTree *tree; +}; + +struct _GnTreeCol +{ + char *text; + int span; /* How many columns does it span? */ +}; + +static GntWidgetClass *parent_class = NULL; +static guint signals[SIGS] = { 0 }; + +/* Move the item at position old to position new */ +static GList * +g_list_reposition_child(GList *list, int old, int new) +{ + gpointer item = g_list_nth_data(list, old); + list = g_list_remove(list, item); + if (old < new) + new--; /* because the positions would have shifted after removing the item */ + list = g_list_insert(list, item, new); + return list; +} + +static GntTreeRow * +_get_next(GntTreeRow *row, gboolean godeep) +{ + if (row == NULL) + return NULL; + if (godeep && row->child) + return row->child; + if (row->next) + return row->next; + return _get_next(row->parent, FALSE); +} + +static gboolean +row_matches_search(GntTreeRow *row) +{ + GntTree *t = row->tree; + if (t->search && t->search->len > 0) { + char *one = g_utf8_casefold(((GntTreeCol*)row->columns->data)->text, -1); + char *two = g_utf8_casefold(t->search->str, -1); + char *z = strstr(one, two); + g_free(one); + g_free(two); + if (z == NULL) + return FALSE; + } + return TRUE; +} + +static GntTreeRow * +get_next(GntTreeRow *row) +{ + if (row == NULL) + return NULL; + while ((row = _get_next(row, !row->collapsed)) != NULL) { + if (row_matches_search(row)) + break; + } + return row; +} + +/* Returns the n-th next row. If it doesn't exist, returns NULL */ +static GntTreeRow * +get_next_n(GntTreeRow *row, int n) +{ + while (row && n--) + row = get_next(row); + return row; +} + +/* Returns the n-th next row. If it doesn't exist, then the last non-NULL node */ +static GntTreeRow * +get_next_n_opt(GntTreeRow *row, int n, int *pos) +{ + GntTreeRow *next = row; + int r = 0; + + if (row == NULL) + return NULL; + + while (row && n--) + { + row = get_next(row); + if (row) + { + next = row; + r++; + } + } + + if (pos) + *pos = r; + + return next; +} + +static GntTreeRow * +get_last_child(GntTreeRow *row) +{ + if (row == NULL) + return NULL; + if (!row->collapsed && row->child) + row = row->child; + else + return row; + + while(row->next) + row = row->next; + if (!row->collapsed && row->child) + row = get_last_child(row->child); + return row; +} + +static GntTreeRow * +get_prev(GntTreeRow *row) +{ + if (row == NULL) + return NULL; + while (row) { + if (row->prev) + row = get_last_child(row->prev); + else + row = row->parent; + if (!row || row_matches_search(row)) + break; + } + return row; +} + +static GntTreeRow * +get_prev_n(GntTreeRow *row, int n) +{ + while (row && n--) + row = get_prev(row); + return row; +} + +/* Distance of row from the root */ +/* XXX: This is uber-inefficient */ +static int +get_root_distance(GntTreeRow *row) +{ + if (row == NULL) + return -1; + return get_root_distance(get_prev(row)) + 1; +} + +/* Returns the distance between a and b. + * If a is 'above' b, then the distance is positive */ +static int +get_distance(GntTreeRow *a, GntTreeRow *b) +{ + /* First get the distance from a to the root. + * Then the distance from b to the root. + * Subtract. + * It's not that good, but it works. */ + int ha = get_root_distance(a); + int hb = get_root_distance(b); + + return (hb - ha); +} + +static int +find_depth(GntTreeRow *row) +{ + int dep = -1; + + while (row) + { + dep++; + row = row->parent; + } + + return dep; +} + +static char * +update_row_text(GntTree *tree, GntTreeRow *row) +{ + GString *string = g_string_new(NULL); + GList *iter; + int i; + + for (i = 0, iter = row->columns; i < tree->ncol && iter; i++, iter = iter->next) + { + GntTreeCol *col = iter->data; + const char *text; + int len = gnt_util_onscreen_width(col->text, NULL); + int fl = 0; + gboolean cut = FALSE; + + if (i == 0) + { + if (row->choice) + { + g_string_append_printf(string, "[%c] ", + row->isselected ? 'X' : ' '); + fl = 4; + } + else if (row->parent == NULL && row->child) + { + if (row->collapsed) + { + string = g_string_append(string, "+ "); + } + else + { + string = g_string_append(string, "- "); + } + fl = 2; + } + else + { + fl = TAB_SIZE * find_depth(row); + g_string_append_printf(string, "%*s", fl, ""); + } + len += fl; + } + else + g_string_append_c(string, '|'); + + if (len > tree->columns[i].width) { + len = tree->columns[i].width - 1; + cut = TRUE; + } + text = gnt_util_onscreen_width_to_pointer(col->text, len - fl, NULL); + string = g_string_append_len(string, col->text, text - col->text); + if (cut) { /* ellipsis */ + if (gnt_ascii_only()) + g_string_append_c(string, '~'); + else + string = g_string_append(string, "\342\200\246"); + len++; + } + + if (len < tree->columns[i].width && iter->next) + g_string_append_printf(string, "%*s", tree->columns[i].width - len, ""); + } + return g_string_free(string, FALSE); +} + +static void +tree_mark_columns(GntTree *tree, int pos, int y, chtype type) +{ + GntWidget *widget = GNT_WIDGET(tree); + int i; + int x = pos; + + for (i = 0; i < tree->ncol - 1; i++) + { + x += tree->columns[i].width; + mvwaddch(widget->window, y, x + i, type); + } +} + +static void +redraw_tree(GntTree *tree) +{ + int start, i; + GntWidget *widget = GNT_WIDGET(tree); + GntTreeRow *row; + int pos, up, down; + int rows, scrcol; + + if (!GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(tree), GNT_WIDGET_MAPPED)) + return; + + if (GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER)) + pos = 0; + else + pos = 1; + + if (tree->top == NULL) + tree->top = tree->root; + if (tree->current == NULL) + tree->current = tree->root; + + wbkgd(widget->window, COLOR_PAIR(GNT_COLOR_NORMAL)); + + start = 0; + if (tree->show_title) + { + int i; + int x = pos; + + mvwhline(widget->window, pos + 1, pos, ACS_HLINE | COLOR_PAIR(GNT_COLOR_NORMAL), + widget->priv.width - pos - 1); + + for (i = 0; i < tree->ncol; i++) + { + mvwaddstr(widget->window, pos, x + i, tree->columns[i].title); + x += tree->columns[i].width; + } + if (pos) + { + tree_mark_columns(tree, pos, 0, ACS_TTEE | COLOR_PAIR(GNT_COLOR_NORMAL)); + tree_mark_columns(tree, pos, widget->priv.height - pos, + ACS_BTEE | COLOR_PAIR(GNT_COLOR_NORMAL)); + } + tree_mark_columns(tree, pos, pos + 1, + (tree->show_separator ? ACS_PLUS : ACS_HLINE) | COLOR_PAIR(GNT_COLOR_NORMAL)); + tree_mark_columns(tree, pos, pos, + (tree->show_separator ? ACS_VLINE : ' ') | COLOR_PAIR(GNT_COLOR_NORMAL)); + start = 2; + } + + rows = widget->priv.height - pos * 2 - start - 1; + tree->bottom = get_next_n_opt(tree->top, rows, &down); + if (down < rows) + { + tree->top = get_prev_n(tree->bottom, rows); + if (tree->top == NULL) + tree->top = tree->root; + } + + up = get_distance(tree->top, tree->current); + if (up < 0) + tree->top = tree->current; + else if (up >= widget->priv.height - pos) + tree->top = get_prev_n(tree->current, rows); + + if (tree->top && !row_matches_search(tree->top)) + tree->top = get_next(tree->top); + row = tree->top; + scrcol = widget->priv.width - 1 - 2 * pos; /* exclude the borders and the scrollbar */ + for (i = start + pos; row && i < widget->priv.height - pos; + i++, row = get_next(row)) + { + char *str; + int wr; + + GntTextFormatFlags flags = row->flags; + int attr = 0; + + if (!row_matches_search(row)) + continue; + str = update_row_text(tree, row); + + if ((wr = gnt_util_onscreen_width(str, NULL)) > scrcol) + { + char *s = (char*)gnt_util_onscreen_width_to_pointer(str, scrcol, &wr); + *s = '\0'; + } + + if (flags & GNT_TEXT_FLAG_BOLD) + attr |= A_BOLD; + if (flags & GNT_TEXT_FLAG_UNDERLINE) + attr |= A_UNDERLINE; + if (flags & GNT_TEXT_FLAG_BLINK) + attr |= A_BLINK; + + if (row == tree->current) + { + if (gnt_widget_has_focus(widget)) + attr |= COLOR_PAIR(GNT_COLOR_HIGHLIGHT); + else + attr |= COLOR_PAIR(GNT_COLOR_HIGHLIGHT_D); + } + else + { + if (flags & GNT_TEXT_FLAG_DIM) + attr |= (A_DIM | COLOR_PAIR(GNT_COLOR_DISABLED)); + else if (flags & GNT_TEXT_FLAG_HIGHLIGHT) + attr |= (A_DIM | COLOR_PAIR(GNT_COLOR_HIGHLIGHT)); + else + attr |= COLOR_PAIR(GNT_COLOR_NORMAL); + } + + wbkgdset(widget->window, '\0' | attr); + mvwaddstr(widget->window, i, pos, str); + whline(widget->window, ' ', scrcol - wr); + tree->bottom = row; + g_free(str); + tree_mark_columns(tree, pos, i, + (tree->show_separator ? ACS_VLINE : ' ') | attr); + } + + wbkgdset(widget->window, '\0' | COLOR_PAIR(GNT_COLOR_NORMAL)); + while (i < widget->priv.height - pos) + { + mvwhline(widget->window, i, pos, ' ', + widget->priv.width - pos * 2 - 1); + tree_mark_columns(tree, pos, i, + (tree->show_separator ? ACS_VLINE : ' ')); + i++; + } + + scrcol = widget->priv.width - pos - 1; /* position of the scrollbar */ + rows--; + if (rows > 0) + { + int total; + int showing, position; + + get_next_n_opt(tree->root, g_list_length(tree->list), &total); + showing = rows * rows / MAX(total, 1) + 1; + showing = MIN(rows, showing); + + total -= rows; + up = get_distance(tree->root, tree->top); + down = total - up; + + position = (rows - showing) * up / MAX(1, up + down); + position = MAX((tree->top != tree->root), position); + + if (showing + position > rows) + position = rows - showing; + + if (showing + position == rows && row) + position = MAX(0, rows - 1 - showing); + else if (showing + position < rows && !row) + position = rows - showing; + + position += pos + start + 1; + + mvwvline(widget->window, pos + start + 1, scrcol, + ' ' | COLOR_PAIR(GNT_COLOR_NORMAL), rows); + mvwvline(widget->window, position, scrcol, + ACS_CKBOARD | COLOR_PAIR(GNT_COLOR_HIGHLIGHT_D), showing); + } + + mvwaddch(widget->window, start + pos, scrcol, + ((tree->top != tree->root) ? ACS_UARROW : ' ') | + COLOR_PAIR(GNT_COLOR_HIGHLIGHT_D)); + + mvwaddch(widget->window, widget->priv.height - pos - 1, scrcol, + (row ? ACS_DARROW : ' ') | COLOR_PAIR(GNT_COLOR_HIGHLIGHT_D)); + + gnt_widget_queue_update(widget); +} + +static void +gnt_tree_draw(GntWidget *widget) +{ + GntTree *tree = GNT_TREE(widget); + + redraw_tree(tree); + + GNTDEBUG; +} + +static void +gnt_tree_size_request(GntWidget *widget) +{ + if (widget->priv.height == 0) + widget->priv.height = 10; /* XXX: Why?! */ + if (widget->priv.width == 0) + { + GntTree *tree = GNT_TREE(widget); + int i, width = 0; + for (i = 0; i < tree->ncol; i++) + width += tree->columns[i].width; + widget->priv.width = width + i; + } +} + +static void +gnt_tree_map(GntWidget *widget) +{ + GntTree *tree = GNT_TREE(widget); + if (widget->priv.width == 0 || widget->priv.height == 0) + { + gnt_widget_size_request(widget); + } + tree->top = tree->root; + tree->current = tree->root; + GNTDEBUG; +} + +static void +tree_selection_changed(GntTree *tree, GntTreeRow *old, GntTreeRow *current) +{ + g_signal_emit(tree, signals[SIG_SELECTION_CHANGED], 0, old ? old->key : NULL, + current ? current->key : NULL); +} + +static gboolean +action_down(GntBindable *bind, GList *null) +{ + int dist; + GntTree *tree = GNT_TREE(bind); + GntTreeRow *old = tree->current; + GntTreeRow *row = get_next(tree->current); + if (row == NULL) + return FALSE; + tree->current = row; + if ((dist = get_distance(tree->current, tree->bottom)) < 0) + gnt_tree_scroll(tree, -dist); + else + redraw_tree(tree); + if (old != tree->current) + tree_selection_changed(tree, old, tree->current); + return TRUE; +} + +static gboolean +action_up(GntBindable *bind, GList *list) +{ + int dist; + GntTree *tree = GNT_TREE(bind); + GntTreeRow *old = tree->current; + GntTreeRow *row = get_prev(tree->current); + if (!row) + return FALSE; + tree->current = row; + if ((dist = get_distance(tree->current, tree->top)) > 0) + gnt_tree_scroll(tree, -dist); + else + redraw_tree(tree); + if (old != tree->current) + tree_selection_changed(tree, old, tree->current); + + return TRUE; +} + +static gboolean +action_page_down(GntBindable *bind, GList *null) +{ + GntTree *tree = GNT_TREE(bind); + GntTreeRow *old = tree->current; + GntTreeRow *row = get_next(tree->bottom); + if (row) + { + int dist = get_distance(tree->top, tree->current); + tree->top = tree->bottom; + tree->current = get_next_n_opt(tree->top, dist, NULL); + redraw_tree(tree); + } + else if (tree->current != tree->bottom) + { + tree->current = tree->bottom; + redraw_tree(tree); + } + + if (old != tree->current) + tree_selection_changed(tree, old, tree->current); + return TRUE; +} + +static gboolean +action_page_up(GntBindable *bind, GList *null) +{ + GntWidget *widget = GNT_WIDGET(bind); + GntTree *tree = GNT_TREE(bind); + GntTreeRow *row; + GntTreeRow *old = tree->current; + + if (tree->top != tree->root) + { + int dist = get_distance(tree->top, tree->current); + row = get_prev_n(tree->top, widget->priv.height - 1 - + tree->show_title * 2 - 2 * (GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER) == 0)); + if (row == NULL) + row = tree->root; + tree->top = row; + tree->current = get_next_n_opt(tree->top, dist, NULL); + redraw_tree(tree); + } + else if (tree->current != tree->top) + { + tree->current = tree->top; + redraw_tree(tree); + } + if (old != tree->current) + tree_selection_changed(tree, old, tree->current); + return TRUE; +} + +static void +end_search(GntTree *tree) +{ + if (tree->search) { + g_source_remove(tree->search_timeout); + g_string_free(tree->search, TRUE); + tree->search = NULL; + tree->search_timeout = 0; + } +} + +static gboolean +search_timeout(gpointer data) +{ + GntTree *tree = data; + + end_search(tree); + redraw_tree(tree); + + return FALSE; +} + +static gboolean +gnt_tree_key_pressed(GntWidget *widget, const char *text) +{ + GntTree *tree = GNT_TREE(widget); + GntTreeRow *old = tree->current; + + if (text[0] == '\r') { + end_search(tree); + gnt_widget_activate(widget); + } else if (tree->search) { + if (isalnum(*text)) { + tree->search = g_string_append_c(tree->search, *text); + redraw_tree(tree); + g_source_remove(tree->search_timeout); + tree->search_timeout = g_timeout_add(SEARCH_TIMEOUT, search_timeout, tree); + } + return TRUE; + } else if (text[0] == ' ' && text[1] == 0) { + /* Space pressed */ + GntTreeRow *row = tree->current; + if (row && row->child) + { + row->collapsed = !row->collapsed; + redraw_tree(tree); + } + else if (row && row->choice) + { + row->isselected = !row->isselected; + g_signal_emit(tree, signals[SIG_TOGGLED], 0, row->key); + redraw_tree(tree); + } + } + + if (old != tree->current) + { + tree_selection_changed(tree, old, tree->current); + return TRUE; + } + + return FALSE; +} + +static void +gnt_tree_destroy(GntWidget *widget) +{ + GntTree *tree = GNT_TREE(widget); + int i; + + end_search(tree); + if (tree->hash) + g_hash_table_destroy(tree->hash); + g_list_free(tree->list); + + for (i = 0; i < tree->ncol; i++) + { + g_free(tree->columns[i].title); + } + g_free(tree->columns); +} + +static gboolean +gnt_tree_clicked(GntWidget *widget, GntMouseEvent event, int x, int y) +{ + GntTree *tree = GNT_TREE(widget); + GntTreeRow *old = tree->current; + if (event == GNT_MOUSE_SCROLL_UP) { + action_up(GNT_BINDABLE(widget), NULL); + } else if (event == GNT_MOUSE_SCROLL_DOWN) { + action_down(GNT_BINDABLE(widget), NULL); + } else if (event == GNT_LEFT_MOUSE_DOWN) { + GntTreeRow *row; + GntTree *tree = GNT_TREE(widget); + int pos = 1; + if (GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER)) + pos = 0; + if (tree->show_title) + pos += 2; + pos = y - widget->priv.y - pos; + row = get_next_n(tree->top, pos); + if (row && tree->current != row) { + GntTreeRow *old = tree->current; + tree->current = row; + redraw_tree(tree); + tree_selection_changed(tree, old, tree->current); + } else if (row && row == tree->current) { + if (row->choice) { + row->isselected = !row->isselected; + g_signal_emit(tree, signals[SIG_TOGGLED], 0, row->key); + redraw_tree(tree); + } else { + gnt_widget_activate(widget); + } + } + } else { + return FALSE; + } + if (old != tree->current) { + tree_selection_changed(tree, old, tree->current); + } + return TRUE; +} + +static void +gnt_tree_size_changed(GntWidget *widget, int w, int h) +{ + GntTree *tree = GNT_TREE(widget); + int i; + int n = 0; + if (widget->priv.width <= 0) + return; + for (i = 0; i < tree->ncol; ++i) + n += tree->columns[i].width; + if (GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER)) + tree->columns[tree->ncol - 1].width += widget->priv.width - n - 1 * tree->ncol; + else + tree->columns[tree->ncol - 1].width += widget->priv.width - n - 2 - 1 * tree->ncol; +} + +static gboolean +start_search(GntBindable *bindable, GList *list) +{ + GntTree *tree = GNT_TREE(bindable); + if (tree->search) + return FALSE; + tree->search = g_string_new(NULL); + tree->search_timeout = g_timeout_add(SEARCH_TIMEOUT, search_timeout, tree); + return TRUE; +} + +static gboolean +end_search_action(GntBindable *bindable, GList *list) +{ + GntTree *tree = GNT_TREE(bindable); + if (tree->search == NULL) + return FALSE; + end_search(tree); + redraw_tree(tree); + return TRUE; +} + +static void +gnt_tree_class_init(GntTreeClass *klass) +{ + GntBindableClass *bindable = GNT_BINDABLE_CLASS(klass); + parent_class = GNT_WIDGET_CLASS(klass); + parent_class->destroy = gnt_tree_destroy; + parent_class->draw = gnt_tree_draw; + parent_class->map = gnt_tree_map; + parent_class->size_request = gnt_tree_size_request; + parent_class->key_pressed = gnt_tree_key_pressed; + parent_class->clicked = gnt_tree_clicked; + parent_class->size_changed = gnt_tree_size_changed; + + signals[SIG_SELECTION_CHANGED] = + g_signal_new("selection-changed", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GntTreeClass, selection_changed), + NULL, NULL, + gnt_closure_marshal_VOID__POINTER_POINTER, + G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER); + signals[SIG_SCROLLED] = + g_signal_new("scrolled", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__INT, + G_TYPE_NONE, 1, G_TYPE_INT); + signals[SIG_TOGGLED] = + g_signal_new("toggled", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GntTreeClass, toggled), + NULL, NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, 1, G_TYPE_POINTER); + + gnt_bindable_class_register_action(bindable, "move-up", action_up, + GNT_KEY_UP, NULL); + gnt_bindable_register_binding(bindable, "move-up", GNT_KEY_CTRL_P, NULL); + 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, "page-up", action_page_up, + GNT_KEY_PGUP, NULL); + gnt_bindable_class_register_action(bindable, "page-down", action_page_down, + GNT_KEY_PGDOWN, NULL); + gnt_bindable_class_register_action(bindable, "start-search", start_search, + "/", NULL); + gnt_bindable_class_register_action(bindable, "end-search", end_search_action, + "\033", NULL); + + gnt_style_read_actions(G_OBJECT_CLASS_TYPE(klass), bindable); + GNTDEBUG; +} + +static void +gnt_tree_init(GTypeInstance *instance, gpointer class) +{ + GntWidget *widget = GNT_WIDGET(instance); + GntTree *tree = GNT_TREE(widget); + tree->show_separator = TRUE; + GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_GROW_X | GNT_WIDGET_GROW_Y); + widget->priv.minw = 4; + widget->priv.minh = 1; + GNTDEBUG; +} + +/****************************************************************************** + * GntTree API + *****************************************************************************/ +GType +gnt_tree_get_gtype(void) +{ + static GType type = 0; + + if(type == 0) + { + static const GTypeInfo info = { + sizeof(GntTreeClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc)gnt_tree_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof(GntTree), + 0, /* n_preallocs */ + gnt_tree_init, /* instance_init */ + NULL /* value_table */ + }; + + type = g_type_register_static(GNT_TYPE_WIDGET, + "GntTree", + &info, 0); + } + + return type; +} + +static void +free_tree_col(gpointer data) +{ + GntTreeCol *col = data; + + g_free(col->text); + g_free(col); +} + +static void +free_tree_row(gpointer data) +{ + GntTreeRow *row = data; + + if (!row) + return; + + g_list_foreach(row->columns, (GFunc)free_tree_col, NULL); + g_list_free(row->columns); + g_free(row); +} + +GntWidget *gnt_tree_new() +{ + return gnt_tree_new_with_columns(1); +} + +void gnt_tree_set_visible_rows(GntTree *tree, int rows) +{ + GntWidget *widget = GNT_WIDGET(tree); + widget->priv.height = rows; + if (!GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER)) + widget->priv.height += 2; +} + +int gnt_tree_get_visible_rows(GntTree *tree) +{ + GntWidget *widget = GNT_WIDGET(tree); + int ret = widget->priv.height; + if (!GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER)) + ret -= 2; + return ret; +} + +const GList *gnt_tree_get_rows(GntTree *tree) +{ + return tree->list; +} + +void gnt_tree_scroll(GntTree *tree, int count) +{ + GntTreeRow *row; + + if (count < 0) + { + if (get_root_distance(tree->top) == 0) + return; + row = get_prev_n(tree->top, -count); + if (row == NULL) + row = tree->root; + tree->top = row; + } + else + { + get_next_n_opt(tree->bottom, count, &count); + tree->top = get_next_n(tree->top, count); + } + + redraw_tree(tree); + g_signal_emit(tree, signals[SIG_SCROLLED], 0, count); +} + +static gpointer +find_position(GntTree *tree, gpointer key, gpointer parent) +{ + GntTreeRow *row; + + if (tree->compare == NULL) + return NULL; + + if (parent == NULL) + row = tree->root; + else + row = g_hash_table_lookup(tree->hash, parent); + + if (!row) + return NULL; + + if (parent) + row = row->child; + + while (row) + { + if (tree->compare(key, row->key) < 0) + return (row->prev ? row->prev->key : NULL); + if (row->next) + row = row->next; + else + return row->key; + } + return NULL; +} + +void gnt_tree_sort_row(GntTree *tree, gpointer key) +{ + GntTreeRow *row, *q, *s; + int current, newp; + + if (!tree->compare) + return; + + row = g_hash_table_lookup(tree->hash, key); + g_return_if_fail(row != NULL); + + current = g_list_index(tree->list, key); + + if (row->parent) + s = row->parent->child; + else + s = tree->root; + + q = NULL; + while (s) { + if (tree->compare(row->key, s->key) < 0) + break; + q = s; + s = s->next; + } + + /* Move row between q and s */ + if (row == q || row == s) + return; + + if (q == NULL) { + /* row becomes the first child of its parent */ + row->prev->next = row->next; /* row->prev cannot be NULL at this point */ + if (row->next) + row->next->prev = row->prev; + if (row->parent) + row->parent->child = row; + else + tree->root = row; + row->next = s; + s->prev = row; /* s cannot be NULL */ + row->prev = NULL; + newp = g_list_index(tree->list, s) - 1; + } else { + if (row->prev) { + row->prev->next = row->next; + } else { + /* row was the first child of its parent */ + if (row->parent) + row->parent->child = row->next; + else + tree->top = row->next; + } + + if (row->next) + row->next->prev = row->prev; + + q->next = row; + row->prev = q; + if (s) + s->prev = row; + row->next = s; + newp = g_list_index(tree->list, q) + 1; + } + tree->list = g_list_reposition_child(tree->list, current, newp); + + redraw_tree(tree); +} + +GntTreeRow *gnt_tree_add_row_after(GntTree *tree, void *key, GntTreeRow *row, void *parent, void *bigbro) +{ + GntTreeRow *pr = NULL; + + g_hash_table_replace(tree->hash, key, row); + row->tree = tree; + + if (bigbro == NULL && tree->compare) + { + bigbro = find_position(tree, key, parent); + } + + if (tree->root == NULL) + { + tree->root = row; + tree->list = g_list_prepend(tree->list, key); + } + else + { + int position = 0; + + if (bigbro) + { + pr = g_hash_table_lookup(tree->hash, bigbro); + if (pr) + { + if (pr->next) pr->next->prev = row; + row->next = pr->next; + row->prev = pr; + pr->next = row; + row->parent = pr->parent; + + position = g_list_index(tree->list, bigbro); + } + } + + if (pr == NULL && parent) + { + pr = g_hash_table_lookup(tree->hash, parent); + if (pr) + { + if (pr->child) pr->child->prev = row; + row->next = pr->child; + pr->child = row; + row->parent = pr; + + position = g_list_index(tree->list, parent); + } + } + + if (pr == NULL) + { + GntTreeRow *r = tree->root; + row->next = r; + if (r) r->prev = row; + if (tree->current == tree->root) + tree->current = row; + tree->root = row; + tree->list = g_list_prepend(tree->list, key); + } + else + { + tree->list = g_list_insert(tree->list, key, position + 1); + } + } + + row->key = key; + row->data = NULL; + + redraw_tree(tree); + + return row; +} + +GntTreeRow *gnt_tree_add_row_last(GntTree *tree, void *key, GntTreeRow *row, void *parent) +{ + GntTreeRow *pr = NULL, *br = NULL; + + if (parent) + pr = g_hash_table_lookup(tree->hash, parent); + + if (pr) + br = pr->child; + else + br = tree->root; + + if (br) + { + while (br->next) + br = br->next; + } + + return gnt_tree_add_row_after(tree, key, row, parent, br ? br->key : NULL); +} + +gpointer gnt_tree_get_selection_data(GntTree *tree) +{ + if (tree->current) + return tree->current->key; /* XXX: perhaps we should just get rid of 'data' */ + return NULL; +} + +char *gnt_tree_get_selection_text(GntTree *tree) +{ + if (tree->current) + return update_row_text(tree, tree->current); + return NULL; +} + +GList *gnt_tree_get_selection_text_list(GntTree *tree) +{ + GList *list = NULL, *iter; + int i; + + if (!tree->current) + return NULL; + + for (i = 0, iter = tree->current->columns; i < tree->ncol && iter; + i++, iter = iter->next) + { + GntTreeCol *col = iter->data; + list = g_list_append(list, g_strdup(col->text)); + } + + return list; +} + +void gnt_tree_remove(GntTree *tree, gpointer key) +{ + GntTreeRow *row = g_hash_table_lookup(tree->hash, key); + static int depth = 0; /* Only redraw after all child nodes are removed */ + if (row) + { + gboolean redraw = FALSE; + + if (row->child) { + depth++; + while (row->child) { + gnt_tree_remove(tree, row->child->key); + } + depth--; + } + + if (get_distance(tree->top, row) >= 0 && get_distance(row, tree->bottom) >= 0) + redraw = TRUE; + + /* Update root/top/current/bottom if necessary */ + if (tree->root == row) + tree->root = get_next(row); + if (tree->top == row) + { + if (tree->top != tree->root) + tree->top = get_prev(row); + else + tree->top = get_next(row); + } + if (tree->current == row) + { + if (tree->current != tree->root) + tree->current = get_prev(row); + else + tree->current = get_next(row); + tree_selection_changed(tree, row, tree->current); + } + if (tree->bottom == row) + { + tree->bottom = get_prev(row); + } + + /* Fix the links */ + if (row->next) + row->next->prev = row->prev; + if (row->parent && row->parent->child == row) + row->parent->child = row->next; + if (row->prev) + row->prev->next = row->next; + + g_hash_table_remove(tree->hash, key); + tree->list = g_list_remove(tree->list, key); + + if (redraw && depth == 0) + { + redraw_tree(tree); + } + } +} + +static gboolean +return_true(gpointer key, gpointer data, gpointer null) +{ + return TRUE; +} + +void gnt_tree_remove_all(GntTree *tree) +{ + tree->root = NULL; + g_hash_table_foreach_remove(tree->hash, (GHRFunc)return_true, tree); + g_list_free(tree->list); + tree->list = NULL; + tree->current = tree->top = tree->bottom = NULL; +} + +int gnt_tree_get_selection_visible_line(GntTree *tree) +{ + return get_distance(tree->top, tree->current) + + !!(GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(tree), GNT_WIDGET_NO_BORDER)); +} + +void gnt_tree_change_text(GntTree *tree, gpointer key, int colno, const char *text) +{ + GntTreeRow *row; + GntTreeCol *col; + + g_return_if_fail(colno < tree->ncol); + + row = g_hash_table_lookup(tree->hash, key); + if (row) + { + col = g_list_nth_data(row->columns, colno); + g_free(col->text); + col->text = g_strdup(text); + + if (get_distance(tree->top, row) >= 0 && get_distance(row, tree->bottom) >= 0) + redraw_tree(tree); + } +} + +GntTreeRow *gnt_tree_add_choice(GntTree *tree, void *key, GntTreeRow *row, void *parent, void *bigbro) +{ + GntTreeRow *r; + r = g_hash_table_lookup(tree->hash, key); + g_return_val_if_fail(!r || !r->choice, NULL); + + if (bigbro == NULL) { + if (tree->compare) + bigbro = find_position(tree, key, parent); + else { + r = g_hash_table_lookup(tree->hash, parent); + if (!r) + r = tree->root; + else + r = r->child; + if (r) { + while (r->next) + r = r->next; + bigbro = r->key; + } + } + } + row = gnt_tree_add_row_after(tree, key, row, parent, bigbro); + row->choice = TRUE; + + return row; +} + +void gnt_tree_set_choice(GntTree *tree, void *key, gboolean set) +{ + GntTreeRow *row = g_hash_table_lookup(tree->hash, key); + + if (!row) + return; + g_return_if_fail(row->choice); + + row->isselected = set; + redraw_tree(tree); +} + +gboolean gnt_tree_get_choice(GntTree *tree, void *key) +{ + GntTreeRow *row = g_hash_table_lookup(tree->hash, key); + + if (!row) + return FALSE; + g_return_val_if_fail(row->choice, FALSE); + + return row->isselected; +} + +void gnt_tree_set_row_flags(GntTree *tree, void *key, GntTextFormatFlags flags) +{ + GntTreeRow *row = g_hash_table_lookup(tree->hash, key); + if (!row || row->flags == flags) + return; + + row->flags = flags; + redraw_tree(tree); /* XXX: It shouldn't be necessary to redraw the whole darned tree */ +} + +void gnt_tree_set_selected(GntTree *tree , void *key) +{ + int dist; + GntTreeRow *row = g_hash_table_lookup(tree->hash, key); + if (!row) + return; + + if (tree->top == NULL) + tree->top = row; + if (tree->bottom == NULL) + tree->bottom = row; + + tree->current = row; + if ((dist = get_distance(tree->current, tree->bottom)) < 0) + gnt_tree_scroll(tree, -dist); + else if ((dist = get_distance(tree->current, tree->top)) > 0) + gnt_tree_scroll(tree, -dist); + else + redraw_tree(tree); +} + +void _gnt_tree_init_internals(GntTree *tree, int col) +{ + tree->ncol = col; + tree->hash = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, free_tree_row); + tree->columns = g_new0(struct _GntTreeColInfo, col); + while (col--) + { + tree->columns[col].width = 15; + } + tree->list = NULL; + tree->show_title = FALSE; +} + +GntWidget *gnt_tree_new_with_columns(int col) +{ + GntWidget *widget = g_object_new(GNT_TYPE_TREE, NULL); + GntTree *tree = GNT_TREE(widget); + + _gnt_tree_init_internals(tree, col); + + GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_NO_SHADOW); + gnt_widget_set_take_focus(widget, TRUE); + + return widget; +} + +GntTreeRow *gnt_tree_create_row_from_list(GntTree *tree, GList *list) +{ + GList *iter; + int i; + GntTreeRow *row = g_new0(GntTreeRow, 1); + + for (i = 0, iter = list; i < tree->ncol && iter; iter = iter->next, i++) + { + GntTreeCol *col = g_new0(GntTreeCol, 1); + col->span = 1; + col->text = g_strdup(iter->data ? iter->data : ""); + + row->columns = g_list_append(row->columns, col); + } + + return row; +} + +GntTreeRow *gnt_tree_create_row(GntTree *tree, ...) +{ + int i; + va_list args; + GList *list = NULL; + GntTreeRow *row; + + va_start(args, tree); + for (i = 0; i < tree->ncol; i++) + { + list = g_list_append(list, va_arg(args, char *)); + } + va_end(args); + + row = gnt_tree_create_row_from_list(tree, list); + g_list_free(list); + + return row; +} + +void gnt_tree_set_col_width(GntTree *tree, int col, int width) +{ + g_return_if_fail(col < tree->ncol); + + tree->columns[col].width = width; +} + +void gnt_tree_set_column_titles(GntTree *tree, ...) +{ + int i; + va_list args; + + va_start(args, tree); + for (i = 0; i < tree->ncol; i++) + { + const char *title = va_arg(args, const char *); + tree->columns[i].title = g_strdup(title); + } + va_end(args); +} + +void gnt_tree_set_show_title(GntTree *tree, gboolean set) +{ + tree->show_title = set; + GNT_WIDGET(tree)->priv.minh = (set ? 6 : 4); +} + +void gnt_tree_set_compare_func(GntTree *tree, GCompareFunc func) +{ + tree->compare = func; +} + +void gnt_tree_set_expanded(GntTree *tree, void *key, gboolean expanded) +{ + GntTreeRow *row = g_hash_table_lookup(tree->hash, key); + if (row) { + row->collapsed = !expanded; + if (GNT_WIDGET(tree)->window) + gnt_widget_draw(GNT_WIDGET(tree)); + } +} + +void gnt_tree_set_show_separator(GntTree *tree, gboolean set) +{ + tree->show_separator = set; +} + +void gnt_tree_adjust_columns(GntTree *tree) +{ + GntTreeRow *row = tree->root; + int *widths, i, twidth, height; + + widths = g_new0(int, tree->ncol); + while (row) { + GList *iter; + for (i = 0, iter = row->columns; iter; iter = iter->next, i++) { + GntTreeCol *col = iter->data; + int w = gnt_util_onscreen_width(col->text, NULL); + if (widths[i] < w) + widths[i] = w; + } + row = row->next; + } + + twidth = 1 + 2 * (!GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(tree), GNT_WIDGET_NO_BORDER)); + for (i = 0; i < tree->ncol; i++) { + gnt_tree_set_col_width(tree, i, widths[i]); + twidth += widths[i] + (tree->show_separator ? 1 : 0) + 1; + } + g_free(widths); + + gnt_widget_get_size(GNT_WIDGET(tree), NULL, &height); + gnt_widget_set_size(GNT_WIDGET(tree), twidth, height); +} + +void gnt_tree_set_hash_fns(GntTree *tree, gpointer hash, gpointer eq, gpointer kd) +{ + g_hash_table_foreach_remove(tree->hash, return_true, NULL); + g_hash_table_destroy(tree->hash); + tree->hash = g_hash_table_new_full(hash, eq, kd, free_tree_row); +} + diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gnttree.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gnttree.h Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,150 @@ +#ifndef GNT_TREE_H +#define GNT_TREE_H + +#include "gntwidget.h" +#include "gnt.h" +#include "gntcolors.h" +#include "gntkeys.h" +#include "gnttextview.h" + +#define GNT_TYPE_TREE (gnt_tree_get_gtype()) +#define GNT_TREE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNT_TYPE_TREE, GntTree)) +#define GNT_TREE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GNT_TYPE_TREE, GntTreeClass)) +#define GNT_IS_TREE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GNT_TYPE_TREE)) +#define GNT_IS_TREE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GNT_TYPE_TREE)) +#define GNT_TREE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GNT_TYPE_TREE, GntTreeClass)) + +#define GNT_TREE_FLAGS(obj) (GNT_TREE(obj)->priv.flags) +#define GNT_TREE_SET_FLAGS(obj, flags) (GNT_TREE_FLAGS(obj) |= flags) +#define GNT_TREE_UNSET_FLAGS(obj, flags) (GNT_TREE_FLAGS(obj) &= ~(flags)) + +typedef struct _GnTree GntTree; +typedef struct _GnTreePriv GntTreePriv; +typedef struct _GnTreeClass GntTreeClass; + +typedef struct _GnTreeRow GntTreeRow; +typedef struct _GnTreeCol GntTreeCol; + +struct _GnTree +{ + GntWidget parent; + + GntTreeRow *current; /* current selection */ + + GntTreeRow *top; /* The topmost visible item */ + GntTreeRow *bottom; /* The bottommost visible item */ + + GntTreeRow *root; /* The root of all evil */ + + GList *list; /* List of GntTreeRow s */ + GHashTable *hash; /* We need this for quickly referencing the rows */ + guint (*hash_func)(gconstpointer); + gboolean (*hash_eq_func)(gconstpointer, gconstpointer); + GDestroyNotify key_destroy; + GDestroyNotify value_destroy; + + int ncol; /* No. of columns */ + struct _GntTreeColInfo + { + int width; + char *title; + } *columns; /* Would a GList be better? */ + gboolean show_title; + gboolean show_separator; /* Whether to show column separators */ + + GString *search; + int search_timeout; + + GCompareFunc compare; +}; + +struct _GnTreeClass +{ + GntWidgetClass parent; + + void (*selection_changed)(GntTreeRow *old, GntTreeRow * current); + void (*toggled)(GntTree *tree, gpointer key); + + void (*gnt_reserved1)(void); + void (*gnt_reserved2)(void); + void (*gnt_reserved3)(void); + void (*gnt_reserved4)(void); +}; + +G_BEGIN_DECLS + +GType gnt_tree_get_gtype(void); + +GntWidget *gnt_tree_new(void); /* A tree with just one column */ + +GntWidget *gnt_tree_new_with_columns(int columns); + +void gnt_tree_set_visible_rows(GntTree *tree, int rows); + +int gnt_tree_get_visible_rows(GntTree *tree); + +void gnt_tree_scroll(GntTree *tree, int count); + +GntTreeRow *gnt_tree_add_row_after(GntTree *tree, void *key, GntTreeRow *row, void *parent, void *bigbro); + +GntTreeRow *gnt_tree_add_row_last(GntTree *tree, void *key, GntTreeRow *row, void *parent); + +gpointer gnt_tree_get_selection_data(GntTree *tree); + +/* Returned string needs to be freed */ +char *gnt_tree_get_selection_text(GntTree *tree); + +GList *gnt_tree_get_selection_text_list(GntTree *tree); + +const GList *gnt_tree_get_rows(GntTree *tree); + +void gnt_tree_remove(GntTree *tree, gpointer key); + +void gnt_tree_remove_all(GntTree *tree); + +/* Returns the visible line number of the selected row */ +int gnt_tree_get_selection_visible_line(GntTree *tree); + +void gnt_tree_change_text(GntTree *tree, gpointer key, int colno, const char *text); + +GntTreeRow *gnt_tree_add_choice(GntTree *tree, void *key, GntTreeRow *row, void *parent, void *bigbro); + +void gnt_tree_set_choice(GntTree *tree, void *key, gboolean set); + +gboolean gnt_tree_get_choice(GntTree *tree, void *key); + +void gnt_tree_set_row_flags(GntTree *tree, void *key, GntTextFormatFlags flags); + +void gnt_tree_set_selected(GntTree *tree , void *key); + +GntTreeRow *gnt_tree_create_row(GntTree *tree, ...); + +GntTreeRow *gnt_tree_create_row_from_list(GntTree *tree, GList *list); + +void gnt_tree_set_col_width(GntTree *tree, int col, int width); + +void gnt_tree_set_column_titles(GntTree *tree, ...); + +void gnt_tree_set_show_title(GntTree *tree, gboolean set); + +void gnt_tree_set_compare_func(GntTree *tree, GCompareFunc func); + +void gnt_tree_set_expanded(GntTree *tree, void *key, gboolean expanded); + +void gnt_tree_set_show_separator(GntTree *tree, gboolean set); + +void gnt_tree_sort_row(GntTree *tree, void *row); + +/* This will try to automatically adjust the width of the columns in the tree */ +void gnt_tree_adjust_columns(GntTree *tree); + +void gnt_tree_set_hash_fns(GntTree *tree, gpointer hash, gpointer eq, gpointer kd); + +G_END_DECLS + +/* The following functions should NOT be used by applications. */ + +/* This should be called by the subclasses of GntTree's in their _new function */ +void _gnt_tree_init_internals(GntTree *tree, int col); + +#endif /* GNT_TREE_H */ diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gntutils.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gntutils.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,147 @@ +#include "gntutils.h" + +#include +#include + +#include "config.h" + +void gnt_util_get_text_bound(const char *text, int *width, int *height) +{ + const char *s = text, *last; + int count = 1, max = 0; + int len; + + /* XXX: ew ... everyone look away */ + last = s; + if (s) + { + while (*s) + { + if (*s == '\n' || *s == '\r') + { + count++; + len = gnt_util_onscreen_width(last, s); + if (max < len) + max = len; + last = s + 1; + } + s = g_utf8_next_char(s); + } + + len = gnt_util_onscreen_width(last, s); + if (max < len) + max = len; + } + + if (height) + *height = count; + if (width) + *width = max + (count > 1); +} + +int gnt_util_onscreen_width(const char *start, const char *end) +{ + int width = 0; + + if (end == NULL) + end = start + strlen(start); + + while (start < end) { + width += g_unichar_iswide(g_utf8_get_char(start)) ? 2 : 1; + start = g_utf8_next_char(start); + } + return width; +} + +const char *gnt_util_onscreen_width_to_pointer(const char *string, int len, int *w) +{ + int size; + int width = 0; + const char *str = string; + + if (len <= 0) { + len = gnt_util_onscreen_width(string, NULL); + } + + while (width < len && *str) { + size = g_unichar_iswide(g_utf8_get_char(str)) ? 2 : 1; + if (width + size > len) + break; + str = g_utf8_next_char(str); + width += size; + } + if (w) + *w = width; + return str; +} + +char *gnt_util_onscreen_fit_string(const char *string, int maxw) +{ + const char *start, *end; + GString *str; + + if (maxw <= 0) + maxw = getmaxx(stdscr) - 4; + + start = string; + str = g_string_new(NULL); + + while (*start) { + if ((end = strchr(start, '\n')) != NULL || + (end = strchr(start, '\r')) != NULL) { + if (gnt_util_onscreen_width(start, end) > maxw) + end = NULL; + } + if (end == NULL) + end = gnt_util_onscreen_width_to_pointer(start, maxw, NULL); + str = g_string_append_len(str, start, end - start); + if (*end) { + str = g_string_append_c(str, '\n'); + if (*end == '\n' || *end == '\r') + end++; + } + start = end; + } + return g_string_free(str, FALSE); +} + +struct duplicate_fns +{ + GDupFunc key_dup; + GDupFunc value_dup; + GHashTable *table; +}; + +static void +duplicate_values(gpointer key, gpointer value, gpointer data) +{ + struct duplicate_fns *fns = data; + g_hash_table_insert(fns->table, fns->key_dup ? fns->key_dup(key) : key, + fns->value_dup ? fns->value_dup(value) : value); +} + +GHashTable *g_hash_table_duplicate(GHashTable *src, GHashFunc hash, + GEqualFunc equal, GDestroyNotify key_d, GDestroyNotify value_d, + GDupFunc key_dup, GDupFunc value_dup) +{ + GHashTable *dest = g_hash_table_new_full(hash, equal, key_d, value_d); + struct duplicate_fns fns = {key_dup, value_dup, dest}; + g_hash_table_foreach(src, duplicate_values, &fns); + return dest; +} + +gboolean gnt_boolean_handled_accumulator(GSignalInvocationHint *ihint, + GValue *return_accu, + const GValue *handler_return, + gpointer dummy) +{ + gboolean continue_emission; + gboolean signal_handled; + + signal_handled = g_value_get_boolean (handler_return); + g_value_set_boolean (return_accu, signal_handled); + continue_emission = !signal_handled; + + return continue_emission; +} + diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gntutils.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gntutils.h Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,36 @@ +#include + +#include "gnt.h" +#include "gntwidget.h" + +typedef gpointer (*GDupFunc)(gconstpointer data); + +void gnt_util_get_text_bound(const char *text, int *width, int *height); + +/* excluding *end */ +int gnt_util_onscreen_width(const char *start, const char *end); + +const char *gnt_util_onscreen_width_to_pointer(const char *str, int len, int *w); + +/* Inserts newlines in 'string' where necessary so that its onscreen width is + * no more than 'maxw'. + * 'maxw' can be <= 0, in which case the maximum screen width is considered. + * + * Returns a newly allocated string. + */ +char *gnt_util_onscreen_fit_string(const char *string, int maxw); + +GHashTable *g_hash_table_duplicate(GHashTable *src, GHashFunc hash, + GEqualFunc equal, GDestroyNotify key_d, GDestroyNotify value_d, + GDupFunc key_dup, GDupFunc value_dup); + + +/** + * To be used with g_signal_new. Look in the key_pressed signal-definition in + * gntwidget.c for usage. + */ +gboolean gnt_boolean_handled_accumulator(GSignalInvocationHint *ihint, + GValue *return_accu, + const GValue *handler_return, + gpointer dummy); + diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gntwidget.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gntwidget.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,630 @@ +/* Stuff brutally ripped from Gflib */ + +#include "gntwidget.h" +#include "gntstyle.h" +#include "gntmarshal.h" +#include "gntutils.h" +#include "gnt.h" + +enum +{ + SIG_DESTROY, + SIG_DRAW, + SIG_HIDE, + SIG_GIVE_FOCUS, + SIG_LOST_FOCUS, + SIG_KEY_PRESSED, + SIG_MAP, + SIG_ACTIVATE, + SIG_EXPOSE, + SIG_SIZE_REQUEST, + SIG_CONFIRM_SIZE, + SIG_SIZE_CHANGED, + SIG_POSITION, + SIG_CLICKED, + SIG_CONTEXT_MENU, + SIGS +}; + +static GObjectClass *parent_class = NULL; +static guint signals[SIGS] = { 0 }; + +static void init_widget(GntWidget *widget); + +static void +gnt_widget_init(GTypeInstance *instance, gpointer class) +{ + GntWidget *widget = GNT_WIDGET(instance); + widget->priv.name = NULL; + GNTDEBUG; +} + +static void +gnt_widget_map(GntWidget *widget) +{ + /* Get some default size for the widget */ + GNTDEBUG; + g_signal_emit(widget, signals[SIG_MAP], 0); + GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_MAPPED); +} + +static void +gnt_widget_dispose(GObject *obj) +{ + GntWidget *self = GNT_WIDGET(obj); + + if(!(GNT_WIDGET_FLAGS(self) & GNT_WIDGET_DESTROYING)) { + GNT_WIDGET_SET_FLAGS(self, GNT_WIDGET_DESTROYING); + + g_signal_emit(self, signals[SIG_DESTROY], 0); + + GNT_WIDGET_UNSET_FLAGS(self, GNT_WIDGET_DESTROYING); + } + + parent_class->dispose(obj); + GNTDEBUG; +} + +static void +gnt_widget_focus_change(GntWidget *widget) +{ + if (GNT_WIDGET_FLAGS(widget) & GNT_WIDGET_MAPPED) + gnt_widget_draw(widget); +} + +static gboolean +gnt_widget_dummy_confirm_size(GntWidget *widget, int width, int height) +{ + if (width < widget->priv.minw || height < widget->priv.minh) + return FALSE; + if (widget->priv.width != width && !GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_GROW_X)) + return FALSE; + if (widget->priv.height != height && !GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_GROW_Y)) + return FALSE; + return TRUE; +} + +static gboolean +context_menu(GntBindable *bind, GList *null) +{ + gboolean ret = FALSE; + g_signal_emit(bind, signals[SIG_CONTEXT_MENU], 0, &ret); + return ret; +} + +static void +gnt_widget_class_init(GntWidgetClass *klass) +{ + GObjectClass *obj_class = G_OBJECT_CLASS(klass); + + parent_class = g_type_class_peek_parent(klass); + + obj_class->dispose = gnt_widget_dispose; + + klass->destroy = gnt_widget_destroy; + klass->show = gnt_widget_show; + klass->draw = gnt_widget_draw; + klass->expose = gnt_widget_expose; + klass->map = gnt_widget_map; + klass->lost_focus = gnt_widget_focus_change; + klass->gained_focus = gnt_widget_focus_change; + klass->confirm_size = gnt_widget_dummy_confirm_size; + + klass->key_pressed = NULL; + klass->activate = NULL; + klass->clicked = NULL; + + signals[SIG_DESTROY] = + g_signal_new("destroy", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GntWidgetClass, destroy), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + signals[SIG_GIVE_FOCUS] = + g_signal_new("gained-focus", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GntWidgetClass, gained_focus), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + signals[SIG_LOST_FOCUS] = + g_signal_new("lost-focus", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GntWidgetClass, lost_focus), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + signals[SIG_ACTIVATE] = + g_signal_new("activate", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GntWidgetClass, activate), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + signals[SIG_MAP] = + g_signal_new("map", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GntWidgetClass, map), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + signals[SIG_DRAW] = + g_signal_new("draw", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GntWidgetClass, draw), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + signals[SIG_HIDE] = + g_signal_new("hide", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GntWidgetClass, hide), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + signals[SIG_EXPOSE] = + g_signal_new("expose", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GntWidgetClass, expose), + NULL, NULL, + gnt_closure_marshal_VOID__INT_INT_INT_INT, + G_TYPE_NONE, 4, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT); + signals[SIG_POSITION] = + g_signal_new("position-set", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GntWidgetClass, set_position), + NULL, NULL, + gnt_closure_marshal_VOID__INT_INT, + G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT); + signals[SIG_SIZE_REQUEST] = + g_signal_new("size_request", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GntWidgetClass, size_request), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + signals[SIG_SIZE_CHANGED] = + g_signal_new("size_changed", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GntWidgetClass, size_changed), + NULL, NULL, + gnt_closure_marshal_VOID__INT_INT, + G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT); + signals[SIG_CONFIRM_SIZE] = + g_signal_new("confirm_size", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GntWidgetClass, confirm_size), + NULL, NULL, + gnt_closure_marshal_BOOLEAN__INT_INT, + G_TYPE_BOOLEAN, 2, G_TYPE_INT, G_TYPE_INT); + signals[SIG_KEY_PRESSED] = + g_signal_new("key_pressed", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GntWidgetClass, key_pressed), + gnt_boolean_handled_accumulator, NULL, + gnt_closure_marshal_BOOLEAN__STRING, + G_TYPE_BOOLEAN, 1, G_TYPE_STRING); + + signals[SIG_CLICKED] = + g_signal_new("clicked", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GntWidgetClass, clicked), + gnt_boolean_handled_accumulator, NULL, + gnt_closure_marshal_BOOLEAN__INT_INT_INT, + G_TYPE_BOOLEAN, 3, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT); + + signals[SIG_CONTEXT_MENU] = + g_signal_new("context-menu", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + 0, + gnt_boolean_handled_accumulator, NULL, + gnt_closure_marshal_BOOLEAN__VOID, + G_TYPE_BOOLEAN, 0); + + /* This is relevant for all widgets */ + gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "context-menu", context_menu, + GNT_KEY_POPUP, NULL); + gnt_bindable_register_binding(GNT_BINDABLE_CLASS(klass), "context-menu", GNT_KEY_F11, NULL); + + gnt_style_read_actions(G_OBJECT_CLASS_TYPE(klass), GNT_BINDABLE_CLASS(klass)); + GNTDEBUG; +} + +/****************************************************************************** + * GntWidget API + *****************************************************************************/ +GType +gnt_widget_get_gtype(void) +{ + static GType type = 0; + + if(type == 0) { + static const GTypeInfo info = { + sizeof(GntWidgetClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc)gnt_widget_class_init, + NULL, + NULL, /* class_data */ + sizeof(GntWidget), + 0, /* n_preallocs */ + gnt_widget_init, /* instance_init */ + NULL /* value_table */ + }; + + type = g_type_register_static(GNT_TYPE_BINDABLE, + "GntWidget", + &info, G_TYPE_FLAG_ABSTRACT); + } + + return type; +} + +void gnt_widget_set_take_focus(GntWidget *widget, gboolean can) +{ + if (can) + GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_CAN_TAKE_FOCUS); + else + GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_CAN_TAKE_FOCUS); +} + +/** + * gnt_widget_destroy: + * @obj: The #GntWidget instance. + * + * Emits the "destroy" signal notifying all reference holders that they + * should release @obj. + */ +void +gnt_widget_destroy(GntWidget *obj) +{ + g_return_if_fail(GNT_IS_WIDGET(obj)); + + gnt_widget_hide(obj); + delwin(obj->window); + if(!(GNT_WIDGET_FLAGS(obj) & GNT_WIDGET_DESTROYING)) + g_object_run_dispose(G_OBJECT(obj)); + GNTDEBUG; +} + +void +gnt_widget_show(GntWidget *widget) +{ + gnt_widget_draw(widget); + gnt_screen_occupy(widget); +} + +void +gnt_widget_draw(GntWidget *widget) +{ + /* Draw the widget */ + if (GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_DRAWING)) + return; + + GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_DRAWING); + if (!(GNT_WIDGET_FLAGS(widget) & GNT_WIDGET_MAPPED)) { + gnt_widget_map(widget); + } + + if (widget->window == NULL) + { +#if 0 + int x, y, maxx, maxy, w, h; + int oldw, oldh; + gboolean shadow = TRUE; + + if (!gnt_widget_has_shadow(widget)) + shadow = FALSE; + + x = widget->priv.x; + y = widget->priv.y; + w = oldw = widget->priv.width + shadow; + h = oldh = widget->priv.height + shadow; + + getmaxyx(stdscr, maxy, maxx); + maxy -= 1; /* room for the taskbar */ + + x = MAX(0, x); + y = MAX(0, y); + if (x + w >= maxx) + x = MAX(0, maxx - w); + if (y + h >= maxy) + y = MAX(0, maxy - h); + + w = MIN(w, maxx); + h = MIN(h, maxy); + + widget->priv.x = x; + widget->priv.y = y; + if (w != oldw || h != oldh) { + widget->priv.width = w - shadow; + widget->priv.height = h - shadow; + g_signal_emit(widget, signals[SIG_SIZE_CHANGED], 0, oldw, oldh); + } +#else + widget->window = newpad(widget->priv.height + 20, widget->priv.width + 20); /* XXX: */ +#endif + init_widget(widget); + } + + g_signal_emit(widget, signals[SIG_DRAW], 0); + gnt_widget_queue_update(widget); + GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_DRAWING); +} + +gboolean +gnt_widget_key_pressed(GntWidget *widget, const char *keys) +{ + gboolean ret; + if (!GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_CAN_TAKE_FOCUS)) + return FALSE; + + if (gnt_bindable_perform_action_key(GNT_BINDABLE(widget), keys)) + return TRUE; + + keys = gnt_bindable_remap_keys(GNT_BINDABLE(widget), keys); + g_signal_emit(widget, signals[SIG_KEY_PRESSED], 0, keys, &ret); + return ret; +} + +gboolean +gnt_widget_clicked(GntWidget *widget, GntMouseEvent event, int x, int y) +{ + gboolean ret; + g_signal_emit(widget, signals[SIG_CLICKED], 0, event, x, y, &ret); + return ret; +} + +void +gnt_widget_expose(GntWidget *widget, int x, int y, int width, int height) +{ + g_signal_emit(widget, signals[SIG_EXPOSE], 0, x, y, width, height); +} + +void +gnt_widget_hide(GntWidget *widget) +{ + g_signal_emit(widget, signals[SIG_HIDE], 0); + wbkgdset(widget->window, '\0' | COLOR_PAIR(GNT_COLOR_NORMAL)); +#if 0 + /* XXX: I have no clue why, but this seemed to be necessary. */ + if (gnt_widget_has_shadow(widget)) + mvwvline(widget->window, 1, widget->priv.width, ' ', widget->priv.height); +#endif + gnt_screen_release(widget); + GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_INVISIBLE); + GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_MAPPED); +} + +void +gnt_widget_set_position(GntWidget *wid, int x, int y) +{ + g_signal_emit(wid, signals[SIG_POSITION], 0, x, y); + /* XXX: Need to install properties for these and g_object_notify */ + wid->priv.x = x; + wid->priv.y = y; +} + +void +gnt_widget_get_position(GntWidget *wid, int *x, int *y) +{ + if (x) + *x = wid->priv.x; + if (y) + *y = wid->priv.y; +} + +void +gnt_widget_size_request(GntWidget *widget) +{ + g_signal_emit(widget, signals[SIG_SIZE_REQUEST], 0); +} + +void +gnt_widget_get_size(GntWidget *wid, int *width, int *height) +{ + gboolean shadow = TRUE; + if (!gnt_widget_has_shadow(wid)) + shadow = FALSE; + + if (width) + *width = wid->priv.width + shadow; + if (height) + *height = wid->priv.height + shadow; + +} + +static void +init_widget(GntWidget *widget) +{ + gboolean shadow = TRUE; + + if (!gnt_widget_has_shadow(widget)) + shadow = FALSE; + + wbkgd(widget->window, COLOR_PAIR(GNT_COLOR_NORMAL)); + werase(widget->window); + + if (!(GNT_WIDGET_FLAGS(widget) & GNT_WIDGET_NO_BORDER)) + { + /* - This is ugly. */ + /* - What's your point? */ + mvwvline(widget->window, 0, 0, ACS_VLINE | COLOR_PAIR(GNT_COLOR_NORMAL), widget->priv.height); + mvwvline(widget->window, 0, widget->priv.width - 1, + ACS_VLINE | COLOR_PAIR(GNT_COLOR_NORMAL), widget->priv.height); + mvwhline(widget->window, widget->priv.height - 1, 0, + ACS_HLINE | COLOR_PAIR(GNT_COLOR_NORMAL), widget->priv.width); + mvwhline(widget->window, 0, 0, ACS_HLINE | COLOR_PAIR(GNT_COLOR_NORMAL), widget->priv.width); + mvwaddch(widget->window, 0, 0, ACS_ULCORNER | COLOR_PAIR(GNT_COLOR_NORMAL)); + mvwaddch(widget->window, 0, widget->priv.width - 1, + ACS_URCORNER | COLOR_PAIR(GNT_COLOR_NORMAL)); + mvwaddch(widget->window, widget->priv.height - 1, 0, + ACS_LLCORNER | COLOR_PAIR(GNT_COLOR_NORMAL)); + mvwaddch(widget->window, widget->priv.height - 1, widget->priv.width - 1, + ACS_LRCORNER | COLOR_PAIR(GNT_COLOR_NORMAL)); + } + + if (shadow) + { + wbkgdset(widget->window, '\0' | COLOR_PAIR(GNT_COLOR_SHADOW)); + mvwvline(widget->window, 1, widget->priv.width, ' ', widget->priv.height); + mvwhline(widget->window, widget->priv.height, 1, ' ', widget->priv.width); + } +} + +gboolean +gnt_widget_set_size(GntWidget *widget, int width, int height) +{ + gboolean ret = TRUE; + + if (gnt_widget_has_shadow(widget)) + { + width--; + height--; + } + if (width <= 0) + width = widget->priv.width; + if (height <= 0) + height = widget->priv.height; + + if (GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_MAPPED)) + { + ret = gnt_widget_confirm_size(widget, width, height); + } + + if (ret) + { + gboolean shadow = TRUE; + int oldw, oldh; + + if (!gnt_widget_has_shadow(widget)) + shadow = FALSE; + + oldw = widget->priv.width; + oldh = widget->priv.height; + + widget->priv.width = width; + widget->priv.height = height; + if (width >= getmaxx(widget->window) || height >= getmaxy(widget->window)) { + delwin(widget->window); + widget->window = newpad(height + 20, width + 20); + } + + g_signal_emit(widget, signals[SIG_SIZE_CHANGED], 0, oldw, oldh); + + if (widget->window) + { + init_widget(widget); + } + if (GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_MAPPED)) + init_widget(widget); + else + GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_MAPPED); + } + + return ret; +} + +gboolean +gnt_widget_set_focus(GntWidget *widget, gboolean set) +{ + if (!(GNT_WIDGET_FLAGS(widget) & GNT_WIDGET_CAN_TAKE_FOCUS)) + return FALSE; + + if (set && !GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_HAS_FOCUS)) + { + GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_HAS_FOCUS); + g_signal_emit(widget, signals[SIG_GIVE_FOCUS], 0); + } + else if (!set) + { + GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_HAS_FOCUS); + g_signal_emit(widget, signals[SIG_LOST_FOCUS], 0); + } + else + return FALSE; + + return TRUE; +} + +void gnt_widget_set_name(GntWidget *widget, const char *name) +{ + g_free(widget->priv.name); + widget->priv.name = g_strdup(name); +} + +const char *gnt_widget_get_name(GntWidget *widget) +{ + return widget->priv.name; +} + +void gnt_widget_activate(GntWidget *widget) +{ + g_signal_emit(widget, signals[SIG_ACTIVATE], 0); +} + +static gboolean +update_queue_callback(gpointer data) +{ + GntWidget *widget = GNT_WIDGET(data); + + if (!g_object_get_data(G_OBJECT(widget), "gnt:queue_update")) + return FALSE; + if (GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_MAPPED)) + gnt_screen_update(widget); + g_object_set_data(G_OBJECT(widget), "gnt:queue_update", NULL); + return FALSE; +} + +void gnt_widget_queue_update(GntWidget *widget) +{ + if (widget->window == NULL) + return; + while (widget->parent) + widget = widget->parent; + + if (!g_object_get_data(G_OBJECT(widget), "gnt:queue_update")) + { + int id = g_timeout_add(0, update_queue_callback, widget); + g_object_set_data_full(G_OBJECT(widget), "gnt:queue_update", GINT_TO_POINTER(id), + (GDestroyNotify)g_source_remove); + } +} + +gboolean gnt_widget_confirm_size(GntWidget *widget, int width, int height) +{ + gboolean ret = FALSE; + g_signal_emit(widget, signals[SIG_CONFIRM_SIZE], 0, width, height, &ret); + return ret; +} + +void gnt_widget_set_visible(GntWidget *widget, gboolean set) +{ + if (set) + GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_INVISIBLE); + else + GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_INVISIBLE); +} + +gboolean gnt_widget_has_shadow(GntWidget *widget) +{ + return (!GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_SHADOW) && + gnt_style_get_bool(GNT_STYLE_SHADOW, FALSE)); +} + diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gntwidget.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gntwidget.h Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,152 @@ +#ifndef GNT_WIDGET_H +#define GNT_WIDGET_H + +#include +#include +#include + +#include "gntbindable.h" + +#define GNT_TYPE_WIDGET (gnt_widget_get_gtype()) +#define GNT_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNT_TYPE_WIDGET, GntWidget)) +#define GNT_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GNT_TYPE_WIDGET, GntWidgetClass)) +#define GNT_IS_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GNT_TYPE_WIDGET)) +#define GNT_IS_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GNT_TYPE_WIDGET)) +#define GNT_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GNT_TYPE_WIDGET, GntWidgetClass)) + +#define GNT_WIDGET_FLAGS(obj) (GNT_WIDGET(obj)->priv.flags) +#define GNT_WIDGET_SET_FLAGS(obj, flags) (GNT_WIDGET_FLAGS(obj) |= flags) +#define GNT_WIDGET_UNSET_FLAGS(obj, flags) (GNT_WIDGET_FLAGS(obj) &= ~(flags)) +#define GNT_WIDGET_IS_FLAG_SET(obj, flags) (GNT_WIDGET_FLAGS(obj) & (flags)) + +typedef struct _GnWidget GntWidget; +typedef struct _GnWidgetPriv GntWidgetPriv; +typedef struct _GnWidgetClass GntWidgetClass; + +typedef enum _GnWidgetFlags +{ + GNT_WIDGET_DESTROYING = 1 << 0, + GNT_WIDGET_CAN_TAKE_FOCUS = 1 << 1, + GNT_WIDGET_MAPPED = 1 << 2, + /* XXX: Need to set the following two as properties, and setup a callback whenever these + * get chnaged. */ + GNT_WIDGET_NO_BORDER = 1 << 3, + GNT_WIDGET_NO_SHADOW = 1 << 4, + GNT_WIDGET_HAS_FOCUS = 1 << 5, + GNT_WIDGET_DRAWING = 1 << 6, + GNT_WIDGET_URGENT = 1 << 7, + GNT_WIDGET_GROW_X = 1 << 8, + GNT_WIDGET_GROW_Y = 1 << 9, + GNT_WIDGET_INVISIBLE = 1 << 10, + GNT_WIDGET_TRANSIENT = 1 << 11, +} GntWidgetFlags; + +/* XXX: This will probably move elsewhere */ +typedef enum _GnMouseEvent +{ + GNT_LEFT_MOUSE_DOWN = 1, + GNT_RIGHT_MOUSE_DOWN, + GNT_MIDDLE_MOUSE_DOWN, + GNT_MOUSE_UP, + GNT_MOUSE_SCROLL_UP, + GNT_MOUSE_SCROLL_DOWN +} GntMouseEvent; + +/* XXX: I'll have to ask grim what he's using this for in guifications. */ +typedef enum _GnParamFlags +{ + GNT_PARAM_SERIALIZABLE = 1 << G_PARAM_USER_SHIFT +} GntParamFlags; + +struct _GnWidgetPriv +{ + int x, y; + int width, height; + GntWidgetFlags flags; + char *name; + + int minw, minh; /* Minimum size for the widget */ +}; + +struct _GnWidget +{ + GntBindable inherit; + + GntWidget *parent; + + GntWidgetPriv priv; + WINDOW *window; + + void (*gnt_reserved1)(void); + void (*gnt_reserved2)(void); + void (*gnt_reserved3)(void); + void (*gnt_reserved4)(void); +}; + +struct _GnWidgetClass +{ + GntBindableClass parent; + + void (*map)(GntWidget *obj); + void (*show)(GntWidget *obj); /* This will call draw() and take focus (if it can take focus) */ + void (*destroy)(GntWidget *obj); + void (*draw)(GntWidget *obj); /* This will draw the widget */ + void (*hide)(GntWidget *obj); + void (*expose)(GntWidget *widget, int x, int y, int width, int height); + void (*gained_focus)(GntWidget *widget); + void (*lost_focus)(GntWidget *widget); + + void (*size_request)(GntWidget *widget); + gboolean (*confirm_size)(GntWidget *widget, int x, int y); + void (*size_changed)(GntWidget *widget, int w, int h); + void (*set_position)(GntWidget *widget, int x, int y); + gboolean (*key_pressed)(GntWidget *widget, const char *key); + void (*activate)(GntWidget *widget); + gboolean (*clicked)(GntWidget *widget, GntMouseEvent event, int x, int y); + + void (*gnt_reserved1)(void); + void (*gnt_reserved2)(void); + void (*gnt_reserved3)(void); + void (*gnt_reserved4)(void); +}; + +G_BEGIN_DECLS + +GType gnt_widget_get_gtype(void); +void gnt_widget_destroy(GntWidget *widget); +void gnt_widget_show(GntWidget *widget); +void gnt_widget_draw(GntWidget *widget); +void gnt_widget_expose(GntWidget *widget, int x, int y, int width, int height); +void gnt_widget_hide(GntWidget *widget); + +void gnt_widget_get_position(GntWidget *widget, int *x, int *y); +void gnt_widget_set_position(GntWidget *widget, int x, int y); +void gnt_widget_size_request(GntWidget *widget); +void gnt_widget_get_size(GntWidget *widget, int *width, int *height); +gboolean gnt_widget_set_size(GntWidget *widget, int width, int height); +gboolean gnt_widget_confirm_size(GntWidget *widget, int width, int height); + +gboolean gnt_widget_key_pressed(GntWidget *widget, const char *keys); + +gboolean gnt_widget_clicked(GntWidget *widget, GntMouseEvent event, int x, int y); + +gboolean gnt_widget_set_focus(GntWidget *widget, gboolean set); +void gnt_widget_activate(GntWidget *widget); + +void gnt_widget_set_name(GntWidget *widget, const char *name); + +const char *gnt_widget_get_name(GntWidget *widget); + +/* Widget-subclasses should call this from the draw-callback. + * Applications should just call gnt_widget_draw instead of this. */ +void gnt_widget_queue_update(GntWidget *widget); + +void gnt_widget_set_take_focus(GntWidget *widget, gboolean set); + +void gnt_widget_set_visible(GntWidget *widget, gboolean set); + +gboolean gnt_widget_has_shadow(GntWidget *widget); + +G_END_DECLS + +#endif /* GNT_WIDGET_H */ diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gntwindow.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gntwindow.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,119 @@ +#include "gntstyle.h" +#include "gntwindow.h" + +#include + +enum +{ + SIGS = 1, +}; + +static GntBoxClass *parent_class = NULL; + +static void (*org_destroy)(GntWidget *widget); + +static gboolean +show_menu(GntBindable *bind, GList *null) +{ + GntWindow *win = GNT_WINDOW(bind); + if (win->menu) { + gnt_screen_menu_show(win->menu); + return TRUE; + } + return FALSE; +} + +static void +gnt_window_destroy(GntWidget *widget) +{ + GntWindow *window = GNT_WINDOW(widget); + if (window->menu) + gnt_widget_destroy(GNT_WIDGET(window->menu)); + org_destroy(widget); +} + +static void +gnt_window_class_init(GntWindowClass *klass) +{ + GntBindableClass *bindable = GNT_BINDABLE_CLASS(klass); + GntWidgetClass *wid_class = GNT_WIDGET_CLASS(klass); + parent_class = GNT_BOX_CLASS(klass); + + org_destroy = wid_class->destroy; + wid_class->destroy = gnt_window_destroy; + + gnt_bindable_class_register_action(bindable, "show-menu", show_menu, + GNT_KEY_CTRL_O, NULL); + gnt_bindable_register_binding(bindable, "show-menu", GNT_KEY_F10, NULL); + gnt_style_read_actions(G_OBJECT_CLASS_TYPE(klass), bindable); + + GNTDEBUG; +} + +static void +gnt_window_init(GTypeInstance *instance, gpointer class) +{ + GntWidget *widget = GNT_WIDGET(instance); + GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW); + GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_CAN_TAKE_FOCUS); + GNTDEBUG; +} + +/****************************************************************************** + * GntWindow API + *****************************************************************************/ +GType +gnt_window_get_gtype(void) +{ + static GType type = 0; + + if(type == 0) + { + static const GTypeInfo info = { + sizeof(GntWindowClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc)gnt_window_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof(GntWindow), + 0, /* n_preallocs */ + gnt_window_init, /* instance_init */ + NULL /* value_table */ + }; + + type = g_type_register_static(GNT_TYPE_BOX, + "GntWindow", + &info, 0); + } + + return type; +} + +GntWidget *gnt_window_new() +{ + GntWidget *widget = g_object_new(GNT_TYPE_WINDOW, NULL); + + return widget; +} + +GntWidget *gnt_window_box_new(gboolean homo, gboolean vert) +{ + GntWidget *wid = gnt_window_new(); + GntBox *box = GNT_BOX(wid); + + box->homogeneous = homo; + box->vertical = vert; + box->alignment = vert ? GNT_ALIGN_LEFT : GNT_ALIGN_MID; + + return wid; +} + +void gnt_window_set_menu(GntWindow *window, GntMenu *menu) +{ + /* If a menu already existed, then destroy that first. */ + if (window->menu) + gnt_widget_destroy(GNT_WIDGET(window->menu)); + window->menu = menu; +} + diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gntwindow.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gntwindow.h Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,56 @@ +#ifndef GNT_WINDOW_H +#define GNT_WINDOW_H + +#include "gnt.h" +#include "gntbox.h" +#include "gntcolors.h" +#include "gntkeys.h" +#include "gntmenu.h" + +#define GNT_TYPE_WINDOW (gnt_window_get_gtype()) +#define GNT_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNT_TYPE_WINDOW, GntWindow)) +#define GNT_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GNT_TYPE_WINDOW, GntWindowClass)) +#define GNT_IS_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GNT_TYPE_WINDOW)) +#define GNT_IS_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GNT_TYPE_WINDOW)) +#define GNT_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GNT_TYPE_WINDOW, GntWindowClass)) + +#define GNT_WINDOW_FLAGS(obj) (GNT_WINDOW(obj)->priv.flags) +#define GNT_WINDOW_SET_FLAGS(obj, flags) (GNT_WINDOW_FLAGS(obj) |= flags) +#define GNT_WINDOW_UNSET_FLAGS(obj, flags) (GNT_WINDOW_FLAGS(obj) &= ~(flags)) + +typedef struct _GnWindow GntWindow; +typedef struct _GnWindowPriv GntWindowPriv; +typedef struct _GnWindowClass GntWindowClass; + +struct _GnWindow +{ + GntBox parent; + GntMenu *menu; +}; + +struct _GnWindowClass +{ + GntBoxClass parent; + + void (*gnt_reserved1)(void); + void (*gnt_reserved2)(void); + void (*gnt_reserved3)(void); + void (*gnt_reserved4)(void); +}; + +G_BEGIN_DECLS + +GType gnt_window_get_gtype(void); + +#define gnt_vwindow_new(homo) gnt_window_box_new(homo, TRUE) +#define gnt_hwindow_new(homo) gnt_window_box_new(homo, FALSE) + +GntWidget *gnt_window_new(void); + +GntWidget *gnt_window_box_new(gboolean homo, gboolean vert); + +void gnt_window_set_menu(GntWindow *window, GntMenu *menu); + +G_END_DECLS + +#endif /* GNT_WINDOW_H */ diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gntwm.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gntwm.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,1504 @@ +#define _GNU_SOURCE +#if defined(__APPLE__) +#define _XOPEN_SOURCE_EXTENDED +#endif + +#include "config.h" + +#include +#include +#include +#include + +#include "gntwm.h" +#include "gntstyle.h" +#include "gntmarshal.h" +#include "gnt.h" +#include "gntbox.h" +#include "gntmenu.h" +#include "gnttextview.h" +#include "gnttree.h" +#include "gntutils.h" + +#define IDLE_CHECK_INTERVAL 5 /* 5 seconds */ + +enum +{ + SIG_NEW_WIN, + SIG_DECORATE_WIN, + SIG_CLOSE_WIN, + SIG_CONFIRM_RESIZE, + SIG_RESIZED, + SIG_CONFIRM_MOVE, + SIG_MOVED, + SIG_UPDATE_WIN, + SIG_GIVE_FOCUS, + SIG_KEY_PRESS, + SIG_MOUSE_CLICK, + SIGS +}; + +static guint signals[SIGS] = { 0 }; +static void gnt_wm_new_window_real(GntWM *wm, GntWidget *widget); +static void gnt_wm_win_resized(GntWM *wm, GntNode *node); +static void gnt_wm_win_moved(GntWM *wm, GntNode *node); +static void gnt_wm_give_focus(GntWM *wm, GntWidget *widget); +static void update_window_in_list(GntWM *wm, GntWidget *wid); +static void shift_window(GntWM *wm, GntWidget *widget, int dir); + +static gboolean write_already(gpointer data); +static int write_timeout; +static time_t last_active_time; +static gboolean idle_update; + +static GList * +g_list_bring_to_front(GList *list, gpointer data) +{ + list = g_list_remove(list, data); + list = g_list_prepend(list, data); + return list; +} + +static void +free_node(gpointer data) +{ + GntNode *node = data; + hide_panel(node->panel); + del_panel(node->panel); + g_free(node); +} + +static void +draw_taskbar(GntWM *wm, gboolean reposition) +{ + static WINDOW *taskbar = NULL; + GList *iter; + int n, width = 0; + int i; + + if (taskbar == NULL) { + taskbar = newwin(1, getmaxx(stdscr), getmaxy(stdscr) - 1, 0); + } else if (reposition) { + int Y_MAX = getmaxy(stdscr) - 1; + mvwin(taskbar, Y_MAX, 0); + } + + wbkgdset(taskbar, '\0' | COLOR_PAIR(GNT_COLOR_NORMAL)); + werase(taskbar); + + n = g_list_length(wm->list); + if (n) + width = getmaxx(stdscr) / n; + + for (i = 0, iter = wm->list; iter; iter = iter->next, i++) + { + GntWidget *w = iter->data; + int color; + const char *title; + + if (w == wm->ordered->data) { + /* This is the current window in focus */ + color = GNT_COLOR_TITLE; + } else if (GNT_WIDGET_IS_FLAG_SET(w, GNT_WIDGET_URGENT)) { + /* This is a window with the URGENT hint set */ + color = GNT_COLOR_URGENT; + } else { + color = GNT_COLOR_NORMAL; + } + wbkgdset(taskbar, '\0' | COLOR_PAIR(color)); + if (iter->next) + mvwhline(taskbar, 0, width * i, ' ' | COLOR_PAIR(color), width); + else + mvwhline(taskbar, 0, width * i, ' ' | COLOR_PAIR(color), getmaxx(stdscr) - width * i); + title = GNT_BOX(w)->title; + mvwprintw(taskbar, 0, width * i, "%s", title ? title : ""); + if (i) + mvwaddch(taskbar, 0, width *i - 1, ACS_VLINE | A_STANDOUT | COLOR_PAIR(GNT_COLOR_NORMAL)); + + update_window_in_list(wm, w); + } + + wrefresh(taskbar); +} + +static void +copy_win(GntWidget *widget, GntNode *node) +{ + WINDOW *src, *dst; + int shadow; + if (!node) + return; + src = widget->window; + dst = node->window; + shadow = gnt_widget_has_shadow(widget) ? 1 : 0; + copywin(src, dst, node->scroll, 0, 0, 0, getmaxy(dst) - 1, getmaxx(dst) - 1, 0); +} + +static gboolean +update_screen(GntWM *wm) +{ + if (wm->menu) { + GntMenu *top = wm->menu; + while (top) { + GntNode *node = g_hash_table_lookup(wm->nodes, top); + if (node) + top_panel(node->panel); + top = top->submenu; + } + } + update_panels(); + doupdate(); + return TRUE; +} + +static gboolean +sanitize_position(GntWidget *widget, int *x, int *y) +{ + int X_MAX = getmaxx(stdscr); + int Y_MAX = getmaxy(stdscr) - 1; + int w, h; + int nx, ny; + gboolean changed = FALSE; + + gnt_widget_get_size(widget, &w, &h); + if (x) { + if (*x + w > X_MAX) { + nx = MAX(0, X_MAX - w); + if (nx != *x) { + *x = nx; + changed = TRUE; + } + } + } + if (y) { + if (*y + h > Y_MAX) { + ny = MAX(0, Y_MAX - h); + if (ny != *y) { + *y = ny; + changed = TRUE; + } + } + } + return changed; +} + +static void +refresh_node(GntWidget *widget, GntNode *node, gpointer null) +{ + int x, y, w, h; + int nw, nh; + + int X_MAX = getmaxx(stdscr); + int Y_MAX = getmaxy(stdscr) - 1; + + gnt_widget_get_position(widget, &x, &y); + gnt_widget_get_size(widget, &w, &h); + + if (sanitize_position(widget, &x, &y)) + gnt_screen_move_widget(widget, x, y); + + nw = MIN(w, X_MAX); + nh = MIN(h, Y_MAX); + if (nw != w || nh != h) + gnt_screen_resize_widget(widget, nw, nh); +} + +static void +read_window_positions(GntWM *wm) +{ +#if GLIB_CHECK_VERSION(2,6,0) + GKeyFile *gfile = g_key_file_new(); + char *filename = g_build_filename(g_get_home_dir(), ".gntpositions", NULL); + GError *error = NULL; + char **keys; + gsize nk; + + if (!g_key_file_load_from_file(gfile, filename, G_KEY_FILE_NONE, &error)) { + g_printerr("GntWM: %s\n", error->message); + g_error_free(error); + g_free(filename); + return; + } + + keys = g_key_file_get_keys(gfile, "positions", &nk, &error); + if (error) { + g_printerr("GntWM: %s\n", error->message); + g_error_free(error); + error = NULL; + } else { + while (nk--) { + char *title = keys[nk]; + gsize l; + char **coords = g_key_file_get_string_list(gfile, "positions", title, &l, NULL); + if (l == 2) { + int x = atoi(coords[0]); + int y = atoi(coords[1]); + GntPosition *p = g_new0(GntPosition, 1); + p->x = x; + p->y = y; + g_hash_table_replace(wm->positions, g_strdup(title + 1), p); + } else { + g_printerr("GntWM: Invalid number of arguments for positioing a window.\n"); + } + g_strfreev(coords); + } + g_strfreev(keys); + } + + g_free(filename); +#endif +} + +static gboolean check_idle(gpointer n) +{ + if (idle_update) { + time(&last_active_time); + idle_update = FALSE; + } + return TRUE; +} + +static void +gnt_wm_init(GTypeInstance *instance, gpointer class) +{ + GntWM *wm = GNT_WM(instance); + wm->list = NULL; + wm->ordered = NULL; + wm->event_stack = FALSE; + wm->windows = NULL; + wm->actions = NULL; + wm->nodes = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, free_node); + wm->positions = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + if (gnt_style_get_bool(GNT_STYLE_REMPOS, TRUE)) + read_window_positions(wm); + g_timeout_add(IDLE_CHECK_INTERVAL * 1000, check_idle, NULL); + time(&last_active_time); +} + +static void +switch_window(GntWM *wm, int direction) +{ + GntWidget *w = NULL, *wid = NULL; + int pos; + + if (wm->_list.window || wm->menu) + return; + + if (!wm->ordered || !wm->ordered->next) + return; + + w = wm->ordered->data; + pos = g_list_index(wm->list, w); + pos += direction; + + if (pos < 0) + wid = g_list_last(wm->list)->data; + else if (pos >= g_list_length(wm->list)) + wid = wm->list->data; + else if (pos >= 0) + wid = g_list_nth_data(wm->list, pos); + + wm->ordered = g_list_bring_to_front(wm->ordered, wid); + + gnt_wm_raise_window(wm, wm->ordered->data); + + if (w != wid) { + gnt_widget_set_focus(w, FALSE); + } +} + +static gboolean +window_next(GntBindable *bindable, GList *null) +{ + GntWM *wm = GNT_WM(bindable); + switch_window(wm, 1); + return TRUE; +} + +static gboolean +window_prev(GntBindable *bindable, GList *null) +{ + GntWM *wm = GNT_WM(bindable); + switch_window(wm, -1); + return TRUE; +} + +static gboolean +switch_window_n(GntBindable *bind, GList *list) +{ + GntWM *wm = GNT_WM(bind); + GntWidget *w = NULL; + GList *l; + int n; + + if (!wm->ordered) + return TRUE; + + if (list) + n = GPOINTER_TO_INT(list->data); + else + n = 0; + + w = wm->ordered->data; + + if ((l = g_list_nth(wm->list, n)) != NULL) + { + gnt_wm_raise_window(wm, l->data); + } + + if (l && w != l->data) + { + gnt_widget_set_focus(w, FALSE); + } + return TRUE; +} + +static gboolean +window_scroll_up(GntBindable *bindable, GList *null) +{ + GntWM *wm = GNT_WM(bindable); + GntWidget *window; + GntNode *node; + + if (!wm->ordered) + return TRUE; + + window = wm->ordered->data; + node = g_hash_table_lookup(wm->nodes, window); + if (!node) + return TRUE; + + if (node->scroll) { + node->scroll--; + copy_win(window, node); + update_screen(wm); + } + return TRUE; +} + +static gboolean +window_scroll_down(GntBindable *bindable, GList *null) +{ + GntWM *wm = GNT_WM(bindable); + GntWidget *window; + GntNode *node; + int w, h; + + if (!wm->ordered) + return TRUE; + + window = wm->ordered->data; + node = g_hash_table_lookup(wm->nodes, window); + if (!node) + return TRUE; + + gnt_widget_get_size(window, &w, &h); + if (h - node->scroll > getmaxy(node->window)) { + node->scroll++; + copy_win(window, node); + update_screen(wm); + } + return TRUE; +} + +static gboolean +window_close(GntBindable *bindable, GList *null) +{ + GntWM *wm = GNT_WM(bindable); + + if (wm->_list.window) + return TRUE; + + if (wm->ordered) { + gnt_widget_destroy(wm->ordered->data); + } + + return TRUE; +} + +static void +destroy__list(GntWidget *widget, GntWM *wm) +{ + wm->_list.window = NULL; + wm->_list.tree = NULL; + wm->windows = NULL; + wm->actions = NULL; + update_screen(wm); +} + +static void +setup__list(GntWM *wm) +{ + GntWidget *tree, *win; + win = wm->_list.window = gnt_box_new(FALSE, FALSE); + gnt_box_set_toplevel(GNT_BOX(win), TRUE); + gnt_box_set_pad(GNT_BOX(win), 0); + GNT_WIDGET_SET_FLAGS(win, GNT_WIDGET_TRANSIENT); + + tree = wm->_list.tree = gnt_tree_new(); + gnt_box_add_widget(GNT_BOX(win), tree); + + g_signal_connect(G_OBJECT(win), "destroy", G_CALLBACK(destroy__list), wm); +} + +static void +window_list_activate(GntTree *tree, GntWM *wm) +{ + GntWidget *widget = gnt_tree_get_selection_data(GNT_TREE(tree)); + + if (!wm->ordered || !widget) + return; + + gnt_widget_destroy(wm->_list.window); + gnt_wm_raise_window(wm, widget); +} + +static void +populate_window_list(GntWM *wm) +{ + GList *iter; + GntTree *tree = GNT_TREE(wm->windows->tree); + for (iter = wm->list; iter; iter = iter->next) { + GntBox *box = GNT_BOX(iter->data); + + gnt_tree_add_row_last(tree, box, + gnt_tree_create_row(tree, box->title), NULL); + update_window_in_list(wm, GNT_WIDGET(box)); + } +} + +static gboolean +window_list_key_pressed(GntWidget *widget, const char *text, GntWM *wm) +{ + if (text[1] == 0 && wm->ordered) { + GntWidget *sel = gnt_tree_get_selection_data(GNT_TREE(widget)); + switch (text[0]) { + case '-': + case '<': + shift_window(wm, sel, -1); + break; + case '+': + case '>': + shift_window(wm, sel, 1); + break; + default: + return FALSE; + } + gnt_tree_remove_all(GNT_TREE(widget)); + populate_window_list(wm); + gnt_tree_set_selected(GNT_TREE(widget), sel); + return TRUE; + } + return FALSE; +} + +static gboolean +window_list(GntBindable *bindable, GList *null) +{ + GntWM *wm = GNT_WM(bindable); + GntWidget *tree, *win; + + if (wm->_list.window || wm->menu) + return TRUE; + + if (!wm->ordered) + return TRUE; + + setup__list(wm); + wm->windows = &wm->_list; + + win = wm->windows->window; + tree = wm->windows->tree; + + gnt_box_set_title(GNT_BOX(win), "Window List"); + + populate_window_list(wm); + + gnt_tree_set_selected(GNT_TREE(tree), wm->ordered->data); + g_signal_connect(G_OBJECT(tree), "activate", G_CALLBACK(window_list_activate), wm); + g_signal_connect(G_OBJECT(tree), "key_pressed", G_CALLBACK(window_list_key_pressed), wm); + + gnt_tree_set_col_width(GNT_TREE(tree), 0, getmaxx(stdscr) / 3); + gnt_widget_set_size(tree, 0, getmaxy(stdscr) / 2); + gnt_widget_set_position(win, getmaxx(stdscr) / 3, getmaxy(stdscr) / 4); + + gnt_widget_show(win); + return TRUE; +} + +static gboolean +dump_screen(GntBindable *bindable, GList *null) +{ + int x, y; + chtype old = 0, now = 0; + FILE *file = fopen("dump.html", "w"); + + fprintf(file, "
");
+	for (y = 0; y < getmaxy(stdscr); y++) {
+		for (x = 0; x < getmaxx(stdscr); x++) {
+			char ch;
+			now = mvwinch(curscr, y, x);
+			ch = now & A_CHARTEXT;
+			now ^= ch;
+
+#define CHECK(attr, start, end) \
+			do \
+			{  \
+				if (now & attr)  \
+				{  \
+					if (!(old & attr))  \
+						fprintf(file, "%s", start);  \
+				}  \
+				else if (old & attr)  \
+				{  \
+					fprintf(file, "%s", end);  \
+				}  \
+			} while (0) 
+
+			CHECK(A_BOLD, "", "");
+			CHECK(A_UNDERLINE, "", "");
+			CHECK(A_BLINK, "", "");
+
+			if ((now & A_COLOR) != (old & A_COLOR) ||
+				(now & A_REVERSE) != (old & A_REVERSE))
+			{
+				int ret;
+				short fgp, bgp, r, g, b;
+				struct
+				{
+					int r, g, b;
+				} fg, bg;
+
+				ret = pair_content(PAIR_NUMBER(now & A_COLOR), &fgp, &bgp);
+				if (fgp == -1)
+					fgp = COLOR_BLACK;
+				if (bgp == -1)
+					bgp = COLOR_WHITE;
+				if (now & A_REVERSE)
+					fgp ^= bgp ^= fgp ^= bgp;  /* *wink* */
+				ret = color_content(fgp, &r, &g, &b);
+				fg.r = r; fg.b = b; fg.g = g;
+				ret = color_content(bgp, &r, &g, &b);
+				bg.r = r; bg.b = b; bg.g = g;
+#define ADJUST(x) (x = x * 255 / 1000)
+				ADJUST(fg.r);
+				ADJUST(fg.g);
+				ADJUST(fg.b);
+				ADJUST(bg.r);
+				ADJUST(bg.b);
+				ADJUST(bg.g);
+				
+				if (x) fprintf(file, "");
+				fprintf(file, "",
+						bg.r, bg.g, bg.b, fg.r, fg.g, fg.b);
+			}
+			if (now & A_ALTCHARSET)
+			{
+				switch (ch)
+				{
+					case 'q':
+						ch = '-'; break;
+					case 't':
+					case 'u':
+					case 'x':
+						ch = '|'; break;
+					case 'v':
+					case 'w':
+					case 'l':
+					case 'm':
+					case 'k':
+					case 'j':
+					case 'n':
+						ch = '+'; break;
+					case '-':
+						ch = '^'; break;
+					case '.':
+						ch = 'v'; break;
+					case 'a':
+						ch = '#'; break;
+					default:
+						ch = ' '; break;
+				}
+			}
+			if (ch == '&')
+				fprintf(file, "&");
+			else if (ch == '<')
+				fprintf(file, "<");
+			else if (ch == '>')
+				fprintf(file, ">");
+			else
+				fprintf(file, "%c", ch);
+			old = now;
+		}
+		fprintf(file, "\n");
+		old = 0;
+	}
+	fprintf(file, "
"); + fclose(file); + return TRUE; +} + +static void +shift_window(GntWM *wm, GntWidget *widget, int dir) +{ + GList *all = wm->list; + GList *list = g_list_find(all, widget); + int length, pos; + if (!list) + return; + + length = g_list_length(all); + pos = g_list_position(all, list); + + pos += dir; + if (dir > 0) + pos++; + + if (pos < 0) + pos = length; + else if (pos > length) + pos = 0; + + all = g_list_insert(all, widget, pos); + all = g_list_delete_link(all, list); + wm->list = all; + draw_taskbar(wm, FALSE); +} + +static gboolean +shift_left(GntBindable *bindable, GList *null) +{ + GntWM *wm = GNT_WM(bindable); + if (wm->_list.window) + return TRUE; + + shift_window(wm, wm->ordered->data, -1); + return TRUE; +} + +static gboolean +shift_right(GntBindable *bindable, GList *null) +{ + GntWM *wm = GNT_WM(bindable); + if (wm->_list.window) + return TRUE; + + shift_window(wm, wm->ordered->data, 1); + return TRUE; +} + +static void +action_list_activate(GntTree *tree, GntWM *wm) +{ + GntAction *action = gnt_tree_get_selection_data(tree); + action->callback(); + gnt_widget_destroy(wm->_list.window); +} + +static int +compare_action(gconstpointer p1, gconstpointer p2) +{ + const GntAction *a1 = p1; + const GntAction *a2 = p2; + + return g_utf8_collate(a1->label, a2->label); +} + +static gboolean +list_actions(GntBindable *bindable, GList *null) +{ + GntWidget *tree, *win; + GList *iter; + GntWM *wm = GNT_WM(bindable); + if (wm->_list.window || wm->menu) + return TRUE; + + if (wm->acts == NULL) + return TRUE; + + setup__list(wm); + wm->actions = &wm->_list; + + win = wm->actions->window; + tree = wm->actions->tree; + + gnt_box_set_title(GNT_BOX(win), "Actions"); + GNT_WIDGET_SET_FLAGS(tree, GNT_WIDGET_NO_BORDER); + /* XXX: Do we really want this? */ + gnt_tree_set_compare_func(GNT_TREE(tree), compare_action); + + for (iter = wm->acts; iter; iter = iter->next) { + GntAction *action = iter->data; + gnt_tree_add_row_last(GNT_TREE(tree), action, + gnt_tree_create_row(GNT_TREE(tree), action->label), NULL); + } + g_signal_connect(G_OBJECT(tree), "activate", G_CALLBACK(action_list_activate), wm); + gnt_widget_set_size(tree, 0, g_list_length(wm->acts)); + gnt_widget_set_position(win, 0, getmaxy(stdscr) - 3 - g_list_length(wm->acts)); + + gnt_widget_show(win); + return TRUE; +} + +#ifndef NO_WIDECHAR +static int +widestringwidth(wchar_t *wide) +{ + int len, ret; + char *string; + + len = wcstombs(NULL, wide, 0) + 1; + string = g_new0(char, len); + wcstombs(string, wide, len); + ret = gnt_util_onscreen_width(string, NULL); + g_free(string); + return ret; +} +#endif + +/* Returns the onscreen width of the character at the position */ +static int +reverse_char(WINDOW *d, int y, int x, gboolean set) +{ +#define DECIDE(ch) (set ? ((ch) | A_REVERSE) : ((ch) & ~A_REVERSE)) + +#ifdef NO_WIDECHAR + chtype ch; + ch = mvwinch(d, y, x); + mvwaddch(d, y, x, DECIDE(ch)); + return 1; +#else + cchar_t ch; + int wc = 1; + if (mvwin_wch(d, y, x, &ch) == OK) { + wc = widestringwidth(ch.chars); + ch.attr = DECIDE(ch.attr); + ch.attr &= WA_ATTRIBUTES; /* XXX: This is a workaround for a bug */ + mvwadd_wch(d, y, x, &ch); + } + + return wc; +#endif +} + +static void +window_reverse(GntWidget *win, gboolean set, GntWM *wm) +{ + int i; + int w, h; + WINDOW *d; + + if (GNT_WIDGET_IS_FLAG_SET(win, GNT_WIDGET_NO_BORDER)) + return; + + d = win->window; + gnt_widget_get_size(win, &w, &h); + + if (gnt_widget_has_shadow(win)) { + --w; + --h; + } + + /* the top and bottom */ + for (i = 0; i < w; i += reverse_char(d, 0, i, set)); + for (i = 0; i < w; i += reverse_char(d, h-1, i, set)); + + /* the left and right */ + for (i = 0; i < h; i += reverse_char(d, i, 0, set)); + for (i = 0; i < h; i += reverse_char(d, i, w-1, set)); + + copy_win(win, g_hash_table_lookup(wm->nodes, win)); + update_screen(wm); +} + +static gboolean +start_move(GntBindable *bindable, GList *null) +{ + GntWM *wm = GNT_WM(bindable); + if (wm->_list.window || wm->menu) + return TRUE; + if (!wm->ordered) + return TRUE; + + wm->mode = GNT_KP_MODE_MOVE; + window_reverse(GNT_WIDGET(wm->ordered->data), TRUE, wm); + + return TRUE; +} + +static gboolean +start_resize(GntBindable *bindable, GList *null) +{ + GntWM *wm = GNT_WM(bindable); + if (wm->_list.window || wm->menu) + return TRUE; + if (!wm->ordered) + return TRUE; + + wm->mode = GNT_KP_MODE_RESIZE; + window_reverse(GNT_WIDGET(wm->ordered->data), TRUE, wm); + + return TRUE; +} + +static gboolean +wm_quit(GntBindable *bindable, GList *list) +{ + GntWM *wm = GNT_WM(bindable); + if (write_timeout) + write_already(wm); + g_main_loop_quit(wm->loop); + return TRUE; +} + +static gboolean +return_true(GntWM *wm, GntWidget *w, int *a, int *b) +{ + return TRUE; +} + +static gboolean +refresh_screen(GntBindable *bindable, GList *null) +{ + GntWM *wm = GNT_WM(bindable); + + endwin(); + refresh(); + curs_set(0); /* endwin resets the cursor to normal */ + + g_hash_table_foreach(wm->nodes, (GHFunc)refresh_node, NULL); + update_screen(wm); + draw_taskbar(wm, TRUE); + + return FALSE; +} + +static void +gnt_wm_class_init(GntWMClass *klass) +{ + int i; + + klass->new_window = gnt_wm_new_window_real; + klass->decorate_window = NULL; + klass->close_window = NULL; + klass->window_resize_confirm = return_true; + klass->window_resized = gnt_wm_win_resized; + klass->window_move_confirm = return_true; + klass->window_moved = gnt_wm_win_moved; + klass->window_update = NULL; + klass->key_pressed = NULL; + klass->mouse_clicked = NULL; + klass->give_focus = gnt_wm_give_focus; + + signals[SIG_NEW_WIN] = + g_signal_new("new_win", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GntWMClass, new_window), + NULL, NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, 1, G_TYPE_POINTER); + signals[SIG_DECORATE_WIN] = + g_signal_new("decorate_win", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GntWMClass, decorate_window), + NULL, NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, 1, G_TYPE_POINTER); + signals[SIG_CLOSE_WIN] = + g_signal_new("close_win", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GntWMClass, close_window), + NULL, NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, 1, G_TYPE_POINTER); + signals[SIG_CONFIRM_RESIZE] = + g_signal_new("confirm_resize", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GntWMClass, window_resize_confirm), + gnt_boolean_handled_accumulator, NULL, + gnt_closure_marshal_BOOLEAN__POINTER_POINTER_POINTER, + G_TYPE_BOOLEAN, 3, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER); + + signals[SIG_CONFIRM_MOVE] = + g_signal_new("confirm_move", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GntWMClass, window_move_confirm), + gnt_boolean_handled_accumulator, NULL, + gnt_closure_marshal_BOOLEAN__POINTER_POINTER_POINTER, + G_TYPE_BOOLEAN, 3, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER); + + signals[SIG_RESIZED] = + g_signal_new("window_resized", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GntWMClass, window_resized), + NULL, NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, 1, G_TYPE_POINTER); + signals[SIG_MOVED] = + g_signal_new("window_moved", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GntWMClass, window_moved), + NULL, NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, 1, G_TYPE_POINTER); + signals[SIG_UPDATE_WIN] = + g_signal_new("window_update", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GntWMClass, window_update), + NULL, NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, 1, G_TYPE_POINTER); + + signals[SIG_GIVE_FOCUS] = + g_signal_new("give_focus", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GntWMClass, give_focus), + NULL, NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, 1, G_TYPE_POINTER); + + signals[SIG_MOUSE_CLICK] = + g_signal_new("mouse_clicked", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GntWMClass, mouse_clicked), + gnt_boolean_handled_accumulator, NULL, + gnt_closure_marshal_BOOLEAN__INT_INT_INT_POINTER, + G_TYPE_BOOLEAN, 4, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_POINTER); + + gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "window-next", window_next, + "\033" "n", NULL); + gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "window-prev", window_prev, + "\033" "p", NULL); + gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "window-close", window_close, + "\033" "c", NULL); + gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "window-list", window_list, + "\033" "w", NULL); + gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "dump-screen", dump_screen, + "\033" "d", NULL); + gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "shift-left", shift_left, + "\033" ",", NULL); + gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "shift-right", shift_right, + "\033" ".", NULL); + gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "action-list", list_actions, + "\033" "a", NULL); + gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "start-move", start_move, + "\033" "m", NULL); + gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "start-resize", start_resize, + "\033" "r", NULL); + gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "wm-quit", wm_quit, + "\033" "q", NULL); + gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "refresh-screen", refresh_screen, + "\033" "l", NULL); + gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "switch-window-n", switch_window_n, + NULL, NULL); + gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "window-scroll-down", window_scroll_down, + "\033" GNT_KEY_CTRL_J, NULL); + gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "window-scroll-up", window_scroll_up, + "\033" GNT_KEY_CTRL_K, NULL); + + gnt_style_read_actions(G_OBJECT_CLASS_TYPE(klass), GNT_BINDABLE_CLASS(klass)); + + /* Make sure Alt+x are detected properly. */ + for (i = '0'; i <= '9'; i++) { + char str[] = "\033X"; + str[1] = i; + gnt_keys_add_combination(str); + } + + GNTDEBUG; +} + +/****************************************************************************** + * GntWM API + *****************************************************************************/ +GType +gnt_wm_get_gtype(void) +{ + static GType type = 0; + + if(type == 0) { + static const GTypeInfo info = { + sizeof(GntWMClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc)gnt_wm_class_init, + NULL, + NULL, /* class_data */ + sizeof(GntWM), + 0, /* n_preallocs */ + gnt_wm_init, /* instance_init */ + NULL /* value_table */ + }; + + type = g_type_register_static(GNT_TYPE_BINDABLE, + "GntWM", + &info, 0); + } + + return type; +} +static void +update_window_in_list(GntWM *wm, GntWidget *wid) +{ + GntTextFormatFlags flag = 0; + + if (wm->windows == NULL) + return; + + if (wid == wm->ordered->data) + flag |= GNT_TEXT_FLAG_DIM; + else if (GNT_WIDGET_IS_FLAG_SET(wid, GNT_WIDGET_URGENT)) + flag |= GNT_TEXT_FLAG_BOLD; + + gnt_tree_set_row_flags(GNT_TREE(wm->windows->tree), wid, flag); +} + +static void +gnt_wm_new_window_real(GntWM *wm, GntWidget *widget) +{ + GntNode *node; + gboolean transient = FALSE; + + if (widget->window == NULL) + return; + + node = g_new0(GntNode, 1); + node->me = widget; + node->scroll = 0; + + g_hash_table_replace(wm->nodes, widget, node); + + refresh_node(widget, node, NULL); + + transient = !!GNT_WIDGET_IS_FLAG_SET(node->me, GNT_WIDGET_TRANSIENT); + +#if 1 + { + int x, y, w, h, maxx, maxy; + gboolean shadow = TRUE; + + if (!gnt_widget_has_shadow(widget)) + shadow = FALSE; + x = widget->priv.x; + y = widget->priv.y; + w = widget->priv.width; + h = widget->priv.height; + + getmaxyx(stdscr, maxy, maxx); + maxy -= 1; /* room for the taskbar */ + maxy -= shadow; + maxx -= shadow; + + x = MAX(0, x); + y = MAX(0, y); + if (x + w >= maxx) + x = MAX(0, maxx - w); + if (y + h >= maxy) + y = MAX(0, maxy - h); + + w = MIN(w, maxx); + h = MIN(h, maxy); + node->window = newwin(h + shadow, w + shadow, y, x); + copy_win(widget, node); + } +#endif + + node->panel = new_panel(node->window); + set_panel_userptr(node->panel, node); + + if (!transient) { + if (node->me != wm->_list.window) { + GntWidget *w = NULL; + + if (wm->ordered) + w = wm->ordered->data; + + wm->list = g_list_append(wm->list, widget); + + if (wm->event_stack) + wm->ordered = g_list_prepend(wm->ordered, widget); + else + wm->ordered = g_list_append(wm->ordered, widget); + + gnt_widget_set_focus(widget, TRUE); + if (w) + gnt_widget_set_focus(w, FALSE); + } + + if (wm->event_stack || node->me == wm->_list.window) { + gnt_wm_raise_window(wm, node->me); + } else { + bottom_panel(node->panel); /* New windows should not grab focus */ + gnt_widget_set_urgent(node->me); + } + } +} + +void gnt_wm_new_window(GntWM *wm, GntWidget *widget) +{ + while (widget->parent) + widget = widget->parent; + + if (GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_INVISIBLE) || + g_hash_table_lookup(wm->nodes, widget)) { + update_screen(wm); + return; + } + + if (GNT_IS_BOX(widget)) { + const char *title = GNT_BOX(widget)->title; + GntPosition *p = NULL; + if (title && (p = g_hash_table_lookup(wm->positions, title)) != NULL) { + sanitize_position(widget, &p->x, &p->y); + gnt_widget_set_position(widget, p->x, p->y); + mvwin(widget->window, p->y, p->x); + } + } + + g_signal_emit(wm, signals[SIG_NEW_WIN], 0, widget); + g_signal_emit(wm, signals[SIG_DECORATE_WIN], 0, widget); + + if (wm->windows && !GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_TRANSIENT)) { + if ((GNT_IS_BOX(widget) && GNT_BOX(widget)->title) && wm->_list.window != widget + && GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_CAN_TAKE_FOCUS)) { + gnt_tree_add_row_last(GNT_TREE(wm->windows->tree), widget, + gnt_tree_create_row(GNT_TREE(wm->windows->tree), GNT_BOX(widget)->title), + NULL); + update_window_in_list(wm, widget); + } + } + + update_screen(wm); + draw_taskbar(wm, FALSE); +} + +void gnt_wm_window_decorate(GntWM *wm, GntWidget *widget) +{ + g_signal_emit(wm, signals[SIG_DECORATE_WIN], 0, widget); +} + +void gnt_wm_window_close(GntWM *wm, GntWidget *widget) +{ + GntNode *node; + int pos; + + if ((node = g_hash_table_lookup(wm->nodes, widget)) == NULL) + return; + + g_signal_emit(wm, signals[SIG_CLOSE_WIN], 0, widget); + g_hash_table_remove(wm->nodes, widget); + + if (wm->windows) { + gnt_tree_remove(GNT_TREE(wm->windows->tree), widget); + } + + pos = g_list_index(wm->list, widget); + + if (pos != -1) { + wm->list = g_list_remove(wm->list, widget); + wm->ordered = g_list_remove(wm->ordered, widget); + + if (wm->ordered) + gnt_wm_raise_window(wm, wm->ordered->data); + } + + update_screen(wm); + draw_taskbar(wm, FALSE); +} + +time_t gnt_wm_get_idle_time() +{ + return time(NULL) - last_active_time; +} + +gboolean gnt_wm_process_input(GntWM *wm, const char *keys) +{ + gboolean ret = FALSE; + + keys = gnt_bindable_remap_keys(GNT_BINDABLE(wm), keys); + + idle_update = TRUE; + + if (gnt_bindable_perform_action_key(GNT_BINDABLE(wm), keys)) + return TRUE; + + /* Do some manual checking */ + if (wm->ordered && wm->mode != GNT_KP_MODE_NORMAL) { + int xmin = 0, ymin = 0, xmax = getmaxx(stdscr), ymax = getmaxy(stdscr) - 1; + int x, y, w, h; + GntWidget *widget = GNT_WIDGET(wm->ordered->data); + int ox, oy, ow, oh; + + gnt_widget_get_position(widget, &x, &y); + gnt_widget_get_size(widget, &w, &h); + ox = x; oy = y; + ow = w; oh = h; + + if (wm->mode == GNT_KP_MODE_MOVE) { + if (strcmp(keys, GNT_KEY_LEFT) == 0) { + if (x > xmin) + x--; + } else if (strcmp(keys, GNT_KEY_RIGHT) == 0) { + if (x + w < xmax) + x++; + } else if (strcmp(keys, GNT_KEY_UP) == 0) { + if (y > ymin) + y--; + } else if (strcmp(keys, GNT_KEY_DOWN) == 0) { + if (y + h < ymax) + y++; + } + if (ox != x || oy != y) { + gnt_screen_move_widget(widget, x, y); + window_reverse(widget, TRUE, wm); + return TRUE; + } + } else if (wm->mode == GNT_KP_MODE_RESIZE) { + if (strcmp(keys, GNT_KEY_LEFT) == 0) { + w--; + } else if (strcmp(keys, GNT_KEY_RIGHT) == 0) { + if (x + w < xmax) + w++; + } else if (strcmp(keys, GNT_KEY_UP) == 0) { + h--; + } else if (strcmp(keys, GNT_KEY_DOWN) == 0) { + if (y + h < ymax) + h++; + } + if (oh != h || ow != w) { + gnt_screen_resize_widget(widget, w, h); + window_reverse(widget, TRUE, wm); + return TRUE; + } + } + if (strcmp(keys, "\r") == 0 || strcmp(keys, "\033") == 0) { + window_reverse(widget, FALSE, wm); + wm->mode = GNT_KP_MODE_NORMAL; + } + return TRUE; + } + + wm->event_stack = TRUE; + + /* Escape to close the window-list or action-list window */ + if (strcmp(keys, "\033") == 0) { + if (wm->_list.window) { + gnt_widget_destroy(wm->_list.window); + wm->event_stack = FALSE; + return TRUE; + } + } else if (keys[0] == '\033' && isdigit(keys[1]) && keys[2] == '\0') { + /* Alt+x for quick switch */ + int n = *(keys + 1) - '0'; + GList *list = NULL; + + if (n == 0) + n = 10; + + list = g_list_append(list, GINT_TO_POINTER(n - 1)); + switch_window_n(GNT_BINDABLE(wm), list); + g_list_free(list); + return TRUE; + } + + if (wm->menu) + ret = gnt_widget_key_pressed(GNT_WIDGET(wm->menu), keys); + else if (wm->_list.window) + ret = gnt_widget_key_pressed(wm->_list.window, keys); + else if (wm->ordered) + ret = gnt_widget_key_pressed(GNT_WIDGET(wm->ordered->data), keys); + wm->event_stack = FALSE; + return ret; +} + +static void +gnt_wm_win_resized(GntWM *wm, GntNode *node) +{ + /*refresh_node(node->me, node, NULL);*/ +} + +static void +gnt_wm_win_moved(GntWM *wm, GntNode *node) +{ + refresh_node(node->me, node, NULL); +} + +void gnt_wm_resize_window(GntWM *wm, GntWidget *widget, int width, int height) +{ + gboolean ret = TRUE; + GntNode *node; + int shadow; + int maxx, maxy; + + while (widget->parent) + widget = widget->parent; + node = g_hash_table_lookup(wm->nodes, widget); + if (!node) + return; + + g_signal_emit(wm, signals[SIG_CONFIRM_RESIZE], 0, widget, &width, &height, &ret); + if (!ret) + return; /* resize is not permitted */ + hide_panel(node->panel); + gnt_widget_set_size(widget, width, height); + gnt_widget_draw(widget); + + shadow = gnt_widget_has_shadow(widget) ? 1 : 0; + maxx = getmaxx(stdscr) - shadow; + maxy = getmaxy(stdscr) - 1 - shadow; + height = MIN(height, maxy); + width = MIN(width, maxx); + wresize(node->window, height + shadow, width + shadow); + replace_panel(node->panel, node->window); + + g_signal_emit(wm, signals[SIG_RESIZED], 0, node); + + show_panel(node->panel); + update_screen(wm); +} + +static void +write_gdi(gpointer key, gpointer value, gpointer data) +{ + GntPosition *p = value; + fprintf(data, ".%s = %d;%d\n", (char *)key, p->x, p->y); +} + +static gboolean +write_already(gpointer data) +{ + GntWM *wm = data; + FILE *file; + char *filename; + + filename = g_build_filename(g_get_home_dir(), ".gntpositions", NULL); + + file = fopen(filename, "wb"); + if (file == NULL) { + g_printerr("GntWM: error opening file to save positions\n"); + } else { + fprintf(file, "[positions]\n"); + g_hash_table_foreach(wm->positions, write_gdi, file); + fclose(file); + } + + g_free(filename); + g_source_remove(write_timeout); + write_timeout = 0; + return FALSE; +} + +static void +write_positions_to_file(GntWM *wm) +{ + if (write_timeout) { + g_source_remove(write_timeout); + } + write_timeout = g_timeout_add(10000, write_already, wm); +} + +void gnt_wm_move_window(GntWM *wm, GntWidget *widget, int x, int y) +{ + gboolean ret = TRUE; + GntNode *node; + + while (widget->parent) + widget = widget->parent; + node = g_hash_table_lookup(wm->nodes, widget); + if (!node) + return; + + g_signal_emit(wm, signals[SIG_CONFIRM_MOVE], 0, widget, &x, &y, &ret); + if (!ret) + return; /* resize is not permitted */ + + gnt_widget_set_position(widget, x, y); + move_panel(node->panel, y, x); + + g_signal_emit(wm, signals[SIG_MOVED], 0, node); + if (gnt_style_get_bool(GNT_STYLE_REMPOS, TRUE) && GNT_IS_BOX(widget)) { + const char *title = GNT_BOX(widget)->title; + if (title) { + GntPosition *p = g_new0(GntPosition, 1); + GntWidget *wid = node->me; + p->x = wid->priv.x; + p->y = wid->priv.y; + g_hash_table_replace(wm->positions, g_strdup(title), p); + write_positions_to_file(wm); + } + } + + update_screen(wm); +} + +static void +gnt_wm_give_focus(GntWM *wm, GntWidget *widget) +{ + GntNode *node = g_hash_table_lookup(wm->nodes, widget); + + if (!node) + return; + + if (widget != wm->_list.window && !GNT_IS_MENU(widget) && + wm->ordered->data != widget) { + GntWidget *w = wm->ordered->data; + wm->ordered = g_list_bring_to_front(wm->ordered, widget); + gnt_widget_set_focus(w, FALSE); + } + + gnt_widget_set_focus(widget, TRUE); + GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_URGENT); + gnt_widget_draw(widget); + top_panel(node->panel); + + if (wm->_list.window) { + GntNode *nd = g_hash_table_lookup(wm->nodes, wm->_list.window); + top_panel(nd->panel); + } + update_screen(wm); + draw_taskbar(wm, FALSE); +} + +void gnt_wm_update_window(GntWM *wm, GntWidget *widget) +{ + GntNode *node; + + while (widget->parent) + widget = widget->parent; + if (!GNT_IS_MENU(widget)) + gnt_box_sync_children(GNT_BOX(widget)); + + node = g_hash_table_lookup(wm->nodes, widget); + if (node == NULL) { + gnt_wm_new_window(wm, widget); + } else + g_signal_emit(wm, signals[SIG_UPDATE_WIN], 0, node); + + copy_win(widget, node); + update_screen(wm); + draw_taskbar(wm, FALSE); +} + +gboolean gnt_wm_process_click(GntWM *wm, GntMouseEvent event, int x, int y, GntWidget *widget) +{ + gboolean ret = TRUE; + idle_update = TRUE; + g_signal_emit(wm, signals[SIG_MOUSE_CLICK], 0, event, x, y, widget, &ret); + return ret; +} + +void gnt_wm_raise_window(GntWM *wm, GntWidget *widget) +{ + g_signal_emit(wm, signals[SIG_GIVE_FOCUS], 0, widget); +} + diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/gntwm.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gntwm.h Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,168 @@ + +#include "gntwidget.h" +#include "gntmenu.h" + +#include + +#define GNT_TYPE_WM (gnt_wm_get_gtype()) +#define GNT_WM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNT_TYPE_WM, GntWM)) +#define GNT_WM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GNT_TYPE_WM, GntWMClass)) +#define GNT_IS_WM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GNT_TYPE_WM)) +#define GNT_IS_WM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GNT_TYPE_WM)) +#define GNT_WM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GNT_TYPE_WM, GntWMClass)) + +typedef enum +{ + GNT_KP_MODE_NORMAL, + GNT_KP_MODE_RESIZE, + GNT_KP_MODE_MOVE, +} GntKeyPressMode; + +typedef struct +{ + GntWidget *me; + + WINDOW *window; + int scroll; + PANEL *panel; +} GntNode; + +typedef struct _GntWM GntWM; + +typedef struct _GnPosition +{ + int x; + int y; +} GntPosition; + +/** + * An application can register actions which will show up in a 'start-menu' like popup + */ +typedef struct _GnAction +{ + const char *label; + void (*callback)(); +} GntAction; + +struct _GntWM +{ + GntBindable inherit; + + GMainLoop *loop; + + GList *list; /* List of windows ordered on their creation time */ + GList *ordered; /* List of windows ordered on their focus */ + + struct { + GntWidget *window; + GntWidget *tree; + } _list, + *windows, /* Window-list window */ + *actions; /* Action-list window */ + + GHashTable *nodes; /* GntWidget -> GntNode */ + + GList *acts; /* List of actions */ + + /** + * There can be at most one menu at a time on the screen. + * If there is a menu being displayed, then all the keystrokes will be sent to + * the menu until it is closed, either when the user activates a menuitem, or + * presses Escape to cancel the menu. + */ + GntMenu *menu; /* Currently active menu */ + + /** + * 'event_stack' will be set to TRUE when a user-event, ie. a mouse-click + * or a key-press is being processed. This variable will be used to determine + * whether to give focus to a new window. + */ + gboolean event_stack; + + GntKeyPressMode mode; + + GHashTable *positions; + + void *res1; + void *res2; + void *res3; + void *res4; +}; + +typedef struct _GnWMClass GntWMClass; + +struct _GnWMClass +{ + GntBindableClass parent; + + /* This is called when a new window is shown */ + void (*new_window)(GntWM *wm, GntWidget *win); + + void (*decorate_window)(GntWM *wm, GntWidget *win); + /* This is called when a window is being closed */ + gboolean (*close_window)(GntWM *wm, GntWidget *win); + + /* The WM may want to confirm a size for a window first */ + gboolean (*window_resize_confirm)(GntWM *wm, GntWidget *win, int *w, int *h); + + void (*window_resized)(GntWM *wm, GntNode *node); + + /* The WM may want to confirm the position of a window */ + gboolean (*window_move_confirm)(GntWM *wm, GntWidget *win, int *x, int *y); + + void (*window_moved)(GntWM *wm, GntNode *node); + + /* This gets called when: + * - the title of the window changes + * - the 'urgency' of the window changes + */ + void (*window_update)(GntWM *wm, GntNode *node); + + /* This should usually return NULL if the keys were processed by the WM. + * If not, the WM can simply return the original string, which will be + * processed by the default WM. The custom WM can also return a different + * static string for the default WM to process. + */ + gboolean (*key_pressed)(GntWM *wm, const char *key); + + gboolean (*mouse_clicked)(GntWM *wm, GntMouseEvent event, int x, int y, GntWidget *widget); + + /* Whatever the WM wants to do when a window is given focus */ + void (*give_focus)(GntWM *wm, GntWidget *widget); + + /* List of windows. Although the WM can keep a list of its own for the windows, + * it'd be better if there was a way to share between the 'core' and the WM. + */ + /*const GList *(*window_list)();*/ + + void (*res1)(void); + void (*res2)(void); + void (*res3)(void); + void (*res4)(void); +}; + +G_BEGIN_DECLS + +GType gnt_wm_get_gtype(void); + +void gnt_wm_new_window(GntWM *wm, GntWidget *widget); + +void gnt_wm_window_decorate(GntWM *wm, GntWidget *widget); + +void gnt_wm_window_close(GntWM *wm, GntWidget *widget); + +gboolean gnt_wm_process_input(GntWM *wm, const char *string); + +gboolean gnt_wm_process_click(GntWM *wm, GntMouseEvent event, int x, int y, GntWidget *widget); + +void gnt_wm_resize_window(GntWM *wm, GntWidget *widget, int width, int height); + +void gnt_wm_move_window(GntWM *wm, GntWidget *widget, int x, int y); + +void gnt_wm_update_window(GntWM *wm, GntWidget *widget); + +void gnt_wm_raise_window(GntWM *wm, GntWidget *widget); + +time_t gnt_wm_get_idle_time(void); + +G_END_DECLS diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/test.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/test.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,125 @@ +#include "gntbutton.h" +#include "gnt.h" +#include "gntkeys.h" +#include "gnttree.h" +#include "gntbox.h" + +static gboolean +key_pressed(GntWidget *widget, const char *text, gpointer null) +{ + GntWidget *w = null; + GntWidget *box = gnt_box_new(FALSE, FALSE); + GntWidget *label = gnt_label_new("so wassup!!"); + + gnt_box_add_widget(GNT_BOX(box), label); + GNT_WIDGET_UNSET_FLAGS(box, GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW); + gnt_box_set_title(GNT_BOX(box), "This is a test"); + + gnt_widget_show(box); +#if 0 + + gnt_widget_set_focus(w, TRUE); + + /* XXX: This is to just test stuff */ + if (text[0] == 27) + { + if (strcmp(text+1, GNT_KEY_LEFT) == 0 && w->priv.x) + (w->priv.x)--; + else if (strcmp(text+1, GNT_KEY_RIGHT) == 0) + (w->priv.x)++; + else if (strcmp(text+1, GNT_KEY_UP) == 0 && w->priv.y) + (w->priv.y)--; + else if (strcmp(text+1, GNT_KEY_DOWN) == 0) + (w->priv.y)++; + } + + gnt_widget_draw(w); +#endif + + return FALSE; +} + +static void +button1(GntWidget *widget, gpointer null) +{ + printf("OLAAA"); + gnt_widget_destroy(null); +} + +static void +button2(GntWidget *widget, gpointer null) +{ + printf("BOOYAA"); +} + +static gboolean +w_scroll(GntWidget *tree) +{ + g_return_val_if_fail(GNT_IS_TREE(tree), FALSE); + gnt_tree_scroll(GNT_TREE(tree), 1); + /*wscrl(tree->window, 1);*/ + /*box(tree->window, ACS_VLINE, ACS_HLINE);*/ + /*wrefresh(tree->window);*/ + /*char *s = 0;*/ + /**s = 'a';*/ + return TRUE; +} + +int main() +{ + gnt_init(); + + GntWidget *widget = gnt_button_new("Button 1"); + GntWidget *widget2 = gnt_button_new("Button 2 has a longish text with a UTF-8 thing …"); + GntWidget *label = gnt_label_new("So wassup dudes and dudettes!!\nSo this is, like,\nthe third line!! \\o/"); + GntWidget *vbox, *hbox, *tree; + WINDOW *test; + + box(stdscr, 0, 0); + wrefresh(stdscr); + + vbox = gnt_box_new(FALSE, FALSE); + hbox = gnt_box_new(FALSE, TRUE); + + gnt_widget_set_name(vbox, "vbox"); + gnt_widget_set_name(hbox, "hbox"); + gnt_widget_set_name(widget, "widget"); + gnt_widget_set_name(widget2, "widget2"); + + gnt_box_add_widget(GNT_BOX(vbox), widget); + gnt_box_add_widget(GNT_BOX(vbox), widget2); + + gnt_box_add_widget(GNT_BOX(hbox), label); + /*gnt_box_add_widget(GNT_BOX(hbox), vbox);*/ + + gnt_box_add_widget(GNT_BOX(hbox), gnt_entry_new("a")); + + tree = gnt_tree_new(); + gnt_box_add_widget(GNT_BOX(hbox), tree); + + gnt_tree_add_row_after(GNT_TREE(tree), "a", "a", NULL, NULL); + gnt_tree_add_row_after(GNT_TREE(tree), "c", "c", NULL, NULL); + gnt_tree_add_row_after(GNT_TREE(tree), "d", "d", NULL, NULL); + gnt_tree_add_row_after(GNT_TREE(tree), "e", "e", "a", NULL); + gnt_tree_add_row_after(GNT_TREE(tree), "b", "b", "d", NULL); + + GNT_WIDGET_UNSET_FLAGS(hbox, GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW); + gnt_box_set_title(GNT_BOX(hbox), "111111111111111111111111111111111111111111111111111111111111111This is the title …"); + + /*gnt_widget_set_take_focus(vbox, TRUE);*/ + /*gnt_widget_set_take_focus(hbox, TRUE);*/ + /*gnt_widget_set_position(hbox, 10, 10);*/ + + gnt_widget_show(hbox); + + g_signal_connect(hbox, "key_pressed", G_CALLBACK(key_pressed), tree); + g_signal_connect(widget, "activate", G_CALLBACK(button1), hbox); + g_signal_connect(widget2, "activate", G_CALLBACK(button2), hbox); + + /*g_timeout_add(1000, (GSourceFunc)w_scroll, tree);*/ + + gnt_main(); + + return 0; +} + diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/test/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/test/Makefile Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,16 @@ +CC=gcc +CFLAGS=`pkg-config --cflags gobject-2.0 gmodule-2.0` -g -I../ -DSTANDALONE +LDFLAGS=`pkg-config --libs gobject-2.0 gmodule-2.0 gnt` -pg + +EXAMPLES=combo focus tv multiwin keys menu + +all: + make examples + +clean: + rm -f $(EXAMPLES) *.so wm + +WM: wm + for i in $(EXAMPLES); do gcc -shared $(CFLAGS) -USTANDALONE $(LDFLAGS) $${i}.c -o $${i}.so ; done + +examples: $(EXAMPLES) diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/test/combo.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/test/combo.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,82 @@ +#include +#include +#include +#include +#include +#include + +static void +button_activated(GntWidget *b, GntComboBox *combo) +{ + GntWidget *w = b->parent; + + gnt_box_add_widget(GNT_BOX(w), + gnt_label_new(gnt_combo_box_get_selected_data(GNT_COMBO_BOX(combo)))); + fprintf(stderr, "%s\n", gnt_combo_box_get_selected_data(GNT_COMBO_BOX(combo))); + gnt_box_readjust(GNT_BOX(w->parent)); +} + +int main() +{ + GntWidget *box, *combo, *button; + GntWidget *hbox; + +#ifdef STANDALONE + freopen(".error", "w", stderr); + gnt_init(); +#endif + + box = gnt_box_new(FALSE, TRUE); + gnt_widget_set_name(box, "box"); + gnt_box_set_alignment(GNT_BOX(box), GNT_ALIGN_MID); + gnt_box_set_pad(GNT_BOX(box), 0); + + gnt_box_set_toplevel(GNT_BOX(box), TRUE); + gnt_box_set_title(GNT_BOX(box), "Checkbox"); + + hbox = gnt_box_new(FALSE, FALSE); + gnt_box_set_pad(GNT_BOX(hbox), 0); + gnt_box_set_alignment(GNT_BOX(hbox), GNT_ALIGN_MID); + gnt_widget_set_name(hbox, "upper"); + + combo = gnt_combo_box_new(); + gnt_combo_box_add_data(GNT_COMBO_BOX(combo), "1", "1"); + gnt_combo_box_add_data(GNT_COMBO_BOX(combo), "2", "2"); + gnt_combo_box_add_data(GNT_COMBO_BOX(combo), "3", "3abcdefghijklmnopqrstuvwxyz"); + gnt_combo_box_add_data(GNT_COMBO_BOX(combo), "4", "4"); + gnt_combo_box_add_data(GNT_COMBO_BOX(combo), "5", "5"); + gnt_combo_box_add_data(GNT_COMBO_BOX(combo), "6", "6"); + gnt_combo_box_add_data(GNT_COMBO_BOX(combo), "7", "7"); + gnt_combo_box_add_data(GNT_COMBO_BOX(combo), "8", "8"); + gnt_combo_box_add_data(GNT_COMBO_BOX(combo), "9", "9"); + + GntWidget *l = gnt_label_new("Select"); + gnt_box_add_widget(GNT_BOX(hbox), l); + gnt_widget_set_size(l, 0, 1); + gnt_box_add_widget(GNT_BOX(hbox), combo); + + gnt_box_add_widget(GNT_BOX(box), hbox); + + hbox = gnt_box_new(TRUE, FALSE); + gnt_box_set_alignment(GNT_BOX(hbox), GNT_ALIGN_MID); + gnt_widget_set_name(hbox, "lower"); + + button = gnt_button_new("OK"); + gnt_box_add_widget(GNT_BOX(hbox), button); + g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(button_activated), combo); + + gnt_box_add_widget(GNT_BOX(box), hbox); + + gnt_box_add_widget(GNT_BOX(box), gnt_check_box_new("check box")); + + gnt_widget_show(box); + +#ifdef STANDALONE + gnt_main(); + + gnt_quit(); +#endif + + return 0; +} + diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/test/focus.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/test/focus.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,92 @@ +#include "gntbutton.h" +#include "gnt.h" +#include "gntkeys.h" +#include "gnttree.h" +#include "gntbox.h" +#include "gntentry.h" +#include "gntlabel.h" + +static void +toggled(GntWidget *tree, gpointer key, gpointer null) +{ + GntWidget *w = gnt_box_new(FALSE, FALSE); + + gnt_box_set_toplevel(GNT_BOX(w), TRUE); + + gnt_box_add_widget(GNT_BOX(w), + gnt_label_new(gnt_tree_get_choice(GNT_TREE(tree), key) ? "Selected" : "NOT")); + gnt_widget_show(w); +} + +int main() +{ +#ifdef STANDALONE + freopen(".error", "w", stderr); + gnt_init(); +#endif + + GntWidget *label = gnt_label_new("So wassup dudes and dudettes!!\u4e0a1\u6d772\u67003\u4f4e4\u67085\nSo this is, like,\nthe third line!! \\o/"); + GntWidget *vbox, *hbox, *tree, *box, *button; + WINDOW *test; + + vbox = gnt_box_new(FALSE, FALSE); + hbox = gnt_box_new(FALSE, TRUE); + gnt_box_set_alignment(GNT_BOX(hbox), GNT_ALIGN_MID); + + gnt_widget_set_name(vbox, "vbox"); + gnt_widget_set_name(hbox, "hbox"); + + gnt_box_add_widget(GNT_BOX(hbox), label); + + GntWidget *entry = gnt_entry_new("a"); + gnt_widget_set_name(entry, "entry"); + gnt_box_add_widget(GNT_BOX(hbox), entry); + + box = gnt_box_new(FALSE, FALSE); + tree = gnt_tree_new(); + gnt_tree_set_compare_func(GNT_TREE(tree), g_utf8_collate); + gnt_widget_set_name(tree, "tree"); + gnt_box_add_widget(GNT_BOX(box), tree); + gnt_box_add_widget(GNT_BOX(hbox), box); + + gnt_tree_add_row_after(GNT_TREE(tree), "c", gnt_tree_create_row(GNT_TREE(tree), "c"), NULL, NULL); + gnt_tree_add_row_after(GNT_TREE(tree), "a", gnt_tree_create_row(GNT_TREE(tree), "a"), NULL, NULL); + gnt_tree_add_row_after(GNT_TREE(tree), "z", gnt_tree_create_row(GNT_TREE(tree), "z"), "a", NULL); + gnt_tree_add_row_after(GNT_TREE(tree), "y", gnt_tree_create_row(GNT_TREE(tree), "y"), "a", NULL); + gnt_tree_add_row_after(GNT_TREE(tree), "g", gnt_tree_create_row(GNT_TREE(tree), "g"), "a", NULL); + gnt_tree_add_row_after(GNT_TREE(tree), "d", gnt_tree_create_row(GNT_TREE(tree), "d"), NULL, NULL); + gnt_tree_add_row_after(GNT_TREE(tree), "x", gnt_tree_create_row(GNT_TREE(tree), "x"), "a", NULL); + gnt_tree_add_row_after(GNT_TREE(tree), "k", gnt_tree_create_row(GNT_TREE(tree), "k"), "a", NULL); + gnt_tree_add_row_after(GNT_TREE(tree), "e", gnt_tree_create_row(GNT_TREE(tree), "e"), "a", NULL); + gnt_tree_add_choice(GNT_TREE(tree), "b", gnt_tree_create_row(GNT_TREE(tree), "b"), "d", NULL); + + GNT_WIDGET_UNSET_FLAGS(hbox, GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW); + gnt_box_set_title(GNT_BOX(hbox), "\u4e0a\u6d77\u6700\u4f4e\u6708\u5de5 \u4e0a\u6d77\u6700\u4f4e\u6708\u5de5 ……\u4e0a\u6d77\u6700\u4f4e\u6708\u5de5 …"); + + g_signal_connect(G_OBJECT(tree), "toggled", G_CALLBACK(toggled), NULL); + + button = gnt_button_new("one"); + gnt_widget_set_name(button, "one"); + gnt_box_add_widget(GNT_BOX(vbox), button); + + button = gnt_button_new("two"); + gnt_widget_set_name(button, "two"); + gnt_box_add_widget(GNT_BOX(vbox), button); + + button = gnt_button_new("three"); + gnt_widget_set_name(button, "three"); + gnt_box_add_widget(GNT_BOX(vbox), button); + + gnt_box_add_widget(GNT_BOX(hbox), vbox); + + gnt_widget_show(hbox); + +#ifdef STANDALONE + gnt_main(); + + gnt_quit(); +#endif + + return 0; +} + diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/test/key.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/test/key.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,18 @@ +#include + +int main() +{ + int ch; + initscr(); + + noecho(); + + while ((ch = getch())) { + printw("%d ", ch); + refresh(); + } + + endwin(); + return 0; +} + diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/test/keys.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/test/keys.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,60 @@ +#include +#include +#include +#include + +static gboolean +print_keycode(GntEntry *entry, const char *text, gpointer null) +{ + char *s = g_strdup_printf("%s ", text); + gnt_entry_set_text(entry, s); + g_free(s); + if (text[0] == 27) + { + if (strncmp(text + 1, "[M ", 3) == 0) + { + int x = (unsigned)text[4]; + int y = (unsigned)text[5]; + if (x < 0) x += 256; + if (y < 0) y += 256; + x -= 33; + y -= 33; + s = g_strdup_printf("ldown %d %d", x, y); + gnt_entry_set_text(entry, s); + g_free(s); + } + else if (strncmp(text + 1, "[M#", 3) == 0) + gnt_entry_set_text(entry, "up"); + else + return FALSE; + return TRUE; + } + else + return TRUE; +} + +int main() +{ + GntWidget *window, *entry; + + gnt_init(); + + freopen(".error", "w", stderr); + + window = gnt_hbox_new(FALSE); + gnt_box_set_toplevel(GNT_BOX(window), TRUE); + + gnt_box_add_widget(GNT_BOX(window), gnt_label_new("Press any key: ")); + + entry = gnt_entry_new(NULL); + gnt_box_add_widget(GNT_BOX(window), entry); + g_signal_connect(G_OBJECT(entry), "key_pressed", G_CALLBACK(print_keycode), NULL); + + gnt_widget_set_position(window, getmaxx(stdscr) / 2 - 12, getmaxy(stdscr) / 2 - 3); + gnt_widget_show(window); + + gnt_main(); + gnt_quit(); + return 0; +} + diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/test/menu.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/test/menu.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,64 @@ +#include "gnt.h" +#include "gntbox.h" +#include "gntlabel.h" +#include "gntmenu.h" +#include "gntmenuitem.h" +#include "gntwindow.h" + +void dothis(GntMenuItem *item, gpointer null) +{ + GntWidget *w = gnt_vbox_new(FALSE); + gnt_box_set_toplevel(GNT_BOX(w), TRUE); + gnt_box_add_widget(GNT_BOX(w), + gnt_label_new("Callback to a menuitem")); + gnt_widget_show(w); +} + +int main() +{ + freopen(".error", "w", stderr); + gnt_init(); + + GntWidget *menu = gnt_menu_new(GNT_MENU_TOPLEVEL); + GObject *item = gnt_menuitem_new("File"); + + gnt_menu_add_item(GNT_MENU(menu), GNT_MENUITEM(item)); + + item = gnt_menuitem_new("Edit"); + gnt_menu_add_item(GNT_MENU(menu), GNT_MENUITEM(item)); + + item = gnt_menuitem_new("Help"); + gnt_menu_add_item(GNT_MENU(menu), GNT_MENUITEM(item)); + + GntWidget *sub = gnt_menu_new(GNT_MENU_POPUP); + gnt_menuitem_set_submenu(GNT_MENUITEM(item), GNT_MENU(sub)); + + item = gnt_menuitem_new("Online Help"); + gnt_menu_add_item(GNT_MENU(sub), GNT_MENUITEM(item)); + + item = gnt_menuitem_new("About"); + gnt_menu_add_item(GNT_MENU(sub), GNT_MENUITEM(item)); + + sub = gnt_menu_new(GNT_MENU_POPUP); + gnt_menuitem_set_submenu(GNT_MENUITEM(item), GNT_MENU(sub)); + + item = gnt_menuitem_new("Online Help"); + gnt_menu_add_item(GNT_MENU(sub), GNT_MENUITEM(item)); + gnt_menuitem_set_callback(GNT_MENUITEM(item), dothis, NULL); + + gnt_screen_menu_show(menu); + + GntWidget *win = gnt_window_new(); + gnt_box_add_widget(GNT_BOX(win), + gnt_label_new("...")); + gnt_box_set_title(GNT_BOX(win), "Title"); + gnt_window_set_menu(GNT_WINDOW(win), GNT_MENU(menu)); + gnt_widget_show(win); + + gnt_main(); + + gnt_quit(); + + return 0; +} + diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/test/multiwin.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/test/multiwin.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,87 @@ +#include "gnt.h" +#include "gntbutton.h" +#include "gntentry.h" +#include "gntkeys.h" +#include "gntlabel.h" +#include "gnttree.h" +#include "gntbox.h" + +gboolean show(GntWidget *w) +{ + return FALSE; +} + +int main() +{ +#ifdef STANDALONE + freopen(".error", "w", stderr); + gnt_init(); +#endif + + GntWidget *hbox, *tree, *box2; + + hbox = gnt_box_new(FALSE, TRUE); + box2 = gnt_box_new(FALSE, TRUE); + + gnt_widget_set_name(hbox, "hbox"); + gnt_widget_set_name(box2, "box2"); + + tree = gnt_tree_new_with_columns(3); + GNT_WIDGET_SET_FLAGS(tree, GNT_WIDGET_NO_BORDER); + gnt_tree_set_column_titles(GNT_TREE(tree), "12345678901234567890", "column 2", "column3"); + gnt_tree_set_show_title(GNT_TREE(tree), TRUE); + gnt_widget_set_name(tree, "tree"); + gnt_box_add_widget(GNT_BOX(hbox), tree); + + gnt_box_set_toplevel(GNT_BOX(hbox), TRUE); + gnt_box_set_title(GNT_BOX(hbox), "Testing the tree widget"); + + gnt_box_set_toplevel(GNT_BOX(box2), TRUE); + gnt_box_set_title(GNT_BOX(box2), "On top"); + + gnt_box_add_widget(GNT_BOX(box2), gnt_label_new("asdasd")); + gnt_box_add_widget(GNT_BOX(box2), gnt_entry_new(NULL)); + + gnt_widget_show(hbox); + gnt_widget_set_position(box2, 80, 40); + gnt_widget_show(box2); + + gnt_tree_add_row_after(GNT_TREE(tree), "a", + gnt_tree_create_row(GNT_TREE(tree), "alaskdjfkashfashfah kfalkdhflsiafhlasf", " long text", "a2"), NULL, NULL); + gnt_tree_add_row_after(GNT_TREE(tree), "c", + gnt_tree_create_row(GNT_TREE(tree), "casdgertqhyeqgasfeytwfga fg arf agfwa ", " long text", "a2"), NULL, NULL); + gnt_tree_add_row_after(GNT_TREE(tree), "d", gnt_tree_create_row(GNT_TREE(tree), "d", " long text", "a2"), NULL, NULL); + gnt_tree_add_row_after(GNT_TREE(tree), "e", gnt_tree_create_row(GNT_TREE(tree), "e", " long text", "a2"), "a", NULL); + gnt_tree_add_row_after(GNT_TREE(tree), "b", gnt_tree_create_row(GNT_TREE(tree), "b", "this is", "a2"), "d", NULL); + + gnt_tree_add_choice(GNT_TREE(tree), "1", gnt_tree_create_row(GNT_TREE(tree), "1", " long text", "a2"), NULL, NULL); + gnt_tree_add_row_after(GNT_TREE(tree), "2", gnt_tree_create_row(GNT_TREE(tree), "2", " long text", "a2"), NULL, NULL); + gnt_tree_add_row_after(GNT_TREE(tree), "3", gnt_tree_create_row(GNT_TREE(tree), "3", " long text", "a2"), NULL, NULL); + gnt_tree_add_row_after(GNT_TREE(tree), "4", gnt_tree_create_row(GNT_TREE(tree), "4", " long text", "a2"), "a", NULL); + gnt_tree_add_row_after(GNT_TREE(tree), "5", gnt_tree_create_row(GNT_TREE(tree), "5", " long text", "a2"), "d", NULL); + + gnt_tree_add_row_after(GNT_TREE(tree), "6", gnt_tree_create_row(GNT_TREE(tree), "6", " long text", "a2"), "4", NULL); + + int i; + for (i = 110; i < 430; i++) + { + char *s; + s = g_strdup_printf("%d", i); /* XXX: yes, leaking */ + gnt_tree_add_row_after(GNT_TREE(tree), s, gnt_tree_create_row(GNT_TREE(tree), s, " long text", "a2"), "4", NULL); + } + + gnt_tree_set_row_flags(GNT_TREE(tree), "e", GNT_TEXT_FLAG_DIM); + + gnt_tree_set_selected(GNT_TREE(tree), "2"); + + g_timeout_add(5000, (GSourceFunc)show, box2); + +#ifdef STANDALONE + gnt_main(); + + gnt_quit(); +#endif + + return 0; +} + diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/test/tv.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/test/tv.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,107 @@ +#include "gntbutton.h" +#include "gnt.h" +#include "gntkeys.h" +#include "gnttree.h" +#include "gntbox.h" +#include "gntentry.h" +#include "gnttextview.h" + +static gboolean +key_pressed(GntWidget *w, const char *key, GntWidget *view) +{ + if (key[0] == '\r' && key[1] == 0) + { + gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(view), + gnt_entry_get_text(GNT_ENTRY(w)), + GNT_TEXT_FLAG_UNDERLINE | GNT_TEXT_FLAG_HIGHLIGHT); + gnt_entry_add_to_history(GNT_ENTRY(w), gnt_entry_get_text(GNT_ENTRY(w))); + gnt_text_view_next_line(GNT_TEXT_VIEW(view)); + gnt_entry_clear(GNT_ENTRY(w)); + if (gnt_text_view_get_lines_below(GNT_TEXT_VIEW(view)) <= 1) + gnt_text_view_scroll(GNT_TEXT_VIEW(view), 0); + gnt_entry_remove_suggest(GNT_ENTRY(w), "acb"); + + return TRUE; + } + else if (key[0] == 27) + { + if (strcmp(key, GNT_KEY_UP) == 0) + gnt_text_view_scroll(GNT_TEXT_VIEW(view), -1); + else if (strcmp(key, GNT_KEY_DOWN) == 0) + gnt_text_view_scroll(GNT_TEXT_VIEW(view), 1); + else + return FALSE; + return TRUE; + } + + return FALSE; +} + +int main() +{ + GntWidget *hbox, *entry, *view; + +#ifdef STANDALONE + freopen(".error", "w", stderr); + + gnt_init(); +#endif + + hbox = gnt_box_new(FALSE, TRUE); + gnt_widget_set_name(hbox, "hbox"); + gnt_box_set_toplevel(GNT_BOX(hbox), TRUE); + gnt_box_set_fill(GNT_BOX(hbox), FALSE); + gnt_box_set_title(GNT_BOX(hbox), "Textview test"); + gnt_box_set_alignment(GNT_BOX(hbox), GNT_ALIGN_MID); + + entry = gnt_entry_new(NULL); + gnt_widget_set_name(entry, "entry"); + GNT_WIDGET_SET_FLAGS(entry, GNT_WIDGET_CAN_TAKE_FOCUS); + + gnt_entry_set_word_suggest(GNT_ENTRY(entry), TRUE); + gnt_entry_set_always_suggest(GNT_ENTRY(entry), FALSE); + gnt_entry_add_suggest(GNT_ENTRY(entry), "a"); + gnt_entry_add_suggest(GNT_ENTRY(entry), "ab"); + gnt_entry_add_suggest(GNT_ENTRY(entry), "abe"); + gnt_entry_add_suggest(GNT_ENTRY(entry), "abc"); + gnt_entry_add_suggest(GNT_ENTRY(entry), "abcde"); + gnt_entry_add_suggest(GNT_ENTRY(entry), "abcd"); + gnt_entry_add_suggest(GNT_ENTRY(entry), "acb"); + + view = gnt_text_view_new(); + gnt_widget_set_name(view, "view"); + + gnt_widget_set_size(view, 20, 15); + gnt_widget_set_size(entry, 20, 1); + + gnt_box_add_widget(GNT_BOX(hbox), view); + gnt_box_add_widget(GNT_BOX(hbox), entry); + gnt_box_add_widget(GNT_BOX(hbox), gnt_button_new("OK")); + + gnt_widget_show(hbox); + + gnt_entry_set_history_length(GNT_ENTRY(entry), -1); + g_signal_connect_after(G_OBJECT(entry), "key_pressed", G_CALLBACK(key_pressed), view); + + gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(view), "\n", GNT_TEXT_FLAG_NORMAL); + gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(view), "plugins: ", GNT_TEXT_FLAG_BOLD); + gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(view), "this is the 1st line\n", GNT_TEXT_FLAG_NORMAL); + + gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(view), "plugins: ", GNT_TEXT_FLAG_BOLD); + gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(view), "this is the 2nd line\n", GNT_TEXT_FLAG_NORMAL); + + gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(view), "plugins: ", GNT_TEXT_FLAG_BOLD); + gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(view), "this is the 3rd line\n", GNT_TEXT_FLAG_NORMAL); + + gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(view), "plugins: ", GNT_TEXT_FLAG_BOLD); + gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(view), "this is the 4th line\n", GNT_TEXT_FLAG_NORMAL); + +#ifdef STANDALONE + gnt_main(); + + gnt_quit(); +#endif + + return 0; +} + diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/test/wm.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/test/wm.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,67 @@ +#include + +#include +#include +#include +#include + +static gboolean +key_pressed(GntEntry *entry, const char *text, gpointer null) +{ + if (*text != '\r') + return FALSE; + + { + const char *cmd; + void *handle; + void (*func)(); + + cmd = gnt_entry_get_text(entry); + handle = g_module_open(cmd, G_MODULE_BIND_LOCAL); + if (handle && g_module_symbol(handle, "main", (gpointer)&func)) + { + char *argv[] = {cmd, NULL}; + gnt_entry_clear(entry); + func(1, argv); + } + else + { + GntWidget *widget = gnt_vbox_new(FALSE); + gnt_box_set_toplevel(GNT_BOX(widget), TRUE); + gnt_box_set_title(GNT_BOX(widget), "Error"); + gnt_box_add_widget(GNT_BOX(widget), gnt_label_new("Could not execute.")); + gnt_box_add_widget(GNT_BOX(widget), gnt_label_new(g_module_error())); + + gnt_widget_show(widget); + } + } + + return TRUE; +} + +int main() +{ + GntWidget *window, *entry; + + freopen(".error", "w", stderr); + + gnt_init(); + + window = gnt_hbox_new(FALSE); + + gnt_box_add_widget(GNT_BOX(window), gnt_label_new("Command")); + + entry = gnt_entry_new(NULL); + g_signal_connect(G_OBJECT(entry), "key_pressed", G_CALLBACK(key_pressed), NULL); + gnt_box_add_widget(GNT_BOX(window), entry); + + gnt_widget_set_position(window, 0, getmaxy(stdscr) - 2); + gnt_widget_show(window); + + gnt_main(); + + gnt_quit(); + + return 0; +} + diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/wms/Makefile.am --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/wms/Makefile.am Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,26 @@ +s_la_LDFLAGS = -module -avoid-version + +plugin_LTLIBRARIES = \ + s.la + +plugindir = $(libdir)/gaim + +s_la_SOURCES = s.c +s_la_LIBADD = \ + $(GLIB_LIBS) \ + $(top_builddir)/finch/libgnt/libgnt.la \ + $(top_builddir)/libpurple/libpurple.la + +EXTRA_DIST = + +AM_CPPFLAGS = \ + -DDATADIR=\"$(datadir)\" \ + -DVERSION=\"$(VERSION)\" \ + -I$(top_srcdir)/libpurple \ + -I$(top_srcdir)/finch \ + -I$(top_srcdir)/finch/libgnt \ + $(DEBUG_CFLAGS) \ + $(GLIB_CFLAGS) \ + $(GNT_CFLAGS) \ + $(PLUGIN_CFLAGS) + diff -r 317e7613e581 -r 0e3a8505ebbe finch/libgnt/wms/s.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/wms/s.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,247 @@ +#include +#include + +#include "gnt.h" +#include "gntbox.h" +#include "gntmenu.h" +#include "gntstyle.h" +#include "gntwm.h" +#include "gntwindow.h" +#include "gntlabel.h" + +#include "blist.h" + +#define TYPE_S (s_get_gtype()) + +typedef struct _S +{ + GntWM inherit; +} S; + +typedef struct _SClass +{ + GntWMClass inherit; +} SClass; + +GType s_get_gtype(void); +void gntwm_init(GntWM **wm); + +static void (*org_new_window)(GntWM *wm, GntWidget *win); + +static void +envelope_buddylist(GntWidget *win) +{ + int w, h; + gnt_widget_get_size(win, &w, &h); + wresize(win->window, h, w + 1); + mvwvline(win->window, 0, w, ACS_VLINE | COLOR_PAIR(GNT_COLOR_NORMAL), h); + touchwin(win->window); +} + +static void +envelope_normal_window(GntWidget *win) +{ + int w, h; + + if (GNT_WIDGET_IS_FLAG_SET(win, GNT_WIDGET_NO_BORDER | GNT_WIDGET_TRANSIENT)) + return; + + gnt_widget_get_size(win, &w, &h); + wbkgdset(win->window, ' ' | COLOR_PAIR(GNT_COLOR_NORMAL)); + mvwprintw(win->window, 0, w - 4, "[X]"); +} + +static void +s_decorate_window(GntWM *wm, GntWidget *win) +{ + const char *name; + + name = gnt_widget_get_name(win); + if (name && strcmp(name, "buddylist") == 0) { + envelope_buddylist(win); + } else { + envelope_normal_window(win); + } +} + +static void +s_window_update(GntWM *wm, GntNode *node) +{ + s_decorate_window(wm, node->me); +} + +static void +s_new_window(GntWM *wm, GntWidget *win) +{ + int x, y, w, h; + int maxx, maxy; + const char *name; + gboolean blist = FALSE; + + if (!GNT_IS_MENU(win)) { + getmaxyx(stdscr, maxy, maxx); + + gnt_widget_get_position(win, &x, &y); + gnt_widget_get_size(win, &w, &h); + + name = gnt_widget_get_name(win); + + if (name && strcmp(name, "buddylist") == 0) { + /* The buddylist doesn't have no border nor nothing! */ + x = 0; + y = 0; + h = maxy - 1; + blist = TRUE; + + gnt_box_set_toplevel(GNT_BOX(win), FALSE); + GNT_WIDGET_SET_FLAGS(win, GNT_WIDGET_CAN_TAKE_FOCUS); + + gnt_widget_set_position(win, x, y); + mvwin(win->window, y, x); + + gnt_widget_set_size(win, -1, h + 2); /* XXX: Why is the +2 needed here? -- sadrul */ + } else if (!GNT_WIDGET_IS_FLAG_SET(win, GNT_WIDGET_TRANSIENT)) { + const char *title = GNT_BOX(win)->title; + if (title == NULL || !g_hash_table_lookup(wm->positions, title)) { + /* In the middle of the screen */ + x = (maxx - w) / 2; + y = (maxy - h) / 2; + + gnt_widget_set_position(win, x, y); + mvwin(win->window, y, x); + } + } + } + org_new_window(wm, win); + + if (blist) + gnt_wm_raise_window(wm, win); +} + +static GntWidget * +find_widget(GntWM *wm, const char *wname) +{ + const GList *iter = wm->list; + for (; iter; iter = iter->next) { + GntWidget *widget = iter->data; + const char *name = gnt_widget_get_name(widget); + if (name && strcmp(name, wname) == 0) { + return widget; + } + } + return NULL; +} + +static gboolean +s_mouse_clicked(GntWM *wm, GntMouseEvent event, int cx, int cy, GntWidget *widget) +{ + int x, y, w, h; + + if (!widget) + return FALSE; + /* This might be a place to bring up a context menu */ + + if (event != GNT_LEFT_MOUSE_DOWN || + GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER)) + return FALSE; + + gnt_widget_get_position(widget, &x, &y); + gnt_widget_get_size(widget, &w, &h); + + if (cy == y && cx == x + w - 3) { + gnt_widget_destroy(widget); + return TRUE; + } + + return FALSE; +} + +static gboolean +toggle_buddylist(GntBindable *bindable, GList *null) +{ + GntWM *wm = GNT_WM(bindable); + GntWidget *blist = find_widget(wm, "buddylist"); + if (blist) + gnt_widget_destroy(blist); + else + gaim_blist_show(); + return TRUE; +} + +static gboolean +toggle_clipboard(GntBindable *bindable, GList *n) +{ + static GntWidget *clip; + gchar *text; + int maxx, maxy; + if (clip) { + gnt_widget_destroy(clip); + clip = NULL; + return TRUE; + } + getmaxyx(stdscr, maxy, maxx); + text = gnt_get_clipboard_string(); + clip = gnt_hwindow_new(FALSE); + GNT_WIDGET_SET_FLAGS(clip, GNT_WIDGET_TRANSIENT); + GNT_WIDGET_SET_FLAGS(clip, GNT_WIDGET_NO_BORDER); + gnt_box_set_pad(GNT_BOX(clip), 0); + gnt_box_add_widget(GNT_BOX(clip), gnt_label_new(" ")); + gnt_box_add_widget(GNT_BOX(clip), gnt_label_new(text)); + gnt_box_add_widget(GNT_BOX(clip), gnt_label_new(" ")); + gnt_widget_set_position(clip, 0, 0); + gnt_widget_draw(clip); + g_free(text); + return TRUE; +} + +static void +s_class_init(SClass *klass) +{ + GntWMClass *pclass = GNT_WM_CLASS(klass); + + org_new_window = pclass->new_window; + + pclass->new_window = s_new_window; + pclass->decorate_window = s_decorate_window; + pclass->window_update = s_window_update; + pclass->mouse_clicked = s_mouse_clicked; + + gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "toggle-buddylist", + toggle_buddylist, "\033" "b", NULL); + gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "toggle-clipboard", + toggle_clipboard, "\033" "C", NULL); + gnt_style_read_actions(G_OBJECT_CLASS_TYPE(klass), GNT_BINDABLE_CLASS(klass)); + GNTDEBUG; +} + +void gntwm_init(GntWM **wm) +{ + *wm = g_object_new(TYPE_S, NULL); +} + +GType s_get_gtype(void) +{ + static GType type = 0; + + if(type == 0) { + static const GTypeInfo info = { + sizeof(SClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc)s_class_init, + NULL, + NULL, /* class_data */ + sizeof(S), + 0, /* n_preallocs */ + NULL, /* instance_init */ + NULL + }; + + type = g_type_register_static(GNT_TYPE_WM, + "GntS", + &info, 0); + } + + return type; +} + diff -r 317e7613e581 -r 0e3a8505ebbe finch/plugins/Makefile.am --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/plugins/Makefile.am Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,51 @@ +gntgf_la_LDFLAGS = -module -avoid-version +gnthistory_la_LDFLAGS = -module -avoid-version +gntlastlog_la_LDFLAGS = -module -avoid-version + +if PLUGINS + +plugin_LTLIBRARIES = \ + gntgf.la \ + gnthistory.la \ + gntlastlog.la + +plugindir = $(libdir)/gaim + +gntgf_la_SOURCES = gntgf.c +gnthistory_la_SOURCES = gnthistory.c +gntlastlog_la_SOURCES = lastlog.c + +gntgf_la_CFLAGS = $(X11_CFLAGS) + +gntgf_la_LIBADD = $(GLIB_LIBS) $(X11_LIBS) $(top_builddir)/finch/libgnt/libgnt.la +gnthistory_la_LIBADD = $(GLIB_LIBS) +gntlastlog_la_LIBADD = $(GLIB_LIBS) + +endif # PLUGINS + +EXTRA_DIST = + +AM_CPPFLAGS = \ + -DDATADIR=\"$(datadir)\" \ + -DVERSION=\"$(VERSION)\" \ + -I$(top_builddir)/libpurple \ + -I$(top_srcdir)/libpurple \ + -I$(top_srcdir) \ + -I$(top_srcdir)/finch \ + -I$(top_srcdir)/finch/libgnt \ + $(DEBUG_CFLAGS) \ + $(GLIB_CFLAGS) \ + $(GNT_CFLAGS) \ + $(PLUGIN_CFLAGS) + +# +# This part allows people to build their own plugins in here. +# Yes, it's a mess. +# +SUFFIXES = .c .so +.c.so: + $(LIBTOOL) --mode=compile $(CC) -DHAVE_CONFIG_H -I$(top_srcdir) $(AM_CPPFLAGS) $(CFLAGS) -c $< -o tmp$@.lo $(PLUGIN_CFLAGS) + $(LIBTOOL) --mode=link $(CC) $(CFLAGS) -o libtmp$@.la -rpath $(plugindir) tmp$@.lo $(LIBS) $(LDFLAGS) -module -avoid-version $(PLUGIN_LIBS) + @rm -f tmp$@.lo tmp$@.o libtmp$@.la + @cp .libs/libtmp$@.so* $@ + @rm -f .libs/libtmp$@.* diff -r 317e7613e581 -r 0e3a8505ebbe finch/plugins/gntclipboard.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/plugins/gntclipboard.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,168 @@ +/** + * @file gntclipboard.c + * + * Copyright (C) 2007 Richard Nelson + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "internal.h" +#include + +#define PLUGIN_STATIC_NAME "GntClipboard" + +#ifdef HAVE_X11 +#include +#include +#include +#endif + +#include +#include + +#include + +#include +#include +#include +#include + +#include + +static pid_t child = 0; + +static gulong sig_handle; + +static void +set_clip(gchar *string) +{ +#ifdef HAVE_X11 + Window w; + XEvent e, respond; + XSelectionRequestEvent *req; + const char *ids; + Display *dpy = XOpenDisplay(NULL); + + if (!dpy) + return; + ids = getenv("WINDOWID"); + if (ids == NULL) + return; + w = atoi(ids); + XSetSelectionOwner(dpy, XA_PRIMARY, w, CurrentTime); + XFlush(dpy); + XSelectInput(dpy, w, StructureNotifyMask); + while (TRUE) { + XNextEvent(dpy, &e); /* this blocks. */ + req = &e.xselectionrequest; + if (e.type == SelectionRequest) { + XChangeProperty(dpy, + req->requestor, + req->property, + XA_STRING, + 8, PropModeReplace, + (unsigned char *)string, + strlen(string)); + respond.xselection.property = req->property; + respond.xselection.type = SelectionNotify; + respond.xselection.display = req->display; + respond.xselection.requestor = req->requestor; + respond.xselection.selection = req->selection; + respond.xselection.target= req->target; + respond.xselection.time = req->time; + XSendEvent(dpy, req->requestor, 0, 0, &respond); + XFlush (dpy); + } else if (e.type == SelectionClear) { + return; + } + } +#endif + return; +} + +static void +clipboard_changed(GntWM *wm, gchar *string) +{ +#ifdef HAVE_X11 + if (child) { + kill(child, SIGTERM); + } + if ((child = fork() == 0)) { + set_clip(string); + _exit(0); + } +#endif +} + +static gboolean +plugin_load(GaimPlugin *plugin) +{ + if (!XOpenDisplay(NULL)) { + gaim_debug_warning("gntclipboard", "Couldn't find X display\n"); + return FALSE; + } + if (!getenv("WINDOWID")) { + gaim_debug_warning("gntclipboard", "Couldn't find window\n"); + return FALSE; + } + sig_handle = g_signal_connect(G_OBJECT(gnt_get_clipboard()), "clipboard_changed", G_CALLBACK(clipboard_changed), NULL); + return TRUE; +} + +static gboolean +plugin_unload(GaimPlugin *plugin) +{ + if (child) { + kill(child, SIGTERM); + child = 0; + } + g_signal_handler_disconnect(G_OBJECT(gnt_get_clipboard()), sig_handle); + return TRUE; +} + +static GaimPluginInfo info = +{ + GAIM_PLUGIN_MAGIC, + GAIM_MAJOR_VERSION, + GAIM_MINOR_VERSION, + GAIM_PLUGIN_STANDARD, + GAIM_GNT_PLUGIN_TYPE, + 0, + NULL, + GAIM_PRIORITY_DEFAULT, + "gntclipboard", + N_("GntClipboard"), + VERSION, + N_("Clipboard plugin"), + N_("When the gnt clipboard contents change, " + "the contents are made available to X, if possible."), + "Richard Nelson ", + "http://gaim.sourceforge.net", + plugin_load, + plugin_unload, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +static void +init_plugin(GaimPlugin *plugin) +{ +} + +GAIM_INIT_PLUGIN(PLUGIN_STATIC_NAME, init_plugin, info) diff -r 317e7613e581 -r 0e3a8505ebbe finch/plugins/gntgf.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/plugins/gntgf.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,390 @@ +/** + * @file gntgf.c Minimal toaster plugin in Gnt. + * + * Copyright (C) 2006 Sadrul Habib Chowdhury + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "internal.h" + +#define PLUGIN_STATIC_NAME "GntGf" + +#define PREFS_PREFIX "/plugins/gnt/gntgf" +#define PREFS_EVENT PREFS_PREFIX "/events" +#define PREFS_EVENT_SIGNONF PREFS_EVENT "/signonf" +#define PREFS_EVENT_IM_MSG PREFS_EVENT "/immsg" +#define PREFS_EVENT_CHAT_MSG PREFS_EVENT "/chatmsg" +#define PREFS_EVENT_CHAT_NICK PREFS_EVENT "/chatnick" +#define PREFS_BEEP PREFS_PREFIX "/beep" + +#define MAX_COLS 3 + +#ifdef HAVE_X11 +#define PREFS_URGENT PREFS_PREFIX "/urgent" + +#include +#include +#endif + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +typedef struct +{ + GntWidget *window; + int timer; + int column; +} GntToast; + +static GList *toasters; +static int gpsy[MAX_COLS]; +static int gpsw[MAX_COLS]; + +static void +destroy_toaster(GntToast *toast) +{ + toasters = g_list_remove(toasters, toast); + gnt_widget_destroy(toast->window); + g_source_remove(toast->timer); + g_free(toast); +} + +static gboolean +remove_toaster(GntToast *toast) +{ + GList *iter; + int h; + int col; + int nwin[MAX_COLS]; + + gnt_widget_get_size(toast->window, NULL, &h); + gpsy[toast->column] -= h; + col = toast->column; + + memset(&nwin, 0, sizeof(nwin)); + destroy_toaster(toast); + + for (iter = toasters; iter; iter = iter->next) + { + int x, y; + toast = iter->data; + nwin[toast->column]++; + if (toast->column != col) continue; + gnt_widget_get_position(toast->window, &x, &y); + y += h; + gnt_screen_move_widget(toast->window, x, y); + } + + if (nwin[col] == 0) + gpsw[col] = 0; + + return FALSE; +} + +#ifdef HAVE_X11 +static void +urgent() +{ + /* This is from deryni/tuomov's urgent_test.c */ + Display *dpy; + Window id; + const char *ids; + XWMHints *hints; + + ids = getenv("WINDOWID"); + if (ids == NULL) + return; + + id = atoi(ids); + + dpy = XOpenDisplay(NULL); + if (dpy == NULL) + return; + + hints = XGetWMHints(dpy, id); + hints->flags|=XUrgencyHint; + XSetWMHints(dpy, id, hints); + + XFlush(dpy); + XCloseDisplay(dpy); +} +#endif + +static void +notify(const char *fmt, ...) +{ + GntWidget *window; + GntToast *toast; + char *str; + int h, w, i; + va_list args; + + if (gaim_prefs_get_bool(PREFS_BEEP)) + beep(); +#ifdef HAVE_X11 + if (gaim_prefs_get_bool(PREFS_URGENT)) + urgent(); +#endif + + window = gnt_vbox_new(FALSE); + GNT_WIDGET_SET_FLAGS(window, GNT_WIDGET_TRANSIENT); + GNT_WIDGET_UNSET_FLAGS(window, GNT_WIDGET_NO_BORDER); + + va_start(args, fmt); + str = g_strdup_vprintf(fmt, args); + va_end(args); + + gnt_box_add_widget(GNT_BOX(window), + gnt_label_new_with_format(str, GNT_TEXT_FLAG_HIGHLIGHT)); + + g_free(str); + gnt_widget_size_request(window); + gnt_widget_get_size(window, &w, &h); + for (i = 0; i < MAX_COLS && gpsy[i] + h >= getmaxy(stdscr) ; ++i) + ; + if (i >= MAX_COLS) { + gaim_debug_warning("GntGf", "Dude, that's way too many popups\n"); + gnt_widget_destroy(window); + return; + } + + toast = g_new0(GntToast, 1); + toast->window = window; + toast->column = i; + gpsy[i] += h; + if (w > gpsw[i]) { + if (i == 0) + gpsw[i] = w; + else + gpsw[i] = gpsw[i - 1] + w + 1; + } + + if (i == 0 || (w + gpsw[i - 1] >= getmaxx(stdscr))) { + /* if it's going to be too far left, overlap. */ + gnt_widget_set_position(window, getmaxx(stdscr) - w - 1, + getmaxy(stdscr) - gpsy[i] - 1); + } else { + gnt_widget_set_position(window, getmaxx(stdscr) - gpsw[i - 1] - w - 1, + getmaxy(stdscr) - gpsy[i] - 1); + } + gnt_widget_draw(window); + + toast->timer = g_timeout_add(4000, (GSourceFunc)remove_toaster, toast); + toasters = g_list_prepend(toasters, toast); +} + +static void +buddy_signed_on(GaimBuddy *buddy, gpointer null) +{ + if (gaim_prefs_get_bool(PREFS_EVENT_SIGNONF)) + notify(_("%s just signed on"), gaim_buddy_get_alias(buddy)); +} + +static void +buddy_signed_off(GaimBuddy *buddy, gpointer null) +{ + if (gaim_prefs_get_bool(PREFS_EVENT_SIGNONF)) + notify(_("%s just signed off"), gaim_buddy_get_alias(buddy)); +} + +static void +received_im_msg(GaimAccount *account, const char *sender, const char *msg, + GaimConversation *conv, GaimMessageFlags flags, gpointer null) +{ + if (gaim_prefs_get_bool(PREFS_EVENT_IM_MSG)) + notify(_("%s sent you a message"), sender); +} + +static void +received_chat_msg(GaimAccount *account, const char *sender, const char *msg, + GaimConversation *conv, GaimMessageFlags flags, gpointer null) +{ + const char *nick; + + if (flags & GAIM_MESSAGE_WHISPER) + return; + + nick = GAIM_CONV_CHAT(conv)->nick; + + if (g_utf8_collate(sender, nick) == 0) + return; + + if (gaim_prefs_get_bool(PREFS_EVENT_CHAT_NICK) && + (gaim_utf8_has_word(msg, nick))) + notify(_("%s said your nick in %s"), sender, gaim_conversation_get_name(conv)); + else if (gaim_prefs_get_bool(PREFS_EVENT_CHAT_MSG)) + notify(_("%s sent a message in %s"), sender, gaim_conversation_get_name(conv)); +} + +static gboolean +plugin_load(GaimPlugin *plugin) +{ + gaim_signal_connect(gaim_blist_get_handle(), "buddy-signed-on", plugin, + GAIM_CALLBACK(buddy_signed_on), NULL); + gaim_signal_connect(gaim_blist_get_handle(), "buddy-signed-off", plugin, + GAIM_CALLBACK(buddy_signed_off), NULL); + gaim_signal_connect(gaim_conversations_get_handle(), "received-im-msg", plugin, + GAIM_CALLBACK(received_im_msg), NULL); + gaim_signal_connect(gaim_conversations_get_handle(), "received-chat-msg", plugin, + GAIM_CALLBACK(received_chat_msg), NULL); + + memset(&gpsy, 0, sizeof(gpsy)); + memset(&gpsw, 0, sizeof(gpsw)); + + return TRUE; +} + +static gboolean +plugin_unload(GaimPlugin *plugin) +{ + while (toasters) + { + GntToast *toast = toasters->data; + destroy_toaster(toast); + } + return TRUE; +} + +static struct +{ + char *pref; + char *display; +} prefs[] = +{ + {PREFS_EVENT_SIGNONF, N_("Buddy signs on/off")}, + {PREFS_EVENT_IM_MSG, N_("You receive an IM")}, + {PREFS_EVENT_CHAT_MSG, N_("Someone speaks in a chat")}, + {PREFS_EVENT_CHAT_NICK, N_("Someone says your name in a chat")}, + {NULL, NULL} +}; + +static void +pref_toggled(GntTree *tree, char *key, gpointer null) +{ + gaim_prefs_set_bool(key, gnt_tree_get_choice(tree, key)); +} + +static void +toggle_option(GntCheckBox *check, gpointer str) +{ + gaim_prefs_set_bool(str, gnt_check_box_get_checked(check)); +} + +static GntWidget * +config_frame() +{ + GntWidget *window, *tree, *check; + int i; + + window = gnt_vbox_new(FALSE); + gnt_box_set_pad(GNT_BOX(window), 0); + gnt_box_set_alignment(GNT_BOX(window), GNT_ALIGN_MID); + gnt_box_set_fill(GNT_BOX(window), TRUE); + + gnt_box_add_widget(GNT_BOX(window), + gnt_label_new(_("Notify with a toaster when"))); + + tree = gnt_tree_new(); + gnt_box_add_widget(GNT_BOX(window), tree); + + for (i = 0; prefs[i].pref; i++) + { + gnt_tree_add_choice(GNT_TREE(tree), prefs[i].pref, + gnt_tree_create_row(GNT_TREE(tree), prefs[i].display), NULL, NULL); + gnt_tree_set_choice(GNT_TREE(tree), prefs[i].pref, + gaim_prefs_get_bool(prefs[i].pref)); + } + gnt_tree_set_col_width(GNT_TREE(tree), 0, 40); + g_signal_connect(G_OBJECT(tree), "toggled", G_CALLBACK(pref_toggled), NULL); + + check = gnt_check_box_new(_("Beep too!")); + gnt_check_box_set_checked(GNT_CHECK_BOX(check), gaim_prefs_get_bool(PREFS_BEEP)); + g_signal_connect(G_OBJECT(check), "toggled", G_CALLBACK(toggle_option), PREFS_BEEP); + gnt_box_add_widget(GNT_BOX(window), check); + +#ifdef HAVE_X11 + check = gnt_check_box_new(_("Set URGENT for the terminal window.")); + gnt_check_box_set_checked(GNT_CHECK_BOX(check), gaim_prefs_get_bool(PREFS_URGENT)); + g_signal_connect(G_OBJECT(check), "toggled", G_CALLBACK(toggle_option), PREFS_URGENT); + gnt_box_add_widget(GNT_BOX(window), check); +#endif + + return window; +} + +static GaimPluginInfo info = +{ + GAIM_PLUGIN_MAGIC, + GAIM_MAJOR_VERSION, + GAIM_MINOR_VERSION, + GAIM_PLUGIN_STANDARD, + GAIM_GNT_PLUGIN_TYPE, + 0, + NULL, + GAIM_PRIORITY_DEFAULT, + "gntgf", + N_("GntGf"), + VERSION, + N_("Toaster plugin"), + N_("Toaster plugin"), + "Sadrul H Chowdhury ", + "http://gaim.sourceforge.net", + plugin_load, + plugin_unload, + NULL, + config_frame, + NULL, + NULL, + NULL +}; + +static void +init_plugin(GaimPlugin *plugin) +{ + gaim_prefs_add_none("/plugins"); + gaim_prefs_add_none("/plugins/gnt"); + + gaim_prefs_add_none("/plugins/gnt/gntgf"); + gaim_prefs_add_none(PREFS_EVENT); + + gaim_prefs_add_bool(PREFS_EVENT_SIGNONF, TRUE); + gaim_prefs_add_bool(PREFS_EVENT_IM_MSG, TRUE); + gaim_prefs_add_bool(PREFS_EVENT_CHAT_MSG, TRUE); + gaim_prefs_add_bool(PREFS_EVENT_CHAT_NICK, TRUE); + + gaim_prefs_add_bool(PREFS_BEEP, TRUE); +#ifdef HAVE_X11 + gaim_prefs_add_bool(PREFS_URGENT, FALSE); +#endif +} + +GAIM_INIT_PLUGIN(PLUGIN_STATIC_NAME, init_plugin, info) diff -r 317e7613e581 -r 0e3a8505ebbe finch/plugins/gnthistory.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/plugins/gnthistory.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,202 @@ +/** + * @file gnthistory.c Show log from previous conversation + * + * Copyright (C) 2006 Sadrul Habib Chowdhury + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* Ripped from gtk/plugins/history.c */ + +#include "internal.h" + +#include "conversation.h" +#include "debug.h" +#include "log.h" +#include "notify.h" +#include "prefs.h" +#include "signals.h" +#include "util.h" +#include "version.h" + +#include "gntplugin.h" + +#define HISTORY_PLUGIN_ID "gnt-history" + +#define HISTORY_SIZE (4 * 1024) + +static void historize(GaimConversation *c) +{ + GaimAccount *account = gaim_conversation_get_account(c); + const char *name = gaim_conversation_get_name(c); + GaimConversationType convtype; + GList *logs = NULL; + const char *alias = name; + GaimLogReadFlags flags; + char *history; + char *header; + GaimMessageFlags mflag; + + convtype = gaim_conversation_get_type(c); + if (convtype == GAIM_CONV_TYPE_IM) + { + GSList *buddies; + GSList *cur; + + /* If we're not logging, don't show anything. + * Otherwise, we might show a very old log. */ + if (!gaim_prefs_get_bool("/core/logging/log_ims")) + return; + + /* Find buddies for this conversation. */ + buddies = gaim_find_buddies(account, name); + + /* If we found at least one buddy, save the first buddy's alias. */ + if (buddies != NULL) + alias = gaim_buddy_get_contact_alias((GaimBuddy *)buddies->data); + + for (cur = buddies; cur != NULL; cur = cur->next) + { + GaimBlistNode *node = cur->data; + if ((node != NULL) && ((node->prev != NULL) || (node->next != NULL))) + { + GaimBlistNode *node2; + + alias = gaim_buddy_get_contact_alias((GaimBuddy *)node); + + /* We've found a buddy that matches this conversation. It's part of a + * GaimContact with more than one GaimBuddy. Loop through the GaimBuddies + * in the contact and get all the logs. */ + for (node2 = node->parent->child ; node2 != NULL ; node2 = node2->next) + { + logs = g_list_concat( + gaim_log_get_logs(GAIM_LOG_IM, + gaim_buddy_get_name((GaimBuddy *)node2), + gaim_buddy_get_account((GaimBuddy *)node2)), + logs); + } + break; + } + } + g_slist_free(buddies); + + if (logs == NULL) + logs = gaim_log_get_logs(GAIM_LOG_IM, name, account); + else + logs = g_list_sort(logs, gaim_log_compare); + } + else if (convtype == GAIM_CONV_TYPE_CHAT) + { + /* If we're not logging, don't show anything. + * Otherwise, we might show a very old log. */ + if (!gaim_prefs_get_bool("/core/logging/log_chats")) + return; + + logs = gaim_log_get_logs(GAIM_LOG_CHAT, name, account); + } + + if (logs == NULL) + return; + + mflag = GAIM_MESSAGE_NO_LOG | GAIM_MESSAGE_SYSTEM | GAIM_MESSAGE_DELAYED; + history = gaim_log_read((GaimLog*)logs->data, &flags); + + header = g_strdup_printf(_("Conversation with %s on %s:
"), alias, + gaim_date_format_full(localtime(&((GaimLog *)logs->data)->time))); + gaim_conversation_write(c, "", header, mflag, time(NULL)); + g_free(header); + + if (flags & GAIM_LOG_READ_NO_NEWLINE) + gaim_str_strip_char(history, '\n'); + gaim_conversation_write(c, "", history, mflag, time(NULL)); + g_free(history); + + gaim_conversation_write(c, "", "
", mflag, time(NULL)); + + g_list_foreach(logs, (GFunc)gaim_log_free, NULL); + g_list_free(logs); +} + +static void +history_prefs_check(GaimPlugin *plugin) +{ + if (!gaim_prefs_get_bool("/core/logging/log_ims") && + !gaim_prefs_get_bool("/core/logging/log_chats")) + { + gaim_notify_warning(plugin, NULL, _("History Plugin Requires Logging"), + _("Logging can be enabled from Tools -> Preferences -> Logging.\n\n" + "Enabling logs for instant messages and/or chats will activate " + "history for the same conversation type(s).")); + } +} + +static void history_prefs_cb(const char *name, GaimPrefType type, + gconstpointer val, gpointer data) +{ + history_prefs_check((GaimPlugin *)data); +} + +static gboolean +plugin_load(GaimPlugin *plugin) +{ + gaim_signal_connect(gaim_conversations_get_handle(), + "conversation-created", + plugin, GAIM_CALLBACK(historize), NULL); + + gaim_prefs_connect_callback(plugin, "/core/logging/log_ims", + history_prefs_cb, plugin); + gaim_prefs_connect_callback(plugin, "/core/logging/log_chats", + history_prefs_cb, plugin); + + history_prefs_check(plugin); + + return TRUE; +} + +static GaimPluginInfo info = +{ + GAIM_PLUGIN_MAGIC, + GAIM_MAJOR_VERSION, + GAIM_MINOR_VERSION, + GAIM_PLUGIN_STANDARD, + NULL, + 0, + NULL, + GAIM_PRIORITY_DEFAULT, + HISTORY_PLUGIN_ID, + N_("GntHistory"), + VERSION, + N_("Shows recently logged conversations in new conversations."), + N_("When a new conversation is opened this plugin will insert " + "the last conversation into the current conversation."), + "Sean Egan \n" + "Sadrul H Chowdhury ", + GAIM_WEBSITE, + plugin_load, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +static void +init_plugin(GaimPlugin *plugin) +{ +} + +GAIM_INIT_PLUGIN(gnthistory, init_plugin, info) + diff -r 317e7613e581 -r 0e3a8505ebbe finch/plugins/lastlog.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/plugins/lastlog.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,142 @@ +/** + * @file lastlog.c Lastlog plugin for gaim-text. + * + * Copyright (C) 2006 Sadrul Habib Chowdhury + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#define PLUGIN_STATIC_NAME "GntLastlog" + +#include "internal.h" + +#include +#include + +#include + +#include +#include +#include + +#include +#include + +static GaimCmdId cmd; + +static gboolean +window_kpress_cb(GntWidget *wid, const char *key, GntTextView *view) +{ + if (key[0] == 27) + { + if (strcmp(key, GNT_KEY_DOWN) == 0) + gnt_text_view_scroll(view, 1); + else if (strcmp(key, GNT_KEY_UP) == 0) + gnt_text_view_scroll(view, -1); + else if (strcmp(key, GNT_KEY_PGDOWN) == 0) + gnt_text_view_scroll(view, wid->priv.height - 2); + else if (strcmp(key, GNT_KEY_PGUP) == 0) + gnt_text_view_scroll(view, -(wid->priv.height - 2)); + else + return FALSE; + return TRUE; + } + return FALSE; +} + +static GaimCmdRet +lastlog_cb(GaimConversation *conv, const char *cmd, char **args, char **error, gpointer null) +{ + FinchConv *ggconv = conv->ui_data; + char **strings = g_strsplit(GNT_TEXT_VIEW(ggconv->tv)->string->str, "\n", 0); + GntWidget *win, *tv; + int i, j; + + win = gnt_window_new(); + gnt_box_set_title(GNT_BOX(win), _("Lastlog")); + + tv = gnt_text_view_new(); + gnt_box_add_widget(GNT_BOX(win), tv); + + gnt_widget_show(win); + + for (i = 0; strings[i]; i++) { + if (strstr(strings[i], args[0]) != NULL) { + char **finds = g_strsplit(strings[i], args[0], 0); + for (j = 0; finds[j]; j++) { + if (j) + gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(tv), args[0], GNT_TEXT_FLAG_BOLD); + gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(tv), finds[j], GNT_TEXT_FLAG_NORMAL); + } + g_strfreev(finds); + gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(tv), "\n", GNT_TEXT_FLAG_NORMAL); + } + } + + g_signal_connect(G_OBJECT(win), "key_pressed", G_CALLBACK(window_kpress_cb), tv); + g_strfreev(strings); + return GAIM_CMD_STATUS_OK; +} + +static gboolean +plugin_load(GaimPlugin *plugin) +{ + cmd = gaim_cmd_register("lastlog", "s", GAIM_CMD_P_DEFAULT, + GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_IM, NULL, + lastlog_cb, _("lastlog: Searches for a substring in the backlog."), NULL); + return TRUE; +} + +static gboolean +plugin_unload(GaimPlugin *plugin) +{ + gaim_cmd_unregister(cmd); + return TRUE; +} + +static GaimPluginInfo info = +{ + GAIM_PLUGIN_MAGIC, + GAIM_MAJOR_VERSION, + GAIM_MINOR_VERSION, + GAIM_PLUGIN_STANDARD, + GAIM_GNT_PLUGIN_TYPE, + 0, + NULL, + GAIM_PRIORITY_DEFAULT, + "gntlastlog", + N_("GntLastlog"), + VERSION, + N_("Lastlog plugin."), + N_("Lastlog plugin."), + "Sadrul H Chowdhury ", + "http://gaim.sourceforge.net", + plugin_load, + plugin_unload, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +static void +init_plugin(GaimPlugin *plugin) +{ +} + +GAIM_INIT_PLUGIN(PLUGIN_STATIC_NAME, init_plugin, info) + diff -r 317e7613e581 -r 0e3a8505ebbe po/ta.po --- a/po/ta.po Sun Mar 18 18:17:14 2007 +0000 +++ b/po/ta.po Sun Mar 18 19:38:15 2007 +0000 @@ -8981,10 +8981,10 @@ #: ../src/protocols/oscar/oscar.c:4793 #, c-format -msgid "" -"The user %u wants to add %s to their buddy list for the following reason:\n" -"%s" -msgstr "பயனர் %u %s ஐ தன் நண்பர் பட்டியலில் பின்வரும் காரணத்திற்காக சேர்க்க விரும்புகிறார்.:\n" +#msgid "" +#"The user %u wants to add %s to their buddy list for the following reason:\n" +#"%s" +#msgstr "பயனர் %u %s ஐ தன் நண்பர் பட்டியலில் பின்வரும் காரணத்திற்காக சேர்க்க விரும்புகிறார்.:\n" #: ../src/protocols/oscar/oscar.c:4803 #: ../src/protocols/oscar/oscar.c:7480