Update to 24f58c58bb8d22c0e8e6c5ce43c536c47b719bc6
[gnt.git] / gntwm.c
blob62380884d2c8b8c0021166373049efaf5c482317
1 /**
2 * GNT - The GLib Ncurses Toolkit
4 * GNT is the legal property of its developers, whose names are too numerous
5 * to list here. Please refer to the COPYRIGHT file distributed with this
6 * source distribution.
8 * This library is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
23 #include "config.h"
25 #ifdef USE_PYTHON
26 #include <Python.h>
27 #else
28 #define _GNU_SOURCE
29 #if (defined(__APPLE__) || defined(__unix__)) && !defined(__FreeBSD__)
30 #define _XOPEN_SOURCE_EXTENDED
31 #endif
32 #endif
34 #include <glib.h>
35 #include <glib/gstdio.h>
36 #include <ctype.h>
37 #include <gmodule.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <time.h>
42 #include "gntwm.h"
43 #include "gntstyle.h"
44 #include "gntmarshal.h"
45 #include "gnt.h"
46 #include "gntbox.h"
47 #include "gntbutton.h"
48 #include "gntentry.h"
49 #include "gntfilesel.h"
50 #include "gntlabel.h"
51 #include "gntmenu.h"
52 #include "gnttextview.h"
53 #include "gnttree.h"
54 #include "gntutils.h"
55 #include "gntwindow.h"
57 #define IDLE_CHECK_INTERVAL 5 /* 5 seconds */
59 enum
61 SIG_NEW_WIN,
62 SIG_DECORATE_WIN,
63 SIG_CLOSE_WIN,
64 SIG_CONFIRM_RESIZE,
65 SIG_RESIZED,
66 SIG_CONFIRM_MOVE,
67 SIG_MOVED,
68 SIG_UPDATE_WIN,
69 SIG_GIVE_FOCUS,
70 SIG_KEY_PRESS,
71 SIG_MOUSE_CLICK,
72 SIG_TERMINAL_REFRESH,
73 SIGS
76 static guint signals[SIGS] = { 0 };
77 static void gnt_wm_new_window_real(GntWM *wm, GntWidget *widget);
78 static void gnt_wm_win_resized(GntWM *wm, GntNode *node);
79 static void gnt_wm_win_moved(GntWM *wm, GntNode *node);
80 static void gnt_wm_give_focus(GntWM *wm, GntWidget *widget);
81 static void update_window_in_list(GntWM *wm, GntWidget *wid);
82 static void shift_window(GntWM *wm, GntWidget *widget, int dir);
83 static gboolean workspace_next(GntBindable *wm, GList *n);
84 static gboolean workspace_prev(GntBindable *wm, GList *n);
86 #ifndef NO_WIDECHAR
87 static int widestringwidth(wchar_t *wide);
88 #endif
90 static void ensure_normal_mode(GntWM *wm);
91 static gboolean write_already(gpointer data);
92 static int write_timeout;
93 static time_t last_active_time;
94 static gboolean idle_update;
95 static GList *act = NULL; /* list of WS with unseen activitiy */
96 static gboolean ignore_keys = FALSE;
98 static GList *
99 g_list_bring_to_front(GList *list, gpointer data)
101 list = g_list_remove(list, data);
102 list = g_list_prepend(list, data);
103 return list;
106 static void
107 free_node(gpointer data)
109 GntNode *node = data;
110 hide_panel(node->panel);
111 del_panel(node->panel);
112 g_free(node);
115 void
116 gnt_wm_copy_win(GntWidget *widget, GntNode *node)
118 WINDOW *src, *dst;
119 if (!node)
120 return;
121 src = widget->window;
122 dst = node->window;
123 copywin(src, dst, node->scroll, 0, 0, 0, getmaxy(dst) - 1, getmaxx(dst) - 1, 0);
127 * The following is a workaround for a bug in most versions of ncursesw.
128 * Read about it in: http://article.gmane.org/gmane.comp.lib.ncurses.bugs/2751
130 * In short, if a panel hides one cell of a multi-cell character, then the rest
131 * of the characters in that line get screwed. The workaround here is to erase
132 * any such character preemptively.
134 * Caveat: If a wide character is erased, and the panel above it is moved enough
135 * to expose the entire character, it is not always redrawn.
137 static void
138 work_around_for_ncurses_bug(void)
140 #ifndef NO_WIDECHAR
141 PANEL *panel = NULL;
142 while ((panel = panel_below(panel)) != NULL) {
143 int sx, ex, sy, ey, w, y;
144 cchar_t ch;
145 PANEL *below = panel;
147 sx = panel->win->_begx;
148 ex = panel->win->_maxx + sx;
149 sy = panel->win->_begy;
150 ey = panel->win->_maxy + sy;
152 while ((below = panel_below(below)) != NULL) {
153 if (sy > below->win->_begy + below->win->_maxy ||
154 ey < below->win->_begy)
155 continue;
156 if (sx > below->win->_begx + below->win->_maxx ||
157 ex < below->win->_begx)
158 continue;
159 for (y = MAX(sy, below->win->_begy); y <= MIN(ey, below->win->_begy + below->win->_maxy); y++) {
160 if (mvwin_wch(below->win, y - below->win->_begy, sx - 1 - below->win->_begx, &ch) != OK)
161 goto right;
162 w = widestringwidth(ch.chars);
163 if (w > 1 && (ch.attr & 1)) {
164 ch.chars[0] = ' ';
165 ch.attr &= ~ A_CHARTEXT;
166 mvwadd_wch(below->win, y - below->win->_begy, sx - 1 - below->win->_begx, &ch);
167 touchline(below->win, y - below->win->_begy, 1);
169 right:
170 if (mvwin_wch(below->win, y - below->win->_begy, ex + 1 - below->win->_begx, &ch) != OK)
171 continue;
172 w = widestringwidth(ch.chars);
173 if (w > 1 && !(ch.attr & 1)) {
174 ch.chars[0] = ' ';
175 ch.attr &= ~ A_CHARTEXT;
176 mvwadd_wch(below->win, y - below->win->_begy, ex + 1 - below->win->_begx, &ch);
177 touchline(below->win, y - below->win->_begy, 1);
182 #endif
185 static void
186 update_act_msg(void)
188 GntWidget *label;
189 GList *iter;
190 static GntWidget *message = NULL;
191 GString *text = g_string_new("act: ");
192 if (message)
193 gnt_widget_destroy(message);
194 if (g_list_length(act) == 0)
195 return;
196 for (iter = act; iter; iter = iter->next) {
197 GntWS *ws = iter->data;
198 g_string_append_printf(text, "%s, ", gnt_ws_get_name(ws));
200 g_string_erase(text, text->len - 2, 2);
201 message = gnt_vbox_new(FALSE);
202 label = gnt_label_new_with_format(text->str, GNT_TEXT_FLAG_BOLD | GNT_TEXT_FLAG_HIGHLIGHT);
203 GNT_WIDGET_UNSET_FLAGS(GNT_BOX(message), GNT_WIDGET_CAN_TAKE_FOCUS);
204 GNT_WIDGET_SET_FLAGS(GNT_BOX(message), GNT_WIDGET_TRANSIENT);
205 gnt_box_add_widget(GNT_BOX(message), label);
206 gnt_widget_set_name(message, "wm-message");
207 gnt_widget_set_position(message, 0, 0);
208 gnt_widget_draw(message);
209 g_string_free(text, TRUE);
212 static gboolean
213 update_screen(GntWM *wm)
215 if (wm->mode == GNT_KP_MODE_WAIT_ON_CHILD)
216 return TRUE;
218 if (wm->menu) {
219 GntMenu *top = wm->menu;
220 while (top) {
221 GntNode *node = g_hash_table_lookup(wm->nodes, top);
222 if (node)
223 top_panel(node->panel);
224 top = top->submenu;
227 work_around_for_ncurses_bug();
228 update_panels();
229 doupdate();
230 return TRUE;
233 static gboolean
234 sanitize_position(GntWidget *widget, int *x, int *y, gboolean m)
236 int X_MAX = getmaxx(stdscr);
237 int Y_MAX = getmaxy(stdscr) - 1;
238 int w, h;
239 int nx, ny;
240 gboolean changed = FALSE;
241 GntWindowFlags flags = GNT_IS_WINDOW(widget) ?
242 gnt_window_get_maximize(GNT_WINDOW(widget)) : 0;
244 gnt_widget_get_size(widget, &w, &h);
245 if (x) {
246 if (m && (flags & GNT_WINDOW_MAXIMIZE_X) && *x != 0) {
247 *x = 0;
248 changed = TRUE;
249 } else if (*x + w > X_MAX) {
250 nx = MAX(0, X_MAX - w);
251 if (nx != *x) {
252 *x = nx;
253 changed = TRUE;
257 if (y) {
258 if (m && (flags & GNT_WINDOW_MAXIMIZE_Y) && *y != 0) {
259 *y = 0;
260 changed = TRUE;
261 } else if (*y + h > Y_MAX) {
262 ny = MAX(0, Y_MAX - h);
263 if (ny != *y) {
264 *y = ny;
265 changed = TRUE;
269 return changed;
272 static void
273 refresh_node(GntWidget *widget, GntNode *node, gpointer m)
275 int x, y, w, h;
276 int nw, nh;
278 int X_MAX = getmaxx(stdscr);
279 int Y_MAX = getmaxy(stdscr) - 1;
281 GntWindowFlags flags = 0;
283 if (m && GNT_IS_WINDOW(widget)) {
284 flags = gnt_window_get_maximize(GNT_WINDOW(widget));
287 gnt_widget_get_position(widget, &x, &y);
288 gnt_widget_get_size(widget, &w, &h);
290 if (sanitize_position(widget, &x, &y, !!m))
291 gnt_screen_move_widget(widget, x, y);
293 if (flags & GNT_WINDOW_MAXIMIZE_X)
294 nw = X_MAX;
295 else
296 nw = MIN(w, X_MAX);
298 if (flags & GNT_WINDOW_MAXIMIZE_Y)
299 nh = Y_MAX;
300 else
301 nh = MIN(h, Y_MAX);
303 if (nw != w || nh != h)
304 gnt_screen_resize_widget(widget, nw, nh);
307 static void
308 read_window_positions(GntWM *wm)
310 #if GLIB_CHECK_VERSION(2,6,0)
311 GKeyFile *gfile = g_key_file_new();
312 char *filename = g_build_filename(g_get_home_dir(), ".gntpositions", NULL);
313 GError *error = NULL;
314 char **keys;
315 gsize nk;
317 if (!g_key_file_load_from_file(gfile, filename, G_KEY_FILE_NONE, &error)) {
318 g_printerr("GntWM: %s\n", error->message);
319 g_error_free(error);
320 g_free(filename);
321 return;
324 keys = g_key_file_get_keys(gfile, "positions", &nk, &error);
325 if (error) {
326 g_printerr("GntWM: %s\n", error->message);
327 g_error_free(error);
328 error = NULL;
329 } else {
330 while (nk--) {
331 char *title = keys[nk];
332 gsize l;
333 char **coords = g_key_file_get_string_list(gfile, "positions", title, &l, NULL);
334 if (l == 2) {
335 int x = atoi(coords[0]);
336 int y = atoi(coords[1]);
337 GntPosition *p = g_new0(GntPosition, 1);
338 p->x = x;
339 p->y = y;
340 g_hash_table_replace(wm->positions, g_strdup(title + 1), p);
341 } else {
342 g_printerr("GntWM: Invalid number of arguments for positioing a window.\n");
344 g_strfreev(coords);
346 g_strfreev(keys);
349 g_free(filename);
350 g_key_file_free(gfile);
351 #endif
354 static gboolean check_idle(gpointer n)
356 if (idle_update) {
357 time(&last_active_time);
358 idle_update = FALSE;
360 return TRUE;
363 static void
364 gnt_wm_init(GTypeInstance *instance, gpointer class)
366 GntWM *wm = GNT_WM(instance);
367 wm->workspaces = NULL;
368 wm->name_places = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
369 wm->title_places = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
370 gnt_style_read_workspaces(wm);
371 if (wm->workspaces == NULL) {
372 wm->cws = gnt_ws_new("default");
373 gnt_wm_add_workspace(wm, wm->cws);
374 } else {
375 wm->cws = wm->workspaces->data;
377 wm->event_stack = FALSE;
378 wm->tagged = NULL;
379 wm->windows = NULL;
380 wm->actions = NULL;
381 wm->nodes = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, free_node);
382 wm->positions = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
383 if (gnt_style_get_bool(GNT_STYLE_REMPOS, TRUE))
384 read_window_positions(wm);
385 g_timeout_add(IDLE_CHECK_INTERVAL * 1000, check_idle, NULL);
386 time(&last_active_time);
387 gnt_wm_switch_workspace(wm, 0);
390 static void
391 switch_window(GntWM *wm, int direction, gboolean urgent)
393 GntWidget *w = NULL, *wid = NULL;
394 int pos, orgpos;
396 if (wm->_list.window || wm->menu)
397 return;
399 if (!wm->cws->ordered || !wm->cws->ordered->next)
400 return;
402 if (wm->mode != GNT_KP_MODE_NORMAL) {
403 ensure_normal_mode(wm);
406 w = wm->cws->ordered->data;
407 orgpos = pos = g_list_index(wm->cws->list, w);
409 do {
410 pos += direction;
412 if (pos < 0) {
413 wid = g_list_last(wm->cws->list)->data;
414 pos = g_list_length(wm->cws->list) - 1;
415 } else if (pos >= g_list_length(wm->cws->list)) {
416 wid = wm->cws->list->data;
417 pos = 0;
418 } else
419 wid = g_list_nth_data(wm->cws->list, pos);
420 } while (urgent && !GNT_WIDGET_IS_FLAG_SET(wid, GNT_WIDGET_URGENT) && pos != orgpos);
422 gnt_wm_raise_window(wm, wid);
425 static gboolean
426 window_next(GntBindable *bindable, GList *null)
428 GntWM *wm = GNT_WM(bindable);
429 switch_window(wm, 1, FALSE);
430 return TRUE;
433 static gboolean
434 window_prev(GntBindable *bindable, GList *null)
436 GntWM *wm = GNT_WM(bindable);
437 switch_window(wm, -1, FALSE);
438 return TRUE;
441 static gboolean
442 switch_window_n(GntBindable *bind, GList *list)
444 GntWM *wm = GNT_WM(bind);
445 GList *l;
446 int n;
448 if (!wm->cws->ordered)
449 return TRUE;
451 if (list)
452 n = GPOINTER_TO_INT(list->data);
453 else
454 n = 0;
456 if ((l = g_list_nth(wm->cws->list, n)) != NULL)
458 gnt_wm_raise_window(wm, l->data);
461 return TRUE;
464 static gboolean
465 window_scroll_up(GntBindable *bindable, GList *null)
467 GntWM *wm = GNT_WM(bindable);
468 GntWidget *window;
469 GntNode *node;
471 if (!wm->cws->ordered)
472 return TRUE;
474 window = wm->cws->ordered->data;
475 node = g_hash_table_lookup(wm->nodes, window);
476 if (!node)
477 return TRUE;
479 if (node->scroll) {
480 node->scroll--;
481 gnt_wm_copy_win(window, node);
482 update_screen(wm);
484 return TRUE;
487 static gboolean
488 window_scroll_down(GntBindable *bindable, GList *null)
490 GntWM *wm = GNT_WM(bindable);
491 GntWidget *window;
492 GntNode *node;
493 int w, h;
495 if (!wm->cws->ordered)
496 return TRUE;
498 window = wm->cws->ordered->data;
499 node = g_hash_table_lookup(wm->nodes, window);
500 if (!node)
501 return TRUE;
503 gnt_widget_get_size(window, &w, &h);
504 if (h - node->scroll > getmaxy(node->window)) {
505 node->scroll++;
506 gnt_wm_copy_win(window, node);
507 update_screen(wm);
509 return TRUE;
512 static gboolean
513 window_close(GntBindable *bindable, GList *null)
515 GntWM *wm = GNT_WM(bindable);
517 if (wm->_list.window)
518 return TRUE;
520 if (wm->cws->ordered) {
521 gnt_widget_destroy(wm->cws->ordered->data);
522 ensure_normal_mode(wm);
525 return TRUE;
528 static void
529 destroy__list(GntWidget *widget, GntWM *wm)
531 wm->_list.window = NULL;
532 wm->_list.tree = NULL;
533 wm->windows = NULL;
534 wm->actions = NULL;
535 update_screen(wm);
538 static void
539 setup__list(GntWM *wm)
541 GntWidget *tree, *win;
542 ensure_normal_mode(wm);
543 win = wm->_list.window = gnt_box_new(FALSE, FALSE);
544 gnt_box_set_toplevel(GNT_BOX(win), TRUE);
545 gnt_box_set_pad(GNT_BOX(win), 0);
546 GNT_WIDGET_SET_FLAGS(win, GNT_WIDGET_TRANSIENT);
548 tree = wm->_list.tree = gnt_tree_new();
549 gnt_box_add_widget(GNT_BOX(win), tree);
551 g_signal_connect(G_OBJECT(win), "destroy", G_CALLBACK(destroy__list), wm);
554 static void
555 window_list_activate(GntTree *tree, GntWM *wm)
557 GntBindable *sel = gnt_tree_get_selection_data(GNT_TREE(tree));
559 gnt_widget_destroy(wm->_list.window);
561 if (!sel)
562 return;
564 if (GNT_IS_WS(sel)) {
565 gnt_wm_switch_workspace(wm, g_list_index(wm->workspaces, sel));
566 } else {
567 gnt_wm_raise_window(wm, GNT_WIDGET(sel));
571 static void
572 populate_window_list(GntWM *wm, gboolean workspace)
574 GList *iter;
575 GntTree *tree = GNT_TREE(wm->windows->tree);
576 if (!workspace) {
577 for (iter = wm->cws->list; iter; iter = iter->next) {
578 GntBox *box = GNT_BOX(iter->data);
580 gnt_tree_add_row_last(tree, box,
581 gnt_tree_create_row(tree, box->title), NULL);
582 update_window_in_list(wm, GNT_WIDGET(box));
584 } else {
585 GList *ws = wm->workspaces;
586 for (; ws; ws = ws->next) {
587 gnt_tree_add_row_last(tree, ws->data,
588 gnt_tree_create_row(tree, gnt_ws_get_name(GNT_WS(ws->data))), NULL);
589 for (iter = GNT_WS(ws->data)->list; iter; iter = iter->next) {
590 GntBox *box = GNT_BOX(iter->data);
592 gnt_tree_add_row_last(tree, box,
593 gnt_tree_create_row(tree, box->title), ws->data);
594 update_window_in_list(wm, GNT_WIDGET(box));
600 static gboolean
601 window_list_key_pressed(GntWidget *widget, const char *text, GntWM *wm)
603 if (text[1] == 0 && wm->cws->ordered) {
604 GntBindable *sel = gnt_tree_get_selection_data(GNT_TREE(widget));
605 switch (text[0]) {
606 case '-':
607 case ',':
608 if (GNT_IS_WS(sel)) {
609 /* reorder the workspace. */
610 } else
611 shift_window(wm, GNT_WIDGET(sel), -1);
612 break;
613 case '=':
614 case '.':
615 if (GNT_IS_WS(sel)) {
616 /* reorder the workspace. */
617 } else
618 shift_window(wm, GNT_WIDGET(sel), 1);
619 break;
620 default:
621 return FALSE;
623 gnt_tree_remove_all(GNT_TREE(widget));
624 populate_window_list(wm, GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "workspace")));
625 gnt_tree_set_selected(GNT_TREE(widget), sel);
626 return TRUE;
628 return FALSE;
631 static void
632 list_of_windows(GntWM *wm, gboolean workspace)
634 GntWidget *tree, *win;
635 setup__list(wm);
636 wm->windows = &wm->_list;
638 win = wm->windows->window;
639 tree = wm->windows->tree;
641 gnt_box_set_title(GNT_BOX(win), workspace ? "Workspace List" : "Window List");
643 populate_window_list(wm, workspace);
645 if (wm->cws->ordered)
646 gnt_tree_set_selected(GNT_TREE(tree), wm->cws->ordered->data);
647 else if (workspace)
648 gnt_tree_set_selected(GNT_TREE(tree), wm->cws);
650 g_signal_connect(G_OBJECT(tree), "activate", G_CALLBACK(window_list_activate), wm);
651 g_signal_connect(G_OBJECT(tree), "key_pressed", G_CALLBACK(window_list_key_pressed), wm);
652 g_object_set_data(G_OBJECT(tree), "workspace", GINT_TO_POINTER(workspace));
654 gnt_tree_set_col_width(GNT_TREE(tree), 0, getmaxx(stdscr) / 3);
655 gnt_widget_set_size(tree, 0, getmaxy(stdscr) / 2);
656 gnt_widget_set_position(win, getmaxx(stdscr) / 3, getmaxy(stdscr) / 4);
658 gnt_widget_show(win);
661 static gboolean
662 window_list(GntBindable *bindable, GList *null)
664 GntWM *wm = GNT_WM(bindable);
666 if (wm->_list.window || wm->menu)
667 return TRUE;
669 if (!wm->cws->ordered)
670 return TRUE;
672 list_of_windows(wm, FALSE);
674 return TRUE;
677 static void
678 dump_file_save(GntFileSel *fs, const char *path, const char *f, gpointer n)
680 FILE *file;
681 int x, y;
682 chtype old = 0, now = 0;
683 struct {
684 char ascii;
685 char *unicode;
686 } unis[] = {
687 {'q', "&#x2500;"},
688 {'t', "&#x251c;"},
689 {'u', "&#x2524;"},
690 {'x', "&#x2502;"},
691 {'-', "&#x2191;"},
692 {'.', "&#x2193;"},
693 {'l', "&#x250c;"},
694 {'k', "&#x2510;"},
695 {'m', "&#x2514;"},
696 {'j', "&#x2518;"},
697 {'a', "&#x2592;"},
698 {'n', "&#x253c;"},
699 {'w', "&#x252c;"},
700 {'v', "&#x2534;"},
701 {'\0', NULL}
704 gnt_widget_destroy(GNT_WIDGET(fs));
706 if ((file = g_fopen(path, "w+")) == NULL) {
707 return;
710 fprintf(file, "<head>\n <meta http-equiv='Content-Type' content='text/html; charset=utf-8' />\n</head>\n<body>\n");
711 fprintf(file, "<pre>");
712 for (y = 0; y < getmaxy(stdscr); y++) {
713 for (x = 0; x < getmaxx(stdscr); x++) {
714 char ch[2] = {0, 0}, *print;
715 #ifdef NO_WIDECHAR
716 now = mvwinch(curscr, y, x);
717 ch[0] = now & A_CHARTEXT;
718 now ^= ch[0];
719 #else
720 cchar_t wch;
721 char unicode[12];
722 mvwin_wch(curscr, y, x, &wch);
723 now = wch.attr;
724 ch[0] = (char)(wch.chars[0] & 0xff);
725 #endif
727 #define CHECK(attr, start, end) \
728 do \
730 if (now & attr) \
732 if (!(old & attr)) \
733 fprintf(file, "%s", start); \
735 else if (old & attr) \
737 fprintf(file, "%s", end); \
739 } while (0)
741 CHECK(A_BOLD, "<b>", "</b>");
742 CHECK(A_UNDERLINE, "<u>", "</u>");
743 CHECK(A_BLINK, "<blink>", "</blink>");
745 if ((now & A_COLOR) != (old & A_COLOR) ||
746 (now & A_REVERSE) != (old & A_REVERSE))
748 int ret;
749 short fgp, bgp, r, g, b;
750 struct
752 int r, g, b;
753 } fg, bg;
755 ret = pair_content(PAIR_NUMBER(now & A_COLOR), &fgp, &bgp);
756 if (fgp == -1)
757 fgp = COLOR_BLACK;
758 if (bgp == -1)
759 bgp = COLOR_WHITE;
760 if (now & A_REVERSE)
762 short tmp = fgp;
763 fgp = bgp;
764 bgp = tmp;
766 ret = color_content(fgp, &r, &g, &b);
767 fg.r = r; fg.b = b; fg.g = g;
768 ret = color_content(bgp, &r, &g, &b);
769 bg.r = r; bg.b = b; bg.g = g;
770 #define ADJUST(x) (x = x * 255 / 1000)
771 ADJUST(fg.r);
772 ADJUST(fg.g);
773 ADJUST(fg.b);
774 ADJUST(bg.r);
775 ADJUST(bg.b);
776 ADJUST(bg.g);
778 if (x) fprintf(file, "</span>");
779 fprintf(file, "<span style=\"background:#%02x%02x%02x;color:#%02x%02x%02x\">",
780 bg.r, bg.g, bg.b, fg.r, fg.g, fg.b);
782 print = ch;
783 #ifndef NO_WIDECHAR
784 if (wch.chars[0] > 255) {
785 snprintf(unicode, sizeof(unicode), "&#x%x;", (unsigned int)wch.chars[0]);
786 print = unicode;
788 #endif
789 if (now & A_ALTCHARSET)
791 int u;
792 for (u = 0; unis[u].ascii; u++) {
793 if (ch[0] == unis[u].ascii) {
794 print = unis[u].unicode;
795 break;
798 if (!unis[u].ascii)
799 print = " ";
801 if (ch[0] == '&')
802 fprintf(file, "&amp;");
803 else if (ch[0] == '<')
804 fprintf(file, "&lt;");
805 else if (ch[0] == '>')
806 fprintf(file, "&gt;");
807 else
808 fprintf(file, "%s", print);
809 old = now;
811 fprintf(file, "</span>\n");
812 old = 0;
814 fprintf(file, "</pre>\n</body>");
815 fclose(file);
818 static void
819 dump_file_cancel(GntWidget *w, GntFileSel *fs)
821 gnt_widget_destroy(GNT_WIDGET(fs));
824 static gboolean
825 dump_screen(GntBindable *b, GList *null)
827 GntWidget *window = gnt_file_sel_new();
828 GntFileSel *sel = GNT_FILE_SEL(window);
830 g_object_set(G_OBJECT(window), "vertical", TRUE, NULL);
831 gnt_box_add_widget(GNT_BOX(window), gnt_label_new("Please enter the filename to save the screenshot."));
832 gnt_box_set_title(GNT_BOX(window), "Save Screenshot...");
834 gnt_file_sel_set_suggested_filename(sel, "dump.html");
835 g_signal_connect(G_OBJECT(sel), "file_selected", G_CALLBACK(dump_file_save), NULL);
836 g_signal_connect(G_OBJECT(sel->cancel), "activate", G_CALLBACK(dump_file_cancel), sel);
837 gnt_widget_show(window);
838 return TRUE;
841 static void
842 shift_window(GntWM *wm, GntWidget *widget, int dir)
844 GList *all = wm->cws->list;
845 GList *list = g_list_find(all, widget);
846 int length, pos;
847 if (!list)
848 return;
850 length = g_list_length(all);
851 pos = g_list_position(all, list);
853 pos += dir;
854 if (dir > 0)
855 pos++;
857 if (pos < 0)
858 pos = length;
859 else if (pos > length)
860 pos = 0;
862 all = g_list_insert(all, widget, pos);
863 all = g_list_delete_link(all, list);
864 wm->cws->list = all;
865 gnt_ws_draw_taskbar(wm->cws, FALSE);
868 static gboolean
869 shift_left(GntBindable *bindable, GList *null)
871 GntWM *wm = GNT_WM(bindable);
872 if (wm->_list.window)
873 return TRUE;
875 if(!wm->cws->ordered)
876 return FALSE;
878 shift_window(wm, wm->cws->ordered->data, -1);
879 return TRUE;
882 static gboolean
883 shift_right(GntBindable *bindable, GList *null)
885 GntWM *wm = GNT_WM(bindable);
887 if (wm->_list.window)
888 return TRUE;
890 if(!wm->cws->ordered)
891 return FALSE;
893 shift_window(wm, wm->cws->ordered->data, 1);
894 return TRUE;
897 static void
898 action_list_activate(GntTree *tree, GntWM *wm)
900 GntAction *action = gnt_tree_get_selection_data(tree);
901 action->callback();
902 gnt_widget_destroy(wm->_list.window);
905 static int
906 compare_action(gconstpointer p1, gconstpointer p2)
908 const GntAction *a1 = p1;
909 const GntAction *a2 = p2;
911 return g_utf8_collate(a1->label, a2->label);
914 static gboolean
915 list_actions(GntBindable *bindable, GList *null)
917 GntWidget *tree, *win;
918 GList *iter;
919 GntWM *wm = GNT_WM(bindable);
920 if (wm->_list.window || wm->menu)
921 return TRUE;
923 if (wm->acts == NULL)
924 return TRUE;
926 setup__list(wm);
927 wm->actions = &wm->_list;
929 win = wm->actions->window;
930 tree = wm->actions->tree;
932 gnt_box_set_title(GNT_BOX(win), "Actions");
933 GNT_WIDGET_SET_FLAGS(tree, GNT_WIDGET_NO_BORDER);
934 /* XXX: Do we really want this? */
935 gnt_tree_set_compare_func(GNT_TREE(tree), compare_action);
937 for (iter = wm->acts; iter; iter = iter->next) {
938 GntAction *action = iter->data;
939 gnt_tree_add_row_last(GNT_TREE(tree), action,
940 gnt_tree_create_row(GNT_TREE(tree), action->label), NULL);
942 g_signal_connect(G_OBJECT(tree), "activate", G_CALLBACK(action_list_activate), wm);
943 gnt_widget_set_size(tree, 0, g_list_length(wm->acts));
944 gnt_widget_set_position(win, 0, getmaxy(stdscr) - 3 - g_list_length(wm->acts));
946 gnt_widget_show(win);
947 return TRUE;
950 #ifndef NO_WIDECHAR
951 static int
952 widestringwidth(wchar_t *wide)
954 int len, ret;
955 char *string;
957 len = wcstombs(NULL, wide, 0) + 1;
958 string = g_new0(char, len);
959 wcstombs(string, wide, len);
960 ret = string ? gnt_util_onscreen_width(string, NULL) : 1;
961 g_free(string);
962 return ret;
964 #endif
966 /* Returns the onscreen width of the character at the position */
967 static int
968 reverse_char(WINDOW *d, int y, int x, gboolean set)
970 #define DECIDE(ch) (set ? ((ch) | A_REVERSE) : ((ch) & ~A_REVERSE))
972 #ifdef NO_WIDECHAR
973 chtype ch;
974 ch = mvwinch(d, y, x);
975 mvwaddch(d, y, x, DECIDE(ch));
976 return 1;
977 #else
978 cchar_t ch;
979 int wc = 1;
980 if (mvwin_wch(d, y, x, &ch) == OK) {
981 wc = widestringwidth(ch.chars);
982 ch.attr = DECIDE(ch.attr);
983 ch.attr &= WA_ATTRIBUTES; /* XXX: This is a workaround for a bug */
984 mvwadd_wch(d, y, x, &ch);
987 return wc;
988 #endif
991 static void
992 window_reverse(GntWidget *win, gboolean set, GntWM *wm)
994 int i;
995 int w, h;
996 WINDOW *d;
998 if (GNT_WIDGET_IS_FLAG_SET(win, GNT_WIDGET_NO_BORDER))
999 return;
1001 d = win->window;
1002 gnt_widget_get_size(win, &w, &h);
1004 if (gnt_widget_has_shadow(win)) {
1005 --w;
1006 --h;
1009 /* the top and bottom */
1010 for (i = 0; i < w; i += reverse_char(d, 0, i, set));
1011 for (i = 0; i < w; i += reverse_char(d, h-1, i, set));
1013 /* the left and right */
1014 for (i = 0; i < h; i += reverse_char(d, i, 0, set));
1015 for (i = 0; i < h; i += reverse_char(d, i, w-1, set));
1017 gnt_wm_copy_win(win, g_hash_table_lookup(wm->nodes, win));
1018 update_screen(wm);
1021 static void
1022 ensure_normal_mode(GntWM *wm)
1024 if (wm->mode != GNT_KP_MODE_NORMAL) {
1025 if (wm->cws->ordered)
1026 window_reverse(wm->cws->ordered->data, FALSE, wm);
1027 wm->mode = GNT_KP_MODE_NORMAL;
1031 static gboolean
1032 start_move(GntBindable *bindable, GList *null)
1034 GntWM *wm = GNT_WM(bindable);
1035 if (wm->_list.window || wm->menu)
1036 return TRUE;
1037 if (!wm->cws->ordered)
1038 return TRUE;
1040 wm->mode = GNT_KP_MODE_MOVE;
1041 window_reverse(GNT_WIDGET(wm->cws->ordered->data), TRUE, wm);
1043 return TRUE;
1046 static gboolean
1047 start_resize(GntBindable *bindable, GList *null)
1049 GntWM *wm = GNT_WM(bindable);
1050 if (wm->_list.window || wm->menu)
1051 return TRUE;
1052 if (!wm->cws->ordered)
1053 return TRUE;
1055 wm->mode = GNT_KP_MODE_RESIZE;
1056 window_reverse(GNT_WIDGET(wm->cws->ordered->data), TRUE, wm);
1058 return TRUE;
1061 static gboolean
1062 wm_quit(GntBindable *bindable, GList *list)
1064 GntWM *wm = GNT_WM(bindable);
1065 if (write_timeout)
1066 write_already(wm);
1067 g_main_loop_quit(wm->loop);
1068 return TRUE;
1071 static gboolean
1072 return_true(GntWM *wm, GntWidget *w, int *a, int *b)
1074 return TRUE;
1077 static gboolean
1078 refresh_screen(GntBindable *bindable, GList *null)
1080 GntWM *wm = GNT_WM(bindable);
1082 endwin();
1083 refresh();
1085 g_hash_table_foreach(wm->nodes, (GHFunc)refresh_node, GINT_TO_POINTER(TRUE));
1086 g_signal_emit(wm, signals[SIG_TERMINAL_REFRESH], 0);
1087 update_screen(wm);
1088 gnt_ws_draw_taskbar(wm->cws, TRUE);
1089 curs_set(0); /* endwin resets the cursor to normal */
1091 return TRUE;
1094 static gboolean
1095 toggle_clipboard(GntBindable *bindable, GList *n)
1097 static GntWidget *clip;
1098 gchar *text;
1099 int maxx, maxy;
1100 if (clip) {
1101 gnt_widget_destroy(clip);
1102 clip = NULL;
1103 return TRUE;
1105 getmaxyx(stdscr, maxy, maxx);
1106 text = gnt_get_clipboard_string();
1107 clip = gnt_hwindow_new(FALSE);
1108 GNT_WIDGET_SET_FLAGS(clip, GNT_WIDGET_TRANSIENT);
1109 GNT_WIDGET_SET_FLAGS(clip, GNT_WIDGET_NO_BORDER);
1110 gnt_box_set_pad(GNT_BOX(clip), 0);
1111 gnt_box_add_widget(GNT_BOX(clip), gnt_label_new(" "));
1112 gnt_box_add_widget(GNT_BOX(clip), gnt_label_new(text));
1113 gnt_box_add_widget(GNT_BOX(clip), gnt_label_new(" "));
1114 gnt_widget_set_position(clip, 0, 0);
1115 gnt_widget_draw(clip);
1116 g_free(text);
1117 return TRUE;
1120 static void remove_tag(gpointer wid, gpointer wim)
1122 GntWM *wm = GNT_WM(wim);
1123 GntWidget *w = GNT_WIDGET(wid);
1124 wm->tagged = g_list_remove(wm->tagged, w);
1125 mvwhline(w->window, 0, 1, ACS_HLINE | gnt_color_pair(GNT_COLOR_NORMAL), 3);
1126 gnt_widget_draw(w);
1129 static gboolean
1130 tag_widget(GntBindable *b, GList *params)
1132 GntWM *wm = GNT_WM(b);
1133 GntWidget *widget;
1135 if (!wm->cws->ordered)
1136 return FALSE;
1137 widget = wm->cws->ordered->data;
1139 if (g_list_find(wm->tagged, widget)) {
1140 remove_tag(widget, wm);
1141 return TRUE;
1144 wm->tagged = g_list_prepend(wm->tagged, widget);
1145 wbkgdset(widget->window, ' ' | gnt_color_pair(GNT_COLOR_HIGHLIGHT));
1146 mvwprintw(widget->window, 0, 1, "[T]");
1147 gnt_widget_draw(widget);
1148 return TRUE;
1151 static void
1152 widget_move_ws(gpointer wid, gpointer w)
1154 GntWM *wm = GNT_WM(w);
1155 gnt_wm_widget_move_workspace(wm, wm->cws, GNT_WIDGET(wid));
1158 static gboolean
1159 place_tagged(GntBindable *b, GList *params)
1161 GntWM *wm = GNT_WM(b);
1162 g_list_foreach(wm->tagged, widget_move_ws, wm);
1163 g_list_foreach(wm->tagged, remove_tag, wm);
1164 g_list_free(wm->tagged);
1165 wm->tagged = NULL;
1166 return TRUE;
1169 static gboolean
1170 workspace_list(GntBindable *b, GList *params)
1172 GntWM *wm = GNT_WM(b);
1174 if (wm->_list.window || wm->menu)
1175 return TRUE;
1177 list_of_windows(wm, TRUE);
1179 return TRUE;
1182 static gboolean
1183 workspace_new(GntBindable *bindable, GList *null)
1185 GntWM *wm = GNT_WM(bindable);
1186 GntWS *ws = gnt_ws_new(NULL);
1187 gnt_wm_add_workspace(wm, ws);
1188 gnt_wm_switch_workspace(wm, g_list_index(wm->workspaces, ws));
1189 return TRUE;
1192 static gboolean
1193 ignore_keys_start(GntBindable *bindable, GList *n)
1195 GntWM *wm = GNT_WM(bindable);
1197 if(!wm->menu && !wm->_list.window && wm->mode == GNT_KP_MODE_NORMAL){
1198 ignore_keys = TRUE;
1199 return TRUE;
1201 return FALSE;
1204 static gboolean
1205 ignore_keys_end(GntBindable *bindable, GList *n)
1207 return ignore_keys ? !(ignore_keys = FALSE) : FALSE;
1210 static gboolean
1211 window_next_urgent(GntBindable *bindable, GList *n)
1213 GntWM *wm = GNT_WM(bindable);
1214 switch_window(wm, 1, TRUE);
1215 return TRUE;
1218 static gboolean
1219 window_prev_urgent(GntBindable *bindable, GList *n)
1221 GntWM *wm = GNT_WM(bindable);
1222 switch_window(wm, -1, TRUE);
1223 return TRUE;
1226 #ifdef USE_PYTHON
1227 static void
1228 python_script_selected(GntFileSel *fs, const char *path, const char *f, gpointer n)
1230 char *dir = g_path_get_dirname(path);
1231 FILE *file = fopen(path, "r");
1232 PyObject *pp = PySys_GetObject("path"), *dirobj = PyString_FromString(dir);
1234 PyList_Insert(pp, 0, dirobj);
1235 Py_DECREF(dirobj);
1236 PyRun_SimpleFile(file, path);
1237 fclose(file);
1239 if (PyErr_Occurred()) {
1240 PyErr_Print();
1242 g_free(dir);
1244 gnt_widget_destroy(GNT_WIDGET(fs));
1247 static gboolean
1248 run_python(GntBindable *bindable, GList *n)
1250 GntWidget *window = gnt_file_sel_new();
1251 GntFileSel *sel = GNT_FILE_SEL(window);
1253 g_object_set(G_OBJECT(window), "vertical", TRUE, NULL);
1254 gnt_box_add_widget(GNT_BOX(window), gnt_label_new("Please select the python script you want to run."));
1255 gnt_box_set_title(GNT_BOX(window), "Select Python Script...");
1257 g_signal_connect(G_OBJECT(sel), "file_selected", G_CALLBACK(python_script_selected), NULL);
1258 g_signal_connect_swapped(G_OBJECT(sel->cancel), "activate", G_CALLBACK(gnt_widget_destroy), sel);
1259 gnt_widget_show(window);
1260 return TRUE;
1262 #endif /* USE_PYTHON */
1264 static gboolean
1265 help_for_bindable(GntWM *wm, GntBindable *bindable)
1267 gboolean ret = TRUE;
1268 GntBindableClass *klass = GNT_BINDABLE_GET_CLASS(bindable);
1270 if (klass->help_window) {
1271 gnt_wm_raise_window(wm, GNT_WIDGET(klass->help_window));
1272 } else {
1273 ret = gnt_bindable_build_help_window(bindable);
1275 return ret;
1278 static gboolean
1279 help_for_wm(GntBindable *bindable, GList *null)
1281 return help_for_bindable(GNT_WM(bindable),bindable);
1284 static gboolean
1285 help_for_window(GntBindable *bindable, GList *null)
1287 GntWM *wm = GNT_WM(bindable);
1288 GntWidget *widget;
1290 if(!wm->cws->ordered)
1291 return FALSE;
1293 widget = wm->cws->ordered->data;
1295 return help_for_bindable(wm,GNT_BINDABLE(widget));
1298 static gboolean
1299 help_for_widget(GntBindable *bindable, GList *null)
1301 GntWM *wm = GNT_WM(bindable);
1302 GntWidget *widget;
1304 if (!wm->cws->ordered)
1305 return TRUE;
1307 widget = wm->cws->ordered->data;
1308 if (!GNT_IS_BOX(widget))
1309 return TRUE;
1311 return help_for_bindable(wm, GNT_BINDABLE(GNT_BOX(widget)->active));
1314 static void
1315 accumulate_windows(gpointer window, gpointer node, gpointer p)
1317 GList *list = *(GList**)p;
1318 list = g_list_prepend(list, window);
1319 *(GList**)p = list;
1322 static void
1323 gnt_wm_destroy(GObject *obj)
1325 GntWM *wm = GNT_WM(obj);
1326 GList *list = NULL;
1327 g_hash_table_foreach(wm->nodes, accumulate_windows, &list);
1328 g_list_foreach(list, (GFunc)gnt_widget_destroy, NULL);
1329 g_list_free(list);
1330 g_hash_table_destroy(wm->nodes);
1331 wm->nodes = NULL;
1333 while (wm->workspaces) {
1334 g_object_unref(wm->workspaces->data);
1335 wm->workspaces = g_list_delete_link(wm->workspaces, wm->workspaces);
1337 #ifdef USE_PYTHON
1338 Py_Finalize();
1339 #endif
1342 static void
1343 gnt_wm_class_init(GntWMClass *klass)
1345 int i;
1346 GObjectClass *gclass = G_OBJECT_CLASS(klass);
1347 char key[32];
1349 gclass->dispose = gnt_wm_destroy;
1351 klass->new_window = gnt_wm_new_window_real;
1352 klass->decorate_window = NULL;
1353 klass->close_window = NULL;
1354 klass->window_resize_confirm = return_true;
1355 klass->window_resized = gnt_wm_win_resized;
1356 klass->window_move_confirm = return_true;
1357 klass->window_moved = gnt_wm_win_moved;
1358 klass->window_update = NULL;
1359 klass->key_pressed = NULL;
1360 klass->mouse_clicked = NULL;
1361 klass->give_focus = gnt_wm_give_focus;
1363 signals[SIG_NEW_WIN] =
1364 g_signal_new("new_win",
1365 G_TYPE_FROM_CLASS(klass),
1366 G_SIGNAL_RUN_LAST,
1367 G_STRUCT_OFFSET(GntWMClass, new_window),
1368 NULL, NULL,
1369 g_cclosure_marshal_VOID__POINTER,
1370 G_TYPE_NONE, 1, G_TYPE_POINTER);
1371 signals[SIG_DECORATE_WIN] =
1372 g_signal_new("decorate_win",
1373 G_TYPE_FROM_CLASS(klass),
1374 G_SIGNAL_RUN_LAST,
1375 G_STRUCT_OFFSET(GntWMClass, decorate_window),
1376 NULL, NULL,
1377 g_cclosure_marshal_VOID__POINTER,
1378 G_TYPE_NONE, 1, G_TYPE_POINTER);
1379 signals[SIG_CLOSE_WIN] =
1380 g_signal_new("close_win",
1381 G_TYPE_FROM_CLASS(klass),
1382 G_SIGNAL_RUN_LAST,
1383 G_STRUCT_OFFSET(GntWMClass, close_window),
1384 NULL, NULL,
1385 g_cclosure_marshal_VOID__POINTER,
1386 G_TYPE_NONE, 1, G_TYPE_POINTER);
1387 signals[SIG_CONFIRM_RESIZE] =
1388 g_signal_new("confirm_resize",
1389 G_TYPE_FROM_CLASS(klass),
1390 G_SIGNAL_RUN_LAST,
1391 G_STRUCT_OFFSET(GntWMClass, window_resize_confirm),
1392 gnt_boolean_handled_accumulator, NULL,
1393 gnt_closure_marshal_BOOLEAN__POINTER_POINTER_POINTER,
1394 G_TYPE_BOOLEAN, 3, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER);
1396 signals[SIG_CONFIRM_MOVE] =
1397 g_signal_new("confirm_move",
1398 G_TYPE_FROM_CLASS(klass),
1399 G_SIGNAL_RUN_LAST,
1400 G_STRUCT_OFFSET(GntWMClass, window_move_confirm),
1401 gnt_boolean_handled_accumulator, NULL,
1402 gnt_closure_marshal_BOOLEAN__POINTER_POINTER_POINTER,
1403 G_TYPE_BOOLEAN, 3, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER);
1405 signals[SIG_RESIZED] =
1406 g_signal_new("window_resized",
1407 G_TYPE_FROM_CLASS(klass),
1408 G_SIGNAL_RUN_LAST,
1409 G_STRUCT_OFFSET(GntWMClass, window_resized),
1410 NULL, NULL,
1411 g_cclosure_marshal_VOID__POINTER,
1412 G_TYPE_NONE, 1, G_TYPE_POINTER);
1413 signals[SIG_MOVED] =
1414 g_signal_new("window_moved",
1415 G_TYPE_FROM_CLASS(klass),
1416 G_SIGNAL_RUN_LAST,
1417 G_STRUCT_OFFSET(GntWMClass, window_moved),
1418 NULL, NULL,
1419 g_cclosure_marshal_VOID__POINTER,
1420 G_TYPE_NONE, 1, G_TYPE_POINTER);
1421 signals[SIG_UPDATE_WIN] =
1422 g_signal_new("window_update",
1423 G_TYPE_FROM_CLASS(klass),
1424 G_SIGNAL_RUN_LAST,
1425 G_STRUCT_OFFSET(GntWMClass, window_update),
1426 NULL, NULL,
1427 g_cclosure_marshal_VOID__POINTER,
1428 G_TYPE_NONE, 1, G_TYPE_POINTER);
1430 signals[SIG_GIVE_FOCUS] =
1431 g_signal_new("give_focus",
1432 G_TYPE_FROM_CLASS(klass),
1433 G_SIGNAL_RUN_LAST,
1434 G_STRUCT_OFFSET(GntWMClass, give_focus),
1435 NULL, NULL,
1436 g_cclosure_marshal_VOID__POINTER,
1437 G_TYPE_NONE, 1, G_TYPE_POINTER);
1439 signals[SIG_MOUSE_CLICK] =
1440 g_signal_new("mouse_clicked",
1441 G_TYPE_FROM_CLASS(klass),
1442 G_SIGNAL_RUN_LAST,
1443 G_STRUCT_OFFSET(GntWMClass, mouse_clicked),
1444 gnt_boolean_handled_accumulator, NULL,
1445 gnt_closure_marshal_BOOLEAN__INT_INT_INT_POINTER,
1446 G_TYPE_BOOLEAN, 4, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_POINTER);
1448 signals[SIG_TERMINAL_REFRESH] =
1449 g_signal_new("terminal-refresh",
1450 G_TYPE_FROM_CLASS(klass),
1451 G_SIGNAL_RUN_LAST,
1452 G_STRUCT_OFFSET(GntWMClass, terminal_refresh),
1453 NULL, NULL,
1454 g_cclosure_marshal_VOID__VOID,
1455 G_TYPE_NONE, 0);
1457 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "window-next", window_next,
1458 "\033" "n", NULL);
1459 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "window-prev", window_prev,
1460 "\033" "p", NULL);
1461 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "window-close", window_close,
1462 "\033" "c", NULL);
1463 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "window-list", window_list,
1464 "\033" "w", NULL);
1465 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "dump-screen", dump_screen,
1466 "\033" "D", NULL);
1467 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "shift-left", shift_left,
1468 "\033" ",", NULL);
1469 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "shift-right", shift_right,
1470 "\033" ".", NULL);
1471 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "action-list", list_actions,
1472 "\033" "a", NULL);
1473 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "start-move", start_move,
1474 "\033" "m", NULL);
1475 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "start-resize", start_resize,
1476 "\033" "r", NULL);
1477 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "wm-quit", wm_quit,
1478 "\033" "q", NULL);
1479 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "refresh-screen", refresh_screen,
1480 "\033" "l", NULL);
1481 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "switch-window-n", switch_window_n,
1482 NULL, NULL);
1483 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "window-scroll-down", window_scroll_down,
1484 "\033" GNT_KEY_CTRL_J, NULL);
1485 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "window-scroll-up", window_scroll_up,
1486 "\033" GNT_KEY_CTRL_K, NULL);
1487 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "help-for-widget", help_for_widget,
1488 "\033" "/", NULL);
1489 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "workspace-new", workspace_new,
1490 GNT_KEY_F9, NULL);
1491 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "workspace-next", workspace_next,
1492 "\033" ">", NULL);
1493 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "workspace-prev", workspace_prev,
1494 "\033" "<", NULL);
1495 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "window-tag", tag_widget,
1496 "\033" "t", NULL);
1497 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "place-tagged", place_tagged,
1498 "\033" "T", NULL);
1499 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "workspace-list", workspace_list,
1500 "\033" "s", NULL);
1501 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "toggle-clipboard", toggle_clipboard,
1502 "\033" "C", NULL);
1503 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "help-for-wm", help_for_wm,
1504 "\033" "\\", NULL);
1505 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "help-for-window", help_for_window,
1506 "\033" "|", NULL);
1507 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "ignore-keys-start", ignore_keys_start,
1508 GNT_KEY_CTRL_G, NULL);
1509 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "ignore-keys-end", ignore_keys_end,
1510 "\033" GNT_KEY_CTRL_G, NULL);
1511 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "window-next-urgent", window_next_urgent,
1512 "\033" "\t", NULL);
1513 snprintf(key, sizeof(key), "\033%s", GNT_KEY_BACK_TAB);
1514 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "window-prev-urgent", window_prev_urgent,
1515 key[1] ? key : NULL, NULL);
1516 #ifdef USE_PYTHON
1517 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "run-python", run_python,
1518 GNT_KEY_F3, NULL);
1519 Py_SetProgramName("gnt");
1520 Py_Initialize();
1521 #endif
1523 gnt_style_read_actions(G_OBJECT_CLASS_TYPE(klass), GNT_BINDABLE_CLASS(klass));
1525 /* Make sure Alt+x are detected properly. */
1526 for (i = '0'; i <= '9'; i++) {
1527 char str[] = "\033X";
1528 str[1] = i;
1529 gnt_keys_add_combination(str);
1532 GNTDEBUG;
1535 /******************************************************************************
1536 * GntWM API
1537 *****************************************************************************/
1538 GType
1539 gnt_wm_get_gtype(void)
1541 static GType type = 0;
1543 if(type == 0) {
1544 static const GTypeInfo info = {
1545 sizeof(GntWMClass),
1546 NULL, /* base_init */
1547 NULL, /* base_finalize */
1548 (GClassInitFunc)gnt_wm_class_init,
1549 NULL,
1550 NULL, /* class_data */
1551 sizeof(GntWM),
1552 0, /* n_preallocs */
1553 gnt_wm_init, /* instance_init */
1554 NULL /* value_table */
1557 type = g_type_register_static(GNT_TYPE_BINDABLE,
1558 "GntWM",
1559 &info, 0);
1562 return type;
1565 void
1566 gnt_wm_add_workspace(GntWM *wm, GntWS *ws)
1568 wm->workspaces = g_list_append(wm->workspaces, ws);
1571 gboolean
1572 gnt_wm_switch_workspace(GntWM *wm, gint n)
1574 GntWS *s = g_list_nth_data(wm->workspaces, n);
1575 if (!s)
1576 return FALSE;
1578 if (wm->_list.window) {
1579 gnt_widget_destroy(wm->_list.window);
1581 ensure_normal_mode(wm);
1582 gnt_ws_hide(wm->cws, wm->nodes);
1583 wm->cws = s;
1584 gnt_ws_show(wm->cws, wm->nodes);
1586 gnt_ws_draw_taskbar(wm->cws, TRUE);
1587 update_screen(wm);
1588 if (wm->cws->ordered) {
1589 gnt_wm_raise_window(wm, wm->cws->ordered->data);
1592 if (act && g_list_find(act, wm->cws)) {
1593 act = g_list_remove(act, wm->cws);
1594 update_act_msg();
1596 return TRUE;
1599 gboolean
1600 gnt_wm_switch_workspace_prev(GntWM *wm)
1602 int n = g_list_index(wm->workspaces, wm->cws);
1603 return gnt_wm_switch_workspace(wm, --n);
1606 gboolean
1607 gnt_wm_switch_workspace_next(GntWM *wm)
1609 int n = g_list_index(wm->workspaces, wm->cws);
1610 return gnt_wm_switch_workspace(wm, ++n);
1613 static gboolean
1614 workspace_next(GntBindable *wm, GList *n)
1616 return gnt_wm_switch_workspace_next(GNT_WM(wm));
1619 static gboolean
1620 workspace_prev(GntBindable *wm, GList *n)
1622 return gnt_wm_switch_workspace_prev(GNT_WM(wm));
1625 void
1626 gnt_wm_widget_move_workspace(GntWM *wm, GntWS *neww, GntWidget *widget)
1628 GntWS *oldw = gnt_wm_widget_find_workspace(wm, widget);
1629 GntNode *node;
1630 if (!oldw || oldw == neww)
1631 return;
1632 node = g_hash_table_lookup(wm->nodes, widget);
1633 if (node && node->ws == neww)
1634 return;
1636 if (node)
1637 node->ws = neww;
1639 gnt_ws_remove_widget(oldw, widget);
1640 gnt_ws_add_widget(neww, widget);
1641 if (neww == wm->cws) {
1642 gnt_ws_widget_show(widget, wm->nodes);
1643 } else {
1644 gnt_ws_widget_hide(widget, wm->nodes);
1648 static gint widget_in_workspace(gconstpointer workspace, gconstpointer wid)
1650 GntWS *s = (GntWS *)workspace;
1651 if (s->list && g_list_find(s->list, wid))
1652 return 0;
1653 return 1;
1656 GntWS *gnt_wm_widget_find_workspace(GntWM *wm, GntWidget *widget)
1658 GList *l = g_list_find_custom(wm->workspaces, widget, widget_in_workspace);
1659 if (l)
1660 return l->data;
1661 return NULL;
1664 static void free_workspaces(gpointer data, gpointer n)
1666 GntWS *s = data;
1667 g_free(s->name);
1670 void gnt_wm_set_workspaces(GntWM *wm, GList *workspaces)
1672 g_list_foreach(wm->workspaces, free_workspaces, NULL);
1673 wm->workspaces = workspaces;
1674 gnt_wm_switch_workspace(wm, 0);
1677 static void
1678 update_window_in_list(GntWM *wm, GntWidget *wid)
1680 GntTextFormatFlags flag = 0;
1682 if (wm->windows == NULL)
1683 return;
1685 if (wm->cws->ordered && wid == wm->cws->ordered->data)
1686 flag |= GNT_TEXT_FLAG_DIM;
1687 else if (GNT_WIDGET_IS_FLAG_SET(wid, GNT_WIDGET_URGENT))
1688 flag |= GNT_TEXT_FLAG_BOLD;
1690 gnt_tree_set_row_flags(GNT_TREE(wm->windows->tree), wid, flag);
1693 static gboolean
1694 match_title(gpointer title, gpointer n, gpointer wid_title)
1696 /* XXX: do any regex magic here. */
1697 if (g_strrstr((gchar *)wid_title, (gchar *)title))
1698 return TRUE;
1699 return FALSE;
1702 #if !GLIB_CHECK_VERSION(2,4,0)
1703 struct
1705 gpointer data;
1706 gpointer value;
1707 } table_find_data;
1709 static void
1710 table_find_helper(gpointer key, gpointer value, gpointer data)
1712 GHRFunc func = data;
1713 if (func(key, value, table_find_data.data))
1714 table_find_data.value = value;
1717 static gpointer
1718 g_hash_table_find(GHashTable * table, GHRFunc func, gpointer data)
1720 table_find_data.data = data;
1721 table_find_data.value = NULL;
1722 g_hash_table_foreach(table, table_find_helper, func);
1723 return table_find_data.value;
1725 #endif
1727 static GntWS *
1728 new_widget_find_workspace(GntWM *wm, GntWidget *widget)
1730 GntWS *ret = NULL;
1731 const gchar *name, *title;
1732 title = GNT_BOX(widget)->title;
1733 if (title)
1734 ret = g_hash_table_find(wm->title_places, match_title, (gpointer)title);
1735 if (ret)
1736 return ret;
1737 name = gnt_widget_get_name(widget);
1738 if (name)
1739 ret = g_hash_table_find(wm->name_places, match_title, (gpointer)name);
1740 return ret ? ret : wm->cws;
1743 static void
1744 gnt_wm_new_window_real(GntWM *wm, GntWidget *widget)
1746 GntNode *node;
1747 gboolean transient = FALSE;
1749 if (widget->window == NULL)
1750 return;
1752 node = g_new0(GntNode, 1);
1753 node->me = widget;
1754 node->scroll = 0;
1756 g_hash_table_replace(wm->nodes, widget, node);
1758 refresh_node(widget, node, GINT_TO_POINTER(TRUE));
1760 transient = !!GNT_WIDGET_IS_FLAG_SET(node->me, GNT_WIDGET_TRANSIENT);
1762 #if 1
1764 int x, y, w, h, maxx, maxy;
1765 gboolean shadow = TRUE;
1767 if (!gnt_widget_has_shadow(widget))
1768 shadow = FALSE;
1769 x = widget->priv.x;
1770 y = widget->priv.y;
1771 w = widget->priv.width + shadow;
1772 h = widget->priv.height + shadow;
1774 maxx = getmaxx(stdscr);
1775 maxy = getmaxy(stdscr) - 1; /* room for the taskbar */
1777 x = MAX(0, x);
1778 y = MAX(0, y);
1779 if (x + w >= maxx)
1780 x = MAX(0, maxx - w);
1781 if (y + h >= maxy)
1782 y = MAX(0, maxy - h);
1784 w = MIN(w, maxx);
1785 h = MIN(h, maxy);
1786 node->window = newwin(h, w, y, x);
1787 gnt_wm_copy_win(widget, node);
1789 #endif
1791 node->panel = new_panel(node->window);
1792 set_panel_userptr(node->panel, node);
1794 if (!transient) {
1795 GntWS *ws = wm->cws;
1796 if (node->me != wm->_list.window) {
1797 if (GNT_IS_BOX(widget)) {
1798 ws = new_widget_find_workspace(wm, widget);
1800 node->ws = ws;
1801 ws->list = g_list_append(ws->list, widget);
1802 ws->ordered = g_list_append(ws->ordered, widget);
1805 if (wm->event_stack || node->me == wm->_list.window ||
1806 node->me == ws->ordered->data) {
1807 gnt_wm_raise_window(wm, node->me);
1808 } else {
1809 bottom_panel(node->panel); /* New windows should not grab focus */
1810 gnt_widget_set_focus(node->me, FALSE);
1811 gnt_widget_set_urgent(node->me);
1812 if (wm->cws != ws)
1813 gnt_ws_widget_hide(widget, wm->nodes);
1818 void gnt_wm_new_window(GntWM *wm, GntWidget *widget)
1820 while (widget->parent)
1821 widget = widget->parent;
1823 if (GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_INVISIBLE) ||
1824 g_hash_table_lookup(wm->nodes, widget)) {
1825 update_screen(wm);
1826 return;
1829 if (GNT_IS_BOX(widget)) {
1830 const char *title = GNT_BOX(widget)->title;
1831 GntPosition *p = NULL;
1832 if (title && (p = g_hash_table_lookup(wm->positions, title)) != NULL) {
1833 sanitize_position(widget, &p->x, &p->y, TRUE);
1834 gnt_widget_set_position(widget, p->x, p->y);
1835 mvwin(widget->window, p->y, p->x);
1839 g_signal_emit(wm, signals[SIG_NEW_WIN], 0, widget);
1840 g_signal_emit(wm, signals[SIG_DECORATE_WIN], 0, widget);
1842 if (wm->windows && !GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_TRANSIENT)) {
1843 if ((GNT_IS_BOX(widget) && GNT_BOX(widget)->title) && wm->_list.window != widget
1844 && GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_CAN_TAKE_FOCUS)) {
1845 gnt_tree_add_row_last(GNT_TREE(wm->windows->tree), widget,
1846 gnt_tree_create_row(GNT_TREE(wm->windows->tree), GNT_BOX(widget)->title),
1847 g_object_get_data(G_OBJECT(wm->windows->tree), "workspace") ? wm->cws : NULL);
1848 update_window_in_list(wm, widget);
1852 update_screen(wm);
1853 gnt_ws_draw_taskbar(wm->cws, FALSE);
1856 void gnt_wm_window_decorate(GntWM *wm, GntWidget *widget)
1858 g_signal_emit(wm, signals[SIG_DECORATE_WIN], 0, widget);
1861 void gnt_wm_window_close(GntWM *wm, GntWidget *widget)
1863 GntWS *s;
1864 int pos;
1866 s = gnt_wm_widget_find_workspace(wm, widget);
1868 if (g_hash_table_lookup(wm->nodes, widget) == NULL)
1869 return;
1871 g_signal_emit(wm, signals[SIG_CLOSE_WIN], 0, widget);
1872 g_hash_table_remove(wm->nodes, widget);
1874 if (wm->windows) {
1875 gnt_tree_remove(GNT_TREE(wm->windows->tree), widget);
1878 if (s) {
1879 pos = g_list_index(s->list, widget);
1881 if (pos != -1) {
1882 s->list = g_list_remove(s->list, widget);
1883 s->ordered = g_list_remove(s->ordered, widget);
1885 if (s->ordered && wm->cws == s)
1886 gnt_wm_raise_window(wm, s->ordered->data);
1890 update_screen(wm);
1891 gnt_ws_draw_taskbar(wm->cws, FALSE);
1894 time_t gnt_wm_get_idle_time()
1896 return time(NULL) - last_active_time;
1899 gboolean gnt_wm_process_input(GntWM *wm, const char *keys)
1901 gboolean ret = FALSE;
1903 keys = gnt_bindable_remap_keys(GNT_BINDABLE(wm), keys);
1905 idle_update = TRUE;
1906 if(ignore_keys){
1907 if(keys && !strcmp(keys, "\033" GNT_KEY_CTRL_G)){
1908 if(gnt_bindable_perform_action_key(GNT_BINDABLE(wm), keys)){
1909 return TRUE;
1912 return wm->cws->ordered ? gnt_widget_key_pressed(GNT_WIDGET(wm->cws->ordered->data), keys) : FALSE;
1915 if (gnt_bindable_perform_action_key(GNT_BINDABLE(wm), keys)) {
1916 return TRUE;
1919 /* Do some manual checking */
1920 if (wm->cws->ordered && wm->mode != GNT_KP_MODE_NORMAL) {
1921 int xmin = 0, ymin = 0, xmax = getmaxx(stdscr), ymax = getmaxy(stdscr) - 1;
1922 int x, y, w, h;
1923 GntWidget *widget = GNT_WIDGET(wm->cws->ordered->data);
1924 int ox, oy, ow, oh;
1926 gnt_widget_get_position(widget, &x, &y);
1927 gnt_widget_get_size(widget, &w, &h);
1928 ox = x; oy = y;
1929 ow = w; oh = h;
1931 if (wm->mode == GNT_KP_MODE_MOVE) {
1932 if (strcmp(keys, GNT_KEY_LEFT) == 0) {
1933 if (x > xmin)
1934 x--;
1935 } else if (strcmp(keys, GNT_KEY_RIGHT) == 0) {
1936 if (x + w < xmax)
1937 x++;
1938 } else if (strcmp(keys, GNT_KEY_UP) == 0) {
1939 if (y > ymin)
1940 y--;
1941 } else if (strcmp(keys, GNT_KEY_DOWN) == 0) {
1942 if (y + h < ymax)
1943 y++;
1945 if (ox != x || oy != y) {
1946 gnt_screen_move_widget(widget, x, y);
1947 window_reverse(widget, TRUE, wm);
1948 return TRUE;
1950 } else if (wm->mode == GNT_KP_MODE_RESIZE) {
1951 if (strcmp(keys, GNT_KEY_LEFT) == 0) {
1952 w--;
1953 } else if (strcmp(keys, GNT_KEY_RIGHT) == 0) {
1954 if (x + w < xmax)
1955 w++;
1956 } else if (strcmp(keys, GNT_KEY_UP) == 0) {
1957 h--;
1958 } else if (strcmp(keys, GNT_KEY_DOWN) == 0) {
1959 if (y + h < ymax)
1960 h++;
1962 if (oh != h || ow != w) {
1963 gnt_screen_resize_widget(widget, w, h);
1964 window_reverse(widget, TRUE, wm);
1965 return TRUE;
1968 if (strcmp(keys, "\r") == 0 || strcmp(keys, "\033") == 0) {
1969 window_reverse(widget, FALSE, wm);
1970 wm->mode = GNT_KP_MODE_NORMAL;
1972 return TRUE;
1975 /* Escape to close the window-list or action-list window */
1976 if (strcmp(keys, "\033") == 0) {
1977 if (wm->_list.window) {
1978 gnt_widget_destroy(wm->_list.window);
1979 return TRUE;
1981 } else if (keys[0] == '\033' && isdigit(keys[1]) && keys[2] == '\0') {
1982 /* Alt+x for quick switch */
1983 int n = *(keys + 1) - '0';
1984 GList *list = NULL;
1986 if (n == 0)
1987 n = 10;
1989 list = g_list_append(list, GINT_TO_POINTER(n - 1));
1990 switch_window_n(GNT_BINDABLE(wm), list);
1991 g_list_free(list);
1992 return TRUE;
1995 if (wm->menu)
1996 ret = gnt_widget_key_pressed(GNT_WIDGET(wm->menu), keys);
1997 else if (wm->_list.window)
1998 ret = gnt_widget_key_pressed(wm->_list.window, keys);
1999 else if (wm->cws->ordered) {
2000 GntWidget *win = wm->cws->ordered->data;
2001 if (GNT_IS_WINDOW(win)) {
2002 GntMenu *menu = GNT_WINDOW(win)->menu;
2003 if (menu) {
2004 const char *id = gnt_window_get_accel_item(GNT_WINDOW(win), keys);
2005 if (id) {
2006 GntMenuItem *item = gnt_menu_get_item(menu, id);
2007 if (item)
2008 ret = gnt_menuitem_activate(item);
2012 if (!ret)
2013 ret = gnt_widget_key_pressed(win, keys);
2015 return ret;
2018 static void
2019 gnt_wm_win_resized(GntWM *wm, GntNode *node)
2021 /*refresh_node(node->me, node, NULL);*/
2024 static void
2025 gnt_wm_win_moved(GntWM *wm, GntNode *node)
2027 refresh_node(node->me, node, NULL);
2030 void gnt_wm_resize_window(GntWM *wm, GntWidget *widget, int width, int height)
2032 gboolean ret = TRUE;
2033 GntNode *node;
2034 int maxx, maxy;
2036 while (widget->parent)
2037 widget = widget->parent;
2038 node = g_hash_table_lookup(wm->nodes, widget);
2039 if (!node)
2040 return;
2042 g_signal_emit(wm, signals[SIG_CONFIRM_RESIZE], 0, widget, &width, &height, &ret);
2043 if (!ret)
2044 return; /* resize is not permitted */
2045 hide_panel(node->panel);
2046 gnt_widget_set_size(widget, width, height);
2047 gnt_widget_draw(widget);
2049 maxx = getmaxx(stdscr);
2050 maxy = getmaxy(stdscr) - 1;
2051 height = MIN(height, maxy);
2052 width = MIN(width, maxx);
2053 wresize(node->window, height, width);
2054 replace_panel(node->panel, node->window);
2056 g_signal_emit(wm, signals[SIG_RESIZED], 0, node);
2058 show_panel(node->panel);
2059 update_screen(wm);
2062 static void
2063 write_gdi(gpointer key, gpointer value, gpointer data)
2065 GntPosition *p = value;
2066 fprintf(data, ".%s = %d;%d\n", (char *)key, p->x, p->y);
2069 static gboolean
2070 write_already(gpointer data)
2072 GntWM *wm = data;
2073 FILE *file;
2074 char *filename;
2076 filename = g_build_filename(g_get_home_dir(), ".gntpositions", NULL);
2078 file = fopen(filename, "wb");
2079 if (file == NULL) {
2080 g_printerr("GntWM: error opening file to save positions\n");
2081 } else {
2082 fprintf(file, "[positions]\n");
2083 g_hash_table_foreach(wm->positions, write_gdi, file);
2084 fclose(file);
2087 g_free(filename);
2088 g_source_remove(write_timeout);
2089 write_timeout = 0;
2090 return FALSE;
2093 static void
2094 write_positions_to_file(GntWM *wm)
2096 if (write_timeout) {
2097 g_source_remove(write_timeout);
2099 write_timeout = g_timeout_add(10000, write_already, wm);
2102 void gnt_wm_move_window(GntWM *wm, GntWidget *widget, int x, int y)
2104 gboolean ret = TRUE;
2105 GntNode *node;
2107 while (widget->parent)
2108 widget = widget->parent;
2109 node = g_hash_table_lookup(wm->nodes, widget);
2110 if (!node)
2111 return;
2113 g_signal_emit(wm, signals[SIG_CONFIRM_MOVE], 0, widget, &x, &y, &ret);
2114 if (!ret)
2115 return; /* resize is not permitted */
2117 gnt_widget_set_position(widget, x, y);
2118 move_panel(node->panel, y, x);
2120 g_signal_emit(wm, signals[SIG_MOVED], 0, node);
2121 if (gnt_style_get_bool(GNT_STYLE_REMPOS, TRUE) && GNT_IS_BOX(widget) &&
2122 !GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_TRANSIENT)) {
2123 const char *title = GNT_BOX(widget)->title;
2124 if (title) {
2125 GntPosition *p = g_new0(GntPosition, 1);
2126 GntWidget *wid = node->me;
2127 p->x = wid->priv.x;
2128 p->y = wid->priv.y;
2129 g_hash_table_replace(wm->positions, g_strdup(title), p);
2130 write_positions_to_file(wm);
2134 update_screen(wm);
2137 static void
2138 gnt_wm_give_focus(GntWM *wm, GntWidget *widget)
2140 GntNode *node = g_hash_table_lookup(wm->nodes, widget);
2142 if (!node)
2143 return;
2145 if (widget != wm->_list.window && !GNT_IS_MENU(widget) &&
2146 wm->cws->ordered->data != widget) {
2147 GntWidget *w = wm->cws->ordered->data;
2148 wm->cws->ordered = g_list_bring_to_front(wm->cws->ordered, widget);
2149 gnt_widget_set_focus(w, FALSE);
2152 gnt_widget_set_focus(widget, TRUE);
2153 GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_URGENT);
2154 gnt_widget_draw(widget);
2155 top_panel(node->panel);
2157 if (wm->_list.window) {
2158 GntNode *nd = g_hash_table_lookup(wm->nodes, wm->_list.window);
2159 top_panel(nd->panel);
2161 update_screen(wm);
2162 gnt_ws_draw_taskbar(wm->cws, FALSE);
2165 void gnt_wm_update_window(GntWM *wm, GntWidget *widget)
2167 GntNode *node = NULL;
2168 GntWS *ws;
2170 while (widget->parent)
2171 widget = widget->parent;
2172 if (!GNT_IS_MENU(widget)) {
2173 if (!GNT_IS_BOX(widget))
2174 return;
2175 gnt_box_sync_children(GNT_BOX(widget));
2178 ws = gnt_wm_widget_find_workspace(wm, widget);
2179 node = g_hash_table_lookup(wm->nodes, widget);
2180 if (node == NULL) {
2181 gnt_wm_new_window(wm, widget);
2182 } else
2183 g_signal_emit(wm, signals[SIG_UPDATE_WIN], 0, node);
2185 if (ws == wm->cws || GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_TRANSIENT)) {
2186 gnt_wm_copy_win(widget, node);
2187 update_screen(wm);
2188 gnt_ws_draw_taskbar(wm->cws, FALSE);
2189 } else if (ws && ws != wm->cws && GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_URGENT)) {
2190 if (!act || (act && !g_list_find(act, ws)))
2191 act = g_list_prepend(act, ws);
2192 update_act_msg();
2196 gboolean gnt_wm_process_click(GntWM *wm, GntMouseEvent event, int x, int y, GntWidget *widget)
2198 gboolean ret = TRUE;
2199 idle_update = TRUE;
2200 g_signal_emit(wm, signals[SIG_MOUSE_CLICK], 0, event, x, y, widget, &ret);
2201 return ret;
2204 void gnt_wm_raise_window(GntWM *wm, GntWidget *widget)
2206 GntWS *ws = gnt_wm_widget_find_workspace(wm, widget);
2207 if (wm->cws != ws)
2208 gnt_wm_switch_workspace(wm, g_list_index(wm->workspaces, ws));
2209 if (widget != wm->cws->ordered->data) {
2210 GntWidget *wid = wm->cws->ordered->data;
2211 wm->cws->ordered = g_list_bring_to_front(wm->cws->ordered, widget);
2212 gnt_widget_set_focus(wid, FALSE);
2213 gnt_widget_draw(wid);
2215 gnt_widget_set_focus(widget, TRUE);
2216 gnt_widget_draw(widget);
2217 g_signal_emit(wm, signals[SIG_GIVE_FOCUS], 0, widget);
2220 void gnt_wm_set_event_stack(GntWM *wm, gboolean set)
2222 wm->event_stack = set;