Initial commit.
[gnt.git] / wms / irssi.c
blob4f8ddd874183966675805fbc749c1ccface3ef4d
1 /**
2 * 1. Buddylist is aligned on the left.
3 * 2. The rest of the screen is split into MxN grid for conversation windows.
4 * - M = irssi-split-h in ~/.gntrc:[general]
5 * - N = irssi-split-v in ~/.gntrc:[general]
6 * - Press alt-shift-k/j/l/h to move the selected window to the frame
7 * above/below/left/right of the current frame.
8 * 3. All the other windows are always centered.
9 */
10 #include <stdlib.h>
11 #include <string.h>
12 #include <sys/types.h>
14 #include "gnt.h"
15 #include "gntbox.h"
16 #include "gntmenu.h"
17 #include "gntstyle.h"
18 #include "gntwm.h"
19 #include "gntwindow.h"
20 #include "gntlabel.h"
22 #define TYPE_IRSSI (irssi_get_gtype())
24 typedef struct _Irssi
26 GntWM inherit;
27 int vert;
28 int horiz;
30 /* This is changed whenever the buddylist is opened/closed or resized. */
31 int buddylistwidth;
32 } Irssi;
34 typedef struct _IrssiClass
36 GntWMClass inherit;
37 } IrssiClass;
39 GType irssi_get_gtype(void);
40 void gntwm_init(GntWM **wm);
42 static void (*org_new_window)(GntWM *wm, GntWidget *win);
44 static void
45 get_xywh_for_frame(Irssi *irssi, int hor, int vert, int *x, int *y, int *w, int *h)
47 int width, height, rx, ry;
49 width = (getmaxx(stdscr) - irssi->buddylistwidth) / irssi->horiz;
50 height = (getmaxy(stdscr) - 1) / irssi->vert;
52 rx = irssi->buddylistwidth;
53 if (hor)
54 rx += hor * width;
55 rx++;
57 ry = 0;
58 if (vert)
59 ry += vert * height + 1;
61 if (x) *x = rx;
62 if (y) *y = ry;
63 if (w) {
64 *w = (hor == irssi->horiz - 1) ? (getmaxx(stdscr) - rx) : (width - 1);
66 if (h) {
67 *h = (vert == irssi->vert - 1) ? (getmaxy(stdscr) - 1 - ry) : (height - !!vert);
71 static void
72 draw_line_separators(Irssi *irssi)
74 int x, y;
75 int width, height;
77 wclear(stdscr);
78 /* Draw the separator for the buddylist */
79 if (irssi->buddylistwidth)
80 mvwvline(stdscr, 0, irssi->buddylistwidth,
81 ACS_VLINE | COLOR_PAIR(GNT_COLOR_NORMAL), getmaxy(stdscr) - 1);
83 /* Now the separators for the conversation windows */
84 width = (getmaxx(stdscr) - irssi->buddylistwidth) / irssi->horiz;
85 height = (getmaxy(stdscr) - 1) / irssi->vert;
86 for (x = 1; x < irssi->horiz; x++) {
87 mvwvline(stdscr, 0, irssi->buddylistwidth + x * width,
88 ACS_VLINE | COLOR_PAIR(GNT_COLOR_NORMAL), getmaxy(stdscr) - 1);
91 for (y = 1; y < irssi->vert; y++) {
92 mvwhline(stdscr, y * height, irssi->buddylistwidth + 1, ACS_HLINE | COLOR_PAIR(GNT_COLOR_NORMAL),
93 getmaxx(stdscr) - irssi->buddylistwidth);
94 for (x = 1; x < irssi->horiz; x++) {
95 mvwaddch(stdscr, y * height, x * width + irssi->buddylistwidth, ACS_PLUS | COLOR_PAIR(GNT_COLOR_NORMAL));
97 if (irssi->buddylistwidth)
98 mvwaddch(stdscr, y * height, irssi->buddylistwidth, ACS_LTEE | COLOR_PAIR(GNT_COLOR_NORMAL));
102 static gboolean
103 is_budddylist(GntWidget *win)
105 const char *name = gnt_widget_get_name(win);
106 if (name && strcmp(name, "buddylist") == 0)
107 return TRUE;
108 return FALSE;
111 static void
112 remove_border_set_position_size(GntWM *wm, GntWidget *win, int x, int y, int w, int h)
114 gnt_box_set_toplevel(GNT_BOX(win), FALSE);
115 GNT_WIDGET_SET_FLAGS(win, GNT_WIDGET_CAN_TAKE_FOCUS);
117 gnt_widget_set_position(win, x, y);
118 mvwin(win->window, y, x);
119 gnt_widget_set_size(win, (w < 0) ? -1 : w + 2, h + 2);
122 static void
123 irssi_new_window(GntWM *wm, GntWidget *win)
125 const char *name;
126 int x, y, w, h;
128 name = gnt_widget_get_name(win);
129 if (!name || !strstr(name, "conversation-window")) {
130 if (!GNT_IS_MENU(win) && !GNT_WIDGET_IS_FLAG_SET(win, GNT_WIDGET_TRANSIENT)) {
131 if ((!name || strcmp(name, "buddylist"))) {
132 gnt_widget_get_size(win, &w, &h);
133 x = (getmaxx(stdscr) - w) / 2;
134 y = (getmaxy(stdscr) - h) / 2;
135 gnt_widget_set_position(win, x, y);
136 mvwin(win->window, y, x);
137 } else {
138 remove_border_set_position_size(wm, win, 0, 0, -1, getmaxy(stdscr) - 1);
139 gnt_widget_get_size(win, &((Irssi*)wm)->buddylistwidth, NULL);
140 draw_line_separators((Irssi*)wm);
143 org_new_window(wm, win);
144 return;
147 /* The window we have here is a conversation window. */
149 /* XXX: There should be some way to remember which frame a conversation window
150 * was in the last time. Perhaps save them in some ~/.gntpositionirssi or some
151 * such. */
152 get_xywh_for_frame((Irssi*)wm, 0, 0, &x, &y, &w, &h);
153 remove_border_set_position_size(wm, win, x, y, w, h);
154 org_new_window(wm, win);
157 static void
158 irssi_window_resized(GntWM *wm, GntNode *node)
160 if (!is_budddylist(node->me))
161 return;
163 gnt_widget_get_size(node->me, &((Irssi*)wm)->buddylistwidth, NULL);
164 draw_line_separators((Irssi*)wm);
167 static gboolean
168 irssi_close_window(GntWM *wm, GntWidget *win)
170 if (is_budddylist(win))
171 ((Irssi*)wm)->buddylistwidth = 0;
172 return FALSE;
175 static gboolean
176 update_conv_window_title(GntNode *node)
178 char title[256];
179 snprintf(title, sizeof(title), "%d: %s",
180 GPOINTER_TO_INT(g_object_get_data(G_OBJECT(node->me), "irssi-index")) + 1,
181 GNT_BOX(node->me)->title);
182 wbkgdset(node->window, '\0' | COLOR_PAIR(gnt_widget_has_focus(node->me) ? GNT_COLOR_TITLE : GNT_COLOR_TITLE_D));
183 mvwaddstr(node->window, 0, 0, title);
184 if (!gnt_is_refugee()) {
185 update_panels();
186 doupdate();
188 return FALSE;
191 static void
192 irssi_update_window(GntWM *wm, GntNode *node)
194 GntWidget *win = node->me;
195 const char *name = gnt_widget_get_name(win);
196 if (!name || !GNT_IS_BOX(win) || !strstr(name, "conversation-window"))
197 return;
198 g_object_set_data(G_OBJECT(win), "irssi-index", GINT_TO_POINTER(g_list_index(wm->cws->list, win)));
199 g_timeout_add(0, (GSourceFunc)update_conv_window_title, node);
202 static void
203 find_window_position(Irssi *irssi, GntWidget *win, int *h, int *v)
205 int x, y;
206 int width, height;
208 gnt_widget_get_position(win, &x, &y);
209 width = (getmaxx(stdscr) - irssi->buddylistwidth) / irssi->horiz;
210 height = (getmaxy(stdscr) - 1) / irssi->vert;
212 if (h)
213 *h = (x - irssi->buddylistwidth) / width;
214 if (v)
215 *v = y / height;
218 static gboolean
219 move_direction(GntBindable *bindable, GList *list)
221 GntWM *wm = GNT_WM(bindable);
222 Irssi *irssi = (Irssi*)wm;
223 int vert, hor;
224 int x, y, w, h;
225 GntWidget *win;
227 if (wm->cws->ordered == NULL || is_budddylist(win = GNT_WIDGET(wm->cws->ordered->data)))
228 return FALSE;
230 find_window_position(irssi, win, &hor, &vert);
232 switch (GPOINTER_TO_INT(list->data)) {
233 case 'k':
234 vert = MAX(0, vert - 1);
235 break;
236 case 'j':
237 vert = MIN(vert + 1, irssi->vert - 1);
238 break;
239 case 'l':
240 hor = MIN(hor + 1, irssi->horiz - 1);
241 break;
242 case 'h':
243 hor = MAX(0, hor - 1);
244 break;
246 get_xywh_for_frame(irssi, hor, vert, &x, &y, &w, &h);
247 gnt_wm_move_window(wm, win, x, y);
248 gnt_wm_resize_window(wm, win, w, h);
249 return TRUE;
252 static void
253 irssi_terminal_refresh(GntWM *wm)
255 draw_line_separators((Irssi*)wm);
258 static void
259 irssi_class_init(IrssiClass *klass)
261 GntWMClass *pclass = GNT_WM_CLASS(klass);
263 org_new_window = pclass->new_window;
265 pclass->new_window = irssi_new_window;
266 pclass->window_resized = irssi_window_resized;
267 pclass->close_window = irssi_close_window;
268 pclass->window_update = irssi_update_window;
269 pclass->terminal_refresh = irssi_terminal_refresh;
271 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "move-up", move_direction,
272 "\033" "K", GINT_TO_POINTER('k'), NULL);
273 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "move-down", move_direction,
274 "\033" "J", GINT_TO_POINTER('j'), NULL);
275 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "move-right", move_direction,
276 "\033" "L", GINT_TO_POINTER('l'), NULL);
277 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "move-left", move_direction,
278 "\033" "H", GINT_TO_POINTER('h'), NULL);
280 gnt_style_read_actions(G_OBJECT_CLASS_TYPE(klass), GNT_BINDABLE_CLASS(klass));
281 GNTDEBUG;
284 void gntwm_init(GntWM **wm)
286 char *style = NULL;
287 Irssi *irssi;
289 irssi = g_object_new(TYPE_IRSSI, NULL);
290 *wm = GNT_WM(irssi);
292 style = gnt_style_get_from_name("irssi", "split-v");
293 irssi->vert = style ? atoi(style) : 1;
294 g_free(style);
296 style = gnt_style_get_from_name("irssi", "split-h");
297 irssi->horiz = style ? atoi(style) : 1;
298 g_free(style);
300 irssi->vert = MAX(irssi->vert, 1);
301 irssi->horiz = MAX(irssi->horiz, 1);
303 irssi->buddylistwidth = 0;
306 GType irssi_get_gtype(void)
308 static GType type = 0;
310 if(type == 0) {
311 static const GTypeInfo info = {
312 sizeof(IrssiClass),
313 NULL, /* base_init */
314 NULL, /* base_finalize */
315 (GClassInitFunc)irssi_class_init,
316 NULL,
317 NULL, /* class_data */
318 sizeof(Irssi),
319 0, /* n_preallocs */
320 NULL, /* instance_init */
321 NULL
324 type = g_type_register_static(GNT_TYPE_WM,
325 "GntIrssi",
326 &info, 0);
329 return type;