summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cvsignore31
-rw-r--r--AUTHORS1
-rw-r--r--COMMANDS383
-rw-r--r--Makefile.am46
-rw-r--r--NEWS0
-rw-r--r--README82
-rw-r--r--README-HEBREW43
-rw-r--r--TODO140
-rw-r--r--acconfig.h25
-rwxr-xr-xautogen.sh21
-rw-r--r--colorless.theme101
-rw-r--r--config36
-rw-r--r--configure.in363
-rwxr-xr-xfile2header.sh5
-rw-r--r--irssi.desktop6
-rw-r--r--irssi.gnorba5
-rw-r--r--irssi.spec.in87
-rw-r--r--servertest/.cvsignore8
-rw-r--r--servertest/Makefile.am13
-rw-r--r--servertest/server.c463
-rw-r--r--src/.cvsignore2
-rw-r--r--src/Makefile.am17
-rw-r--r--src/common-setup.h125
-rw-r--r--src/common.h114
-rw-r--r--src/irssi-plugin-gui.h11
-rw-r--r--src/irssi-plugin.h9
-rw-r--r--src/signal.doc178
-rw-r--r--stamp.h.in0
-rw-r--r--window-views-patch.diff2672
29 files changed, 4987 insertions, 0 deletions
diff --git a/.cvsignore b/.cvsignore
new file mode 100644
index 00000000..5296986d
--- /dev/null
+++ b/.cvsignore
@@ -0,0 +1,31 @@
+Makefile
+Makefile.in
+aclocal.m4
+config.cache
+config.guess
+config.h
+config.log
+config.status
+config.sub
+configure
+configure.scan
+libtool
+ltconfig
+ltmain.sh
+stamp-h
+stamp-h.in
+stamp.h
+version.h
+config.h.in
+.exrc
+gnome-bug
+gnome-config
+install-sh
+missing
+mkinstalldirs
+INSTALL
+intl
+ABOUT-NLS
+COPYING
+irssi.spec
+default-config.h
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 00000000..d0235c5b
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+Timo Sirainen, cras@irccrew.org
diff --git a/COMMANDS b/COMMANDS
new file mode 100644
index 00000000..71bf1f87
--- /dev/null
+++ b/COMMANDS
@@ -0,0 +1,383 @@
+
+ ** Some definations
+
+
+"Level" usually means that you can use these words there:
+
+ CRAP - Can be almost anything
+ PUB - Public messages in channel
+ MSGS - Private messages
+ CHAN - Channel messages: joins, parts, quits, etc.
+ NOTICES - Notices
+ SNOTES - Notices from server
+ WALLOPS - Wallops
+ ACTIONS - Actions (/me)
+ DCC - DCC messages
+ CTCP - CTCP messages
+ HILIGHT - Hilighted text
+ CLIENTNOTICES - Irssi's notices
+ CLIENTERRORS - Irssi's error messages
+
+
+ ** Server handling
+
+
+CONNECT <address>[:port[:password]]
+
+ Connect to specified server
+
+DISCONNECT <* / tag> [message]
+
+ Disconnect from server
+
+SERVER <address>[:port[:password]]
+
+ Disconnect from current server and connect to new one
+
+SERVERS
+
+ Display a list of servers
+
+RMRECONNS
+
+ Remove all servers from reconnection list
+
+
+ ** Basic IRC commands
+
+
+QUIT [message]
+
+ Quit irssi
+
+JOIN <channel> [key] [, channel...]
+
+ Join to channel(s)
+
+PART [channel] [message]
+
+ Leave from channel
+
+QUERY <nick>
+
+ Create query window
+
+UNQUERY <nick>
+
+ Close query window
+
+MSG <nick/channel> <message>
+
+ Send message to nick/channel
+
+ME <message>
+
+ Send action to channel (/me thinks..)
+
+NOTICE <nick/channel> <message>
+
+ Send notice to nick/channel
+
+WHOIS [server/nick] <nick>
+
+ Send WHOIS query, you can also specify from what server to ask the
+ information. If you type the nick twice it will ask from the same
+ server what nick is using.
+
+AWAY [message]
+
+ Sets yourself away/unaway
+
+AWAYALL [message]
+
+ Sets yourself away/unaway to all connected servers
+
+WHO <nick/channel>
+
+ Show WHO list
+
+NAMES [channel]
+
+ List nicks (in channel)
+
+
+ ** Bit more advanced commands
+
+
+MODE <channel/nick> <mode>
+
+ Get/set channel/nick mode.
+
+ Get channel modes:
+ b - Get ban list
+ e - Get ban exception list
+ I - Get invite list
+
+ Set channel modes (use +/- before these):
+ b *!ban@mask - Set/remove ban
+ e *!ban@mask - Set/remove ban exception
+ I *!ban@mask - Set/remove channel invite
+ o nick - Set/remove op status
+ v nick - Set/remove voice status
+ l limit - Set remove max. people limit in channel
+ k key - Set/remove channel key
+ s - Secret
+ p - Private
+ m - Moderated
+ i - Invite only
+ n - No external messages
+ t - Only ops can change topic
+
+ User modes:
+ i - Invisible
+ w - Show wallops
+ s - Show server notices
+
+TOPIC [channel] [topic]
+
+ Get/set channel topic
+
+INVITE <nick> [channel]
+
+ Invite nick to channel
+
+CTCP <nick/channel> <command>
+
+ Send CTCP request to nick/channel (PING, VERSION, ..)
+
+NCTCP <nick/channel> <reply>
+
+ Send CTCP reply to nick/channel
+
+PING <nick>
+
+ Send CTCP PING to nick and tell how long it took to receive the reply
+
+ISON [nick [nick...]]
+
+ Ask if nicks are in IRC.
+
+WALL [channel] <message>
+
+ Send notice message to all operators in channel.
+
+OP, DEOP, VOICE, DEVOICE [channel] [nick [nick...]
+
+ Op/deop/voice/devoice nick(s) in channel
+
+KICK [channel] <nick> <reason>
+
+ Kick nick from channel
+
+KICKBAN [channel] <nick> <reason>
+
+ Kick+ban nick from channel
+
+KNOCKOUT [secs] <nick> <reason>
+
+ Kick+ban+delay (default to 5min)+unban
+
+BAN [channel] [nick [nick...]]
+
+ Ban nick(s) in channel
+
+UNBAN [channel] [mask [mask...]]
+
+ Remove ban(s) from channel
+
+BANSTAT [channel]
+
+ List bans and ban exceptions in channel
+
+BANTYPE <normal/host/domain/custom>
+
+ Set ban type:
+
+ Normal - *!user@*.domain.net
+ Host - *!*@host.domain.net
+ Domain - *!*@*.domain.net
+ Custom [nick] [user] [host] [domain]
+ eg. /bantype custom nick domain - nick!*@*.domain.net
+ eg. /bantype custom user host - *!user@host.domain.net
+
+INVITELIST [channel]
+
+ List invites (+I) in channel
+
+VERSION [server]
+
+ Displays irssi version and asks IRC server's version
+
+VER [nick/channel]
+
+ Sends CTCP VERSION request to nick/channel
+
+SV [nick/channel]
+
+ Sends irssi version text to nick/channel
+
+KILL <nick> <message>
+
+ Kill nick from irc network. [irc ops only]
+
+WALLOPS <message>
+
+ Write wallops message. [irc ops only]
+
+QUOTE <message>
+
+ Send raw data to irc server - DON'T USE THIS unless you really know
+ what you're doing!
+
+
+ ** DCC handling
+
+
+DCC
+
+ List DCC connections (same as DCC LIST)
+
+DCC CHAT <nick>
+
+ Open DCC chat
+
+DCC SEND <nick> <filename>
+
+ Send file to nick
+
+DCC GET <nick> [filename]
+
+ Get file offered by nick
+
+DCC RESUME <nick> [filename]
+
+ (MIRC) Resume getting file offered by nick
+
+DCC CLOSE <type> <nick> [filename]
+
+ Close DCC connection
+
+DCC LIST
+
+ List DCC connections
+
+MIRCDCC [n]
+
+ Set MIRC style CTCPs on/off
+
+
+ ** User interface handling
+
+
+WINDOW <NEW/CLOSE/SERVER/PREV/NEXT/GOTO/LEVEL>
+
+ NEW [HIDDEN/TAB]
+
+ Create new window (in tab)
+
+ CLOSE
+
+ Close the current window
+
+ SERVER <tag>
+
+ Change which server to use in current window
+
+ PREV/NEXT/GOTO <N>
+
+ Go to previous/next/Nth window
+
+ LEVEL <[+/-]pub/msgs/...>
+
+ Change window level, eg.
+ /window level msgs - creates messages window
+ /window level all -msgs - creates status window
+
+CLEAR
+
+ Clear screen
+
+ECHO <text>
+
+ Print text to screen
+
+MODES
+
+ Open channel modes dialog (GTK/GNOME version)
+
+GWHOIS <nick>
+
+ Display WHOIS information in dialog (GTK/GNOME version)
+
+LAST [-pub -msgs...] <text>
+
+ Display (only public/msgs/..) lines where <text> appears
+ (Text version only)
+
+
+ ** Configuration
+
+
+SET [key [=value / [key [key..]]
+
+ Get/set configuration
+
+ALIAS, UNALIAS <alias> [command]
+
+ Set/remove alias, /unalias is the same as /alias without command
+
+ These codes are extracted in commands:
+ %0 : name of alias
+ %1, %2, %3 .. : %th word
+ &1, &2, &3 .. : &th word + the rest of the text after it
+ %c : channel name
+
+ Typing extra / before /command (//command) ignores any aliases
+
+IGNORE, UNIGNORE <mask> [level [level..]]
+
+ Ignore/unignore specified level(s) or everything from nick
+
+NOTIFY <mask> [ircnet [ircnet..]]
+
+ Add mask (nick) to notify list for specified ircnets..
+
+UNNOTIFY <mask>
+
+ Remove mask from notify list.
+
+LOG <CREATE/CLOSE/START/STOP/LIST>
+
+ CREATE <filename> [<+/->level ...] [#channel/nick [
+ [<+/->level ...] ...]
+
+ Create and start logging to file
+
+ Example: /log create mylog -all +msgs #linux +chan +public
+ (or simply #linux +all logs everything that appears in #linux
+ window).
+
+ CLOSE <filename>
+
+ Close log and remove from configuration
+
+ START <filename>
+
+ Start logging to file
+
+ STOP <filename>
+
+ Stop logging to file
+
+ LIST
+
+ List logs.
+
+LOAD <plugin> [arguments]
+
+ Load plugin
+
+UNLOAD <plugin>
+
+ Unload plugin
+
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 00000000..176258b8
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,46 @@
+# create default-config.h
+config.h: default-config.h
+
+default-config.h: config
+ ./file2header.sh config > default-config.h
+
+## if <internationalization support>
+#SUBDIRS = po intl macros support # <your subdirs here>
+## else
+if BUILD_PLUGINS
+PLUGINS=plugins
+endif
+if BUILD_SERVERTEST
+SERVERTEST=servertest
+endif
+
+SUBDIRS = macros src $(PLUGINS) $(SERVERTEST)
+## endif
+
+## to automatically rebuild aclocal.m4 if any of the macros in
+## `macros/' change
+@MAINT@include macros/macros.dep
+@MAINT@macros/macros.dep: macros/Makefile.am
+@MAINT@ cd macros && $(MAKE) macros.dep
+
+if HAVE_GNOME
+appletdir = $(datadir)/applets/Network
+applet_DATA = irssi.desktop
+
+corbadir = $(sysconfdir)/CORBA/servers
+corba_DATA = irssi.gnorba
+endif
+
+confdir = $(sysconfdir)/irssi
+conf_DATA = config colorless.theme
+
+EXTRA_DIST = window-views-patch.diff \
+ autogen.sh \
+ README-HEBREW \
+ COMMANDS \
+ file2header.sh \
+ irssi.spec.in \
+ irssi.spec \
+ $(conf_DATA) \
+ irssi.gnorba \
+ irssi.desktop
diff --git a/NEWS b/NEWS
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/NEWS
diff --git a/README b/README
new file mode 100644
index 00000000..39514fdc
--- /dev/null
+++ b/README
@@ -0,0 +1,82 @@
+
+
+irssi
+
+
+ * ABOUT
+
+Irssi is an IRC client made with GTK+ toolkit and (optional) GNOME libraries.
+A small text mode version is also somewhat working, there's also a really
+simple daemon version which just loads "bot" plugin (which doesn't exist).
+I'd also like to see KDE version but someone else will have to do it.
+
+
+ * FEATURES
+
+See COMMANDS file for list of all commands irssi knows.
+
+I've been asked quite a lot about why should one use irssi, what does it do
+that other IRC clients don't? Well, to tell you the truth, I have no idea :)
+Still I've got a lot of mails saying it's the best GUI IRC client they've
+ever used :) Let's see.. It should be easy to use, it has most of the
+features IRC client needs and it's pretty stable. Here's a small list of what
+it does:
+
+ - Nice configuration :) Especially the color settings.
+ - You can connect to multiple servers. Irssi is also IRC network aware so
+ you can specify some settings to work only in specified IRC networks.
+ - Automatically connect to IRC server(s) at startup, automatically join to
+ channels when connected
+ - All code is nonblocking, it won't hang while connecting to server or
+ opening DCC connection. Host lookups are done in separate processes.
+ - DCC send, receive and chat with GUI
+ - GNOME panel support, channels and queries are displayed in GNOME panel
+ where you can easily see which channels have been updated (label turns to
+ red) and click in them to open the channel.
+ - Doubleclicking URL in text widget launches specified web/ftp/email client,
+ also doubleclicking channel/nick join to channel or creates query.
+ - Aliases, ignores, autoignoring when flooding, notify lists, completing
+ specified words with tab (like home&lt;tab&gt; -> http://my.home.page),
+ hilighting lines with specified texts
+ - Smart nick completion
+ - Configurable logging support
+ - You can use ZVT widget to print texts, it's really fast so you can be
+ joined to many high traffic channels and irssi won't slow up
+ - Plugins support, creating plugins is really easy.
+ - Lots of nice GUI stuff :)
+
+
+ * INSTALLATION
+
+./configure
+make
+make install
+
+Configure can use these parameters (all of these defaults to yes):
+
+ --with-proplist=dir Specify libPropList directory
+ --with-servertest Build test irc server which you can use to try crash
+ irc clients
+ --without-gnome Build without GNOME libraries
+ --without-gnome-panel Build without GNOME panel
+ --without-imlib Build without Imlib library
+ --without-socks Build without socks library
+ --without-textui Build without text mode version
+ --enable-memdebug Enable memory debugging, great for finding memory
+ leaks
+ --enable-gtk-hebrew Enable Hebrew support - see README-HEBREW
+
+There's also some others, you can get a full list with ./configure --help
+
+If you don't want to run irssi in panel, add --no-applet to command line
+parameters.
+
+
+ * BUGS / SUGGESTIONS
+
+See TODO file if it is already listed in there - if not send me email..
+
+
+ * AUTHOR
+
+Timo Sirainen, cras@irccrew.org, cras/ircnet/#irssi, http://xlife.dhs.org/irssi/
diff --git a/README-HEBREW b/README-HEBREW
new file mode 100644
index 00000000..2f740ae2
--- /dev/null
+++ b/README-HEBREW
@@ -0,0 +1,43 @@
+Hebrew support in irssi
+-----------------------
+
+Before you can enjoy IRCing in Hebrew, you need to get two other things.
+
+1. FriBidi, a free implementation of the Unicode BiDi algorithm).
+ See http://imagic.weizmann.ac.il/~dov/freesw/FriBidi/
+
+2. hebxfonts, a collection of Unicode-encoded Hebrew fonts along
+ with the keyboard mappings to use them (the right Alt key will be
+ configured to generate Hebrew characters).
+ See http://metalab.unc.edu/pub/Linux/X11/fonts/
+
+After you get these two, you should be ok to go. To enable the Hebrew
+support, specify --enable-gtk-hebrew=<path>. If the path starts with a
+tilde (~), it is taken relative to your home directory. Here's a good
+idea:
+
+ configure --enable-gtk-hebrew=~/.gnome/irssi-hebrew.gtkrc
+
+After compiling and installing, you should copy the supplied gtkrc
+file to where you told the program it would find it. Say you're at the
+root of the irssi source tree, typing:
+
+ cp src/gui-gnome/irssi-hebrew.gtkrc ~/.gnome/irssi-hebrew.gtkrc
+
+would do the trick.
+
+One last configuration task is done from within irssi. Fire it up,
+then go to the preferences dialog box and select a Hebrew font.
+(e.g., -misc-fixed-medium-r-normal-*-*-120-*-*-c-*-iso8859-8)
+
+The Hebrew support is not complete; it works as expected (ie, reversing
+stuff with the FriBidi thingy) for the text entry field and for the
+output text. In other places, you may see Hebrew characters, only
+going left-to-right; in yet other places, you may not see Hebrew at all.
+
+I have no intention of making this any better; comprehensive support
+for Hebrew should come from within the GTK+ widget set, and not by
+patching applications.
+
+
+Ronen Tzur <rtzur@shani.net>
diff --git a/TODO b/TODO
new file mode 100644
index 00000000..a3e5d477
--- /dev/null
+++ b/TODO
@@ -0,0 +1,140 @@
+ - window goto active, name
+
+*** Bugs
+
+ - If there's any empty lists in configuration file (like ircnets = ();),
+ libPropList crashes irssi at startup.. Irssi doesn't save any empty lists
+ now, but still this needs to be fixed in libPropList..
+ - after changing irssi-text's screen size to smaller it leaves some empty
+ lines to windows before printing text, redrawing screen moves the lines
+ back up.. hm..
+ - irssi can't find new themes in ~/.irssi/ while running - scan for new
+ themes when opening themes dialog? irssi-text also needs to be restarted
+ to use new themes..
+ - mirc ctcp togglemenuitem isn't updated right
+ - multiple dcc connections from different irc networks from same nick
+ doesn't work. Maybe create "server nick" and "refer nick" variables to
+ DCC_REC?
+ - gfloat doesn't work in formats .. why? In DCC messages kb and kb/s values
+ could be shown as floats..
+
+*** text GUI
+
+ - statusbar:
+ - when starting to run out of space some items could be made smaller,
+ activity for example .. make some generic flag for items to use.
+ - activity: hilight number if window has message for you or hilighted
+ text
+ - "you have new mail"
+ - active server tag somewhere in window
+ - word wrapping doesn't work perfectly, if colors/bolds/etc are used, they're
+ treated as spaces. So things like (<newline>blah blah) can happen (/who)
+ - autojoining to channels, make the code common in gui-gnome and gui-text
+
+*** Big things
+
+ - keyboard configuration
+ - session saving thing.. specify what channels/queries/dcc chats to open in
+ which window (real/tabbed/in same window with some other), what irc net
+ channels goes to where, what channels/queries to open at startup, etc.
+ use dialog with gtktree widget to change it.
+ - split windows with gtkpaned (check window-views-patch.diff)
+ - really transparently working irc proxy, saves scrollback buffers, etc.
+ Or maybe the existing ones already work?
+ - some sort of address book? our own irssi ctcp to ask for other irssi users
+ for their information (of course not without asking (except optionally))..
+ could be nice also to automatically update it, keep track of all seen
+ users gathered when joining channels, whois, who, etc. commands.
+ automatically updating information could be host masks, nicks, ips, seen in
+ channels, operator in channels, .. user specified checks like last topic or
+ mode changes or even msgs to you/some channel/with some keyword. great for
+ spying people ;) maybe even useful sometimes..
+
+ .. but what database would be best for this?
+
+ - GTK version: icons to toolbars, accelerators to menus
+ - Windows style MDI windows are possible with GtkFixed .. Some people would
+ like this.. too much job for me, it would need building the MDI windows
+ ourself (title bar, borders, resizing, etc.)
+
+ - online help, documentation, ...
+ - plugins:
+ - perl plugin .. implementation problems, C's structures need to be
+ handled some way .. like for server structure get_address(),
+ get_port(), set_address(), set_port() etc..
+ - other scripting plugins would be easier? scheme, tcl, pythong?
+ sula premirex uses scheme, it would probably be pretty easy to learn
+ from it how to do it to irssi :)
+ - IRC bot, eggdrop is too old, needs a replacement ;)
+ - DCC file server, I'm not too excited about this, maybe someone else
+ wants to do it..
+ - Multiplayer games! :) Chess, tic-tac-toe, othello, battleship, tetris,
+ etc. Existing games should probably be used .. though there doesn't
+ seem to be any of these (except tetris) for gnome right now..
+ - audio / video chat :)
+
+*** Little things
+
+ - command line parameter handling, specify what server/ircnet to autoconnect
+ or none.
+ - /list:
+ - gui optional
+ - sort it by clicking the headers
+ - change the size of columns
+ - total number of channels
+ - copy/paste things in list?
+ - search the list
+ - log option: add the open/close time to log
+ - log directory, automatically log all channels and queries there
+ - overwrite/append
+ - all windows, just queries, only the channels in channel list
+ - you can be joined to same channels in different irc networks (or even
+ the same ircnet!) - create the logs to different directiories/names
+ - use different themes in different channels/queries?
+ - improve msgslevels and ignoring .. Like ignoring "chan" doesn't work now.
+ It could be changed to joins, parts, quits, topics, nicks, .. just rip all
+ the msglevels from bitchx and use them :)
+ - use server-idle instead of channel.query thing..
+ - lag meter
+ - possibility to display different colors in nicks from different people..
+ and different colors for word hilighting too
+ - /connect ircnet could connect to ircnet
+ - change some GLists to GHashTables, aliases at least
+ - check new irssi versions with http rather than with irssibot..
+ - implement requesting files with DCC GET from remote client for dcc file
+ servers. good for people behind firewalls.
+ - support for ircii translation tables (/usr/lib/irc/translation/*)
+ - use different nicks/realnames in different irc networks
+ - zvt problems/todo:
+ - need some way to disable all the extra features, like sending 0x8e
+ messes up your fonts.
+ - the ugly cursor just keeps blinking
+ - when clicking an empty spot on screen it sometimes tells that there's
+ some weird crap in there..
+ - word wrapping
+ - notify list:
+ - dialog: keep track of hosts/realnames so after closing and opening the
+ dialog again they would show up..
+ - summary list (for irssi-text)
+ - nick-specific options:
+ - check for gone-flag changes (use userhosts instead of isons)
+ - create popup dialog
+ - run some command (like /exec as soon as I get that done :)
+ - gnome statubar:
+ - clock?
+ - dcc transfer meter (gtk progressbar)
+ - you could configure which events (whois, notify, etc.) to show in what
+ windows (all, current, status)
+ - gui for configuring plugin specific theme format texts
+ - awaylog (/log create ~/away.log -all +msgs or something), autoaway
+ - make window/save buffer and find work with zvt
+ - dcc send: allow selection of multiple files to send (also for dnd from
+ gmc!) Allow dropping files to anywhere in irssi.
+ - logging: longer format dd.mm.yy hh:mm:ss (configurable?)
+ - net split/join detection ? is this even needed? more harmful than useful?
+ - /timer, /clones
+ - run multiple commands with one alias (what was this needed for? can't
+ remember..)
+ - regexp for hilighting words?
+ - subcommands (dcc, window, ..) could use common function instead of copy and
+ pasting the same function all the time and modifying just two words...
diff --git a/acconfig.h b/acconfig.h
new file mode 100644
index 00000000..e90d0d05
--- /dev/null
+++ b/acconfig.h
@@ -0,0 +1,25 @@
+#undef HAVE_GTK
+#undef HAVE_GNOME
+#undef HAVE_GNOME_PANEL
+#undef SYSCONFDIR
+#undef PLUGINSDIR
+#undef PERLSCRIPTDIR
+#undef GTK_10
+#undef HAVE_SOCKS_H
+#undef HAVE_IMLIB
+#undef MEM_DEBUG
+#undef HAVE_IPV6
+#undef GTK_HEBREW
+#undef GTK_HEBREW_RC
+
+#undef HAVE_NCURSES_USE_DEFAULT_COLORS
+#undef HAVE_CURSES_IDCOK
+
+#undef HAS_CURSES
+#undef USE_SUNOS_CURSES
+#undef USE_BSD_CURSES
+#undef USE_SYSV_CURSES
+#undef USE_NCURSES
+#undef NO_COLOR_CURSES
+#undef SCO_FLAVOR
+#undef NCURSES_970530
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 00000000..5afe8b70
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,21 @@
+#!/bin/sh
+# Run this to generate all the initial makefiles, etc.
+
+srcdir=`dirname $0`
+test -z "$srcdir" && srcdir=.
+
+# I'm too lazy to update version number into several places.. :)
+version=`cat configure.in|grep AM_INIT_AUTOMAKE|perl -pe 's/^[^,]*,[ ]*([^\)]*).*/$1/'`
+cat irssi.spec.in |sed s/^Version:/Version:\ $version/ > irssi.spec
+
+PKG_NAME="Irssi"
+
+(test -f $srcdir/configure.in \
+## put other tests here
+) || {
+ echo -n "**Error**: Directory "\`$srcdir\'" does not look like the"
+ echo " top-level $PKG_NAME directory"
+ exit 1
+}
+
+. $srcdir/macros/autogen.sh
diff --git a/colorless.theme b/colorless.theme
new file mode 100644
index 00000000..2d8b2c1c
--- /dev/null
+++ b/colorless.theme
@@ -0,0 +1,101 @@
+{
+ default_color = 7;
+ colors = {};
+ formats = {
+ line_start = "-!- ";
+ line_start_irssi = "-!- Irssi: ";
+ connecting = "Connecting to %_$1%_ [$2] port %_$3%_";
+ disconnected = "Disconnected from %_$1%_ [$2]";
+ join = "%_$1%_ [$2] has joined %_$3";
+ cannot_join = "Cannot join to channel %_$1%_ [$2]";
+ part = "%_$1%_ [$2] has left %_$3%_ [$4]";
+ kick = "%_$1%_ was kicked from $2 by %_$3%_ [$4]";
+ quit = "%_$1%_ [$2] has quit IRC [$3]";
+ names = "[%_Users%_($1)] $2";
+ endofnames = "%_$1%_: Total of %_$2%_ nicks [%_$3%_ ops, %_$4%_ voices, %_$5%_ normal]";
+ topic = "Topic for $1: $2";
+ no_topic = "No topic set for $1";
+ new_topic = "%_$1%_ changed the topic of $2 to: $3";
+ topic_unset = "Topic unset by %_$1%_ on $2";
+ topic_info = "Topic set by %_$1%_ [$2]";
+ chanmode_change = "mode/$1 [$2] by %_$3";
+ channel_mode = "mode/$1 [$2]";
+ banlist = "%_$1%_: ban $2";
+ banlist_long = "%_$1%_: ban $2 [by %_$3%_, $4 secs ago]";
+ ebanlist = "%_$1%_: ban exception $2";
+ ebanlist_long = "%_$1%_: ban exception $2 [by %_$3%_, $4 secs ago]";
+ invitelist = "%_$1%_: invite $2";
+ usermode_change = "Mode change [%_$1%_] for user $2";
+ your_nick_changed = "You're now known as $1";
+ nick_changed = "%_$1%_ is now known as $2";
+ your_nick_owned = "Your nick is owned by %_$4%_ [$2@$3]";
+ whois = "%_$1%_ [$2@$3]%N ircname : $4";
+ whois_idle_signon = " idle : $2 hours $3 mins $4 secs [signon: $5]";
+ own_msg = "<$1> $2";
+ own_msg_channel = "<$1:$2> $3";
+ own_msg_private = "[msg($1)] $2";
+ own_notice = "[notice($1)] $2";
+ own_me = " * $1 $2";
+ own_ctcp = "[ctcp($1)] $2 $3";
+ own_dcc = "[dcc($1)] $2";
+ pubmsg_me = "<$1> $2";
+ pubmsg_me_channel = "<$1:$2> $3";
+ pubmsg = "<$1> $2";
+ pubmsg_channel = "<$1:$2> $3";
+ msg_private = "[$1($2)] $3";
+ dcc_msg = "[$1(dcc)] $2";
+ notice_server = "!$1 $2";
+ notice_public = "-$1:$2- $3";
+ notice_private = "-$1($2)- $3";
+ action_dcc = " (*dcc*) $1 $2";
+ action_private = " (*) $1 $2";
+ action_public = " * $1 $2";
+ action_public_channel = " * $1:$2 $3";
+ ctcp_reply = "CTCP %_$1%_ reply from %_$2%_: $3";
+ ctcp_requested = ">>> %_$1%_ [$2] requested %_$3%_ from %_$4";
+ dcc_ctcp = ">>> DCC CTCP received from %_$1%_: $2";
+ dcc_chat = "DCC CHAT from %_$1%_ [$2 port $3]";
+ dcc_chat_not_found = "No DCC CHAT connection open to %_$1";
+ dcc_chat_connected = "DCC %_CHAT%_ connection with %_$1%_ [$2 port $3] established";
+ dcc_chat_disconnected = "DCC lost chat to %_$1";
+ dcc_send = "DCC SEND from %_$1%_ [$2 port $3]: $4 [$5 bytes]";
+ dcc_send_exists = "DCC already sending file $1 for %_$2%_";
+ dcc_send_not_found = "DCC not sending file $2 to %_$1";
+ dcc_send_file_not_found = "DCC file not found: $1";
+ dcc_send_connected = "DCC sending file $1 for %_$2%_ [$3 port $4]";
+ dcc_send_complete = "DCC sent file $1 [%_$2%_kb] for %_$3%_ in %_$4%_ secs [%_$5kb/s%_]";
+ dcc_send_aborted = "DCC aborted sending file $1 for %_$2%_";
+ dcc_get_not_found = "DCC no file offered by %_$1";
+ dcc_get_connected = "DCC receiving file $1 from %_$2%_ [$3 port $4]";
+ dcc_get_complete = "DCC received file $1 [$2kb] from %_$3%_ in %_$4%_ secs [$5kb/s]";
+ dcc_get_aborted = "DCC aborted receiving file $1 from %_$2%_";
+ dcc_unknown_ctcp = "DCC unknown ctcp $1 from %_$2%_ [$3]";
+ dcc_unknown_reply = "DCC unknown reply $1 from %_$2%_ [$3]";
+ dcc_unknown_command = "DCC unknown command: $1";
+ dcc_unknown_type = "DCC unknown type %_$1";
+ dcc_connect_error = "DCC can't connect to %_$1%_ port %_$2";
+ dcc_cant_create = "DCC can't create file $1";
+ dcc_rejected = "DCC $1 was rejected by %_$2%_ [$3]";
+ dcc_close = "DCC $1 close for %_$2%_ [$3]";
+ log_opened = "Log file $1 opened";
+ log_open_failed = "Couldn't open log file $1";
+ log_not_open = "Log file $1 not open";
+ log_closed = "Closed log file $1";
+ log_listentry = "$1: $2";
+ log_sublistentry = " + $1: $2";
+ ircjoin = "%_$1%_ [$2@$3] [%_$4%_] has joined to IRC";
+ plugin_cant_load = "Can't load plugin %_$1%_";
+ plugin_not_loaded = "Plugin %_$1%_ not loaded";
+ };
+
+ plugins = {
+ sample = "start stop";
+ };
+
+ pluginformats = {
+ sample = {
+ start = "Sample plugin loaded";
+ stop = "Sample plugin unloaded";
+ };
+ };
+}
diff --git a/config b/config
new file mode 100644
index 00000000..a1c67685
--- /dev/null
+++ b/config
@@ -0,0 +1,36 @@
+{
+ setupservers = (
+ {server = irc.funet.fi;ircnet = ircnet;port = 6667;autoconnect = No;}
+ );
+
+ ircnets = ({name = ircnet;});
+
+ channels = (
+ {
+ name = "#irssi";
+ ircnet = ircnet;
+ autojoin = No;
+ }
+ );
+ aliases = (
+ {alias = J;command = "/join &1";},
+ {alias = LEAVE;command = "/part &1";},
+ {alias = BYE;command = "/quit &1";},
+ {alias = WI;command = "/whois &1";},
+ {alias = WII;command = "/whois %1 %1";},
+ {alias = WW;command = "/whowas &1";},
+ {alias = W;command = "/who *";},
+ {alias = N;command = "/names *";},
+ {alias = M;command = "/msg &1";},
+ {alias = T;command = "/topic &1";},
+ {alias = C;command = "/clear";},
+ {alias = CL;command = "/clear";},
+ {alias = K;command = "/kick &1";},
+ {alias = KB;command = "/kickban &1";},
+ {alias = KN;command = "/knockout &1";},
+ {alias = B;command = "/ban &1";},
+ {alias = UB;command = "/unban &1";},
+ {alias = IG;command = "/ignore &1";},
+ {alias = UNIG;command = "/unignore &1";}
+ );
+}
diff --git a/configure.in b/configure.in
new file mode 100644
index 00000000..a0af0232
--- /dev/null
+++ b/configure.in
@@ -0,0 +1,363 @@
+AC_INIT(src)
+
+AM_CONFIG_HEADER(config.h)
+AM_INIT_AUTOMAKE(irssi, 0.7.16)
+
+AM_MAINTAINER_MODE
+
+AM_ACLOCAL_INCLUDE(macros)
+
+AC_ISC_POSIX
+AC_PROG_CC
+AC_PROG_CPP
+AC_STDC_HEADERS
+AC_ARG_PROGRAM
+AM_PROG_LIBTOOL
+
+AC_CHECK_HEADERS(string.h stdlib.h unistd.h dirent.h sys/ioctl.h)
+
+GNOME_INIT
+
+AC_ARG_WITH(proplist,
+[ --with-proplist Specify libPropList location],
+ proplist_dir=$withval)
+
+AC_ARG_WITH(socks,
+[ --with-socks Build with socks support],
+ if test x$withval = xyes; then
+ want_socks=yes
+ else
+ if test "x$withval" = xno; then
+ want_socks=no
+ else
+ want_socks=yes
+ fi
+ fi,
+ want_socks=no)
+
+AC_ARG_WITH(imlib,
+[ --with-imlib Build with imlib support],
+ if test x$withval = xyes; then
+ want_imlib=yes
+ else
+ if test "x$withval" = xno; then
+ want_imlib=no
+ else
+ want_imlib=yes
+ fi
+ fi,
+ want_imlib=yes)
+
+AC_ARG_WITH(gnome-panel,
+[ --with-gnome-panel Build with gnome panel applet support],
+ if test x$withval = xyes; then
+ want_gnome_panel=yes
+ else
+ if test "x$withval" = xno; then
+ want_gnome_panel=no
+ else
+ want_gnome_panel=yes
+ fi
+ fi,
+ want_gnome_panel=yes)
+
+AC_ARG_WITH(textui,
+[ --with-textui Build irssi-text],
+ if test x$withval = xyes; then
+ want_textui=yes
+ else
+ if test "x$withval" = xno; then
+ want_textui=no
+ else
+ want_textui=yes
+ fi
+ fi,
+ want_textui=yes)
+
+AC_ARG_WITH(plugins,
+[ --with-plugins Build plugins],
+ if test x$withval = xyes; then
+ want_plugins=yes
+ else
+ if test "x$withval" = xno; then
+ want_plugins=no
+ else
+ want_plugins=yes
+ fi
+ fi,
+ want_plugins=yes)
+
+AC_ARG_WITH(servertest,
+[ --with-servertest Build servertest],
+ if test x$withval = xyes; then
+ want_servertest=yes
+ else
+ if test "x$withval" = xno; then
+ want_servertest=no
+ else
+ want_servertest=yes
+ fi
+ fi,
+ want_servertest=no)
+
+AC_ARG_ENABLE(memdebug,
+[ --enable-memdebug Enable memory debugging],
+ if test x$enableval = xyes; then
+ want_memdebug=yes
+ else
+ if test "x$enableval" = xno; then
+ want_memdebug=no
+ else
+ want_memdebug=yes
+ fi
+ fi,
+ want_memdebug=no)
+
+AC_ARG_ENABLE(ipv6,
+[ --enable-ipv6 Enable IPv6 support],
+ if test x$enableval = xyes; then
+ want_ipv6=yes
+ else
+ if test "x$enableval" = xno; then
+ want_ipv6=no
+ else
+ want_ipv6=yes
+ fi
+ fi,
+ want_ip6=no)
+
+AC_ARG_ENABLE(gtk-hebrew,
+[ --enable-gtk-hebrew Enable Hebrew support],
+ if test "x$enableval" = xno; then
+ want_gtk_hebrew=no
+ HEBREW_LIBS=""
+ else
+ AC_DEFINE(GTK_HEBREW)
+ AC_DEFINE_UNQUOTED(GTK_HEBREW_RC, "$enableval")
+ HEBREW_LIBS="-lfribidi"
+ want_gtk_hebrew=yes
+ fi,
+ want_gtk_hebrew=no)
+
+dnl **
+dnl ** just some generic stuff...
+dnl **
+
+AC_CHECK_FUNCS(mkfifo)
+
+AC_CHECK_LIB(socket, socket, [
+ LIBS="$LIBS -lsocket"
+])
+
+AC_CHECK_LIB(nsl, inet_addr, [
+ LIBS="$LIBS -lnsl"
+], -lsocket)
+
+# gcc specific options
+if test "x$ac_cv_prog_gcc" = "xyes"; then
+ CFLAGS="$CFLAGS -Wall"
+fi
+
+if test "x$prefix" = "xNONE"; then
+ prefix="/usr/local"
+else
+ prefix=$prefix
+fi
+
+AM_CONDITIONAL(BUILD_PLUGINS, test "x$want_plugins" = "xyes")
+AM_CONDITIONAL(BUILD_SERVERTEST, test "x$want_servertest" = "xyes")
+AC_DEFINE_UNQUOTED(SYSCONFDIR, "$prefix/etc")
+AC_DEFINE_UNQUOTED(PLUGINSDIR, "$prefix/lib/irssi/plugins")
+
+dnl **
+dnl ** check for libPropList
+dnl **
+
+if test "x$proplist_dir" = "x"; then
+ proplib=
+else
+ proplib=-L$proplist_dir/lib
+fi
+
+AC_CHECK_LIB(PropList, PLSave, [
+ LIBS="$LIBS $proplib -lPropList"
+ if test "x$proplist_dir" != "x"; then
+ CFLAGS="$CFLAGS -I$proplist_dir/include"
+ fi
+], [
+ echo "ERROR: Irssi needs libPropList for configuration file handling."
+ echo "Go get it from http://xlife.dhs.org/irssi/download.php"
+ AC_ERROR(["libPropList not found"])
+], $LIBS $proplib -lPropList)
+
+
+dnl **
+dnl ** check for socks
+dnl **
+
+if test "x$want_socks" = "xyes"; then
+ AC_CHECK_LIB(socks, connect, [
+ LIBS="$LIBS -lsocks"
+ AC_CHECK_HEADER(socks.h, [
+ AC_DEFINE(HAVE_SOCKS_H)
+ CFLAGS="$CFLAGS -DSOCKS"
+ AC_MSG_RESULT(["socks5 library found, building with it"])
+ ], [
+ AC_MSG_RESULT(["socks4 library found, building with it"])
+ CFLAGS="$CFLAGS -Dconnect=Rconnect -Dgetsockname=Rgetsockname -Dgetpeername=Rgetpeername -Dbind=Rbind -Daccept=Raccept -Dlisten=Rlisten -Dselect=Rselect"
+ ])
+ ])
+fi
+
+dnl **
+dnl ** check for gnome
+dnl **
+
+if test "x$want_gnome" = "xyes"; then
+ if test "x$GNOME_LIBS" = "x"; then
+ want_gnome="no";
+ fi
+fi
+
+AM_CONDITIONAL(HAVE_GNOME, test "x$want_gnome" = "xyes")
+if test "x$want_gnome" = "xyes"; then
+ AC_DEFINE(HAVE_GTK)
+ AC_DEFINE(HAVE_GNOME)
+ GNOME_SUPPORT_CHECKS
+ GUI_CFLAGS="$GNOME_INCLUDEDIR"
+
+ dnl **
+ dnl ** check for gnome panel applet library
+ dnl **
+
+ if test "x$want_gnome_panel" = "xyes"; then
+ AC_CHECK_LIB(panel_applet, applet_widget_init, [
+ GUI_LIBS="$GNOME_LIBDIR $GNOMEGNORBA_LIBS $ZVT_LIBS -lpanel_applet"
+ AC_DEFINE(HAVE_GNOME_PANEL)
+ ], [
+ GUI_LIBS="$GNOME_LIBDIR $GNOMEUI_LIBS $ZVT_LIBS"
+ want_gnome_panel="no"
+ ], $GNOME_LIBDIR $GNOMEGNORBA_LIBS -lpanel_applet)
+ else
+ GUI_LIBS="$GNOME_LIBDIR $GNOMEUI_LIBS $ZVT_LIBS"
+ fi
+
+else
+ want_gnome_panel="no"
+ AC_DEFINE(HAVE_GTK)
+ AM_PATH_GTK(1.2.0)
+ GUI_CFLAGS="$GTK_CFLAGS"
+ GUI_LIBS="$GTK_LIBS"
+
+ if test "x$gtk_config_minor_version" = "x0"; then
+ AC_DEFINE(GTK_10)
+ fi
+
+ if test "x$want_imlib" = "xyes"; then
+ AM_PATH_GDK_IMLIB(, [define_imlib=true])
+ if test x$define_imlib = xtrue; then
+ AC_DEFINE(HAVE_IMLIB)
+ GUI_CFLAGS="$GUI_CFLAGS $GDK_IMLIB_CFLAGS"
+ GUI_LIBS="$GDK_IMLIB_LIBS"
+ fi
+ fi
+fi
+
+if test "x$GUI_LIBS" != "x"; then
+ GUI_LIBS="$GUI_LIBS $HEBREW_LIBS"
+fi
+
+AC_SUBST(GUI_LIBS)
+AC_SUBST(GUI_CFLAGS)
+AM_CONDITIONAL(BUILD_GNOMEUI, test "x$GUI_LIBS" != "x")
+AM_CONDITIONAL(HAVE_GNOME_PANEL, test "x$want_gnome_panel" = "xyes")
+
+dnl **
+dnl ** gui-text checks
+dnl **
+
+AM_PATH_GLIB(1.2.0,,, gmodule)
+
+dnl **
+dnl ** curses checks
+dnl **
+
+if test "x$want_textui" = "xyes"; then
+ AC_CHECK_CURSES
+
+ if test "x$ncurses_version" != "x"; then
+ AC_CHECK_LIB(ncurses, use_default_colors, [
+ AC_DEFINE(HAVE_NCURSES_USE_DEFAULT_COLORS)
+ ],, $CURSES_LIBS)
+ AC_CHECK_LIB(ncurses, idcok, [
+ AC_DEFINE(HAVE_CURSES_IDCOK)
+ ],, $CURSES_LIBS)
+ else
+ AC_CHECK_LIB(curses, idcok, [
+ AC_DEFINE(HAVE_CURSES_IDCOK)
+ ],, $CURSES_LIBS)
+ fi
+else
+ has_curses=false
+fi
+AM_CONDITIONAL(HAS_CURSES, test "$has_curses" = true)
+
+dnl **
+dnl ** memory debugging
+dnl **
+
+if test "x$want_memdebug" = "xyes"; then
+ AC_DEFINE(MEM_DEBUG)
+fi
+AM_CONDITIONAL(BUILD_MEMDEBUG, test "x$want_memdebug" = "xyes")
+
+dnl **
+dnl ** IPv6 support
+dnl **
+
+if test "x$want_ipv6" = "xyes"; then
+ AC_DEFINE(HAVE_IPV6)
+fi
+
+dnl **
+dnl ** internationalization support
+dnl **
+
+dnl ALL_LINGUAS=""
+dnl AM_GNU_GETTEXT
+dnl AC_LINK_FILES($nls_cv_header_libgt, $nls_cv_header_intl)
+
+AC_OUTPUT(
+Makefile
+dnl ## internationalization support
+dnl po/Makefile.in
+dnl intl/Makefile
+macros/Makefile
+src/Makefile
+src/irc-base/Makefile
+src/irc-extra/Makefile
+src/ui-common/Makefile
+src/gui-none/Makefile
+src/gui-text/Makefile
+src/gui-gnome/Makefile
+src/gui-gnome/help/Makefile
+src/gui-gnome/help/C/Makefile
+src/gui-gnome/pixmaps/Makefile
+src/lib-config/Makefile
+src/lib-nongui/Makefile
+src/settings/Makefile
+servertest/Makefile
+plugins/Makefile
+plugins/sample/Makefile
+plugins/speech/Makefile
+plugins/sound/Makefile
+plugins/proxy/Makefile
+plugins/external/Makefile
+plugins/bot/Makefile
+stamp.h)
+
+dnl **
+dnl ** internationalization support
+dnl **
+
+dnl stamp.h],[sed -e "/POTFILES =/r po/POTFILES" po/Makefile.in > po/Makefile])
diff --git a/file2header.sh b/file2header.sh
new file mode 100755
index 00000000..c3729d37
--- /dev/null
+++ b/file2header.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+echo "gchar *default_config ="
+cat $1|sed 's/\\/\\\\/g'|sed 's/"/\\"/g'|sed 's/^/\"/'|sed 's/$/\\n\"/'
+echo ";"
diff --git a/irssi.desktop b/irssi.desktop
new file mode 100644
index 00000000..b90c5a9e
--- /dev/null
+++ b/irssi.desktop
@@ -0,0 +1,6 @@
+[Desktop Entry]
+Name=irssi
+Comment=irssi IRC client
+Exec=irssi
+Terminal=0
+Type=Application
diff --git a/irssi.gnorba b/irssi.gnorba
new file mode 100644
index 00000000..6296e4ff
--- /dev/null
+++ b/irssi.gnorba
@@ -0,0 +1,5 @@
+[irssi]
+type=exe
+repo_id=IDL:GNOME/Applet:1.0
+description=irssi IRC client
+location_info=irssi
diff --git a/irssi.spec.in b/irssi.spec.in
new file mode 100644
index 00000000..9f561d96
--- /dev/null
+++ b/irssi.spec.in
@@ -0,0 +1,87 @@
+Name: irssi
+Version:
+Release: 1
+Packager: Red Hat Contrib|Net <rhcn-bugs@redhat.com>
+Vendor: Timo Sirainen <cras@irccrew.org>
+Distribution: Red Hat Contrib|Net
+Summary: Irssi is a GTK based IRC client
+Copyright: GPL
+Group: X11/Applications/Networking
+URL: http://xlife.dhs.org/irssi/
+Source: http://xlife.dhs.org/irssi/files/%{name}-%{version}.tar.bz2
+Requires: gtk+
+Prefix: /usr
+BuildRoot: /tmp/%{name}-%{version}
+
+%changelog
+* Sun Aug 29 1999 JT Traub <jtraub@dragoncat.net>
+- Updated to 0.7.15 sources
+- Fixed config stuff that changed since last version.
+
+* Thu Mar 25 1999 JT Traub <jtraub@dragoncat.net>
+- Updated sources
+
+* Sat Mar 13 1999 JT Traub <jtraub@dragoncat.net>
+- Updated to 0.7.4 sources
+- Added the irssi-text bin to the package.
+
+* Mon Feb 22 1999 JT Traub <jtraub@dragoncat.net>
+- Made spec file compliant with RHCN guidelines.
+
+* Sun Feb 13 1999 JT Traub <jtraub@dragoncat.net>
+- Updated to 0.6.0 sources.
+- Cleaned up spec file to make it relocatable on install
+
+* Sun Feb 7 1999 JT Traub <jtraub@dragoncat.net>
+- Updated sources to 0.5.0
+- removed obsolete patch lines
+
+* Sat Feb 3 1999 JT Traub <jtraub@dragoncat.net>
+- Updated sources to 0.4.0
+- Deleted old patch line
+
+* Sat Jan 30 1999 JT Traub <jtraub@dragoncat.net>
+- Updated sources to 0.3.6
+- Updated spec to install the .desktop file.
+- Removed the now obsolete patch lines
+
+* Wed Jan 27 1999 JT Traub <jtraub@dragoncat.net>
+- Upgraded to 0.3.5
+
+* Sun Jan 24 1999 JT Traub <jtraub@dragoncat.net>
+- First attempt at building this
+
+%description
+Irssi is a GTK based GUI IRC client by Timo Sirainen <cras@irccrew.org>.
+More information can be found at http://xlife.dhs.org/irssi/.
+
+
+%prep
+%setup
+
+%build
+./configure --prefix=%{prefix}
+make
+
+%install
+rm -rf $RPM_BUILD_ROOT
+make prefix=$RPM_BUILD_ROOT%{prefix} install
+strip $RPM_BUILD_ROOT%{prefix}/bin/irssi
+strip $RPM_BUILD_ROOT%{prefix}/bin/irssi-text
+strip $RPM_BUILD_ROOT%{prefix}/bin/irssi-bot
+
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%files
+%defattr (-,root,root)
+%doc AUTHORS COPYING INSTALL ChangeLog README TODO NEWS
+%attr(755,root,root) %{prefix}/bin/irssi
+%attr(755,root,root) %{prefix}/bin/irssi-text
+%attr(755,root,root) %{prefix}/bin/irssi-bot
+%attr(644,root,root) %config %{prefix}/etc/irssi/*
+%attr(644,root,root) %{prefix}/etc/CORBA/servers/irssi.gnorba
+%attr(644,root,root) %{prefix}/share/applets/Network/irssi.desktop
+%attr(644,root,root) %{prefix}/share/gnome/help/irssi/C/*
+%attr(644,root,root) %{prefix}/lib/irssi/plugins/*
diff --git a/servertest/.cvsignore b/servertest/.cvsignore
new file mode 100644
index 00000000..ca8c752b
--- /dev/null
+++ b/servertest/.cvsignore
@@ -0,0 +1,8 @@
+*.la
+*.lo
+.deps
+.libs
+Makefile
+Makefile.in
+so_locations
+ircserver
diff --git a/servertest/Makefile.am b/servertest/Makefile.am
new file mode 100644
index 00000000..4eb03cdf
--- /dev/null
+++ b/servertest/Makefile.am
@@ -0,0 +1,13 @@
+bin_PROGRAMS = ircserver
+
+INCLUDES = $(GLIB_CFLAGS) -I$(top_srcdir)/src
+
+if BUILD_MEMDEBUG
+memdebug_src=../src/irc-base/memdebug.o
+else
+memdebug_src=
+endif
+
+ircserver_LDADD = -lglib ../src/irc-base/network.o $(memdebug_src)
+
+ircserver_SOURCES = server.c
diff --git a/servertest/server.c b/servertest/server.c
new file mode 100644
index 00000000..90ce2bd5
--- /dev/null
+++ b/servertest/server.c
@@ -0,0 +1,463 @@
+#include <common.h>
+
+#include <irc-base/network.h>
+
+#define FLOOD_TIMEOUT 100000
+
+typedef struct
+{
+ gchar *name;
+ GList *nicks;
+}
+CHANNEL_REC;
+
+GList *channels;
+gchar *clientnick, *clienthost;
+
+int clienth;
+
+/* Read a line */
+gint read_line(gboolean socket, gint handle, GString *output, GString *buffer)
+{
+ gchar tmpbuf[512];
+ gint recvlen, pos;
+
+ g_return_val_if_fail(handle != -1, -1);
+ g_return_val_if_fail(output != NULL, -1);
+ g_return_val_if_fail(buffer != NULL, -1);
+
+ g_string_truncate(output, 0);
+
+ recvlen = socket ?
+ net_receive(handle, tmpbuf, sizeof(tmpbuf)-1) :
+ read(handle, tmpbuf, sizeof(tmpbuf)-1);
+
+ if (recvlen <= 0)
+ {
+ if (buffer->len > 0)
+ {
+ /* no new data got but still something in buffer.. */
+ for (pos = 0; pos < buffer->len; pos++)
+ {
+ if (buffer->str[pos] == 13 || buffer->str[pos] == 10)
+ {
+ recvlen = 0;
+ break;
+ }
+ }
+ if (recvlen < 0 && buffer->len > 0)
+ {
+ /* connection closed and last line is missing \n ..
+ just add it so we can see if it had anything useful.. */
+ recvlen = 0;
+ g_string_append_c(buffer, '\n');
+ }
+ }
+
+ if (recvlen < 0) return -1;
+ }
+ else
+ {
+ /* append received data to buffer */
+ tmpbuf[recvlen] = '\0';
+ g_string_append(buffer, tmpbuf);
+ }
+
+ for (pos = 0; pos < buffer->len; pos++)
+ {
+ if (buffer->str[pos] == 13 || buffer->str[pos] == 10)
+ {
+ /* end of line */
+ buffer->str[pos] = '\0';
+ g_string_assign(output, buffer->str);
+
+ if (buffer->str[pos] == 13 && buffer->str[pos+1] == 10)
+ {
+ /* skip \n too */
+ pos++;
+ }
+
+ g_string_erase(buffer, 0, pos+1);
+ return 1;
+ }
+ }
+
+ /* EOL wasn't found, wait for more data.. */
+ return 0;
+}
+void client_send(char *text)
+{
+ write(clienth, text, strlen(text));
+ write(clienth, "\r\n", 2);
+}
+
+void makerand(char *str, int len)
+{
+ for (; len > 0; len--)
+ *str++ = (rand() % 20)+'A';
+}
+
+void makerand2(char *str, int len)
+{
+#if 0
+ gchar c;
+
+ while (len > 0)
+ {
+ c = rand() & 255;
+ if (c != 0 && c != 13 && c != 10)
+ {
+ *str++ = c;
+ len--;
+ }
+ }
+#else
+ makerand(str, len);
+#endif
+}
+
+void send_cmd(void)
+{
+ static gint nicks = 0;
+ GList *tmp;
+ char str[512];
+ int pos;
+
+ /* send msg to every channel */
+ str[511] = '\0';
+
+ for (tmp = g_list_first(channels); tmp != NULL; tmp = tmp->next)
+ {
+ CHANNEL_REC *rec = tmp->data;
+
+ makerand(str, 511);
+ str[0] = ':';
+ str[10] = '!';
+ str[20] = '@';
+
+ switch (rand() % 10)
+ {
+ case 0:
+ /* join */
+ pos = 2+sprintf(str+2, "%d", nicks++); /* don't use same nick twice */
+ str[pos] = '-';
+ str[10] = '\0';
+ g_list_append(rec->nicks, g_strdup(str+1));
+ str[10] = '!';
+ sprintf(str+30, " JOIN :%s", rec->name);
+ break;
+ case 1:
+ /* part */
+ if (g_list_length(rec->nicks) > 1 && rand() % 3 == 0)
+ {
+ gchar *nick;
+
+ nick = g_list_nth(rec->nicks, rand()%(g_list_length(rec->nicks)-1)+1)->data;
+ if (rand() % 3 == 0)
+ sprintf(str, ":kicker!some@where KICK %s %s :go away", rec->name, nick);
+ else if (rand() % 3 == 0)
+ sprintf(str, ":%s!dunno@where QUIT %s :i'm outta here", nick, rec->name);
+ else
+ sprintf(str, ":%s!dunno@where PART %s", nick, rec->name);
+ rec->nicks = g_list_remove(rec->nicks, nick);
+ g_free(nick);
+ }
+ else
+ str[0] = '\0';
+ break;
+ case 2:
+ /* nick change */
+ if (g_list_length(rec->nicks) > 1)
+ {
+ gchar *nick;
+
+ nick = g_list_nth(rec->nicks, rand()%(g_list_length(rec->nicks)-1)+1)->data;
+ pos = sprintf(str, ":%s!dunno@where NICK ", nick);
+ str[pos] = '_';
+ str[50] = '\0';
+ rec->nicks = g_list_remove(rec->nicks, nick);
+ rec->nicks = g_list_append(rec->nicks, g_strdup(str+pos));
+ g_free(nick);
+ }
+ else
+ str[0] = '\0';
+ break;
+ case 3:
+ /* topic */
+ pos = 30+sprintf(str+30, " TOPIC %s :", rec->name);
+ str[pos] = 'x';
+ break;
+ case 4:
+ /* mode */
+ sprintf(str+30, " MODE %s :%cnt", rec->name, (rand() & 1) ? '+' : '-');
+ break;
+ case 5:
+ /* notice */
+ pos = 30+sprintf(str+30, " NOTICE %s :", rec->name);
+ str[pos] = 'X';
+ break;
+ case 6:
+ /* nick mode change */
+ if (g_list_length(rec->nicks) > 1)
+ {
+ gchar *nick;
+
+ nick = g_list_nth(rec->nicks, rand()%(g_list_length(rec->nicks)-1)+1)->data;
+ pos = sprintf(str, ":server MODE %s +%c %s", rec->name, rand()&1 ? 'o' : 'v', nick);
+ str[pos] = '_';
+ str[50] = '\0';
+ rec->nicks = g_list_remove(rec->nicks, nick);
+ rec->nicks = g_list_append(rec->nicks, g_strdup(str+pos));
+ g_free(nick);
+ }
+ else
+ str[0] = '\0';
+ break;
+ default:
+ pos = 30+sprintf(str+30, " PRIVMSG %s :", rec->name);
+ makerand2(str+pos, 511-pos);
+ if (rand() % 4 == 0)
+ {
+ pos += sprintf(str+pos, "\001ACTION ");
+ str[510] = 1;
+ }
+ else if (rand() % 10 == 0)
+ {
+ pos += sprintf(str+pos, "\001VERSION\001");
+ pos++;
+ }
+ else if (rand() % 2 == 0)
+ {
+ pos += sprintf(str+pos, "%s: ", clientnick);
+ }
+ str[pos] = 'X';
+ break;
+ }
+
+ client_send(str);
+ }
+
+ makerand(str, 511);
+ str[0] = ':';
+ str[10] = '!';
+ str[20] = '@';
+
+ switch (rand() % 11)
+ {
+ case 0:
+ /* join */
+ if (g_list_length(channels) < 20)
+ {
+ CHANNEL_REC *rec;
+ int n, pos;
+
+ n = (rand()%20)+25;
+ pos = sprintf(str, ":%s!%s JOIN :", clientnick, clienthost);
+ str[pos] = '#';
+ str[n] = '\0';
+
+ rec = g_new(CHANNEL_REC, 1);
+ rec->name = g_strdup(str+pos);
+ rec->nicks = g_list_append(NULL, g_strdup(clientnick));
+
+ channels = g_list_append(channels, rec);
+ client_send(str);
+
+ sprintf(str, ":server 353 %s = %s :@%s", clientnick, rec->name, clientnick);
+ client_send(str);
+ sprintf(str, ":server 366 %s %s :End of /NAMES list.", clientnick, rec->name);
+ }
+ else
+ str[0] = '\0';
+ break;
+ case 1:
+ /* leave channel (by kick) */
+ if (g_list_length(channels) > 3)
+ {
+ CHANNEL_REC *chan;
+
+ chan = g_list_nth(channels, rand()%g_list_length(channels))->data;
+ if (rand() % 3 != 0)
+ {
+ pos = sprintf(str, ":%s!%s PART %s :", clientnick, clienthost, chan->name);
+ str[pos] = 'x';
+ }
+ else
+ {
+ str[0] = ':';
+ sprintf(str+30, " KICK %s %s :byebye", chan->name, clientnick);
+ }
+
+ g_free(chan->name);
+ g_list_foreach(chan->nicks, (GFunc) g_free, NULL); g_list_free(chan->nicks);
+ g_free(chan);
+ channels = g_list_remove(channels, chan);
+ }
+ else
+ str[0] = '\0';
+ break;
+ case 2:
+ /* ctcp version */
+ sprintf(str+30, " PRIVMSG %s :\001VERSION\001", clientnick);
+ break;
+ case 3:
+ /* ctcp ping */
+ sprintf(str+30, " PRIVMSG %s :\001PING\001", clientnick);
+ break;
+ case 4:
+ /* user mode */
+ sprintf(str+30, " MODE %s :%ciw", clientnick, (rand() & 1) ? '+' : '-');
+ break;
+ case 5:
+ /* msg */
+ pos = 30+sprintf(str+30, " PRIVMSG %s :", clientnick);
+ str[pos] = 'X';
+ break;
+ case 6:
+ /* notice */
+ pos = 30+sprintf(str+30, " NOTICE %s :", clientnick);
+ str[pos] = 'X';
+ break;
+ case 7:
+ /* invite */
+ pos = 30+sprintf(str+30, " INVITE %s", clientnick);
+ str[pos] = 'X';
+ break;
+ case 8:
+ /* error */
+ pos = sprintf(str, ":server ERROR :");
+ str[pos] = 'X';
+ break;
+ case 9:
+ /* wallops */
+ pos = sprintf(str, ":server WALLOPS :");
+ str[pos] = 'X';
+ break;
+ case 10:
+ /* ping */
+ pos = sprintf(str, ":server PING :");
+ str[pos] = 'X';
+ break;
+ }
+ client_send(str);
+}
+
+void handle_command(char *str)
+{
+ if (strncmp(str, "NICK ", 5) == 0)
+ {
+ clientnick = g_strdup(str+5); /* got the nick */
+ }
+}
+
+guint gui_timeout_add(guint32 interval, GUITimeoutFunction function, gpointer data)
+{
+ return -1;
+}
+
+int main(void)
+{
+ static fd_set fdset;
+ struct timeval tv;
+ int serverh, port;
+ IPADDR ip;
+
+#ifdef HAVE_IPV6
+ if (net_gethostname("::1", &ip) != 0)
+ {
+ printf("net_gethostname()\n");
+ return 1;
+ }
+#else
+ if (net_gethostname("127.0.0.1", &ip) != 0)
+ {
+ printf("net_gethostname()\n");
+ return 1;
+ }
+#endif
+
+ srand(0);
+ port = 6660;
+ serverh = net_listen(&ip, &port);
+ if (serverh == -1)
+ {
+ printf("listen()\n");
+ return 1;
+ }
+
+ clienth = -1; channels = NULL;
+ for (;;)
+ {
+ FD_ZERO(&fdset);
+ if (clienth != -1) FD_SET(clienth, &fdset);
+ FD_SET(serverh, &fdset);
+
+ tv.tv_sec = 0;
+ tv.tv_usec = FLOOD_TIMEOUT;
+ if (select((serverh > clienth ? serverh : clienth)+1, &fdset, NULL, NULL, &tv) <= 0)
+ {
+ /* nothing happened, bug the client with some commands.. */
+ if (clienth != -1 && clientnick != NULL) send_cmd();
+ }
+ else
+ {
+ if (FD_ISSET(serverh, &fdset))
+ {
+ /* client connecting! */
+ if (clienth != -1)
+ {
+ /* only one client allowed.. */
+ int handle;
+
+ handle = net_accept(serverh, NULL, &port);
+ if (handle != -1)
+ {
+ client_send("Only one client allowed");
+ close(handle);
+ continue;
+ }
+ }
+ else
+ {
+ IPADDR clientip;
+
+ clienth = net_accept(serverh, &clientip, &port);
+ if (clienth != -1)
+ {
+ clienthost = g_strdup(net_ip2host(&clientip));
+ client_send(":server 001 pla");
+ client_send(":server 002 plapla");
+ client_send(":server 003 plaplapla");
+ client_send(":server 004 connected!");
+ }
+ }
+ }
+ else
+ {
+ /* clients sending something.. */
+ GString *str, *buf;
+ int ret;
+
+ str = g_string_new(NULL);
+ buf = g_string_new(NULL);
+ do
+ {
+ ret = read_line(TRUE, clienth, str, buf);
+ if (ret == -1)
+ {
+ /* client disconnected */
+ close(clienth);
+ clienth = -1;
+ break;
+ }
+ if (ret == 1) handle_command(str->str);
+ }
+ while (ret == 1);
+ g_string_free(str, TRUE);
+ g_string_free(buf, TRUE);
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/src/.cvsignore b/src/.cvsignore
new file mode 100644
index 00000000..282522db
--- /dev/null
+++ b/src/.cvsignore
@@ -0,0 +1,2 @@
+Makefile
+Makefile.in
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 00000000..d4e162f9
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,17 @@
+if HAS_CURSES
+TEXTUI=gui-text
+endif
+
+if BUILD_GNOMEUI
+GNOMEUI=gui-gnome
+endif
+
+noinst_HEADERS = \
+ common.h \
+ common-setup.h \
+ irssi-plugin.h \
+ irssi-plugin-gui.h
+
+SUBDIRS = irc-base irc-extra ui-common lib-config lib-nongui settings $(GNOMEUI) $(TEXTUI) gui-none
+
+EXTRA_DIST = signal.doc
diff --git a/src/common-setup.h b/src/common-setup.h
new file mode 100644
index 00000000..96549351
--- /dev/null
+++ b/src/common-setup.h
@@ -0,0 +1,125 @@
+#ifndef __COMMON_SETUP_H
+#define __COMMON_SETUP_H
+
+#define DCC_FILE_CREATE_MODE 0644
+#define LOG_FILE_CREATE_MODE 0644
+#define CMD_CHAR '/'
+
+/* How often to check if there's anyone to be unignored in autoignore list */
+#define AUTOIGNORE_TIMECHECK 10000
+
+/* How often to check if there's anyone to be unbanned in knockout list */
+#define KNOCKOUT_TIMECHECK 10000
+
+/* How often to check users in notify list */
+#define NOTIFY_TIMECHECK 30000
+
+/* How often to check for gone status of nick */
+#define MAX_GONE_REFRESH_TIME 300
+
+/* Maximum time to wait for more JOINs before sending massjoin signal */
+#define MAX_MASSJOIN_WAIT 5000
+
+/* lists */
+extern GList *aliases, *ignores, *completions, *notifies, *hilights;
+
+/* look and feel */
+extern gboolean toggle_show_menubar;
+extern gboolean toggle_show_toolbar;
+extern gboolean toggle_show_statusbar;
+extern gboolean toggle_show_nicklist;
+extern gboolean toggle_show_timestamps;
+extern gboolean toggle_hide_text_style;
+extern gboolean toggle_bell_beeps;
+extern gboolean toggle_actlist_moves;
+extern gboolean toggle_privmsg_beeps;
+
+extern gboolean toggle_use_status_window;
+extern gboolean toggle_use_msgs_window;
+extern gboolean toggle_autoraise_msgs_window;
+extern gboolean toggle_autocreate_query;
+extern gboolean toggle_notifylist_popups;
+extern gboolean toggle_use_tabbed_windows;
+extern gint tab_orientation;
+
+/* misc */
+extern gchar *url_www_client;
+extern gchar *url_ftp_client;
+extern gchar *url_mail_client;
+
+extern gchar *ctcp_version_reply;
+extern gchar *default_quit_message;
+extern gchar *default_user_mode;
+
+extern gint max_command_history;
+extern gint max_textwidget_lines;
+extern gint rawlog_lines;
+extern gint block_remove_lines;
+
+extern gint knockout_time; /* How many seconds to keep /knockouted ban */
+extern gboolean check_irssi_versions; /* Check if there's new irssi version available */
+
+/* nick completion */
+extern gchar *completion_char;
+extern gboolean completion_disable_auto;
+extern gint completion_keep_publics;
+extern gint completion_keep_ownpublics;
+extern gint completion_keep_privates;
+
+/* flood protection */
+extern gint flood_timecheck; /* Flood check timeout */
+extern gint flood_max_msgs; /* Max msgs in FLOOD_TIMECHECK msecs before considered as flooding */
+extern gint autoignore_time; /* How many seconds to keep someone autoignored */
+extern gint ctcp_timecheck; /* CTCP reply send timeout */
+extern gint max_ctcp_queue; /* Max CTCP reply queue length */
+extern gint cmd_queue_speed; /* Minimum timeout before sending the next command to server */
+
+/* dcc */
+extern gboolean toggle_dcc_autodisplay_dialog;
+extern gboolean toggle_dcc_autoget;
+extern gboolean toggle_dcc_autorename;
+extern gint dcc_max_autoget_size;
+extern gchar *dcc_download_path;
+
+extern gboolean toggle_dcc_fast_send;
+extern gchar *dcc_upload_path;
+
+extern gboolean toggle_dcc_mirc_ctcp;
+extern gint dcc_block_size;
+extern gint dcc_timeout;
+
+/* servers */
+typedef struct
+{
+ gchar *server;
+ gchar *ircnet;
+ gchar *password;
+ gint port;
+ gboolean autoconnect;
+ time_t last_connect; /* to avoid reconnecting too fast.. */
+}
+SETUP_SERVER_REC;
+
+/* servers */
+extern GList *setupservers; /* list of local servers */
+extern GList *ircnets; /* list of available ircnets */
+extern gint server_reconnect_time; /* reconnect to server no sooner than n seconds */
+extern gchar *source_host; /* Our own IP to use */
+extern gboolean source_host_ok; /* Use source_host_ip .. */
+extern IPADDR source_host_ip; /* Resolved address */
+extern gchar *default_nick, *alternate_nick, *user_name, *real_name;
+extern gboolean toggle_skip_motd;
+
+/* IRC proxy */
+extern gboolean toggle_use_ircproxy;
+extern gchar *proxy_address;
+extern gint proxy_port;
+extern gchar *proxy_string;
+
+/* appearance */
+extern gboolean toggle_use_zvt;
+extern gboolean toggle_use_transparency;
+extern gboolean toggle_shaded_transparency;
+extern gint panel_max_channels;
+
+#endif
diff --git a/src/common.h b/src/common.h
new file mode 100644
index 00000000..d78a5562
--- /dev/null
+++ b/src/common.h
@@ -0,0 +1,114 @@
+#ifndef __COMMON_H
+#define __COMMON_H
+
+#define IRSSI_AUTHOR "Timo Sirainen <cras@irccrew.org>"
+#define IRSSI_WEBSITE "http://xlife.dhs.org/irssi/"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <ctype.h>
+# ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+#include <errno.h>
+#include <time.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/utsname.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#ifdef HAVE_DIRENT_H
+# include <dirent.h>
+#endif
+#include <fcntl.h>
+
+#ifdef HAVE_SOCKS_H
+#include <socks.h>
+#endif
+
+#include <netdb.h>
+#include <sys/socket.h>
+#include <signal.h>
+#include <sys/signal.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <glib.h>
+#include <gmodule.h>
+
+typedef struct
+{
+ gushort family;
+#ifdef HAVE_IPV6
+ struct in6_addr addr;
+#else
+ struct in_addr addr;
+#endif
+}
+IPADDR;
+
+#include "lib-config/irssi-config.h"
+#include "common-setup.h"
+
+/* GUI library must provide these functions: */
+
+typedef enum
+{
+ GUI_INPUT_READ = 1 << 0,
+ GUI_INPUT_WRITE = 1 << 1,
+ GUI_INPUT_EXCEPTION = 1 << 2
+} GUIInputCondition;
+
+typedef void (*GUIInputFunction) (gpointer data, gint handle, GUIInputCondition condition);
+typedef gint (*GUITimeoutFunction) (gpointer data);
+
+gint gui_input_add(gint handle, GUIInputCondition condition,
+ GUIInputFunction function, gpointer data);
+void gui_input_remove(gint tag);
+
+guint gui_timeout_add(guint32 interval, GUITimeoutFunction function, gpointer data);
+void gui_timeout_remove(gint tag);
+
+#ifdef MEM_DEBUG
+
+void ig_mem_profile(void);
+
+void ig_set_data(gchar *data);
+
+gpointer ig_malloc(gint size, gchar *file, gint line);
+gpointer ig_malloc0(gint size, gchar *file, gint line);
+gpointer ig_realloc(gpointer mem, gulong size, gchar *file, gint line);
+gchar *ig_strdup(const char *str, gchar *file, gint line);
+gchar *ig_strconcat(const char *str, ...);
+gchar *ig_strdup_printf(const gchar *format, ...) G_GNUC_PRINTF (1, 2);
+void ig_free(gpointer p);
+GString *ig_string_new(gchar *str);
+void ig_string_free(GString *str, gboolean freeit);
+
+#define g_malloc(a) ig_malloc(a, __FILE__, __LINE__)
+#define g_malloc0(a) ig_malloc0(a, __FILE__, __LINE__)
+#define g_realloc(a,b) ig_realloc(a, b, __FILE__, __LINE__)
+#define g_strdup(a) ig_strdup(a, __FILE__, __LINE__)
+#define g_strconcat ig_strconcat
+#define g_strdup_printf ig_strdup_printf
+#define g_strdup_vprintf ig_strdup_vprintf
+#define g_free ig_free
+#define g_string_new ig_string_new
+#define g_string_free ig_string_free
+
+#endif
+
+#endif
diff --git a/src/irssi-plugin-gui.h b/src/irssi-plugin-gui.h
new file mode 100644
index 00000000..94698308
--- /dev/null
+++ b/src/irssi-plugin-gui.h
@@ -0,0 +1,11 @@
+/* This contains all the necessary includes for creating GUI widgets to
+ plugins */
+
+#ifdef HAVE_GTK
+#include "gui-gnome/irssi.h"
+#include "gui-gnome/setup-int.h"
+#endif
+
+#if defined (HAVE_CURSES) || defined (HAVE_SLANG)
+#include "gui-text/irssi.h"
+#endif
diff --git a/src/irssi-plugin.h b/src/irssi-plugin.h
new file mode 100644
index 00000000..684b56fd
--- /dev/null
+++ b/src/irssi-plugin.h
@@ -0,0 +1,9 @@
+/* This contains all the necessary includes for irssi plugins.
+ irc-extra/plugins.h and irc-extra/plugins-commands.h has all the plugin
+ management functions */
+
+#include "common.h"
+#include "irc-base/irc-base.h"
+#include "irc-extra/irc-extra.h"
+#include "ui-common/ui-common.h"
+#include "settings/settings.h"
diff --git a/src/signal.doc b/src/signal.doc
new file mode 100644
index 00000000..b7e238ef
--- /dev/null
+++ b/src/signal.doc
@@ -0,0 +1,178 @@
+IRC base
+--------
+
+* Requires to work properly:
+
+ "gui exit", CHANNEL_REC
+ "gui channel open", CHANNEL_REC
+ "send command", gchar *command, SERVER_REC, CHANNEL_REC
+
+* Provides signals:
+
+bans.c:
+
+ "ban new", BAN_REC
+ "ban remove", BAN_REC
+ "ban exception new", BAN_REC
+ "ban exception remove", BAN_REC
+ "ban type changed", gchar *bantype
+
+channels.c:
+
+ "channel created", CHANNEL_REC
+ "channel destroyed", CHANNEL_REC
+ "channel name changed", CHANNEL_REC
+ "channel topic changed", CHANNEL_REC
+
+ "channel query", CHANNEL_REC
+ "channel sync", CHANNEL_REC
+
+ctcp.c:
+
+ "ctcp msg "<cmd>, gchar *args, SERVER_REC, gchar *nick, gchar *addr, gchar *target
+ "default ctcp msg", gchar *args, SERVER_REC, gchar *nick, gchar *addr, gchar *target
+ "ctcp reply "<cmd>, gchar *args, SERVER_REC, gchar *nick, gchar *addr, gchar *target
+ "default ctcp reply", gchar *args, SERVER_REC, gchar *nick, gchar *addr, gchar *target
+
+irc.c:
+
+ "send command", gchar *args, SERVER_REC
+ "command "<cmd>, gchar *args, SERVER_REC, CHANNEL_REC
+ "default command", gchar *args, SERVER_REC, CHANNEL_REC
+
+ "server event", gchar *args, SERVER_REC, gchar *sender_nick, gchar *sender_address
+ "event "<cmd>, gchar *args, SERVER_REC, gchar *sender_nick, gchar *sender_address
+ "default event", gchar *args, SERVER_REC, gchar *sender_nick, gchar *sender_address
+
+modes.c:
+
+ "invitelist new", CHANNEL_REC, gchar *mask
+ "invitelist remove", CHANNEL_REC, gchar *mask
+
+ "channel mode changed", CHANNEL_REC
+ "user mode changed", SERVER_REC
+ "nick mode changed", CHANNEL_REC, NICK_REC
+
+nicklist.c:
+
+ "nicklist new" CHANNEL_REC, NICK_REC
+ "nicklist remove" CHANNEL_REC, NICK_REC
+ "nicklist changed" CHANNEL_REC, NICK_REC, gchar *oldnick
+ "server nick changed" SERVER_REC
+ "massjoin" CHANNEL_REC, GList of NICK_RECs
+
+server.c:
+
+ "server connect failed", SERVER_REC
+ "server connected", SERVER_REC
+ "server connecting", SERVER_REC, gulong *ip
+ "server looking", SERVER_REC
+ "server disconnected", SERVER_REC
+ "event connected", SERVER_REC
+
+signal.c:
+ "signal", gchar *name, ...
+
+IRC extra
+---------
+
+* Requires to work properly:
+
+ "print text stripped", SERVER_REC, gchar *channel, GINT_TO_POINTER(level), gchar *text
+ "plugin add menu", gchar *menuitem, void (*unload_func) (gpointer, PLUGIN_REC), PLUGIN_REC
+
+* Provides signals:
+
+dcc.c:
+
+ "dcc ctcp"<cmd>, gchar *args, DCC_REC
+ "default dcc ctcp", gchar *args, DCC_REC
+ "dcc unknown ctcp", gchar *args, gchar *sender, gchar *sendaddr
+
+ "dcc reply"<cmd>, gchar *args, DCC_REC
+ "default dcc reply"<cmd>, gchar *args, DCC_REC
+ "dcc unknown reply", gchar *args, gchar *sender, gchar *sendaddr
+
+ "dcc chat message", DCC_REC, gchar *msg
+
+ "dcc created", DCC_REC
+ "dcc destroyed", DCC_REC
+ "dcc connected", DCC_REC
+ "dcc rejecting", DCC_REC
+ "dcc closed", DCC_REC
+ "dcc chat message", DCC_REC, gchar *msg
+ "dcc transfer update", DCC_REC
+ "dcc request", DCC_REC
+ "dcc get receive", DCC_REC
+ "dcc error connect", DCC_REC
+ "dcc error file create", DCC_REC, gchar *filename
+ "dcc error file not found", gchar *nick, gchar *filename
+ "dcc error get not found", gchar *nick
+ "dcc error send exists", gchar *nick, gchar *filename
+ "dcc error unknown type", gchar *type
+ "dcc error close not found", gchar *type, gchar *nick, gchar *filename
+
+flood.c:
+
+ "flood", SERVER_REC, gchar *nick, gchar *host, gchar *level, gchar *target
+
+ignore.c:
+
+ "autoignore new", SERVER_REC, AUTOIGNORE_REC
+ "autoignore remove", SERVER_REC, AUTOIGNORE_REC
+ "ignore new", LIST_REC
+ "ignore change", LIST_REC
+ "ignore remove", LIST_REC
+
+log.c:
+
+ "log created", LOG_REC
+ "log destroyed", LOG_REC
+ "log opened", LOG_REC
+ "log closed", LOG_REC
+ "log written", LOG_REC, gchar *line
+ "log item created", LOG_REC, LOG_ITEM_REC
+ "log item destroyed", LOG_REC, LOG_ITEM_REC
+
+notifylist.c:
+
+ "notifylist new", LIST_REC
+ "notifylist remove", LIST_REC
+ "notifylist joined", SERVER_REC, gchar *nick, gchar *username, gchar *host, gchar *realname
+ "notifylist left", SERVER_REC, gchar *nick
+
+plugins.c:
+
+ "plugin created", PLUGIN_REC
+ "plugin destroyed", PLUGIN_REC
+ "plugin cant load", gchar *name
+ "plugin already loaded", gchar *name
+ "plugin not loaded", gchar *name
+
+UI common
+---------
+
+* Requires to work properly:
+
+ "gui print text", CHANNEL_REC, GINT_TO_POINTER fg, bg, flags, gchar *text
+ "gui window goto", GINT_TO_POINTER(number)
+
+( "print text finished", CHANNEL_REC ) - can be used to determine when
+ all "gui print text"s are sent
+
+* Provides signals:
+
+ui-printtext.c:
+
+ "print text", SERVER_REC, gchar *channel, GINT_TO_POINTER(level), gchar *text
+ "print text stripped", SERVER_REC, gchar *channel, GINT_TO_POINTER(level), gchar *text
+
+ui-themes.c:
+
+ "theme created", THEME_REC
+ "theme destroyed", THEME_REC
+
+ui-windows.c:
+
+ "window created", WINDOW_REC
+ "window destroyed", WINDOW_REC
diff --git a/stamp.h.in b/stamp.h.in
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/stamp.h.in
diff --git a/window-views-patch.diff b/window-views-patch.diff
new file mode 100644
index 00000000..192b96b1
--- /dev/null
+++ b/window-views-patch.diff
@@ -0,0 +1,2672 @@
+diff -ru irssi-0.7.11/src/gui-gnome/Makefile.am irssi-0.7.11-new/src/gui-gnome/Makefile.am
+--- irssi-0.7.11/src/gui-gnome/Makefile.am Sun Jun 6 18:48:07 1999
++++ irssi-0.7.11-new/src/gui-gnome/Makefile.am Mon Jun 7 18:33:41 1999
+@@ -53,7 +52,8 @@
+ gui-mainwindows.c \
+ gui-printtext.c \
+ gui-server.c \
+- gui-windows.c \
++ gui-windowset.c \
++ gui-windows-view.c \
+ irssi.c \
+ setup-appearance.c \
+ setup-ircproxy.c \
+@@ -98,7 +98,8 @@
+ gui-mainwindows.h \
+ gui-printtext.h \
+ gui-server.h \
+- gui-windows.h \
++ gui-windowset.h \
++ gui-windows-view.h \
+ gtk-specific.h \
+ gnome-specific.h \
+ irssi.h \
+diff -ru irssi-0.7.11/src/gui-gnome/channels-newdata.c irssi-0.7.11-new/src/gui-gnome/channels-newdata.c
+--- irssi-0.7.11/src/gui-gnome/channels-newdata.c Sat May 15 20:23:24 1999
++++ irssi-0.7.11-new/src/gui-gnome/channels-newdata.c Sat Jun 12 17:55:06 1999
+@@ -57,7 +57,7 @@
+ g_return_val_if_fail(channel != NULL, FALSE);
+
+ label = gtk_notebook_get_tab_label(GTK_NOTEBOOK(WINDOW_GUI(CHANNEL_PARENT(channel))->parent->notebook),
+- WINDOW_GUI(CHANNEL_PARENT(channel))->window);
++ WINDOW_GUI(CHANNEL_PARENT(channel))->windowset->window);
+ newdata_label_colorify(channel, label);
+
+ return TRUE;
+diff -ru irssi-0.7.11/src/gui-gnome/dialog-channels.c irssi-0.7.11-new/src/gui-gnome/dialog-channels.c
+--- irssi-0.7.11/src/gui-gnome/dialog-channels.c Wed May 12 17:54:45 1999
++++ irssi-0.7.11-new/src/gui-gnome/dialog-channels.c Mon Jun 7 18:57:46 1999
+@@ -617,7 +617,7 @@
+ {
+ /* channel specific background pixmap */
+ path = convert_home(rec->background);
+- gui_window_set_background_pixmap(CHANNEL_PARENT(channel), path);
++ gui_window_view_set_background_pixmap(WINDOW_GUI(CHANNEL_PARENT(channel)), path);
+ g_free(path);
+ }
+
+diff -ru irssi-0.7.11/src/gui-gnome/dialog-textwidget.c irssi-0.7.11-new/src/gui-gnome/dialog-textwidget.c
+--- irssi-0.7.11/src/gui-gnome/dialog-textwidget.c Thu May 13 14:46:51 1999
++++ irssi-0.7.11-new/src/gui-gnome/dialog-textwidget.c Sat Jun 12 17:26:21 1999
+@@ -134,7 +134,7 @@
+ return;
+ }
+
+- if (WINDOW_GUI(window->active)->zvt)
++ if (window->active->active->zvt)
+ {
+ gui_dialog(DIALOG_ERROR, "Find doesn't work with ZVT windows yet");
+ return;
+@@ -145,7 +145,7 @@
+ GNOME_STOCK_BUTTON_CLOSE, NULL);
+ gtk_signal_connect(GTK_OBJECT(dialog), "delete_event",
+ GTK_SIGNAL_FUNC(gtk_widget_destroy), NULL);
+- gui_widget_depends_data(dialog, "window destroyed", window->active);
++ gui_widget_depends_data(dialog, "window destroyed", window->active->active->window);
+
+ hbox = gtk_hbox_new(FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(dialog)->vbox), hbox, TRUE, TRUE, 0);
+@@ -160,8 +160,8 @@
+ gnome_dialog_button_connect_object(GNOME_DIALOG(dialog), 1, sig_find_next, GTK_OBJECT(dialog));
+ gnome_dialog_button_connect_object(GNOME_DIALOG(dialog), 2, GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(dialog));
+
+- gtk_object_set_data(GTK_OBJECT(dialog), "text", WINDOW_GUI(window->active)->text);
+- gtk_object_set_data(GTK_OBJECT(dialog), "window", window->active);
++ gtk_object_set_data(GTK_OBJECT(dialog), "text", window->active->active->text);
++ gtk_object_set_data(GTK_OBJECT(dialog), "window", window->active->active->window);
+ gtk_object_set_data(GTK_OBJECT(dialog), "entry", entry);
+
+ gtk_widget_show_all(dialog);
+@@ -220,13 +220,13 @@
+ return;
+ }
+
+- if (WINDOW_GUI(window->active)->zvt)
++ if (window->active->active->zvt)
+ {
+ gui_dialog(DIALOG_ERROR, "Save doesn't work with ZVT windows yet");
+ return;
+ }
+
+- if (gtk_text_get_length(GTK_TEXT(WINDOW_GUI(window->active)->text)) == 0)
++ if (gtk_text_get_length(GTK_TEXT(window->active->active->text)) == 0)
+ {
+ gui_dialog(DIALOG_OK, _("Window doesn't have any text"));
+ return;
+@@ -236,12 +236,12 @@
+ GNOME_STOCK_BUTTON_CANCEL, NULL);
+ gtk_signal_connect(GTK_OBJECT(dialog), "delete_event",
+ GTK_SIGNAL_FUNC(gtk_widget_destroy), NULL);
+- gui_widget_depends_data(dialog, "window destroyed", window->active);
++ gui_widget_depends_data(dialog, "window destroyed", window->active->active->window);
+
+ button = gtk_check_button_new_with_label(_("Save only selected text"));
+ gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(dialog)->vbox), button, FALSE, FALSE, 0);
+
+- if (GTK_EDITABLE(WINDOW_GUI(window->active)->text)->has_selection)
++ if (GTK_EDITABLE(window->active->active->text)->has_selection)
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
+ else
+ gtk_widget_set_sensitive(button, FALSE);
+@@ -258,7 +258,7 @@
+ gnome_dialog_button_connect_object(GNOME_DIALOG(dialog), 0, sig_save_ok, GTK_OBJECT(dialog));
+ gnome_dialog_button_connect_object(GNOME_DIALOG(dialog), 1, GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(dialog));
+
+- gtk_object_set_data(GTK_OBJECT(dialog), "text", WINDOW_GUI(window->active)->text);
++ gtk_object_set_data(GTK_OBJECT(dialog), "text", window->active->active->text);
+ gtk_object_set_data(GTK_OBJECT(dialog), "selbut", button);
+ gtk_object_set_data(GTK_OBJECT(dialog), "entry", gnome_file_entry_gtk_entry(GNOME_FILE_ENTRY(entry)));
+
+diff -ru irssi-0.7.11/src/gui-gnome/dialog-window.c irssi-0.7.11-new/src/gui-gnome/dialog-window.c
+--- irssi-0.7.11/src/gui-gnome/dialog-window.c Sun Jun 6 18:34:26 1999
++++ irssi-0.7.11-new/src/gui-gnome/dialog-window.c Sat Jun 12 17:28:12 1999
+@@ -108,13 +108,13 @@
+ hbox2 = gtk_hbox_new(FALSE, 5);
+ gtk_box_pack_start(GTK_BOX(hbox), hbox2, TRUE, TRUE, 0);
+
+- str = g_strdup_printf("%d", WINDOW_GUI(window->active)->text->allocation.width);
++ str = g_strdup_printf("%d", window->active->active->text->allocation.width);
+ entry = gui_create_labelentry(hbox2, _("Width"), str, TRUE);
+ gtk_object_set_data(GTK_OBJECT(dialog), "sizexentry", entry);
+ gtk_widget_set_usize(entry, 50, -1);
+ g_free(str);
+
+- str = g_strdup_printf("%d", WINDOW_GUI(window->active)->text->allocation.height);
++ str = g_strdup_printf("%d", window->active->active->text->allocation.height);
+ entry = gui_create_labelentry(hbox2, _("Height"), str, TRUE);
+ gtk_object_set_data(GTK_OBJECT(dialog), "sizeyentry", entry);
+ gtk_widget_set_usize(entry, 50, -1);
+@@ -154,7 +154,7 @@
+ gtk_widget_set_sensitive(hbox2, FALSE);
+
+ /* window name */
+- channel = window->active->active;
++ channel = window->active->active->window->active;
+ name = gui_channel_get_name(channel);
+ if (name == NULL) name = "default";
+
+diff -ru irssi-0.7.11/src/gui-gnome/gui-channels.c irssi-0.7.11-new/src/gui-gnome/gui-channels.c
+--- irssi-0.7.11/src/gui-gnome/gui-channels.c Sat May 15 15:47:08 1999
++++ irssi-0.7.11-new/src/gui-gnome/gui-channels.c Sat Jun 12 17:51:30 1999
+@@ -41,7 +41,7 @@
+ GList *tmp;
+
+ label = gtk_notebook_get_tab_label(GTK_NOTEBOOK(WINDOW_GUI(window)->parent->notebook),
+- WINDOW_GUI(window)->window);
++ WINDOW_GUI(window)->windowset->window);
+ g_return_if_fail(label != NULL);
+
+ str = g_string_new(NULL);
+@@ -75,7 +75,7 @@
+ if (channel->type == CHANNEL_TYPE_EMPTY)
+ rec->servermenu = TRUE;
+ if (channel->type == CHANNEL_TYPE_CHANNEL && toggle_show_nicklist)
+- gtk_widget_show(WINDOW_GUI(window)->nickscrollbox);
++ gtk_widget_show(WINDOW_GUI(window)->windowset->nickscrollbox);
+
+ name = gui_channel_get_name(channel);
+
+@@ -182,7 +182,7 @@
+ /* create new window to use */
+ window = !toggle_use_tabbed_windows ? NULL :
+ cur_channel != NULL ? CHANNEL_PARENT(cur_channel) : NULL;
+- window = gui_window_create(window == NULL ? NULL : WINDOW_GUI(window)->parent);
++ window = gui_windowset_create(window == NULL ? NULL : WINDOW_GUI(window)->parent)->active->window;
+ }
+
+ gui_channel_init(window, channel);
+@@ -230,7 +230,7 @@
+ else
+ {
+ /* window is useless, destroy it. */
+- gui_window_destroy(window);
++ gui_window_view_destroy(WINDOW_GUI(window));
+ }
+ }
+ return TRUE;
+@@ -253,16 +253,16 @@
+ if (channel->topic == NULL || *channel->topic == '\0')
+ {
+ /* No topic in channel */
+- gtk_entry_set_text(GTK_ENTRY(WINDOW_GUI(window)->topicentry), "");
++ gtk_entry_set_text(GTK_ENTRY(WINDOW_GUI(window)->windowset->topicentry), "");
+ }
+ else
+ {
+- gtk_entry_set_text(GTK_ENTRY(WINDOW_GUI(window)->topicentry), channel->topic);
++ gtk_entry_set_text(GTK_ENTRY(WINDOW_GUI(window)->windowset->topicentry), channel->topic);
+ g_string_sprintfa(tmp, " - %s", channel->topic);
+ }
+ }
+
+- if (window == WINDOW_GUI(window)->parent->active)
++ if (window == WINDOW_GUI(window)->parent->active->active->window)
+ gtk_window_set_title(GTK_WINDOW(WINDOW_GUI(window)->parent->window), tmp->str);
+ g_string_free(tmp, TRUE);
+ return TRUE;
+@@ -276,7 +276,7 @@
+ g_return_if_fail(channel->server != NULL);
+
+ str = g_strconcat(channel->server->nick, " / ", channel->server->tag, NULL);
+- gtk_label_set(GTK_LABEL(WINDOW_GUI(CHANNEL_PARENT(channel))->serverlabel), str);
++ gtk_label_set(GTK_LABEL(WINDOW_GUI(CHANNEL_PARENT(channel))->windowset->serverlabel), str);
+ g_free(str);
+ }
+
+@@ -322,7 +322,7 @@
+ window = CHANNEL_PARENT(channel);
+ if (channel->type != CHANNEL_TYPE_CHANNEL || channel != window->active)
+ return TRUE;
+- gui = WINDOW_GUI(window);
++ gui = WINDOW_GUI(window)->windowset;
+
+ for (num = 0; num < 6; num++)
+ gtk_object_set_data(GTK_OBJECT(gui->modebuttons[num]), "toggling", GINT_TO_POINTER(TRUE));
+@@ -351,20 +351,21 @@
+
+ static gboolean signal_channel_open(CHANNEL_REC *channel)
+ {
+- WINDOW_REC *window;
++ GUI_WINDOW_REC *gui;
+
+ g_return_val_if_fail(channel != NULL, FALSE);
+
+- window = CHANNEL_PARENT(channel);
+- if (WINDOW_GUI(window)->parent->active != window)
++ gui = WINDOW_GUI(CHANNEL_PARENT(channel))->windowset;
++
++ if (gui->parent->active->active->window != CHANNEL_PARENT(channel))
+ {
+ /* change to right window tab */
+ gint page;
+
+- page = gtk_notebook_page_num(GTK_NOTEBOOK(WINDOW_GUI(window)->parent->notebook), WINDOW_GUI(window)->window);
+- gtk_notebook_set_page(GTK_NOTEBOOK(WINDOW_GUI(window)->parent->notebook), page);
++ page = gtk_notebook_page_num(GTK_NOTEBOOK(gui->parent->notebook), gui->window);
++ gtk_notebook_set_page(GTK_NOTEBOOK(gui->parent->notebook), page);
+ }
+- gdk_window_show(WINDOW_GUI(window)->parent->window->window);
++ gdk_window_show(gui->parent->window->window);
+
+ if (CHANNEL_PARENT(channel)->active != channel)
+ {
+diff -ru irssi-0.7.11/src/gui-gnome/gui-mainwindows.c irssi-0.7.11-new/src/gui-gnome/gui-mainwindows.c
+--- irssi-0.7.11/src/gui-gnome/gui-mainwindows.c Thu May 13 15:17:33 1999
++++ irssi-0.7.11-new/src/gui-gnome/gui-mainwindows.c Sat Jun 12 17:31:42 1999
+@@ -23,7 +23,7 @@
+
+ GList *mainwindows;
+
+-static WINDOW_REC *window_find_notebook_child(MAIN_WINDOW_REC *window, GtkWidget *child)
++static GUI_WINDOW_VIEW_REC *window_find_notebook_child(MAIN_WINDOW_REC *window, GtkWidget *child)
+ {
+ GList *tmp;
+
+@@ -32,9 +32,9 @@
+
+ for (tmp = g_list_first(window->children); tmp != NULL; tmp = tmp->next)
+ {
+- WINDOW_REC *rec = tmp->data;
++ GUI_WINDOW_VIEW_REC *rec = tmp->data;
+
+- if (WINDOW_GUI(rec)->window == child) return rec;
++ if (rec->windowset->window == child) return rec;
+ }
+
+ return NULL;
+@@ -57,9 +57,9 @@
+ {
+ g_return_val_if_fail(window != NULL, 0);
+
+- if (cur_channel != window->active->active)
++ if (cur_channel != window->active->active->window->active)
+ {
+- cur_channel = window->active->active;
++ cur_channel = window->active->active->window->active;
+ signal_emit("channel changed", 1, cur_channel);
+ signal_emit("window focused", 1, window->active);
+ }
+@@ -70,7 +70,7 @@
+ /* notebook signal: switch_page */
+ static void sig_switch_page(GtkWidget *notebook, GtkNotebookPage *child, guint pagenum, MAIN_WINDOW_REC *window)
+ {
+- WINDOW_REC *subwin;
++ GUI_WINDOW_VIEW_REC *subwin;
+
+ g_return_if_fail(child != NULL);
+ g_return_if_fail(window != NULL);
+@@ -84,10 +84,10 @@
+ return;
+ }
+
+- window->active = subwin;
+- cur_channel = subwin->active;
++ window->active->active = subwin;
++ cur_channel = subwin->window->active;
+ signal_emit("channel changed", 1, cur_channel);
+- signal_emit("window focused", 1, subwin);
++ signal_emit("window focused", 1, subwin->window);
+ }
+
+ static void window_change_page(WINDOW_REC *window)
+@@ -96,7 +96,7 @@
+
+ g_return_if_fail(window != NULL);
+
+- page = gtk_notebook_page_num(GTK_NOTEBOOK(WINDOW_GUI(window)->parent->notebook), WINDOW_GUI(window)->window);
++ page = gtk_notebook_page_num(GTK_NOTEBOOK(WINDOW_GUI(window)->parent->notebook), WINDOW_GUI(window)->windowset->window);
+ gtk_notebook_set_page(GTK_NOTEBOOK(WINDOW_GUI(window)->parent->notebook), page);
+ }
+
+@@ -105,15 +105,15 @@
+ /* signal: key pressed (in entry field) */
+ static gint sig_keypress(GtkWidget *widget, GdkEventKey *event, MAIN_WINDOW_REC *window)
+ {
+- GUI_WINDOW_REC *guiwin;
++ GUI_WINDOW_VIEW_REC *view;
+ gchar *text;
+
+ g_return_val_if_fail(event != NULL, 0);
+ g_return_val_if_fail(window != NULL, 0);
+
+- guiwin = window->active == NULL ? NULL : WINDOW_GUI(window->active);
+- if (guiwin != NULL && guiwin->topicentry != NULL && GTK_WIDGET_HAS_FOCUS(guiwin->topicentry) &&
+- gtk_object_get_data(GTK_OBJECT(guiwin->topicentry), "editable"))
++ view = window->active == NULL ? NULL : window->active->active ;
++ if (view != NULL && view->windowset->topicentry != NULL && GTK_WIDGET_HAS_FOCUS(view->windowset->topicentry) &&
++ gtk_object_get_data(GTK_OBJECT(view->windowset->topicentry), "editable"))
+ {
+ /* trying to write topic, don't disturb it.. */
+ return 0;
+@@ -143,11 +143,11 @@
+ gint val;
+
+ #ifdef HAVE_GNOME
+- if (guiwin->zvt)
+- adj = ZVT_TERM(guiwin->text)->adjustment;
++ if (view->zvt)
++ adj = ZVT_TERM(view->text)->adjustment;
+ else
+ #endif
+- adj = GTK_TEXT(guiwin->text)->vadj;
++ adj = GTK_TEXT(view->text)->vadj;
+ val = adj->value - (adj->page_size/2);
+ gtk_adjustment_set_value(adj, val > 0 ? val : 0);
+ }
+@@ -161,11 +161,11 @@
+ gint val, max;
+
+ #ifdef HAVE_GNOME
+- if (guiwin->zvt)
+- adj = ZVT_TERM(guiwin->text)->adjustment;
++ if (view->zvt)
++ adj = ZVT_TERM(view->text)->adjustment;
+ else
+ #endif
+- adj = GTK_TEXT(guiwin->text)->vadj;
++ adj = GTK_TEXT(view->text)->vadj;
+ val = adj->value + (adj->page_size/2);
+ max = adj->upper - adj->lower - adj->page_size;
+ gtk_adjustment_set_value(adj, val <= max ? val : max);
+@@ -179,7 +179,7 @@
+ gint pos;
+
+ pos = gtk_editable_get_position(GTK_EDITABLE(window->entry));
+- line = completion_line(window->active->active, gtk_entry_get_text(GTK_ENTRY(window->entry)), &pos);
++ line = completion_line(window->active->active->window->active, gtk_entry_get_text(GTK_ENTRY(window->entry)), &pos);
+ if (line != NULL)
+ {
+ gtk_entry_set_text(GTK_ENTRY(window->entry), line);
+@@ -271,14 +271,14 @@
+
+ ui_history_add(str, FALSE);
+
+- if (cur_channel != window->active->active)
++ if (cur_channel != window->active->active->window->active)
+ {
+ /* we get here at least when using click-to-focus and keyboard
+ focus being in different window than mouse. Is there some
+ event we could use instead of enter_notify_event to find out
+ what window really has the focus? .. probably is, I'm too lazy
+ to find out what it is .. */
+- cur_channel = window->active->active;
++ cur_channel = window->active->active->window->active;
+ signal_emit("channel changed", 1, cur_channel);
+ }
+ signal_emit("send command", 3, str, cur_channel->server, cur_channel);
+@@ -386,7 +403,7 @@
+
+ window->destroying = TRUE;
+ while (window->children != NULL)
+- gui_window_destroy(window->children->data);
++ gui_windowset_destroy(window->children->data);
+ window->destroying = FALSE;
+
+ gtk_widget_destroy(window->window);
+diff -ru irssi-0.7.11/src/gui-gnome/gui-mainwindows.h irssi-0.7.11-new/src/gui-gnome/gui-mainwindows.h
+--- irssi-0.7.11/src/gui-gnome/gui-mainwindows.h Sun Apr 11 23:40:07 1999
++++ irssi-0.7.11-new/src/gui-gnome/gui-mainwindows.h Sat Jun 12 17:23:49 1999
+@@ -1,6 +1,9 @@
+ #ifndef __GUI_MAINWINDOWS_H
+ #define __GUI_MAINWINDOWS_H
+
++typedef struct _GUI_WINDOW_REC GUI_WINDOW_REC;
++typedef struct _GUI_WINDOW_VIEW_REC GUI_WINDOW_VIEW_REC;
++
+ typedef struct
+ {
+ GtkWidget *window;
+@@ -17,7 +20,7 @@
+ guint destroying:1;
+
+ GList *children;
+- WINDOW_REC *active;
++ GUI_WINDOW_REC *active;
+ }
+ MAIN_WINDOW_REC;
+
+diff -ru irssi-0.7.11/src/gui-gnome/gui-printtext.c irssi-0.7.11-new/src/gui-gnome/gui-printtext.c
+--- irssi-0.7.11/src/gui-gnome/gui-printtext.c Sun Jun 6 12:28:08 1999
++++ irssi-0.7.11-new/src/gui-gnome/gui-printtext.c Mon Jun 7 18:44:44 1999
+@@ -51,7 +51,7 @@
+ /* Write text to ZVT window */
+ static gboolean gui_printtext_zvt(CHANNEL_REC *channel, gint fgcolor, gint bgcolor, gint flags, gchar *str)
+ {
+- GUI_WINDOW_REC *gui;
++ GUI_WINDOW_VIEW_REC *view;
+ WINDOW_REC *window;
+ gint fg, bg;
+ GString *out;
+@@ -59,7 +59,7 @@
+ g_return_val_if_fail(str != NULL, FALSE);
+
+ window = CHANNEL_PARENT(channel);
+- gui = WINDOW_GUI(window);
++ view = WINDOW_GUI(window);
+
+ if (flags & PRINTFLAG_BEEP)
+ gdk_beep();
+@@ -75,7 +75,7 @@
+ }
+
+ if (*str == '\n')
+- zvt_term_feed(ZVT_TERM(gui->text), "\r", 1);
++ zvt_term_feed(ZVT_TERM(view->text), "\r", 1);
+
+ out = g_string_new("\033[0;");
+
+@@ -87,8 +87,8 @@
+ g_string_sprintfa(out, "3%dm", ansitab[fg & 7]);
+
+ g_string_append(out, str);
+- zvt_term_feed(ZVT_TERM(gui->text), out->str, out->len);
+- vt_cursor_state(gui->text, 0); /* hide the ugly cursor */
++ zvt_term_feed(ZVT_TERM(view->text), out->str, out->len);
++ vt_cursor_state(view->text, 0); /* hide the ugly cursor */
+
+ g_string_free(out, TRUE);
+
+@@ -99,7 +99,7 @@
+ /* Write text to window */
+ static gboolean gui_printtext(CHANNEL_REC *channel, gpointer fgcolor, gpointer bgcolor, gpointer flags, gchar *str)
+ {
+- GUI_WINDOW_REC *gui;
++ GUI_WINDOW_VIEW_REC *view;
+ WINDOW_REC *window;
+ GdkColor *fg, *bg;
+ GdkFont *font;
+@@ -109,10 +109,10 @@
+ g_return_val_if_fail(str != NULL, FALSE);
+
+ window = CHANNEL_PARENT(channel);
+- gui = WINDOW_GUI(window);
++ view = WINDOW_GUI(window);
+
+ #ifdef HAVE_GNOME
+- if (gui->zvt)
++ if (view->zvt)
+ {
+ /* Use ZVT widget */
+ return gui_printtext_zvt(channel, GPOINTER_TO_INT(fgcolor),
+@@ -126,13 +126,13 @@
+ will happen.. (and this code even looks awful ...) */
+ if (*str == '\n')
+ {
+- gui->linepos = g_list_append(gui->linepos, GINT_TO_POINTER(gui->lastlinelen)+1);
+- gui->lastlinelen = 0;
++ view->linepos = g_list_append(view->linepos, GINT_TO_POINTER(view->lastlinelen)+1);
++ view->lastlinelen = 0;
+ }
+ else
+- gui->lastlinelen += strlen(str);
++ view->lastlinelen += strlen(str);
+
+- gtk_text_freeze(GTK_TEXT(gui->text));
++ gtk_text_freeze(GTK_TEXT(view->text));
+ if (*str == '\n' && max_textwidget_lines > 0 &&
+ max_textwidget_lines+block_remove_lines <= window->lines &&
+ channel->type != CHANNEL_TYPE_SETUP)
+@@ -143,15 +143,15 @@
+ {
+ GList *link;
+
+- link = g_list_first(gui->linepos);
++ link = g_list_first(view->linepos);
+ len += GPOINTER_TO_INT(link->data);
+- gui->linepos = g_list_remove_link(gui->linepos, link);
++ view->linepos = g_list_remove_link(view->linepos, link);
+ g_list_free_1(link);
+ window->lines--;
+ }
+- gtk_text_set_point(GTK_TEXT(gui->text), 0);
+- gtk_text_forward_delete(GTK_TEXT(gui->text), len);
+- gtk_text_set_point(GTK_TEXT(gui->text), gtk_text_get_length(GTK_TEXT(gui->text)));
++ gtk_text_set_point(GTK_TEXT(view->text), 0);
++ gtk_text_forward_delete(GTK_TEXT(view->text), len);
++ gtk_text_set_point(GTK_TEXT(view->text), gtk_text_get_length(GTK_TEXT(view->text)));
+ }
+
+ if (GPOINTER_TO_INT(flags) & PRINTFLAG_BOLD)
+@@ -178,8 +178,8 @@
+ fg = bg != NULL ? bg : &bg_color;
+ bg = tmp;
+ }
+- gtk_text_insert(GTK_TEXT(gui->text), font, fg, bg, str, -1);
+- gtk_text_thaw(GTK_TEXT(gui->text));
++ gtk_text_insert(GTK_TEXT(view->text), font, fg, bg, str, -1);
++ gtk_text_thaw(GTK_TEXT(view->text));
+
+ if (sb_down) set_sb_down(window);
+
+diff -ru irssi-0.7.11/src/gui-gnome/irssi.c irssi-0.7.11-new/src/gui-gnome/irssi.c
+--- irssi-0.7.11/src/gui-gnome/irssi.c Mon May 10 20:32:28 1999
++++ irssi-0.7.11-new/src/gui-gnome/irssi.c Mon Jun 7 19:06:20 1999
+@@ -38,7 +38,8 @@
+
+ gui_printtext_init();
+ mainwindows_init();
+- gui_windows_init();
++ gui_windowset_init();
++ gui_windows_view_init();
+ gui_channels_init();
+ gui_dcc_init();
+ gui_events_init();
+@@ -86,7 +87,8 @@
+ gui_events_deinit();
+ gui_server_deinit();
+ mainwindows_deinit();
+- gui_windows_deinit();
++ gui_windows_view_deinit();
++ gui_windowset_deinit();
+ gui_channels_deinit(); /* channels after mainwindows_deinit()! */
+ gui_printtext_deinit();
+ setup_deinit();
+diff -ru irssi-0.7.11/src/gui-gnome/irssi.h irssi-0.7.11-new/src/gui-gnome/irssi.h
+--- irssi-0.7.11/src/gui-gnome/irssi.h Mon May 10 20:24:46 1999
++++ irssi-0.7.11-new/src/gui-gnome/irssi.h Mon Jun 7 18:34:03 1999
+@@ -35,7 +35,8 @@
+ #include "setup.h"
+ #include "gui-mainwindows.h"
+ #include "gui-channels.h"
+-#include "gui-windows.h"
++#include "gui-windowset.h"
++#include "gui-windows-view.h"
+
+ #include "channels-newdata.h"
+ #include "dialogs.h"
+diff -ru irssi-0.7.11/src/gui-gnome/setup-appearance.c irssi-0.7.11-new/src/gui-gnome/setup-appearance.c
+--- irssi-0.7.11/src/gui-gnome/setup-appearance.c Sun Jun 6 20:10:05 1999
++++ irssi-0.7.11-new/src/gui-gnome/setup-appearance.c Mon Jun 7 19:07:22 1999
+@@ -49,16 +49,16 @@
+
+ static gchar *temp_font_name;
+
+-static void set_window_bg(GUI_WINDOW_REC *window)
++static void set_window_bg(GUI_WINDOW_VIEW_REC *view)
+ {
+ GtkStyle *style;
+
+- g_return_if_fail(window != NULL);
++ g_return_if_fail(view != NULL);
+
+- style = gtk_style_copy(window->text->style);
++ style = gtk_style_copy(view->text->style);
+ gtk_style_ref(style);
+ style->base[0] = temp_bg_color;
+- gtk_widget_set_style(window->text, style);
++ gtk_widget_set_style(view->text, style);
+ gtk_style_unref(style);
+
+ }
+@@ -71,14 +71,14 @@
+ static gboolean old_timestamps;
+ static gint oldlines, len;
+
+- GUI_WINDOW_REC *guiwin;
++ GUI_WINDOW_VIEW_REC *view;
+ WINDOW_REC *window;
+ gint n;
+
+ g_return_if_fail(channel != NULL);
+
+ window = CHANNEL_PARENT(channel);
+- guiwin = WINDOW_GUI(window);
++ view = WINDOW_GUI(window);
+
+ if (init)
+ {
+@@ -90,16 +90,16 @@
+ old_timestamps = toggle_show_timestamps;
+ toggle_show_timestamps = FALSE;
+
+- set_window_bg(guiwin);
++ set_window_bg(view);
+
+ gui_printtext_configure();
+
+- oldval = GTK_TEXT(guiwin->text)->vadj->value;
++ oldval = GTK_TEXT(view->text)->vadj->value;
+ oldlines = window->lines;
+- len = gtk_text_get_length(GTK_TEXT(guiwin->text));
++ len = gtk_text_get_length(GTK_TEXT(view->text));
+
+- gtk_text_freeze(GTK_TEXT(guiwin->text));
+- gtk_text_set_point(GTK_TEXT(guiwin->text), len);
++ gtk_text_freeze(GTK_TEXT(view->text));
++ gtk_text_set_point(GTK_TEXT(view->text), len);
+ }
+ else
+ {
+@@ -108,10 +108,10 @@
+ window->lines = oldlines;
+
+ /*FIXME: this doesn't remove the lines from linelen list*/
+- gtk_text_set_point(GTK_TEXT(guiwin->text), 0);
+- gtk_text_forward_delete(GTK_TEXT(guiwin->text), len);
+- gtk_text_thaw(GTK_TEXT(guiwin->text));
+- gtk_adjustment_set_value(GTK_TEXT(guiwin->text)->vadj, oldval);
++ gtk_text_set_point(GTK_TEXT(view->text), 0);
++ gtk_text_forward_delete(GTK_TEXT(view->text), len);
++ gtk_text_thaw(GTK_TEXT(view->text));
++ gtk_adjustment_set_value(GTK_TEXT(view->text)->vadj, oldval);
+
+ bg_color = old_bg_color;
+ memcpy(setup_colors, old_colors, sizeof(setup_colors));
+diff -ru irssi-0.7.11/src/gui-gnome/snapshot.c irssi-0.7.11-new/src/gui-gnome/snapshot.c
+--- irssi-0.7.11/src/gui-gnome/snapshot.c Thu May 13 16:03:54 1999
++++ irssi-0.7.11-new/src/gui-gnome/snapshot.c Mon Jun 7 19:08:17 1999
+@@ -24,25 +24,25 @@
+
+ static void snapshot_show(WINDOW_REC *window)
+ {
+- GUI_WINDOW_REC *gui;
++ GUI_WINDOW_VIEW_REC *view;
+ GtkWidget *scrollbox;
+ GtkAdjustment *adj;
+ gint x, y, xsize, ysize;
+
+ g_return_if_fail(window != NULL);
+
+- gui = WINDOW_GUI(window);
++ view = WINDOW_GUI(window);
+ gdk_window_get_pointer (NULL, &x, &y, NULL);
+
+- gui->snapshot = gtk_window_new(GTK_WINDOW_POPUP);
++ view->snapshot = gtk_window_new(GTK_WINDOW_POPUP);
+
+ scrollbox = gtk_scrolled_window_new(NULL, NULL);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollbox),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
+- gtk_container_add(GTK_CONTAINER(gui->snapshot), scrollbox);
++ gtk_container_add(GTK_CONTAINER(view->snapshot), scrollbox);
+
+- xsize = gui->text->allocation.width;
+- ysize = gui->text->allocation.height;
++ xsize = view->text->allocation.width;
++ ysize = view->text->allocation.height;
+
+ if (xsize <= 1) xsize = gdk_screen_width()/2;
+ if (ysize <= 1) ysize = gdk_screen_height()*2/5;
+@@ -58,18 +58,18 @@
+ else
+ y += 5;
+
+- gtk_widget_set_uposition(gui->snapshot, x, y);
++ gtk_widget_set_uposition(view->snapshot, x, y);
+
+- gtk_object_set_data(GTK_OBJECT(gui->text), "parent", gui->text->parent);
+- gtk_widget_reparent(gui->text, scrollbox);
+- gtk_widget_show_all(gui->snapshot);
++ gtk_object_set_data(GTK_OBJECT(view->text), "parent", view->text->parent);
++ gtk_widget_reparent(view->text, scrollbox);
++ gtk_widget_show_all(view->snapshot);
+
+ #ifdef HAVE_GNOME
+- if (gui->zvt)
+- adj = ZVT_TERM(gui->text)->adjustment;
++ if (view->zvt)
++ adj = ZVT_TERM(view->text)->adjustment;
+ else
+ #endif
+- adj = GTK_TEXT(gui->text)->vadj;
++ adj = GTK_TEXT(view->text)->vadj;
+ gtk_adjustment_set_value(adj, adj->upper - adj->lower - adj->page_size);
+
+ signal_emit("window focused", 1, window);
+@@ -77,18 +77,18 @@
+
+ static void snapshot_hide(WINDOW_REC *window)
+ {
+- GUI_WINDOW_REC *gui;
++ GUI_WINDOW_VIEW_REC *view;
+ GtkWidget *parent;
+
+ g_return_if_fail(window != NULL);
+
+- gui = WINDOW_GUI(window);
+- parent = gtk_object_get_data(GTK_OBJECT(gui->text), "parent");
++ view = WINDOW_GUI(window);
++ parent = gtk_object_get_data(GTK_OBJECT(view->text), "parent");
+ g_return_if_fail(parent != NULL);
+
+- gtk_widget_reparent(gui->text, parent);
+- gtk_widget_destroy(gui->snapshot);
+- gui->snapshot = NULL;
++ gtk_widget_reparent(view->text, parent);
++ gtk_widget_destroy(view->snapshot);
++ view->snapshot = NULL;
+
+ signal_emit("window focused", 1, ((MAIN_WINDOW_REC *) mainwindows->data)->active);
+ }
+diff -ru irssi-0.7.11/src/gui-gnome/window-menus.c irssi-0.7.11-new/src/gui-gnome/window-menus.c
+--- irssi-0.7.11/src/gui-gnome/window-menus.c Sat May 15 22:08:20 1999
++++ irssi-0.7.11-new/src/gui-gnome/window-menus.c Sat Jun 12 17:34:53 1999
+@@ -280,7 +280,7 @@
+ window = gtk_object_get_data(GTK_OBJECT(menuitem->parent), "window");
+ g_return_if_fail(window != NULL);
+
+- window->active->active->server = server;
++ window->active->active->window->active->server = server;
+ signal_emit("window server changed", 1, window->active);
+ }
+
+@@ -330,7 +330,7 @@
+ gtk_menu_append(GTK_MENU(menu), menuitem);
+
+ if (window->active != NULL)
+- gtk_option_menu_set_history(GTK_OPTION_MENU(window->servermenu), g_list_index(servers, window->active->active->server));
++ gtk_option_menu_set_history(GTK_OPTION_MENU(window->servermenu), g_list_index(servers, window->active->active->window->active->server));
+ }
+
+ return TRUE;
+@@ -381,19 +381,19 @@
+
+ static void menu_chan_toggle_nicklist(GtkWidget *menuitem, CHANNEL_REC *channel)
+ {
+- GUI_WINDOW_REC *window;
++ GtkWidget *nickscrollbox;
+
+ g_return_if_fail(menuitem != NULL);
+ if (channel == NULL) return;
+
+- window = WINDOW_GUI(CHANNEL_PARENT(channel));
+- if (window->nickscrollbox == NULL)
++ nickscrollbox = WINDOW_GUI(CHANNEL_PARENT(channel))->windowset->nickscrollbox;
++ if (nickscrollbox == NULL)
+ return; /* this function was called from window_create().. */
+
+ if (GTK_CHECK_MENU_ITEM(menuitem)->active)
+- gtk_widget_show(window->nickscrollbox);
++ gtk_widget_show(nickscrollbox);
+ else
+- gtk_widget_hide(window->nickscrollbox);
++ gtk_widget_hide(nickscrollbox);
+ }
+
+ static void menu_query_close(GtkWidget *menuitem, CHANNEL_REC *channel)
+@@ -433,7 +433,7 @@
+ toggling = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(menuitem), "toggling"));
+ if (toggling) return;
+
+- server = window->active->active->server;
++ server = window->active->active->window->active->server;
+ gtk_object_set_data(GTK_OBJECT(menuitem), "toggling", GINT_TO_POINTER(TRUE));
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem),
+ server == NULL ? FALSE : server->usermode_away);
+@@ -478,9 +478,9 @@
+ g_return_if_fail(menuitem != NULL);
+ if (window == NULL) return;
+
+- server = window->active->active->server;
++ server = window->active->active->window->active->server;
+ usermode_set(menuitem, 'i', server == NULL ? FALSE :
+- server->usermode_invisible, window->active->active);
++ server->usermode_invisible, window->active->active->window->active);
+ }
+
+ static void menu_usermode_wallops(GtkWidget *menuitem, MAIN_WINDOW_REC *window)
+@@ -490,9 +490,9 @@
+ g_return_if_fail(menuitem != NULL);
+ if (window == NULL) return;
+
+- server = window->active->active->server;
++ server = window->active->active->window->active->server;
+ usermode_set(menuitem, 'w', server == NULL ? FALSE :
+- server->usermode_wallops, window->active->active);
++ server->usermode_wallops, window->active->active->window->active);
+ }
+
+ static void menu_usermode_snotes(GtkWidget *menuitem, MAIN_WINDOW_REC *window)
+@@ -502,19 +502,19 @@
+ g_return_if_fail(menuitem != NULL);
+ if (window == NULL) return;
+
+- server = window->active->active->server;
++ server = window->active->active->window->active->server;
+ usermode_set(menuitem, 's', server == NULL ? FALSE :
+- server->usermode_servernotes, window->active->active);
++ server->usermode_servernotes, window->active->active->window->active);
+ }
+
+ static void menu_dcc_chat(GtkWidget *menuitem, MAIN_WINDOW_REC *window)
+ {
+- gui_dcc_chat(window->active->active != NULL ? window->active->active->server : window->active->active->server);
++ gui_dcc_chat(window->active->active != NULL ? window->active->active->window->active->server : window->active->active->window->active->server);
+ }
+
+ static void menu_dcc_send(GtkWidget *menuitem, MAIN_WINDOW_REC *window)
+ {
+- gui_dcc_send(window->active->active != NULL ? window->active->active->server : window->active->active->server, NULL, NULL);
++ gui_dcc_send(window->active->active != NULL ? window->active->active->window->active->server : window->active->active->window->active->server, NULL, NULL);
+ }
+
+ static void menu_window_new(GtkWidget *menuitem, MAIN_WINDOW_REC *window)
+@@ -526,7 +526,7 @@
+
+ old = toggle_use_tabbed_windows;
+ toggle_use_tabbed_windows = FALSE;
+- channel_create(window->active->active->server, _("(empty)"), CHANNEL_TYPE_EMPTY);
++ channel_create(window->active->active->window->active->server, _("(empty)"), CHANNEL_TYPE_EMPTY);
+ toggle_use_tabbed_windows = old;
+ }
+
+@@ -539,7 +539,7 @@
+
+ old = toggle_use_tabbed_windows;
+ toggle_use_tabbed_windows = TRUE;
+- channel_create(window->active->active->server, _("(empty)"), CHANNEL_TYPE_EMPTY);
++ channel_create(window->active->active->window->active->server, _("(empty)"), CHANNEL_TYPE_EMPTY);
+ toggle_use_tabbed_windows = old;
+ }
+
+@@ -554,7 +554,7 @@
+ toggling = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(menuitem), "toggling"));
+ if (toggling) return;
+
+- gui = CHANNEL_GUI(window->active->active);
++ gui = CHANNEL_GUI(window->active->active->window->active);
+ gui->autoraise = GTK_CHECK_MENU_ITEM(menuitem)->active; /* FIXME: better way for this? gtk needs a function for this.. */
+
+ gtk_object_set_data(GTK_OBJECT(menuitem), "toggling", GINT_TO_POINTER(TRUE));
+@@ -567,7 +567,7 @@
+ g_return_if_fail(menuitem != NULL);
+ if (window == NULL) return;
+
+- gui_window_destroy(window->active);
++ gui_windowset_destroy(window->active);
+ }
+
+ static void menu_settings_preferences(void)
+@@ -657,7 +657,7 @@
+ switch (channel->type)
+ {
+ case CHANNEL_TYPE_CHANNEL:
+- gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(channel_submenu[2].widget), GTK_WIDGET_VISIBLE(WINDOW_GUI(CHANNEL_PARENT(channel))->nickscrollbox));
++ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(channel_submenu[2].widget), GTK_WIDGET_VISIBLE(WINDOW_GUI(CHANNEL_PARENT(channel))->windowset->nickscrollbox));
+ break;
+
+ case CHANNEL_TYPE_QUERY:
+Only in irssi-0.7.11-new/src/gui-gnome: window-menus.o
+diff -ru irssi-0.7.11/src/gui-gnome/window-nicklist.c irssi-0.7.11-new/src/gui-gnome/window-nicklist.c
+--- irssi-0.7.11/src/gui-gnome/window-nicklist.c Thu May 13 15:15:09 1999
++++ irssi-0.7.11-new/src/gui-gnome/window-nicklist.c Mon Jun 7 19:11:02 1999
+@@ -93,7 +93,7 @@
+ g_return_if_fail(nick != NULL);
+
+ if (CHANNEL_PARENT(channel)->active != channel) return;
+- gui = WINDOW_GUI(CHANNEL_PARENT(channel));
++ gui = WINDOW_GUI(CHANNEL_PARENT(channel))->windowset;
+
+ list = GTK_CLIST(gui->nicklist)->row_list;
+ for (row = 0; list != NULL; row++, list = list->next)
+@@ -130,9 +130,9 @@
+ window = CHANNEL_PARENT(channel);
+ if (window->active != channel) return;
+
+- row = gtk_clist_find_row_from_data(GTK_CLIST(WINDOW_GUI(window)->nicklist), nick);
++ row = gtk_clist_find_row_from_data(GTK_CLIST(WINDOW_GUI(window)->windowset->nicklist), nick);
+ if (row != -1)
+- gtk_clist_remove(GTK_CLIST(WINDOW_GUI(window)->nicklist), row);
++ gtk_clist_remove(GTK_CLIST(WINDOW_GUI(window)->windowset->nicklist), row);
+ }
+
+ void window_nicklist_redraw(CHANNEL_REC *channel)
+@@ -141,7 +141,7 @@
+ GList *tmp;
+
+ if (CHANNEL_PARENT(channel)->active != channel) return;
+- gui = WINDOW_GUI(CHANNEL_PARENT(channel));
++ gui = WINDOW_GUI(CHANNEL_PARENT(channel))->windowset;
+
+ gtk_clist_freeze(GTK_CLIST(gui->nicklist));
+ gtk_clist_clear(GTK_CLIST(gui->nicklist));
+@@ -443,7 +443,7 @@
+ g_return_val_if_fail(window != NULL, FALSE);
+
+ /* create op and voice pixmaps */
+- gui = WINDOW_GUI(window);
++ gui = WINDOW_GUI(window)->windowset;
+ gtk_widget_realize(gui->window);
+ gui->op_pixmap = gdk_pixmap_create_from_xpm_d(gui->window->window, &gui->op_mask, NULL, op_xpm);
+ gui->voice_pixmap = gdk_pixmap_create_from_xpm_d(gui->window->window, &gui->voice_mask, NULL, voice_xpm);
+@@ -477,7 +477,7 @@
+
+ chanrec = channel_find(server, channel);
+ if (chanrec != NULL && !server->names_coming)
+- gtk_clist_freeze(GTK_CLIST(WINDOW_GUI(CHANNEL_PARENT(chanrec))->nicklist));
++ gtk_clist_freeze(GTK_CLIST(WINDOW_GUI(CHANNEL_PARENT(chanrec))->windowset->nicklist));
+
+ g_free(params);
+ return TRUE;
+@@ -494,7 +494,7 @@
+
+ chanrec = channel_find(server, channel);
+ if (chanrec != NULL)
+- gtk_clist_thaw(GTK_CLIST(WINDOW_GUI(CHANNEL_PARENT(chanrec))->nicklist));
++ gtk_clist_thaw(GTK_CLIST(WINDOW_GUI(CHANNEL_PARENT(chanrec))->windowset->nicklist));
+
+ g_free(params);
+ return TRUE;
+diff -Nru irssi-0.7.11/src/gui-gnome/gui-windowset.c irssi-0.7.11-new/src/gui-gnome/gui-windowset.c
+--- irssi-0.7.11/src/gui-gnome/gui-windowset.c Thu Jan 1 02:00:00 1970
++++ irssi-0.7.11-new/src/gui-gnome/gui-windowset.c Sat Jun 12 17:39:10 1999
+@@ -0,0 +1,385 @@
++/*
++ gui-windowset.c : irssi
++
++ Copyright (C) 1999 Timo Sirainen
++
++ 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 "irssi.h"
++
++static gchar mode_flags[] = "spmint";
++static gchar *mode_tooltips[] =
++{
++ N_("Secret"),
++ N_("Private"),
++ N_("Moderated"),
++ N_("Joining needs an invitation"),
++ N_("No external messages"),
++ N_("Only operators can change the topic")
++};
++
++static gint sig_topicentry_press(GtkWidget *entry, GdkEventButton *event)
++{
++ gboolean editable;
++
++ g_return_val_if_fail(entry != NULL, 0);
++ g_return_val_if_fail(event != NULL, 0);
++
++ if (event->type == GDK_2BUTTON_PRESS)
++ {
++ editable = !(gboolean) GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(entry), "editable"));
++ gtk_object_set_data(GTK_OBJECT(entry), "editable", GINT_TO_POINTER((gint) editable));
++ gtk_entry_set_editable(GTK_ENTRY(entry), editable);
++ }
++
++ return 0;
++}
++
++static void sig_topicentry_activated(GtkWidget *entry, WINDOW_REC *window)
++{
++ CHANNEL_REC *channel;
++
++ g_return_if_fail(entry != NULL);
++ g_return_if_fail(window != NULL);
++
++ channel = window->active;
++ if (channel == NULL || (!channel->chanop && channel->mode_optopic))
++ {
++ /* can't change topic. */
++ gtk_entry_set_text(GTK_ENTRY(entry),
++ (channel == NULL || channel->topic == NULL) ?
++ "" : channel->topic);
++ return;
++ }
++
++ signal_emit("command topic", 3, gtk_entry_get_text(GTK_ENTRY(entry)),
++ window->active->server, window->active);
++}
++
++static void sig_modebutton_toggled(GtkToggleButton *button, gint mode)
++{
++ WINDOW_REC *window;
++ NICK_REC *nick;
++ GString *str;
++
++ g_return_if_fail(button != NULL);
++ if (gtk_object_get_data(GTK_OBJECT(button), "toggling")) return;
++
++ window = gtk_object_get_data(GTK_OBJECT(button), "window");
++ g_return_if_fail(window->active != NULL);
++
++ nick = nicklist_find(window->active, window->active->server->nick);
++ if (!window->active->chanop)
++ {
++ /* can't change mode */
++ gtk_object_set_data(GTK_OBJECT(button), "toggling", GINT_TO_POINTER(TRUE));
++ gtk_toggle_button_set_active(button, !button->active);
++ gtk_object_set_data(GTK_OBJECT(button), "toggling", GINT_TO_POINTER(FALSE));
++ return;
++ }
++
++ str = g_string_new(NULL);
++ g_string_sprintf(str, "* %c%c", button->active ? '+' : '-', mode_flags[mode]);
++
++ gtk_object_set_data(GTK_OBJECT(button), "toggling", GINT_TO_POINTER(TRUE));
++ signal_emit("command mode", 3, str->str, window->active->server, window->active);
++ g_string_free(str, TRUE);
++ gtk_object_set_data(GTK_OBJECT(button), "toggling", GINT_TO_POINTER(FALSE));
++}
++
++GUI_WINDOW_REC *gui_windowset_create(MAIN_WINDOW_REC *parent)
++{
++ WINDOW_REC *rec;
++ GUI_WINDOW_REC *gui;
++ GUI_WINDOW_VIEW_REC *view;
++ GtkWidget *hbox, *label;
++ GtkTooltips *tooltips;
++ gint num;
++
++ if (parent == NULL) parent = mainwindow_create();
++
++ rec = ui_window_create();
++ g_return_val_if_fail(rec != NULL, NULL);
++
++ gui = g_new0(GUI_WINDOW_REC, 1);
++ gui->parent = parent;
++
++ if (parent->children == NULL) parent->active = gui;
++ parent->children = g_list_append(parent->children, gui);
++
++ gui->window = gtk_vbox_new(FALSE, 2);
++ gtk_container_border_width(GTK_CONTAINER(gui->window), 2);
++
++ /* Add channel topic and modes */
++ gui->channelwidget = gtk_hbox_new(FALSE, 0);
++ gtk_box_pack_start(GTK_BOX(gui->window), gui->channelwidget, FALSE, FALSE, 0);
++
++ gui->serverlabel = gtk_label_new("");
++ gtk_box_pack_start(GTK_BOX(gui->channelwidget), gui->serverlabel, FALSE, FALSE, 0);
++
++ gui->topicentry = gtk_entry_new();
++ gtk_entry_set_editable(GTK_ENTRY(gui->topicentry), FALSE);
++ gtk_signal_connect(GTK_OBJECT(gui->topicentry), "button_press_event",
++ GTK_SIGNAL_FUNC(sig_topicentry_press), rec);
++ gtk_signal_connect(GTK_OBJECT(gui->topicentry), "activate",
++ GTK_SIGNAL_FUNC(sig_topicentry_activated), rec);
++ gtk_box_pack_start(GTK_BOX(gui->channelwidget), gui->topicentry, TRUE, TRUE, 3);
++
++ tooltips = gtk_tooltips_new();
++
++ for (num = 0; num < 6; num++)
++ {
++ gchar str[2];
++
++ str[0] = toupper(mode_flags[num]); str[1] = '\0';
++ gui->modebuttons[num] = gtk_toggle_button_new_with_label(str);
++ gtk_tooltips_set_tip(tooltips, gui->modebuttons[num], mode_tooltips[num], NULL);
++ gtk_widget_set_usize(gui->modebuttons[num], 20, -1);
++ gtk_object_set_data(GTK_OBJECT(gui->modebuttons[num]), "window", rec);
++ gtk_signal_connect(GTK_OBJECT(gui->modebuttons[num]), "toggled",
++ GTK_SIGNAL_FUNC(sig_modebutton_toggled), GINT_TO_POINTER(num));
++ gtk_box_pack_start(GTK_BOX(gui->channelwidget), gui->modebuttons[num], FALSE, FALSE, 0);
++ }
++
++ /* create view for window */
++ hbox = gtk_hbox_new(FALSE, 3);
++ gtk_box_pack_start(GTK_BOX(gui->window), hbox, TRUE, TRUE, 0);
++
++ view = gui_window_view_create(rec, gui, hbox);
++ gui->active = view;
++
++ gtk_widget_show_all(gui->window);
++
++ /* Add nick list */
++ gui->nickscrollbox = gtk_scrolled_window_new(NULL, NULL);
++ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(gui->nickscrollbox),
++ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
++ gtk_box_pack_start(GTK_BOX(hbox), gui->nickscrollbox, FALSE, FALSE, 0);
++
++ gui->nicklist = gtk_clist_new(1);
++ gtk_container_add(GTK_CONTAINER(gui->nickscrollbox), gui->nicklist);
++ gtk_widget_show(gui->nicklist);
++
++ gtk_widget_set_usize(gui->nickscrollbox, 120, -1);
++
++ label = gtk_label_new(_("(none)"));
++ gtk_widget_show(label);
++
++ if (g_list_first(parent->children)->next == NULL)
++ {
++ /* only one child, don't show the notebook tabs.. */
++ gtk_notebook_set_show_tabs(GTK_NOTEBOOK(parent->notebook), FALSE);
++ gtk_notebook_set_show_border(GTK_NOTEBOOK(parent->notebook), FALSE);
++ }
++ else if (g_list_first(parent->children)->next->next == NULL)
++ {
++ /* two children, show the notebook tabs.. */
++ gtk_notebook_set_show_tabs(GTK_NOTEBOOK(parent->notebook), TRUE);
++ gtk_notebook_set_show_border(GTK_NOTEBOOK(parent->notebook), TRUE);
++ }
++
++ gtk_notebook_append_page(GTK_NOTEBOOK(parent->notebook), gui->window, label);
++
++ gtk_widget_hide(gui->channelwidget);
++
++ signal_emit("gui window created", 1, rec);
++ return gui;
++}
++
++void gui_windowset_destroy(GUI_WINDOW_REC *window)
++{
++ MAIN_WINDOW_REC *parent;
++ gint page;
++
++ g_return_if_fail(window != NULL);
++
++ if (window->destroying) return;
++
++ parent = window->parent;
++ parent->children = g_list_remove(parent->children, window);
++
++ signal_emit("gui window destroyed", 1, window);
++
++ window->destroying = TRUE;
++
++ page = gtk_notebook_page_num(GTK_NOTEBOOK(parent->notebook), window->window);
++ gtk_notebook_remove_page(GTK_NOTEBOOK(parent->notebook), page);
++
++ while (window->views != NULL)
++ gui_window_view_destroy(window->views->data);
++
++ g_free(window);
++
++ if (parent->children == NULL)
++ mainwindow_destroy(parent);
++ else if (g_list_length(parent->children) == 1)
++ {
++ /* only one child left, hide the notebook tabs.. */
++ gtk_notebook_set_show_tabs(GTK_NOTEBOOK(parent->notebook), FALSE);
++ gtk_notebook_set_show_border(GTK_NOTEBOOK(parent->notebook), FALSE);
++ }
++}
++
++static gboolean gui_window_server_changed(WINDOW_REC *window)
++{
++ MAIN_WINDOW_REC *parent;
++ SERVER_REC *server;
++ gint num;
++
++ g_return_val_if_fail(window != NULL, FALSE);
++
++ parent = WINDOW_GUI(window)->parent;
++ server = window->active->server;
++
++ if (parent->usermodes[0] == NULL) return TRUE;
++
++ for (num = 0; num < 4; num++)
++ gtk_object_set_data(GTK_OBJECT(parent->usermodes[num]), "toggling", GINT_TO_POINTER(TRUE));
++
++ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(parent->usermodes[0]),
++ server == NULL ? FALSE : server->usermode_away);
++ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(parent->usermodes[1]),
++ server == NULL ? FALSE : server->usermode_invisible);
++ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(parent->usermodes[2]),
++ server == NULL ? FALSE : server->usermode_wallops);
++ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(parent->usermodes[3]),
++ server == NULL ? FALSE : server->usermode_servernotes);
++
++ for (num = 0; num < 4; num++)
++ gtk_object_set_data(GTK_OBJECT(parent->usermodes[num]), "toggling", GINT_TO_POINTER(FALSE));
++
++ return TRUE;
++}
++
++static gboolean gui_windows_usermode_changed(SERVER_REC *server)
++{
++ GList *winlist;
++
++ for (winlist = g_list_first(mainwindows); winlist != NULL; winlist = winlist->next)
++ {
++ MAIN_WINDOW_REC *rec = winlist->data;
++
++ if (server == rec->active->active->window->active->server)
++ signal_emit("window server changed", 1, rec->active);
++ }
++
++ return TRUE;
++}
++
++static gboolean signal_window_focused(WINDOW_REC *window)
++{
++ MAIN_WINDOW_REC *mainwindow;
++ GUI_WINDOW_REC *gui;
++ CHANNEL_REC *channel;
++
++ g_return_val_if_fail(window != NULL, FALSE);
++
++ mainwindow = WINDOW_GUI(window)->parent;
++ channel = window->active;
++
++ gui = mainwindow->active;
++
++ /* remove old extra menus */
++ if (mainwindow->extramenu != NULL)
++ {
++ window_menus_remove(mainwindow, mainwindow->extramenu);
++ g_free(mainwindow->extramenu);
++ mainwindow->extramenu = NULL;
++ }
++ if (channel == NULL) return TRUE;
++
++ if (channel->type == CHANNEL_TYPE_CHANNEL)
++ {
++ /* Add channel menu */
++ mainwindow->extramenu = g_strdup(channel_menu[0].label);
++ window_menus_insert(mainwindow, NULL, channel_menu, channel);
++ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(channel_submenu[2].widget),
++ GTK_WIDGET_VISIBLE(gui->nickscrollbox));
++ gtk_widget_show(gui->channelwidget);
++ }
++ else
++ {
++ gtk_widget_hide(gui->nickscrollbox);
++ gtk_widget_hide(gui->channelwidget);
++ if (channel->type == CHANNEL_TYPE_QUERY)
++ {
++ /* Add query menu */
++ mainwindow->extramenu = g_strdup(query_menu[0].label);
++ window_menus_insert(mainwindow, NULL, query_menu, channel);
++ }
++ }
++
++ if (CHANNEL_GUI(channel)->servermenu)
++ {
++ /* change server selection */
++ gtk_option_menu_set_history(GTK_OPTION_MENU(mainwindow->servermenu),
++ g_list_index(servers, channel->server));
++ gtk_widget_show(mainwindow->servermenu);
++ }
++ else
++ gtk_widget_hide(mainwindow->servermenu);
++
++ /* draw title bar */
++ signal_emit("channel topic changed", 1, window->active);
++
++ return TRUE;
++}
++
++static gboolean gui_server_looking(SERVER_REC *server)
++{
++ GList *tmp, *sub;
++
++ g_return_val_if_fail(server != NULL, FALSE);
++
++ /* try to keep some server assigned to server menus.. */
++ for (tmp = g_list_first(windows); tmp != NULL; tmp = tmp->next)
++ {
++ WINDOW_REC *win = tmp->data;
++ gboolean changed;
++
++ changed = FALSE;
++ for (sub = g_list_first(win->channels); sub != NULL; sub = sub->next)
++ {
++ CHANNEL_REC *chan = sub->data;
++
++ if (chan->server == NULL)
++ {
++ chan->server = server;
++ if (!changed)
++ signal_emit("window server changed", 1, win);
++ changed = TRUE;
++ }
++ }
++ }
++
++ return TRUE;
++}
++
++void gui_windowset_init(void)
++{
++ signal_add("user mode changed", (SIGNAL_FUNC) gui_windows_usermode_changed);
++ signal_add("window server changed", (SIGNAL_FUNC) gui_window_server_changed);
++ signal_add("window focused", (SIGNAL_FUNC) signal_window_focused);
++ signal_add("server looking", (SIGNAL_FUNC) gui_server_looking);
++}
++
++void gui_windowset_deinit(void)
++{
++ signal_remove("user mode changed", (SIGNAL_FUNC) gui_windows_usermode_changed);
++ signal_remove("window server changed", (SIGNAL_FUNC) gui_window_server_changed);
++ signal_remove("window focused", (SIGNAL_FUNC) signal_window_focused);
++ signal_remove("server looking", (SIGNAL_FUNC) gui_server_looking);
++}
+diff -Nru irssi-0.7.11/src/gui-gnome/gui-windowset.h irssi-0.7.11-new/src/gui-gnome/gui-windowset.h
+--- irssi-0.7.11/src/gui-gnome/gui-windowset.h Thu Jan 1 02:00:00 1970
++++ irssi-0.7.11-new/src/gui-gnome/gui-windowset.h Sat Jun 12 17:22:55 1999
+@@ -0,0 +1,32 @@
++#ifndef __GUI_WINDOWSET_H
++#define __GUI_WINDOWSET_H
++
++struct _GUI_WINDOW_REC
++{
++ MAIN_WINDOW_REC *parent;
++
++ GtkWidget *window;
++ GList *views;
++ GUI_WINDOW_VIEW_REC *active;
++
++ GtkWidget *channelwidget;
++ GtkWidget *serverlabel;
++ GtkWidget *topicentry;
++ GtkWidget *modebuttons[6];
++
++ /* nicklist */
++ GtkWidget *nickscrollbox;
++ GtkWidget *nicklist;
++ GdkPixmap *op_pixmap, *voice_pixmap;
++ GdkBitmap *op_mask, *voice_mask;
++
++ gboolean destroying;
++};
++
++void gui_windowset_init(void);
++void gui_windowset_deinit(void);
++
++GUI_WINDOW_REC *gui_windowset_create(MAIN_WINDOW_REC *parent);
++void gui_windowset_destroy(GUI_WINDOW_REC *window);
++
++#endif
+diff -Nru irssi-0.7.11/src/gui-gnome/gui-windows-view.c irssi-0.7.11-new/src/gui-gnome/gui-windows-view.c
+--- irssi-0.7.11/src/gui-gnome/gui-windows-view.c Thu Jan 1 02:00:00 1970
++++ irssi-0.7.11-new/src/gui-gnome/gui-windows-view.c Sat Jun 12 17:16:29 1999
+@@ -0,0 +1,454 @@
++/*
++ gui-windows-view.c : irssi
++
++ Copyright (C) 1999 Timo Sirainen
++
++ 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 "irssi.h"
++
++#define iswordcut(a) (isspace((gint) a) || \
++ (a) == '\n' || (a) == '\0' || (a) == '"' || \
++ (a) == '(' || (a) == ')' || (a) == '[' || (a) == ']' || \
++ (a) == '<' || (a) == '>')
++
++#define URL_MAX_LENGTH 200 /*FIXME: no max. limits*/
++
++GList *window_views;
++
++void gui_window_view_set_background_pixmap(GUI_WINDOW_VIEW_REC *view, gchar *path)
++{
++ GtkStyle *style;
++ GdkPixmap *pixmap;
++ GdkBitmap *mask;
++#if defined (HAVE_IMLIB) || defined (HAVE_GNOME)
++ GdkImlibImage *img;
++#endif
++
++ g_return_if_fail(view != NULL);
++ g_return_if_fail(path != NULL);
++
++ if (view->pixmap != NULL && strcmp(view->pixmap, path) == 0)
++ {
++ /* same pixmap already set for this view.. */
++ return;
++ }
++ if (view->pixmap != NULL)
++ g_free(view->pixmap);
++ view->pixmap = g_strdup(path);
++
++#ifdef HAVE_GNOME
++ if (view->zvt)
++ {
++ zvt_term_set_background(ZVT_TERM(view->text), path, FALSE, FALSE);
++ return;
++ }
++#endif
++
++ if (*path == '\0')
++ pixmap = NULL;
++ else
++ {
++#if defined (HAVE_IMLIB) || defined (HAVE_GNOME)
++ mask = NULL;
++ img = gdk_imlib_load_image(path);
++ if (img == NULL)
++ pixmap = NULL;
++ else
++ {
++ gdk_imlib_render(img, img->rgb_width, img->rgb_height);
++ pixmap = gdk_imlib_move_image(img);
++ gdk_imlib_destroy_image(img);
++ }
++#else
++ pixmap = gdk_pixmap_create_from_xpm(view->text->window, &mask, NULL, path);
++#endif
++ }
++
++ style = gtk_style_copy(view->text->style);
++ gtk_style_ref(style);
++ style->bg_pixmap[GTK_STATE_NORMAL] = pixmap;
++ gtk_widget_set_style(view->text, style);
++ gtk_style_unref(style);
++}
++
++static void gui_window_view_set_background(GUI_WINDOW_VIEW_REC *view)
++{
++ GtkStyle *style;
++ gchar *path;
++
++ g_return_if_fail(view != NULL);
++
++#ifdef HAVE_GNOME
++ if (view->zvt)
++ {
++ if (toggle_use_transparency)
++ {
++ zvt_term_set_background(ZVT_TERM(view->text), 0, TRUE, toggle_shaded_transparency);
++ if (view->pixmap != NULL)
++ {
++ g_free(view->pixmap);
++ view->pixmap = NULL;
++ }
++ return;
++ }
++ }
++ else
++#endif
++ {
++ style = gtk_style_copy(view->text->style);
++ gtk_style_ref(style);
++ style->base[GTK_STATE_NORMAL] = bg_color;;
++ gtk_widget_set_style(view->text, style);
++ gtk_style_unref(style);
++ }
++
++ path = convert_home(background_pixmap);
++ gui_window_view_set_background_pixmap(view, path);
++ g_free(path);
++}
++
++static void init_colors(GtkWidget *window)
++{
++ gint n;
++
++ g_return_if_fail(window != NULL);
++
++ for (n = 0; n < sizeof(setup_colors)/sizeof(setup_colors[0]); n++)
++ {
++ setup_colors[n].pixel =
++ (gulong)((setup_colors[n].red & 0xff00)*256 +
++ (setup_colors[n].green & 0xff00) +
++ (setup_colors[n].blue & 0xff00)/256);
++ gdk_color_alloc(gtk_widget_get_colormap(window), &setup_colors[n]);
++ }
++
++ bg_color.pixel =
++ (gulong)((bg_color.red & 0xff00)*256 +
++ (bg_color.green & 0xff00) +
++ (bg_color.blue & 0xff00)/256);
++ gdk_color_alloc(gtk_widget_get_colormap(window), &bg_color);
++}
++
++#ifdef HAVE_GNOME
++static void init_zvt_colors(ZvtTerm *zvt)
++{
++ static gchar ansitab[16] = { 0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15 };
++ gushort zvt_red[18], zvt_green[18], zvt_blue[18];
++ gint num;
++
++ for (num = 0; num < 16; num++)
++ {
++ zvt_red[num] = (gushort) setup_colors[(gint) ansitab[num]].red;
++ zvt_green[num] = (gushort) setup_colors[(gint) ansitab[num]].green;
++ zvt_blue[num] = (gushort) setup_colors[(gint) ansitab[num]].blue;
++ }
++
++ zvt_red[16] = zvt_green[16] = zvt_blue[16] = 0xffff;
++ zvt_red[17] = zvt_green[17] = zvt_blue[17] = 0;
++
++ zvt_term_set_color_scheme(zvt, zvt_red, zvt_green, zvt_blue);
++}
++
++/* signal: button pressed in text window */
++static gint sig_text_butpress_zvt(GtkWidget *widget, GdkEventButton *event, WINDOW_REC *window)
++{
++ gint x, y, len;
++ gchar *text, *word;
++
++ g_return_val_if_fail(widget != NULL, 0);
++ g_return_val_if_fail(event != NULL, 0);
++ g_return_val_if_fail(window != NULL, 0);
++
++ x = event->x / ZVT_TERM(widget)->charwidth;
++ y = event->y / ZVT_TERM(widget)->charheight;
++
++ word = NULL;
++
++ text = zvt_term_get_buffer(ZVT_TERM(widget), &len, VT_SELTYPE_CHAR,
++ 0, y, ZVT_TERM(widget)->grid_width-1, y);
++ if (text != NULL && len > 0)
++ {
++ len = x;
++ if (!iswordcut(text[x]))
++ while (x > 0 && !iswordcut(text[x-1])) x--;
++ while (!iswordcut(text[len])) len++; len -= x;
++
++ word = g_new(gchar, len+1);
++ memcpy(word, text+x, len); word[len] = '\0';
++ }
++
++ if (event->button == 3 && toggle_show_menubar)
++ {
++ /* create popup menu */
++ window_popupmenu_create(window->active, word, event);
++ gtk_signal_emit_stop_by_name(GTK_OBJECT(widget), "button_press_event");
++ }
++ else if (word != NULL)
++ {
++ /* left mouse button clicked */
++ word_clicked(window, word, event->type == GDK_2BUTTON_PRESS, event->button, NULL);
++ }
++
++ if (word != NULL) g_free(word);
++ return 0;
++}
++#endif
++
++/* signal: button pressed in text window */
++static gint sig_text_butpress(GtkWidget *widget, GdkEventButton *event, GUI_WINDOW_VIEW_REC *view)
++{
++ static gboolean cludging = FALSE;
++ GdkEventButton kludge_event;
++
++ guint pos, spos, len;
++ gchar *text, *word;
++
++ g_return_val_if_fail(widget != NULL, 0);
++ g_return_val_if_fail(event != NULL, 0);
++ g_return_val_if_fail(view != NULL, 0);
++
++ /* so, here's the problem: we need know what word was just clicked, but
++ text widget haven't get button_press_event yet so cursor position is
++ still in the last clicked position.. We could use
++ gtk_signal_connect_after(), but if we create a popup menu with it,
++ text widget's selection gets broken, it never receives the
++ button_release_event .. We could also create the popup menu in
++ button_release_event but it seems to work in some weird way too ..
++ So this kludge seems to work best. */
++ if (cludging) return 0;
++
++ /* send faked left button click to text widget */
++ cludging = TRUE;
++ memcpy(&kludge_event, event, sizeof(kludge_event));
++ kludge_event.button = 1;
++ kludge_event.type = GDK_BUTTON_PRESS;
++ gtk_widget_event(widget, (GdkEvent *) &kludge_event);
++ kludge_event.type = GDK_BUTTON_RELEASE;
++ gtk_widget_event(widget, (GdkEvent *) &kludge_event);
++ cludging = FALSE;
++
++ /* finished, cursor is now in right position! */
++
++ len = gtk_text_get_length(GTK_TEXT(view->text));
++ pos = gtk_editable_get_position(GTK_EDITABLE(view->text));
++
++ word = NULL;
++ if (pos < len)
++ {
++ text = gtk_editable_get_chars(GTK_EDITABLE(view->text), pos < URL_MAX_LENGTH ? 0 : pos-URL_MAX_LENGTH,
++ pos+URL_MAX_LENGTH > len ? len : pos+URL_MAX_LENGTH);
++ len = spos = pos < URL_MAX_LENGTH ? pos : URL_MAX_LENGTH;
++ if (!iswordcut(text[spos]))
++ while (spos > 0 && !iswordcut(text[spos-1])) spos--;
++ while (!iswordcut(text[len])) len++; len -= spos;
++
++ word = g_new(gchar, len+1);
++ memcpy(word, text+spos, len); word[len] = '\0';
++ g_free(text);
++ }
++
++ if (event->button == 3 && toggle_show_menubar)
++ {
++ /* create popup menu */
++ window_popupmenu_create(view->window->active, word, event);
++ gtk_signal_emit_stop_by_name(GTK_OBJECT(widget), "button_press_event");
++ }
++ else if (word != NULL)
++ {
++ /* left mouse button clicked */
++ word_clicked(view->window, word, event->type == GDK_2BUTTON_PRESS, event->button, NULL);
++ }
++
++ if (word != NULL) g_free(word);
++ return 0;
++}
++
++GUI_WINDOW_VIEW_REC *gui_window_view_create(WINDOW_REC *window, GUI_WINDOW_REC *parent, GtkWidget *box)
++{
++ GUI_WINDOW_VIEW_REC *rec;
++ GtkWidget *scrollwin;
++
++ g_return_val_if_fail(parent != NULL, NULL);
++
++ rec = g_new0(GUI_WINDOW_VIEW_REC, 1);
++ parent->views = g_list_append(parent->views, rec);
++ window_views = g_list_append(window_views, rec);
++ window->gui_data = rec;
++
++ rec->window = window;
++ rec->windowset = parent;
++ rec->parent = parent->parent;;
++
++ /* Text window */
++ rec->zvt = toggle_use_zvt;
++#ifdef HAVE_GNOME
++ if (toggle_use_zvt)
++ {
++ GtkWidget *scrollbar;
++
++ rec->text = zvt_term_new();
++ gtk_signal_connect(GTK_OBJECT(rec->text), "button_press_event",
++ GTK_SIGNAL_FUNC(sig_text_butpress_zvt), window);
++ zvt_term_set_scrollback(ZVT_TERM(rec->text), max_textwidget_lines);
++ zvt_term_set_fonts(ZVT_TERM(rec->text), font_normal, font_bold);
++ zvt_term_set_blink(ZVT_TERM(rec->text), FALSE);
++ gtk_box_pack_start(GTK_BOX(box), rec->text, TRUE, TRUE, 0);
++
++ scrollbar = gtk_vscrollbar_new(ZVT_TERM(rec->text)->adjustment);
++ gtk_box_pack_start(GTK_BOX(box), scrollbar, FALSE, FALSE, 0);
++ }
++ else
++#endif
++ {
++ rec->text = gtk_text_new(NULL, NULL);
++ gtk_signal_connect(GTK_OBJECT(rec->text), "button_press_event",
++ GTK_SIGNAL_FUNC(sig_text_butpress), rec);
++ gtk_text_set_word_wrap(GTK_TEXT(rec->text), TRUE);
++
++ scrollwin = gtk_scrolled_window_new(NULL, NULL);
++ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin),
++ GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
++ gtk_box_pack_start(GTK_BOX(box), scrollwin, TRUE, TRUE, 0);
++ gtk_container_add(GTK_CONTAINER(scrollwin), rec->text);
++
++ init_colors(rec->text);
++ }
++
++ gui_window_view_set_background(rec);
++ return rec;
++}
++
++static gboolean gui_window_created(WINDOW_REC *window)
++{
++ GUI_WINDOW_VIEW_REC *view;
++ GtkWidget *popup;
++
++ g_return_val_if_fail(window != NULL, TRUE);
++
++ /* there's only one view after window is created.. */
++ view = WINDOW_GUI(window);
++
++#ifdef HAVE_GNOME
++ if (view->zvt)
++ {
++ gtk_widget_realize(view->text);
++ init_zvt_colors(ZVT_TERM(view->text));
++ vt_cursor_state(view->text, 0);
++ }
++#endif
++
++ if (!toggle_show_menubar)
++ {
++ /* add popup menu created by mainwindow */
++ popup = gtk_object_get_data(GTK_OBJECT(WINDOW_GUI(window)->parent->window), "popup");
++ if (popup != NULL) gnome_popup_menu_attach(popup, view->text, view->parent);
++ }
++
++ return TRUE;
++}
++
++void gui_window_view_destroy(GUI_WINDOW_VIEW_REC *view)
++{
++ WINDOW_REC *window;
++ GUI_WINDOW_REC *gui;
++
++ if (view->destroying) return;
++
++ window = view->window;
++ gui = view->windowset;
++ signal_emit("gui window view destroyed", 1, view);
++
++ view->destroying = TRUE;
++ ui_window_destroy(window);
++
++ gui->views = g_list_remove(gui->views, view);
++ window_views = g_list_remove(window_views, view);
++
++ if (view->pixmap != NULL) g_free(view->pixmap);
++ g_list_free(view->linepos);
++ g_free(view);
++
++ window->gui_data = NULL;
++
++ if (gui->views == NULL)
++ gui_windowset_destroy(gui);
++}
++
++static gboolean cmd_clear(gchar *data, SERVER_REC *server, CHANNEL_REC *channel)
++{
++ WINDOW_REC *window;
++ GUI_WINDOW_VIEW_REC *view;
++
++ g_return_val_if_fail(channel != NULL, FALSE);
++
++ window = CHANNEL_PARENT(channel);
++ view = WINDOW_GUI(window);
++
++#ifdef HAVE_GNOME
++ if (view->zvt)
++ {
++ zvt_term_set_scrollback(ZVT_TERM(view->text), 0);
++ zvt_term_feed(ZVT_TERM(view->text), "\033[H\033[2J", 7);
++ zvt_term_set_scrollback(ZVT_TERM(view->text), max_textwidget_lines);
++ }
++ else
++#endif
++ {
++ g_list_free(view->linepos);
++ view->linepos = NULL;
++ gtk_text_set_point(GTK_TEXT(view->text), 0);
++ gtk_text_forward_delete(GTK_TEXT(view->text), gtk_text_get_length(GTK_TEXT(view->text)));
++ }
++ window->lines = 0;
++
++ return TRUE;
++}
++
++static gboolean setup_changed(void)
++{
++ GList *tmp;
++
++ for (tmp = g_list_first(window_views); tmp != NULL; tmp = tmp->next)
++ {
++ GUI_WINDOW_VIEW_REC *view = tmp->data;
++
++ gui_window_view_set_background(view);
++#ifdef HAVE_GNOME
++ if (view->zvt)
++ {
++ zvt_term_set_fonts(ZVT_TERM(view->text), font_normal, font_bold);
++ init_zvt_colors(ZVT_TERM(view->text));
++ }
++#endif
++ }
++
++ return TRUE;
++}
++
++void gui_windows_view_init(void)
++{
++ signal_add("gui window created", (SIGNAL_FUNC) gui_window_created);
++ signal_add("setup changed", (SIGNAL_FUNC) setup_changed);
++ signal_add("command clear", (SIGNAL_FUNC) cmd_clear);
++}
++
++void gui_windows_view_deinit(void)
++{
++ signal_remove("gui window created", (SIGNAL_FUNC) gui_window_created);
++ signal_remove("setup changed", (SIGNAL_FUNC) setup_changed);
++ signal_remove("command clear", (SIGNAL_FUNC) cmd_clear);
++}
+diff -Nru irssi-0.7.11/src/gui-gnome/gui-windows-view.h irssi-0.7.11-new/src/gui-gnome/gui-windows-view.h
+--- irssi-0.7.11/src/gui-gnome/gui-windows-view.h Thu Jan 1 02:00:00 1970
++++ irssi-0.7.11-new/src/gui-gnome/gui-windows-view.h Sat Jun 12 17:23:39 1999
+@@ -0,0 +1,34 @@
++#ifndef __GUI_WINDOWS_VIEW_H
++#define __GUI_WINDOWS_VIEW_H
++
++#define WINDOW_GUI(a) ((GUI_WINDOW_VIEW_REC *) ((a)->gui_data))
++
++struct _GUI_WINDOW_VIEW_REC
++{
++ WINDOW_REC *window;
++ GUI_WINDOW_REC *windowset;
++ MAIN_WINDOW_REC *parent;
++
++ GtkWidget *text;
++
++ gboolean zvt; /* text is a zvt widget */
++ gchar *pixmap; /* current background pixmap */
++
++ GList *linepos;
++ gint lastlinelen;
++
++ GtkWidget *snapshot;
++ gboolean destroying;
++};
++
++extern GList *window_views;
++
++void gui_windows_view_init(void);
++void gui_windows_view_deinit(void);
++
++GUI_WINDOW_VIEW_REC *gui_window_view_create(WINDOW_REC *window, GUI_WINDOW_REC *parent, GtkWidget *box);
++void gui_window_view_destroy(GUI_WINDOW_VIEW_REC *view);
++
++void gui_window_view_set_background_pixmap(GUI_WINDOW_VIEW_REC *view, gchar *path);
++
++#endif
+diff -Nru irssi-0.7.11/src/gui-gnome/gui-windows.c irssi-0.7.11-new/src/gui-gnome/gui-windows.c
+--- irssi-0.7.11/src/gui-gnome/gui-windows.c Sat May 15 21:38:30 1999
++++ irssi-0.7.11-new/src/gui-gnome/gui-windows.c Thu Jan 1 02:00:00 1970
+@@ -1,750 +0,0 @@
+- /*
+- gui-windows.c : irssi
+-
+- Copyright (C) 1999 Timo Sirainen
+-
+- 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 "irssi.h"
+-
+-#define iswordcut(a) (isspace((gint) a) || \
+- (a) == '\n' || (a) == '\0' || (a) == '"' || \
+- (a) == '(' || (a) == ')' || (a) == '[' || (a) == ']' || \
+- (a) == '<' || (a) == '>')
+-
+-#define URL_MAX_LENGTH 200 /*FIXME: no max. limits*/
+-
+-static gchar mode_flags[] = "spmint";
+-static gchar *mode_tooltips[] =
+-{
+- N_("Secret"),
+- N_("Private"),
+- N_("Moderated"),
+- N_("Joining needs an invitation"),
+- N_("No external messages"),
+- N_("Only operators can change the topic")
+-};
+-
+-static void init_colors(GtkWidget *window)
+-{
+- gint n;
+-
+- g_return_if_fail(window != NULL);
+-
+- for (n = 0; n < sizeof(setup_colors)/sizeof(setup_colors[0]); n++)
+- {
+- setup_colors[n].pixel =
+- (gulong)((setup_colors[n].red & 0xff00)*256 +
+- (setup_colors[n].green & 0xff00) +
+- (setup_colors[n].blue & 0xff00)/256);
+- gdk_color_alloc(gtk_widget_get_colormap(window), &setup_colors[n]);
+- }
+-
+- bg_color.pixel =
+- (gulong)((bg_color.red & 0xff00)*256 +
+- (bg_color.green & 0xff00) +
+- (bg_color.blue & 0xff00)/256);
+- gdk_color_alloc(gtk_widget_get_colormap(window), &bg_color);
+-}
+-
+-void gui_window_set_background_pixmap(WINDOW_REC *window, gchar *path)
+-{
+- GUI_WINDOW_REC *gui;
+- GtkStyle *style;
+- GdkPixmap *pixmap;
+- GdkBitmap *mask;
+-#if defined (HAVE_IMLIB) || defined (HAVE_GNOME)
+- GdkImlibImage *img;
+-#endif
+-
+- g_return_if_fail(window != NULL);
+- g_return_if_fail(path != NULL);
+-
+- gui = WINDOW_GUI(window);
+- if (gui->pixmap != NULL && strcmp(gui->pixmap, path) == 0)
+- {
+- /* same pixmap already set for this window.. */
+- return;
+- }
+- if (gui->pixmap != NULL)
+- g_free(gui->pixmap);
+- gui->pixmap = g_strdup(path);
+-
+-#ifdef HAVE_GNOME
+- if (gui->zvt)
+- {
+- zvt_term_set_background(ZVT_TERM(gui->text), path, FALSE, FALSE);
+- return;
+- }
+-#endif
+-
+- if (*path == '\0')
+- pixmap = NULL;
+- else
+- {
+-#if defined (HAVE_IMLIB) || defined (HAVE_GNOME)
+- mask = NULL;
+- img = gdk_imlib_load_image(path);
+- if (img == NULL)
+- pixmap = NULL;
+- else
+- {
+- gdk_imlib_render(img, img->rgb_width, img->rgb_height);
+- pixmap = gdk_imlib_move_image(img);
+- gdk_imlib_destroy_image(img);
+- }
+-#else
+- pixmap = gdk_pixmap_create_from_xpm(gui->text->window, &mask, NULL, path);
+-#endif
+- }
+-
+- style = gtk_style_copy(gui->text->style);
+- gtk_style_ref(style);
+- style->bg_pixmap[GTK_STATE_NORMAL] = pixmap;
+- gtk_widget_set_style(gui->text, style);
+- gtk_style_unref(style);
+-}
+-
+-static void gui_window_set_background(WINDOW_REC *window)
+-{
+- GUI_WINDOW_REC *gui;
+- GtkStyle *style;
+- gchar *path;
+-
+- g_return_if_fail(window != NULL);
+-
+- gui = WINDOW_GUI(window);
+-#ifdef HAVE_GNOME
+- if (gui->zvt)
+- {
+- if (toggle_use_transparency)
+- {
+- zvt_term_set_background(ZVT_TERM(gui->text), 0, TRUE, toggle_shaded_transparency);
+- if (gui->pixmap != NULL)
+- {
+- g_free(gui->pixmap);
+- gui->pixmap = NULL;
+- }
+- return;
+- }
+- }
+- else
+-#endif
+- {
+- style = gtk_style_copy(gui->text->style);
+- gtk_style_ref(style);
+- style->base[GTK_STATE_NORMAL] = bg_color;;
+- gtk_widget_set_style(gui->text, style);
+- gtk_style_unref(style);
+- }
+-
+- path = convert_home(background_pixmap);
+- gui_window_set_background_pixmap(window, path);
+- g_free(path);
+-}
+-
+-#ifdef HAVE_GNOME
+-static void init_zvt_colors(ZvtTerm *zvt)
+-{
+- static gchar ansitab[16] = { 0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15 };
+- gushort zvt_red[18], zvt_green[18], zvt_blue[18];
+- gint num;
+-
+- for (num = 0; num < 16; num++)
+- {
+- zvt_red[num] = (gushort) setup_colors[(gint) ansitab[num]].red;
+- zvt_green[num] = (gushort) setup_colors[(gint) ansitab[num]].green;
+- zvt_blue[num] = (gushort) setup_colors[(gint) ansitab[num]].blue;
+- }
+-
+- zvt_red[16] = zvt_green[16] = zvt_blue[16] = 0xffff;
+- zvt_red[17] = zvt_green[17] = zvt_blue[17] = 0;
+-
+- zvt_term_set_color_scheme(zvt, zvt_red, zvt_green, zvt_blue);
+-}
+-
+-/* signal: button pressed in text window */
+-static gint sig_text_butpress_zvt(GtkWidget *widget, GdkEventButton *event, WINDOW_REC *window)
+-{
+- gint x, y, len;
+- gchar *text, *word;
+-
+- g_return_val_if_fail(widget != NULL, 0);
+- g_return_val_if_fail(event != NULL, 0);
+- g_return_val_if_fail(window != NULL, 0);
+-
+- x = event->x / ZVT_TERM(widget)->charwidth;
+- y = event->y / ZVT_TERM(widget)->charheight;
+-
+- word = NULL;
+-
+- text = zvt_term_get_buffer(ZVT_TERM(widget), &len, VT_SELTYPE_CHAR,
+- 0, y, ZVT_TERM(widget)->grid_width-1, y);
+- if (text != NULL && len > 0)
+- {
+- len = x;
+- if (!iswordcut(text[x]))
+- while (x > 0 && !iswordcut(text[x-1])) x--;
+- while (!iswordcut(text[len])) len++; len -= x;
+-
+- word = g_new(gchar, len+1);
+- memcpy(word, text+x, len); word[len] = '\0';
+- }
+-
+- if (event->button == 3 && toggle_show_menubar)
+- {
+- /* create popup menu */
+- window_popupmenu_create(window->active, word, event);
+- gtk_signal_emit_stop_by_name(GTK_OBJECT(widget), "button_press_event");
+- }
+- else if (word != NULL)
+- {
+- /* left mouse button clicked */
+- word_clicked(window, word, event->type == GDK_2BUTTON_PRESS, event->button, NULL);
+- }
+-
+- if (word != NULL) g_free(word);
+- return 0;
+-}
+-#endif
+-
+-/* signal: button pressed in text window */
+-static gint sig_text_butpress(GtkWidget *widget, GdkEventButton *event, WINDOW_REC *window)
+-{
+- static gboolean cludging = FALSE;
+- GdkEventButton kludge_event;
+-
+- guint pos, spos, len;
+- gchar *text, *word;
+-
+- g_return_val_if_fail(widget != NULL, 0);
+- g_return_val_if_fail(event != NULL, 0);
+- g_return_val_if_fail(window != NULL, 0);
+-
+- /* so, here's the problem: we need know what word was just clicked, but
+- text widget haven't get button_press_event yet so cursor position is
+- still in the last clicked position.. We could use
+- gtk_signal_connect_after(), but if we create a popup menu with it,
+- text widget's selection gets broken, it never receives the
+- button_release_event .. We could also create the popup menu in
+- button_release_event but it seems to work in some weird way too ..
+- So this kludge seems to work best. */
+- if (cludging) return 0;
+-
+- /* send faked left button click to text widget */
+- cludging = TRUE;
+- memcpy(&kludge_event, event, sizeof(kludge_event));
+- kludge_event.button = 1;
+- kludge_event.type = GDK_BUTTON_PRESS;
+- gtk_widget_event(widget, (GdkEvent *) &kludge_event);
+- kludge_event.type = GDK_BUTTON_RELEASE;
+- gtk_widget_event(widget, (GdkEvent *) &kludge_event);
+- cludging = FALSE;
+-
+- /* finished, cursor is now in right position! */
+-
+- len = gtk_text_get_length(GTK_TEXT(WINDOW_GUI(window)->text));
+- pos = gtk_editable_get_position(GTK_EDITABLE(WINDOW_GUI(window)->text));
+-
+- word = NULL;
+- if (pos < len)
+- {
+- text = gtk_editable_get_chars(GTK_EDITABLE(WINDOW_GUI(window)->text), pos < URL_MAX_LENGTH ? 0 : pos-URL_MAX_LENGTH,
+- pos+URL_MAX_LENGTH > len ? len : pos+URL_MAX_LENGTH);
+- len = spos = pos < URL_MAX_LENGTH ? pos : URL_MAX_LENGTH;
+- if (!iswordcut(text[spos]))
+- while (spos > 0 && !iswordcut(text[spos-1])) spos--;
+- while (!iswordcut(text[len])) len++; len -= spos;
+-
+- word = g_new(gchar, len+1);
+- memcpy(word, text+spos, len); word[len] = '\0';
+- g_free(text);
+- }
+-
+- if (event->button == 3 && toggle_show_menubar)
+- {
+- /* create popup menu */
+- window_popupmenu_create(window->active, word, event);
+- gtk_signal_emit_stop_by_name(GTK_OBJECT(widget), "button_press_event");
+- }
+- else if (word != NULL)
+- {
+- /* left mouse button clicked */
+- word_clicked(window, word, event->type == GDK_2BUTTON_PRESS, event->button, NULL);
+- }
+-
+- if (word != NULL) g_free(word);
+- return 0;
+-}
+-
+-static gint sig_topicentry_press(GtkWidget *entry, GdkEventButton *event)
+-{
+- gboolean editable;
+-
+- g_return_val_if_fail(entry != NULL, 0);
+- g_return_val_if_fail(event != NULL, 0);
+-
+- if (event->type == GDK_2BUTTON_PRESS)
+- {
+- editable = !(gboolean) GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(entry), "editable"));
+- gtk_object_set_data(GTK_OBJECT(entry), "editable", GINT_TO_POINTER((gint) editable));
+- gtk_entry_set_editable(GTK_ENTRY(entry), editable);
+- }
+-
+- return 0;
+-}
+-
+-static void sig_topicentry_activated(GtkWidget *entry, WINDOW_REC *window)
+-{
+- CHANNEL_REC *channel;
+-
+- g_return_if_fail(entry != NULL);
+- g_return_if_fail(window != NULL);
+-
+- channel = window->active;
+- if (channel == NULL || (!channel->chanop && channel->mode_optopic))
+- {
+- /* can't change topic. */
+- gtk_entry_set_text(GTK_ENTRY(entry),
+- (channel == NULL || channel->topic == NULL) ?
+- "" : channel->topic);
+- return;
+- }
+-
+- signal_emit("command topic", 3, gtk_entry_get_text(GTK_ENTRY(entry)),
+- window->active->server, window->active);
+-}
+-
+-static void sig_modebutton_toggled(GtkToggleButton *button, gint mode)
+-{
+- WINDOW_REC *window;
+- NICK_REC *nick;
+- GString *str;
+-
+- g_return_if_fail(button != NULL);
+- if (gtk_object_get_data(GTK_OBJECT(button), "toggling")) return;
+-
+- window = gtk_object_get_data(GTK_OBJECT(button), "window");
+- g_return_if_fail(window->active != NULL);
+-
+- nick = nicklist_find(window->active, window->active->server->nick);
+- if (!window->active->chanop)
+- {
+- /* can't change mode */
+- gtk_object_set_data(GTK_OBJECT(button), "toggling", GINT_TO_POINTER(TRUE));
+- gtk_toggle_button_set_active(button, !button->active);
+- gtk_object_set_data(GTK_OBJECT(button), "toggling", GINT_TO_POINTER(FALSE));
+- return;
+- }
+-
+- str = g_string_new(NULL);
+- g_string_sprintf(str, "* %c%c", button->active ? '+' : '-', mode_flags[mode]);
+-
+- gtk_object_set_data(GTK_OBJECT(button), "toggling", GINT_TO_POINTER(TRUE));
+- signal_emit("command mode", 3, str->str, window->active->server, window->active);
+- g_string_free(str, TRUE);
+- gtk_object_set_data(GTK_OBJECT(button), "toggling", GINT_TO_POINTER(FALSE));
+-}
+-
+-WINDOW_REC *gui_window_create(MAIN_WINDOW_REC *parent)
+-{
+- WINDOW_REC *rec;
+- GUI_WINDOW_REC *gui;
+- GtkWidget *hbox, *scrollwin, *label;
+- GtkTooltips *tooltips;
+- gint num;
+-
+- if (parent == NULL) parent = mainwindow_create();
+-
+- rec = ui_window_create();
+- g_return_val_if_fail(rec != NULL, NULL);
+-
+- gui = g_new0(GUI_WINDOW_REC, 1);
+- rec->gui_data = gui;
+- gui->parent = parent;
+-
+- if (parent->children == NULL) parent->active = rec;
+- parent->children = g_list_append(parent->children, rec);
+-
+- gui->window = gtk_vbox_new(FALSE, 2);
+- gtk_container_border_width(GTK_CONTAINER(gui->window), 2);
+-
+- /* Add channel topic and modes */
+- gui->channelwidget = gtk_hbox_new(FALSE, 0);
+- gtk_box_pack_start(GTK_BOX(gui->window), gui->channelwidget, FALSE, FALSE, 0);
+-
+- gui->serverlabel = gtk_label_new("");
+- gtk_box_pack_start(GTK_BOX(gui->channelwidget), gui->serverlabel, FALSE, FALSE, 0);
+-
+- gui->topicentry = gtk_entry_new();
+- gtk_entry_set_editable(GTK_ENTRY(gui->topicentry), FALSE);
+- gtk_signal_connect(GTK_OBJECT(gui->topicentry), "button_press_event",
+- GTK_SIGNAL_FUNC(sig_topicentry_press), rec);
+- gtk_signal_connect(GTK_OBJECT(gui->topicentry), "activate",
+- GTK_SIGNAL_FUNC(sig_topicentry_activated), rec);
+- gtk_box_pack_start(GTK_BOX(gui->channelwidget), gui->topicentry, TRUE, TRUE, 3);
+-
+- tooltips = gtk_tooltips_new();
+-
+- for (num = 0; num < 6; num++)
+- {
+- gchar str[2];
+-
+- str[0] = toupper(mode_flags[num]); str[1] = '\0';
+- gui->modebuttons[num] = gtk_toggle_button_new_with_label(str);
+- gtk_tooltips_set_tip(tooltips, gui->modebuttons[num], mode_tooltips[num], NULL);
+- gtk_widget_set_usize(gui->modebuttons[num], 20, -1);
+- gtk_object_set_data(GTK_OBJECT(gui->modebuttons[num]), "window", rec);
+- gtk_signal_connect(GTK_OBJECT(gui->modebuttons[num]), "toggled",
+- GTK_SIGNAL_FUNC(sig_modebutton_toggled), GINT_TO_POINTER(num));
+- gtk_box_pack_start(GTK_BOX(gui->channelwidget), gui->modebuttons[num], FALSE, FALSE, 0);
+- }
+-
+- /* Text window */
+- hbox = gtk_hbox_new(FALSE, 3);
+- gtk_box_pack_start(GTK_BOX(gui->window), hbox, TRUE, TRUE, 0);
+-
+- gui->zvt = toggle_use_zvt;
+-#ifdef HAVE_GNOME
+- if (toggle_use_zvt)
+- {
+- GtkWidget *scrollbar;
+-
+- gui->text = zvt_term_new();
+- gtk_signal_connect(GTK_OBJECT(gui->text), "button_press_event",
+- GTK_SIGNAL_FUNC(sig_text_butpress_zvt), rec);
+- zvt_term_set_scrollback(ZVT_TERM(gui->text), max_textwidget_lines);
+- zvt_term_set_fonts(ZVT_TERM(gui->text), font_normal, font_bold);
+- zvt_term_set_blink(ZVT_TERM(gui->text), FALSE);
+- gtk_box_pack_start(GTK_BOX(hbox), gui->text, TRUE, TRUE, 0);
+-
+- scrollbar = gtk_vscrollbar_new(ZVT_TERM(gui->text)->adjustment);
+- gtk_box_pack_start(GTK_BOX(hbox), scrollbar, FALSE, FALSE, 0);
+- }
+- else
+-#endif
+- {
+- gui->text = gtk_text_new(NULL, NULL);
+- gtk_signal_connect(GTK_OBJECT(gui->text), "button_press_event",
+- GTK_SIGNAL_FUNC(sig_text_butpress), rec);
+- gtk_text_set_word_wrap(GTK_TEXT(gui->text), TRUE);
+-
+- scrollwin = gtk_scrolled_window_new(NULL, NULL);
+- gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin),
+- GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
+- gtk_box_pack_start(GTK_BOX(hbox), scrollwin, TRUE, TRUE, 0);
+- gtk_container_add(GTK_CONTAINER(scrollwin), gui->text);
+-
+- init_colors(gui->text);
+- }
+- gui_window_set_background(rec);
+-
+- gtk_widget_show_all(gui->window);
+-
+- /* Add nick list */
+- gui->nickscrollbox = gtk_scrolled_window_new(NULL, NULL);
+- gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(gui->nickscrollbox),
+- GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+- gtk_box_pack_start(GTK_BOX(hbox), gui->nickscrollbox, FALSE, FALSE, 0);
+-
+- gui->nicklist = gtk_clist_new(1);
+- gtk_container_add(GTK_CONTAINER(gui->nickscrollbox), gui->nicklist);
+- gtk_widget_show(gui->nicklist);
+-
+- gtk_widget_set_usize(gui->nickscrollbox, 120, -1);
+-
+- label = gtk_label_new(_("(none)"));
+- gtk_widget_show(label);
+-
+- if (g_list_first(parent->children)->next == NULL)
+- {
+- /* only one child, don't show the notebook tabs.. */
+- gtk_notebook_set_show_tabs(GTK_NOTEBOOK(parent->notebook), FALSE);
+- gtk_notebook_set_show_border(GTK_NOTEBOOK(parent->notebook), FALSE);
+- }
+- else if (g_list_first(parent->children)->next->next == NULL)
+- {
+- /* two children, show the notebook tabs.. */
+- gtk_notebook_set_show_tabs(GTK_NOTEBOOK(parent->notebook), TRUE);
+- gtk_notebook_set_show_border(GTK_NOTEBOOK(parent->notebook), TRUE);
+- }
+-
+- gtk_notebook_append_page(GTK_NOTEBOOK(parent->notebook), gui->window, label);
+-
+-#ifdef HAVE_GNOME
+- if (gui->zvt)
+- {
+- gtk_widget_realize(gui->text);
+- init_zvt_colors(ZVT_TERM(gui->text));
+- vt_cursor_state(gui->text, 0);
+- }
+-#endif
+-
+- if (!toggle_show_menubar)
+- {
+- GtkWidget *popup;
+-
+- /* add popup menu created by mainwindow */
+- popup = gtk_object_get_data(GTK_OBJECT(parent->window), "popup");
+- if (popup != NULL) gnome_popup_menu_attach(popup, gui->text, parent);
+- }
+-
+- gtk_widget_hide(gui->channelwidget);
+-
+- signal_emit("gui window created", 1, rec);
+- return rec;
+-}
+-
+-void gui_window_destroy(WINDOW_REC *window)
+-{
+- MAIN_WINDOW_REC *parent;
+- GUI_WINDOW_REC *gui;
+- gint page;
+-
+- g_return_if_fail(window != NULL);
+- if (WINDOW_GUI(window)->destroying) return;
+-
+- gui = WINDOW_GUI(window);
+- parent = gui->parent;
+- parent->children = g_list_remove(parent->children, window);
+-
+- signal_emit("gui window destroyed", 1, window);
+-
+- gui->destroying = TRUE;
+- ui_window_destroy(window);
+-
+- page = gtk_notebook_page_num(GTK_NOTEBOOK(parent->notebook), gui->window);
+- gtk_notebook_remove_page(GTK_NOTEBOOK(parent->notebook), page);
+-
+- if (gui->pixmap != NULL) g_free(gui->pixmap);
+- g_free(gui);
+- window->gui_data = NULL;
+-
+- if (parent->children == NULL)
+- mainwindow_destroy(parent);
+- else if (g_list_length(parent->children) == 1)
+- {
+- /* only one child left, hide the notebook tabs.. */
+- gtk_notebook_set_show_tabs(GTK_NOTEBOOK(parent->notebook), FALSE);
+- gtk_notebook_set_show_border(GTK_NOTEBOOK(parent->notebook), FALSE);
+- }
+-}
+-
+-static gboolean gui_window_server_changed(WINDOW_REC *window)
+-{
+- MAIN_WINDOW_REC *parent;
+- SERVER_REC *server;
+- gint num;
+-
+- g_return_val_if_fail(window != NULL, FALSE);
+-
+- parent = WINDOW_GUI(window)->parent;
+- server = window->active->server;
+-
+- if (parent->usermodes[0] == NULL) return TRUE;
+-
+- for (num = 0; num < 4; num++)
+- gtk_object_set_data(GTK_OBJECT(parent->usermodes[num]), "toggling", GINT_TO_POINTER(TRUE));
+-
+- gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(parent->usermodes[0]),
+- server == NULL ? FALSE : server->usermode_away);
+- gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(parent->usermodes[1]),
+- server == NULL ? FALSE : server->usermode_invisible);
+- gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(parent->usermodes[2]),
+- server == NULL ? FALSE : server->usermode_wallops);
+- gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(parent->usermodes[3]),
+- server == NULL ? FALSE : server->usermode_servernotes);
+-
+- for (num = 0; num < 4; num++)
+- gtk_object_set_data(GTK_OBJECT(parent->usermodes[num]), "toggling", GINT_TO_POINTER(FALSE));
+-
+- return TRUE;
+-}
+-
+-static gboolean gui_windows_usermode_changed(SERVER_REC *server)
+-{
+- GList *winlist;
+-
+- for (winlist = g_list_first(mainwindows); winlist != NULL; winlist = winlist->next)
+- {
+- MAIN_WINDOW_REC *rec = winlist->data;
+-
+- if (server == rec->active->active->server)
+- signal_emit("window server changed", 1, rec->active);
+- }
+-
+- return TRUE;
+-}
+-
+-static gboolean cmd_clear(gchar *data, SERVER_REC *server, CHANNEL_REC *channel)
+-{
+- WINDOW_REC *window;
+- GUI_WINDOW_REC *gui;
+-
+- g_return_val_if_fail(channel != NULL, FALSE);
+-
+- window = CHANNEL_PARENT(channel);
+- gui = WINDOW_GUI(window);
+-
+-#ifdef HAVE_GNOME
+- if (gui->zvt)
+- {
+- zvt_term_set_scrollback(ZVT_TERM(gui->text), 0);
+- zvt_term_feed(ZVT_TERM(gui->text), "\033[H\033[2J", 7);
+- zvt_term_set_scrollback(ZVT_TERM(gui->text), max_textwidget_lines);
+- }
+- else
+-#endif
+- {
+- g_list_free(gui->linepos);
+- gui->linepos = NULL;
+- gtk_text_set_point(GTK_TEXT(gui->text), 0);
+- gtk_text_forward_delete(GTK_TEXT(gui->text), gtk_text_get_length(GTK_TEXT(gui->text)));
+- }
+- window->lines = 0;
+-
+- return TRUE;
+-}
+-
+-static gboolean signal_window_focused(WINDOW_REC *window)
+-{
+- MAIN_WINDOW_REC *mainwindow;
+- GUI_WINDOW_REC *gui;
+- CHANNEL_REC *channel;
+-
+- g_return_val_if_fail(window != NULL, FALSE);
+-
+- mainwindow = WINDOW_GUI(window)->parent;
+- channel = window->active;
+-
+- gui = WINDOW_GUI(mainwindow->active);
+-
+- /* remove old extra menus */
+- if (mainwindow->extramenu != NULL)
+- {
+- window_menus_remove(mainwindow, mainwindow->extramenu);
+- g_free(mainwindow->extramenu);
+- mainwindow->extramenu = NULL;
+- }
+- if (channel == NULL) return TRUE;
+-
+- if (channel->type == CHANNEL_TYPE_CHANNEL)
+- {
+- /* Add channel menu */
+- mainwindow->extramenu = g_strdup(channel_menu[0].label);
+- window_menus_insert(mainwindow, NULL, channel_menu, channel);
+- gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(channel_submenu[2].widget),
+- GTK_WIDGET_VISIBLE(gui->nickscrollbox));
+- gtk_widget_show(gui->channelwidget);
+- }
+- else
+- {
+- gtk_widget_hide(gui->nickscrollbox);
+- gtk_widget_hide(gui->channelwidget);
+- if (channel->type == CHANNEL_TYPE_QUERY)
+- {
+- /* Add query menu */
+- mainwindow->extramenu = g_strdup(query_menu[0].label);
+- window_menus_insert(mainwindow, NULL, query_menu, channel);
+- }
+- }
+-
+- if (CHANNEL_GUI(channel)->servermenu)
+- {
+- /* change server selection */
+- gtk_option_menu_set_history(GTK_OPTION_MENU(mainwindow->servermenu),
+- g_list_index(servers, channel->server));
+- gtk_widget_show(mainwindow->servermenu);
+- }
+- else
+- gtk_widget_hide(mainwindow->servermenu);
+-
+- /* draw title bar */
+- signal_emit("channel topic changed", 1, window->active);
+-
+- return TRUE;
+-}
+-
+-static gboolean gui_windows_setup_changed(void)
+-{
+- GList *tmp;
+-
+- for (tmp = g_list_first(windows); tmp != NULL; tmp = tmp->next)
+- {
+- WINDOW_REC *rec = tmp->data;
+-
+- gui_window_set_background(rec);
+-#ifdef HAVE_GNOME
+- if (WINDOW_GUI(rec)->zvt)
+- {
+- zvt_term_set_fonts(ZVT_TERM(WINDOW_GUI(rec)->text), font_normal, font_bold);
+- init_zvt_colors(ZVT_TERM(WINDOW_GUI(rec)->text));
+- }
+-#endif
+- }
+-
+- return TRUE;
+-}
+-
+-static gboolean gui_server_looking(SERVER_REC *server)
+-{
+- GList *tmp, *sub;
+-
+- g_return_val_if_fail(server != NULL, FALSE);
+-
+- /* try to keep some server assigned to server menus.. */
+- for (tmp = g_list_first(windows); tmp != NULL; tmp = tmp->next)
+- {
+- WINDOW_REC *win = tmp->data;
+- gboolean changed;
+-
+- changed = FALSE;
+- for (sub = g_list_first(win->channels); sub != NULL; sub = sub->next)
+- {
+- CHANNEL_REC *chan = sub->data;
+-
+- if (chan->server == NULL)
+- {
+- chan->server = server;
+- if (!changed)
+- signal_emit("window server changed", 1, win);
+- changed = TRUE;
+- }
+- }
+- }
+-
+- return TRUE;
+-}
+-
+-void gui_windows_init(void)
+-{
+- signal_add("setup changed", (SIGNAL_FUNC) gui_windows_setup_changed);
+- signal_add("user mode changed", (SIGNAL_FUNC) gui_windows_usermode_changed);
+- signal_add("window server changed", (SIGNAL_FUNC) gui_window_server_changed);
+- signal_add("window focused", (SIGNAL_FUNC) signal_window_focused);
+- signal_add("command clear", (SIGNAL_FUNC) cmd_clear);
+- signal_add("server looking", (SIGNAL_FUNC) gui_server_looking);
+-}
+-
+-void gui_windows_deinit(void)
+-{
+- signal_remove("setup changed", (SIGNAL_FUNC) gui_windows_setup_changed);
+- signal_remove("user mode changed", (SIGNAL_FUNC) gui_windows_usermode_changed);
+- signal_remove("window server changed", (SIGNAL_FUNC) gui_window_server_changed);
+- signal_remove("window focused", (SIGNAL_FUNC) signal_window_focused);
+- signal_remove("command clear", (SIGNAL_FUNC) cmd_clear);
+- signal_remove("server looking", (SIGNAL_FUNC) gui_server_looking);
+-}
+diff -Nru irssi-0.7.11/src/gui-gnome/gui-windows.h irssi-0.7.11-new/src/gui-gnome/gui-windows.h
+--- irssi-0.7.11/src/gui-gnome/gui-windows.h Thu May 13 13:24:58 1999
++++ irssi-0.7.11-new/src/gui-gnome/gui-windows.h Thu Jan 1 02:00:00 1970
+@@ -1,44 +0,0 @@
+-#ifndef __GUI_WINDOWS_H
+-#define __GUI_WINDOWS_H
+-
+-#define WINDOW_GUI(a) ((GUI_WINDOW_REC *) ((a)->gui_data))
+-
+-typedef struct
+-{
+- MAIN_WINDOW_REC *parent;
+-
+- GtkWidget *window;
+- GtkWidget *text;
+-
+- gboolean zvt; /* text is a zvt widget */
+- gchar *pixmap; /* current background pixmap */
+-
+- GtkWidget *channelwidget;
+- GtkWidget *serverlabel;
+- GtkWidget *topicentry;
+- GtkWidget *modebuttons[6];
+-
+- /* nicklist */
+- GtkWidget *nickscrollbox;
+- GtkWidget *nicklist;
+- GdkPixmap *op_pixmap, *voice_pixmap;
+- GdkBitmap *op_mask, *voice_mask;
+-
+- GList *linepos;
+- gint lastlinelen;
+-
+- GtkWidget *snapshot;
+- gboolean destroying;
+- gfloat sb_value; /* to fix those scrollbar problems... */
+-}
+-GUI_WINDOW_REC;
+-
+-void gui_windows_init(void);
+-void gui_windows_deinit(void);
+-
+-WINDOW_REC *gui_window_create(MAIN_WINDOW_REC *parent);
+-void gui_window_destroy(WINDOW_REC *window);
+-
+-void gui_window_set_background_pixmap(WINDOW_REC *window, gchar *path);
+-
+-#endif