Mercurial > pidgin
changeset 18045:08e93462f189
Update the irssi WM to allow tiling the conversation windows.
author | Sadrul Habib Chowdhury <imadil@gmail.com> |
---|---|
date | Wed, 06 Jun 2007 14:34:58 +0000 |
parents | 37469ac119b6 |
children | 9aa2c89c8b9e |
files | finch/libgnt/gntstyle.c finch/libgnt/gntstyle.h finch/libgnt/wms/irssi.c |
diffstat | 3 files changed, 196 insertions(+), 23 deletions(-) [+] |
line wrap: on
line diff
--- a/finch/libgnt/gntstyle.c Tue Jun 05 06:27:48 2007 +0000 +++ b/finch/libgnt/gntstyle.c Wed Jun 06 14:34:58 2007 +0000 @@ -1,6 +1,7 @@ #include "gntstyle.h" #include "gntcolors.h" +#include <glib.h> #include <ctype.h> #include <string.h> @@ -8,6 +9,7 @@ static GKeyFile *gkfile; #endif +static GHashTable *unknowns; static char * str_styles[GNT_STYLES]; static int int_styles[GNT_STYLES]; static int bool_styles[GNT_STYLES]; @@ -17,6 +19,11 @@ return str_styles[style]; } +const char *gnt_style_get_from_name(const char *name) +{ + return g_hash_table_lookup(unknowns, name); +} + gboolean gnt_style_get_bool(GntStyle style, gboolean def) { int i; @@ -221,6 +228,10 @@ str_styles[styles[i].en] = g_key_file_get_string(kfile, "general", styles[i].style, NULL); } + + for (i = 0; i < nkeys; i++) + g_hash_table_replace(unknowns, g_strdup(keys[i]), + g_strdup(g_key_file_get_string(kfile, "general", keys[i], NULL))); } g_strfreev(keys); } @@ -231,6 +242,7 @@ #if GLIB_CHECK_VERSION(2,6,0) GError *error = NULL; gkfile = g_key_file_new(); + unknowns = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); if (!g_key_file_load_from_file(gkfile, filename, G_KEY_FILE_NONE, &error)) { @@ -260,6 +272,7 @@ for (i = 0; i < GNT_STYLES; i++) g_free(str_styles[i]); + g_hash_table_destroy(unknowns); #if GLIB_CHECK_VERSION(2,6,0) g_key_file_free(gkfile); #endif
--- a/finch/libgnt/gntstyle.h Tue Jun 05 06:27:48 2007 +0000 +++ b/finch/libgnt/gntstyle.h Wed Jun 06 14:34:58 2007 +0000 @@ -14,6 +14,8 @@ const char *gnt_style_get(GntStyle style); +const char *gnt_style_get_from_name(const char *key); + gboolean gnt_style_get_bool(GntStyle style, gboolean def); /* This should be called only once for the each type */
--- a/finch/libgnt/wms/irssi.c Tue Jun 05 06:27:48 2007 +0000 +++ b/finch/libgnt/wms/irssi.c Wed Jun 06 14:34:58 2007 +0000 @@ -1,12 +1,13 @@ /** - * 1. Buddylist and conversation windows are borderless and full height of the screen. - * 2. Conversation windows will have (full-screen-width - buddylist-width) width - * - It's possible to auto-resize the conversation windows when the buddylist - * is closed/opened/resized to keep this always true. But resizing the textview - * in conversation window is rather costly, especially when there's a lot of text - * in the scrollback. So it's not done yet. + * 1. Buddylist is aligned on the left. + * 2. The rest of the screen is split into MxN grid for conversation windows. + * - M = irssi-split-h in ~/.gntrc:[general] + * - N = irssi-split-v in ~/.gntrc:[general] + * - Press alt-shift-k/j/l/h to move the selected window to the frame + * above/below/left/right of the current frame. * 3. All the other windows are always centered. */ +#include <stdlib.h> #include <string.h> #include <sys/types.h> @@ -23,6 +24,11 @@ typedef struct _Irssi { GntWM inherit; + int vert; + int horiz; + + /* This is changed whenever the buddylist is opened/closed or resized. */ + int buddylistwidth; } Irssi; typedef struct _IrssiClass @@ -35,8 +41,63 @@ static void (*org_new_window)(GntWM *wm, GntWidget *win); -/* This is changed whenever the buddylist is opened/closed or resized. */ -static int buddylistwidth; +static void +get_xywh_for_frame(Irssi *irssi, int hor, int vert, int *x, int *y, int *w, int *h) +{ + int width, height, rx, ry; + + width = (getmaxx(stdscr) - irssi->buddylistwidth) / irssi->horiz; + height = (getmaxy(stdscr) - 1) / irssi->vert; + + rx = irssi->buddylistwidth; + if (hor) + rx += hor * width; + rx++; + + ry = 0; + if (vert) + ry += vert * height + 1; + + if (x) *x = rx; + if (y) *y = ry; + if (w) { + *w = (hor == irssi->horiz - 1) ? (getmaxx(stdscr) - rx) : (width - 1); + } + if (h) { + *h = (vert == irssi->vert - 1) ? (getmaxy(stdscr) - 1 - ry) : (height - !!vert); + } +} + +static void +draw_line_separators(Irssi *irssi) +{ + int x, y; + int width, height; + + wclear(stdscr); + /* Draw the separator for the buddylist */ + if (irssi->buddylistwidth) + mvwvline(stdscr, 0, irssi->buddylistwidth, + ACS_VLINE | COLOR_PAIR(GNT_COLOR_NORMAL), getmaxy(stdscr) - 1); + + /* Now the separators for the conversation windows */ + width = (getmaxx(stdscr) - irssi->buddylistwidth) / irssi->horiz; + height = (getmaxy(stdscr) - 1) / irssi->vert; + for (x = 1; x < irssi->horiz; x++) { + mvwvline(stdscr, 0, irssi->buddylistwidth + x * width, + ACS_VLINE | COLOR_PAIR(GNT_COLOR_NORMAL), getmaxy(stdscr) - 1); + } + + for (y = 1; y < irssi->vert; y++) { + mvwhline(stdscr, y * height, irssi->buddylistwidth + 1, ACS_HLINE | COLOR_PAIR(GNT_COLOR_NORMAL), + getmaxx(stdscr) - irssi->buddylistwidth); + for (x = 1; x < irssi->horiz; x++) { + mvwaddch(stdscr, y * height, x * width + irssi->buddylistwidth, ACS_PLUS | COLOR_PAIR(GNT_COLOR_NORMAL)); + } + if (irssi->buddylistwidth) + mvwaddch(stdscr, y * height, irssi->buddylistwidth, ACS_LTEE | COLOR_PAIR(GNT_COLOR_NORMAL)); + } +} static gboolean is_budddylist(GntWidget *win) @@ -62,12 +123,12 @@ irssi_new_window(GntWM *wm, GntWidget *win) { const char *name; + int x, y, w, h; name = gnt_widget_get_name(win); if (!name || strcmp(name, "conversation-window")) { if (!GNT_IS_MENU(win) && !GNT_WIDGET_IS_FLAG_SET(win, GNT_WIDGET_TRANSIENT)) { if ((!name || strcmp(name, "buddylist"))) { - int w, h, x, y; gnt_widget_get_size(win, &w, &h); x = (getmaxx(stdscr) - w) / 2; y = (getmaxy(stdscr) - h) / 2; @@ -75,9 +136,8 @@ mvwin(win->window, y, x); } else { remove_border_set_position_size(wm, win, 0, 0, -1, getmaxy(stdscr) - 1); - gnt_widget_get_size(win, &buddylistwidth, NULL); - mvwvline(stdscr, 0, buddylistwidth, ACS_VLINE | COLOR_PAIR(GNT_COLOR_NORMAL), getmaxy(stdscr) - 1); - buddylistwidth++; + gnt_widget_get_size(win, &((Irssi*)wm)->buddylistwidth, NULL); + draw_line_separators((Irssi*)wm); } } org_new_window(wm, win); @@ -85,8 +145,12 @@ } /* The window we have here is a conversation window. */ - remove_border_set_position_size(wm, win, buddylistwidth, 0, - getmaxx(stdscr) - buddylistwidth, getmaxy(stdscr) - 1); + + /* XXX: There should be some way to remember which frame a conversation window + * was in the last time. Perhaps save them in some ~/.gntpositionirssi or some + * such. */ + get_xywh_for_frame((Irssi*)wm, 0, 0, &x, &y, &w, &h); + remove_border_set_position_size(wm, win, x, y, w, h); org_new_window(wm, win); } @@ -96,23 +160,93 @@ if (!is_budddylist(node->me)) return; - if (buddylistwidth) - mvwvline(stdscr, 0, buddylistwidth - 1, - ' ' | COLOR_PAIR(GNT_COLOR_NORMAL), getmaxy(stdscr) - 1); - gnt_widget_get_size(node->me, &buddylistwidth, NULL); - mvwvline(stdscr, 0, buddylistwidth, ACS_VLINE | COLOR_PAIR(GNT_COLOR_NORMAL), getmaxy(stdscr) - 1); - buddylistwidth++; + gnt_widget_get_size(node->me, &((Irssi*)wm)->buddylistwidth, NULL); + draw_line_separators((Irssi*)wm); } static gboolean irssi_close_window(GntWM *wm, GntWidget *win) { if (is_budddylist(win)) - buddylistwidth = 0; + ((Irssi*)wm)->buddylistwidth = 0; + return FALSE; +} + +static gboolean +update_conv_window_title(GntNode *node) +{ + char title[256]; + snprintf(title, sizeof(title), "%d: %s", + (int)g_object_get_data(G_OBJECT(node->me), "irssi-index") + 1, GNT_BOX(node->me)->title); + wbkgdset(node->window, '\0' | COLOR_PAIR(gnt_widget_has_focus(node->me) ? GNT_COLOR_TITLE : GNT_COLOR_TITLE_D)); + mvwaddstr(node->window, 0, 0, title); + update_panels(); + doupdate(); return FALSE; } static void +irssi_update_window(GntWM *wm, GntNode *node) +{ + GntWidget *win = node->me; + const char *name = gnt_widget_get_name(win); + if (!name || !GNT_IS_BOX(win) || strcmp(name, "conversation-window")) + return; + g_object_set_data(G_OBJECT(win), "irssi-index", GINT_TO_POINTER(g_list_index(wm->list, win))); + g_timeout_add(0, (GSourceFunc)update_conv_window_title, node); +} + +static void +find_window_position(Irssi *irssi, GntWidget *win, int *h, int *v) +{ + int x, y; + int width, height; + + gnt_widget_get_position(win, &x, &y); + width = (getmaxx(stdscr) - irssi->buddylistwidth) / irssi->horiz; + height = (getmaxy(stdscr) - 1) / irssi->vert; + + if (h) + *h = (x - irssi->buddylistwidth) / width; + if (v) + *v = y / height; +} + +static gboolean +move_direction(GntBindable *bindable, GList *list) +{ + GntWM *wm = GNT_WM(bindable); + Irssi *irssi = (Irssi*)wm; + int vert, hor; + int x, y, w, h; + GntWidget *win; + + if (wm->ordered == NULL || is_budddylist(win = GNT_WIDGET(wm->ordered->data))) + return FALSE; + + find_window_position(irssi, win, &hor, &vert); + + switch ((int)list->data) { + case 'k': + vert = MAX(0, vert - 1); + break; + case 'j': + vert = MIN(vert + 1, irssi->vert - 1); + break; + case 'l': + hor = MIN(hor + 1, irssi->horiz - 1); + break; + case 'h': + hor = MAX(0, hor - 1); + break; + } + get_xywh_for_frame(irssi, hor, vert, &x, &y, &w, &h); + gnt_wm_move_window(wm, win, x, y); + gnt_wm_resize_window(wm, win, w, h); + return TRUE; +} + +static void irssi_class_init(IrssiClass *klass) { GntWMClass *pclass = GNT_WM_CLASS(klass); @@ -122,6 +256,16 @@ pclass->new_window = irssi_new_window; pclass->window_resized = irssi_window_resized; pclass->close_window = irssi_close_window; + pclass->window_update = irssi_update_window; + + gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "move-up", move_direction, + "\033" "K", GINT_TO_POINTER('k'), NULL); + gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "move-down", move_direction, + "\033" "J", GINT_TO_POINTER('j'), NULL); + gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "move-right", move_direction, + "\033" "L", GINT_TO_POINTER('l'), NULL); + gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "move-left", move_direction, + "\033" "H", GINT_TO_POINTER('h'), NULL); gnt_style_read_actions(G_OBJECT_CLASS_TYPE(klass), GNT_BINDABLE_CLASS(klass)); GNTDEBUG; @@ -129,8 +273,22 @@ void gntwm_init(GntWM **wm) { - buddylistwidth = 0; - *wm = g_object_new(TYPE_IRSSI, NULL); + const char *style = NULL; + Irssi *irssi; + + irssi = g_object_new(TYPE_IRSSI, NULL); + *wm = GNT_WM(irssi); + + style = gnt_style_get_from_name("irssi-split-v"); + irssi->vert = style ? atoi(style) : 1; + + style = gnt_style_get_from_name("irssi-split-h"); + irssi->horiz = style ? atoi(style) : 1; + + irssi->vert = MAX(irssi->vert, 1); + irssi->horiz = MAX(irssi->horiz, 1); + + irssi->buddylistwidth = 0; } GType irssi_get_gtype(void)