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
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
29 #if (defined(__APPLE__) || defined(__unix__)) && !defined(__FreeBSD__) && !defined(__OpenBSD__)
30 #define _XOPEN_SOURCE_EXTENDED
35 #if GLIB_CHECK_VERSION(2,6,0)
36 # include <glib/gstdio.h>
38 # include <sys/types.h>
39 # include <sys/stat.h>
49 #include "gntinternal.h"
51 #define GNT_LOG_DOMAIN "WM"
55 #include "gntmarshal.h"
58 #include "gntbutton.h"
60 #include "gntfilesel.h"
63 #include "gnttextview.h"
66 #include "gntwindow.h"
68 #define IDLE_CHECK_INTERVAL 5 /* 5 seconds */
87 static guint signals
[SIGS
] = { 0 };
88 static void gnt_wm_new_window_real(GntWM
*wm
, GntWidget
*widget
);
89 static void gnt_wm_win_resized(GntWM
*wm
, GntNode
*node
);
90 static void gnt_wm_win_moved(GntWM
*wm
, GntNode
*node
);
91 static void gnt_wm_give_focus(GntWM
*wm
, GntWidget
*widget
);
92 static void update_window_in_list(GntWM
*wm
, GntWidget
*wid
);
93 static void shift_window(GntWM
*wm
, GntWidget
*widget
, int dir
);
94 static gboolean
workspace_next(GntBindable
*wm
, GList
*n
);
95 static gboolean
workspace_prev(GntBindable
*wm
, GList
*n
);
98 static int widestringwidth(wchar_t *wide
);
101 static void ensure_normal_mode(GntWM
*wm
);
102 static gboolean
write_already(gpointer data
);
103 static int write_timeout
;
104 static time_t last_active_time
;
105 static gboolean idle_update
;
106 static GList
*act
= NULL
; /* list of WS with unseen activitiy */
107 static gboolean ignore_keys
= FALSE
;
109 static gboolean started_python
= FALSE
;
113 g_list_bring_to_front(GList
*list
, gpointer data
)
115 list
= g_list_remove(list
, data
);
116 list
= g_list_prepend(list
, data
);
121 free_node(gpointer data
)
123 GntNode
*node
= data
;
124 hide_panel(node
->panel
);
125 del_panel(node
->panel
);
130 gnt_wm_copy_win(GntWidget
*widget
, GntNode
*node
)
135 src
= widget
->window
;
137 copywin(src
, dst
, node
->scroll
, 0, 0, 0, getmaxy(dst
) - 1, getmaxx(dst
) - 1, 0);
139 /* Update the hardware cursor */
140 if (GNT_IS_WINDOW(widget
) || GNT_IS_BOX(widget
)) {
141 GntWidget
*active
= GNT_BOX(widget
)->active
;
143 int curx
= active
->priv
.x
+ getcurx(active
->window
);
144 int cury
= active
->priv
.y
+ getcury(active
->window
);
145 if (wmove(node
->window
, cury
- widget
->priv
.y
, curx
- widget
->priv
.x
) != OK
)
146 wmove(node
->window
, 0, 0);
152 * The following is a workaround for a bug in most versions of ncursesw.
153 * Read about it in: http://article.gmane.org/gmane.comp.lib.ncurses.bugs/2751
155 * In short, if a panel hides one cell of a multi-cell character, then the rest
156 * of the characters in that line get screwed. The workaround here is to erase
157 * any such character preemptively.
159 * Caveat: If a wide character is erased, and the panel above it is moved enough
160 * to expose the entire character, it is not always redrawn.
163 work_around_for_ncurses_bug(void)
167 while ((panel
= panel_below(panel
)) != NULL
) {
168 int sx
, ex
, sy
, ey
, w
, y
;
170 PANEL
*below
= panel
;
172 sx
= panel
->win
->_begx
;
173 ex
= panel
->win
->_maxx
+ sx
;
174 sy
= panel
->win
->_begy
;
175 ey
= panel
->win
->_maxy
+ sy
;
177 while ((below
= panel_below(below
)) != NULL
) {
178 if (sy
> below
->win
->_begy
+ below
->win
->_maxy
||
179 ey
< below
->win
->_begy
)
181 if (sx
> below
->win
->_begx
+ below
->win
->_maxx
||
182 ex
< below
->win
->_begx
)
184 for (y
= MAX(sy
, below
->win
->_begy
); y
<= MIN(ey
, below
->win
->_begy
+ below
->win
->_maxy
); y
++) {
185 if (mvwin_wch(below
->win
, y
- below
->win
->_begy
, sx
- 1 - below
->win
->_begx
, &ch
) != OK
)
187 w
= widestringwidth(ch
.chars
);
188 if (w
> 1 && (ch
.attr
& 1)) {
190 ch
.attr
&= ~ A_CHARTEXT
;
191 mvwadd_wch(below
->win
, y
- below
->win
->_begy
, sx
- 1 - below
->win
->_begx
, &ch
);
192 touchline(below
->win
, y
- below
->win
->_begy
, 1);
195 if (mvwin_wch(below
->win
, y
- below
->win
->_begy
, ex
+ 1 - below
->win
->_begx
, &ch
) != OK
)
197 w
= widestringwidth(ch
.chars
);
198 if (w
> 1 && !(ch
.attr
& 1)) {
200 ch
.attr
&= ~ A_CHARTEXT
;
201 mvwadd_wch(below
->win
, y
- below
->win
->_begy
, ex
+ 1 - below
->win
->_begx
, &ch
);
202 touchline(below
->win
, y
- below
->win
->_begy
, 1);
215 static GntWidget
*message
= NULL
;
216 GString
*text
= g_string_new("act: ");
218 gnt_widget_destroy(message
);
221 for (iter
= act
; iter
; iter
= iter
->next
) {
222 GntWS
*ws
= iter
->data
;
223 g_string_append_printf(text
, "%s, ", gnt_ws_get_name(ws
));
225 g_string_erase(text
, text
->len
- 2, 2);
226 message
= gnt_vbox_new(FALSE
);
227 label
= gnt_label_new_with_format(text
->str
, GNT_TEXT_FLAG_BOLD
| GNT_TEXT_FLAG_HIGHLIGHT
);
228 GNT_WIDGET_UNSET_FLAGS(GNT_BOX(message
), GNT_WIDGET_CAN_TAKE_FOCUS
);
229 GNT_WIDGET_SET_FLAGS(GNT_BOX(message
), GNT_WIDGET_TRANSIENT
);
230 gnt_box_add_widget(GNT_BOX(message
), label
);
231 gnt_widget_set_name(message
, "wm-message");
232 gnt_widget_set_position(message
, 0, 0);
233 gnt_widget_draw(message
);
234 g_string_free(text
, TRUE
);
238 update_screen(GntWM
*wm
)
240 if (wm
->mode
== GNT_KP_MODE_WAIT_ON_CHILD
)
244 GntMenu
*top
= wm
->menu
;
246 GntNode
*node
= g_hash_table_lookup(wm
->nodes
, top
);
248 top_panel(node
->panel
);
252 work_around_for_ncurses_bug();
259 sanitize_position(GntWidget
*widget
, int *x
, int *y
, gboolean m
)
261 int X_MAX
= getmaxx(stdscr
);
262 int Y_MAX
= getmaxy(stdscr
) - 1;
265 gboolean changed
= FALSE
;
266 GntWindowFlags flags
= GNT_IS_WINDOW(widget
) ?
267 gnt_window_get_maximize(GNT_WINDOW(widget
)) : 0;
269 gnt_widget_get_size(widget
, &w
, &h
);
271 if (m
&& (flags
& GNT_WINDOW_MAXIMIZE_X
) && *x
!= 0) {
274 } else if (*x
+ w
> X_MAX
) {
275 nx
= MAX(0, X_MAX
- w
);
283 if (m
&& (flags
& GNT_WINDOW_MAXIMIZE_Y
) && *y
!= 0) {
286 } else if (*y
+ h
> Y_MAX
) {
287 ny
= MAX(0, Y_MAX
- h
);
298 refresh_node(GntWidget
*widget
, GntNode
*node
, gpointer m
)
303 int X_MAX
= getmaxx(stdscr
);
304 int Y_MAX
= getmaxy(stdscr
) - 1;
306 GntWindowFlags flags
= 0;
308 if (m
&& GNT_IS_WINDOW(widget
)) {
309 flags
= gnt_window_get_maximize(GNT_WINDOW(widget
));
312 gnt_widget_get_position(widget
, &x
, &y
);
313 gnt_widget_get_size(widget
, &w
, &h
);
315 if (sanitize_position(widget
, &x
, &y
, !!m
))
316 gnt_screen_move_widget(widget
, x
, y
);
318 if (flags
& GNT_WINDOW_MAXIMIZE_X
)
323 if (flags
& GNT_WINDOW_MAXIMIZE_Y
)
328 if (nw
!= w
|| nh
!= h
)
329 gnt_screen_resize_widget(widget
, nw
, nh
);
333 read_window_positions(GntWM
*wm
)
335 #if GLIB_CHECK_VERSION(2,6,0)
336 GKeyFile
*gfile
= g_key_file_new();
337 char *filename
= g_build_filename(g_get_home_dir(), ".gntpositions", NULL
);
338 GError
*error
= NULL
;
342 if (!g_key_file_load_from_file(gfile
, filename
, G_KEY_FILE_NONE
, &error
)) {
343 gnt_warning("%s", error
->message
);
349 keys
= g_key_file_get_keys(gfile
, "positions", &nk
, &error
);
351 gnt_warning("%s", error
->message
);
356 char *title
= keys
[nk
];
358 char **coords
= g_key_file_get_string_list(gfile
, "positions", title
, &l
, NULL
);
360 int x
= atoi(coords
[0]);
361 int y
= atoi(coords
[1]);
362 GntPosition
*p
= g_new0(GntPosition
, 1);
365 g_hash_table_replace(wm
->positions
, g_strdup(title
+ 1), p
);
367 gnt_warning("Invalid number of arguments (%" G_GSIZE_FORMAT
368 ") for positioning a window.", l
);
376 g_key_file_free(gfile
);
380 static gboolean
check_idle(gpointer n
)
383 time(&last_active_time
);
390 gnt_wm_init(GTypeInstance
*instance
, gpointer
class)
392 GntWM
*wm
= GNT_WM(instance
);
393 wm
->workspaces
= NULL
;
394 wm
->name_places
= g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, g_free
);
395 wm
->title_places
= g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, g_free
);
396 gnt_style_read_workspaces(wm
);
397 if (wm
->workspaces
== NULL
) {
398 wm
->cws
= gnt_ws_new("default");
399 gnt_wm_add_workspace(wm
, wm
->cws
);
401 wm
->cws
= wm
->workspaces
->data
;
403 wm
->event_stack
= FALSE
;
407 wm
->nodes
= g_hash_table_new_full(g_direct_hash
, g_direct_equal
, NULL
, free_node
);
408 wm
->positions
= g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, g_free
);
409 if (gnt_style_get_bool(GNT_STYLE_REMPOS
, TRUE
))
410 read_window_positions(wm
);
411 g_timeout_add_seconds(IDLE_CHECK_INTERVAL
, check_idle
, NULL
);
412 time(&last_active_time
);
413 gnt_wm_switch_workspace(wm
, 0);
417 switch_window(GntWM
*wm
, int direction
, gboolean urgent
)
419 GntWidget
*w
= NULL
, *wid
= NULL
;
422 if (wm
->_list
.window
|| wm
->menu
)
425 if (!wm
->cws
->ordered
|| !wm
->cws
->ordered
->next
)
428 if (wm
->mode
!= GNT_KP_MODE_NORMAL
) {
429 ensure_normal_mode(wm
);
432 w
= wm
->cws
->ordered
->data
;
433 orgpos
= pos
= g_list_index(wm
->cws
->list
, w
);
439 wid
= g_list_last(wm
->cws
->list
)->data
;
440 pos
= g_list_length(wm
->cws
->list
) - 1;
441 } else if (pos
>= g_list_length(wm
->cws
->list
)) {
442 wid
= wm
->cws
->list
->data
;
445 wid
= g_list_nth_data(wm
->cws
->list
, pos
);
446 } while (urgent
&& !GNT_WIDGET_IS_FLAG_SET(wid
, GNT_WIDGET_URGENT
) && pos
!= orgpos
);
448 gnt_wm_raise_window(wm
, wid
);
452 window_next(GntBindable
*bindable
, GList
*null
)
454 GntWM
*wm
= GNT_WM(bindable
);
455 switch_window(wm
, 1, FALSE
);
460 window_prev(GntBindable
*bindable
, GList
*null
)
462 GntWM
*wm
= GNT_WM(bindable
);
463 switch_window(wm
, -1, FALSE
);
468 switch_window_n(GntBindable
*bind
, GList
*list
)
470 GntWM
*wm
= GNT_WM(bind
);
474 if (!wm
->cws
->ordered
)
478 n
= GPOINTER_TO_INT(list
->data
);
482 if ((l
= g_list_nth(wm
->cws
->list
, n
)) != NULL
)
484 gnt_wm_raise_window(wm
, l
->data
);
491 window_scroll_up(GntBindable
*bindable
, GList
*null
)
493 GntWM
*wm
= GNT_WM(bindable
);
497 if (!wm
->cws
->ordered
)
500 window
= wm
->cws
->ordered
->data
;
501 node
= g_hash_table_lookup(wm
->nodes
, window
);
507 gnt_wm_copy_win(window
, node
);
514 window_scroll_down(GntBindable
*bindable
, GList
*null
)
516 GntWM
*wm
= GNT_WM(bindable
);
521 if (!wm
->cws
->ordered
)
524 window
= wm
->cws
->ordered
->data
;
525 node
= g_hash_table_lookup(wm
->nodes
, window
);
529 gnt_widget_get_size(window
, &w
, &h
);
530 if (h
- node
->scroll
> getmaxy(node
->window
)) {
532 gnt_wm_copy_win(window
, node
);
539 window_close(GntBindable
*bindable
, GList
*null
)
541 GntWM
*wm
= GNT_WM(bindable
);
543 if (wm
->_list
.window
)
546 if (wm
->cws
->ordered
) {
547 gnt_widget_destroy(wm
->cws
->ordered
->data
);
548 ensure_normal_mode(wm
);
555 destroy__list(GntWidget
*widget
, GntWM
*wm
)
557 wm
->_list
.window
= NULL
;
558 wm
->_list
.tree
= NULL
;
565 setup__list(GntWM
*wm
)
567 GntWidget
*tree
, *win
;
568 ensure_normal_mode(wm
);
569 win
= wm
->_list
.window
= gnt_box_new(FALSE
, FALSE
);
570 gnt_box_set_toplevel(GNT_BOX(win
), TRUE
);
571 gnt_box_set_pad(GNT_BOX(win
), 0);
572 GNT_WIDGET_SET_FLAGS(win
, GNT_WIDGET_TRANSIENT
);
574 tree
= wm
->_list
.tree
= gnt_tree_new();
575 gnt_box_add_widget(GNT_BOX(win
), tree
);
577 g_signal_connect(G_OBJECT(win
), "destroy", G_CALLBACK(destroy__list
), wm
);
581 window_list_activate(GntTree
*tree
, GntWM
*wm
)
583 GntBindable
*sel
= gnt_tree_get_selection_data(GNT_TREE(tree
));
585 gnt_widget_destroy(wm
->_list
.window
);
590 if (GNT_IS_WS(sel
)) {
591 gnt_wm_switch_workspace(wm
, g_list_index(wm
->workspaces
, sel
));
593 gnt_wm_raise_window(wm
, GNT_WIDGET(sel
));
598 populate_window_list(GntWM
*wm
, gboolean workspace
)
601 GntTree
*tree
= GNT_TREE(wm
->windows
->tree
);
603 for (iter
= wm
->cws
->list
; iter
; iter
= iter
->next
) {
604 GntBox
*box
= GNT_BOX(iter
->data
);
606 gnt_tree_add_row_last(tree
, box
,
607 gnt_tree_create_row(tree
, box
->title
), NULL
);
608 update_window_in_list(wm
, GNT_WIDGET(box
));
611 GList
*ws
= wm
->workspaces
;
612 for (; ws
; ws
= ws
->next
) {
613 gnt_tree_add_row_last(tree
, ws
->data
,
614 gnt_tree_create_row(tree
, gnt_ws_get_name(GNT_WS(ws
->data
))), NULL
);
615 for (iter
= GNT_WS(ws
->data
)->list
; iter
; iter
= iter
->next
) {
616 GntBox
*box
= GNT_BOX(iter
->data
);
618 gnt_tree_add_row_last(tree
, box
,
619 gnt_tree_create_row(tree
, box
->title
), ws
->data
);
620 update_window_in_list(wm
, GNT_WIDGET(box
));
627 window_list_key_pressed(GntWidget
*widget
, const char *text
, GntWM
*wm
)
629 if (text
[1] == 0 && wm
->cws
->ordered
) {
630 GntBindable
*sel
= gnt_tree_get_selection_data(GNT_TREE(widget
));
634 if (GNT_IS_WS(sel
)) {
635 /* reorder the workspace. */
637 shift_window(wm
, GNT_WIDGET(sel
), -1);
641 if (GNT_IS_WS(sel
)) {
642 /* reorder the workspace. */
644 shift_window(wm
, GNT_WIDGET(sel
), 1);
649 gnt_tree_remove_all(GNT_TREE(widget
));
650 populate_window_list(wm
, GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget
), "workspace")));
651 gnt_tree_set_selected(GNT_TREE(widget
), sel
);
658 list_of_windows(GntWM
*wm
, gboolean workspace
)
660 GntWidget
*tree
, *win
;
662 wm
->windows
= &wm
->_list
;
664 win
= wm
->windows
->window
;
665 tree
= wm
->windows
->tree
;
667 gnt_box_set_title(GNT_BOX(win
), workspace
? "Workspace List" : "Window List");
669 populate_window_list(wm
, workspace
);
671 if (wm
->cws
->ordered
)
672 gnt_tree_set_selected(GNT_TREE(tree
), wm
->cws
->ordered
->data
);
674 gnt_tree_set_selected(GNT_TREE(tree
), wm
->cws
);
676 g_signal_connect(G_OBJECT(tree
), "activate", G_CALLBACK(window_list_activate
), wm
);
677 g_signal_connect(G_OBJECT(tree
), "key_pressed", G_CALLBACK(window_list_key_pressed
), wm
);
678 g_object_set_data(G_OBJECT(tree
), "workspace", GINT_TO_POINTER(workspace
));
680 gnt_tree_set_col_width(GNT_TREE(tree
), 0, getmaxx(stdscr
) / 3);
681 gnt_widget_set_size(tree
, 0, getmaxy(stdscr
) / 2);
682 gnt_widget_set_position(win
, getmaxx(stdscr
) / 3, getmaxy(stdscr
) / 4);
684 gnt_widget_show(win
);
688 window_list(GntBindable
*bindable
, GList
*null
)
690 GntWM
*wm
= GNT_WM(bindable
);
692 if (wm
->_list
.window
|| wm
->menu
)
695 if (!wm
->cws
->ordered
)
698 list_of_windows(wm
, FALSE
);
704 dump_file_save(GntFileSel
*fs
, const char *path
, const char *f
, gpointer n
)
708 chtype old
= 0, now
= 0;
730 gnt_widget_destroy(GNT_WIDGET(fs
));
732 if ((file
= g_fopen(path
, "w+")) == NULL
) {
736 fprintf(file
, "<head>\n <meta http-equiv='Content-Type' content='text/html; charset=utf-8' />\n</head>\n<body>\n");
737 fprintf(file
, "<pre>");
738 for (y
= 0; y
< getmaxy(stdscr
); y
++) {
739 for (x
= 0; x
< getmaxx(stdscr
); x
++) {
740 char ch
[2] = {0, 0}, *print
;
742 now
= mvwinch(curscr
, y
, x
);
743 ch
[0] = now
& A_CHARTEXT
;
748 mvwin_wch(curscr
, y
, x
, &wch
);
750 ch
[0] = (char)(wch
.chars
[0] & 0xff);
753 #define CHECK(attr, start, end) \
759 fprintf(file, "%s", start); \
761 else if (old & attr) \
763 fprintf(file, "%s", end); \
767 CHECK(A_BOLD
, "<b>", "</b>");
768 CHECK(A_UNDERLINE
, "<u>", "</u>");
769 CHECK(A_BLINK
, "<blink>", "</blink>");
771 if ((now
& A_COLOR
) != (old
& A_COLOR
) ||
772 (now
& A_REVERSE
) != (old
& A_REVERSE
))
775 short fgp
, bgp
, r
, g
, b
;
781 ret
= pair_content(PAIR_NUMBER(now
& A_COLOR
), &fgp
, &bgp
);
792 ret
= color_content(fgp
, &r
, &g
, &b
);
793 fg
.r
= r
; fg
.b
= b
; fg
.g
= g
;
794 ret
= color_content(bgp
, &r
, &g
, &b
);
795 bg
.r
= r
; bg
.b
= b
; bg
.g
= g
;
796 #define ADJUST(x) (x = x * 255 / 1000)
804 if (x
) fprintf(file
, "</span>");
805 fprintf(file
, "<span style=\"background:#%02x%02x%02x;color:#%02x%02x%02x\">",
806 bg
.r
, bg
.g
, bg
.b
, fg
.r
, fg
.g
, fg
.b
);
810 if (wch
.chars
[0] > 255) {
811 snprintf(unicode
, sizeof(unicode
), "&#x%x;", (unsigned int)wch
.chars
[0]);
815 if (now
& A_ALTCHARSET
)
818 for (u
= 0; unis
[u
].ascii
; u
++) {
819 if (ch
[0] == unis
[u
].ascii
) {
820 print
= unis
[u
].unicode
;
828 fprintf(file
, "&");
829 else if (ch
[0] == '<')
830 fprintf(file
, "<");
831 else if (ch
[0] == '>')
832 fprintf(file
, ">");
834 fprintf(file
, "%s", print
);
837 fprintf(file
, "</span>\n");
840 fprintf(file
, "</pre>\n</body>");
845 dump_file_cancel(GntWidget
*w
, GntFileSel
*fs
)
847 gnt_widget_destroy(GNT_WIDGET(fs
));
851 dump_screen(GntBindable
*b
, GList
*null
)
853 GntWidget
*window
= gnt_file_sel_new();
854 GntFileSel
*sel
= GNT_FILE_SEL(window
);
856 g_object_set(G_OBJECT(window
), "vertical", TRUE
, NULL
);
857 gnt_box_add_widget(GNT_BOX(window
), gnt_label_new("Please enter the filename to save the screenshot."));
858 gnt_box_set_title(GNT_BOX(window
), "Save Screenshot...");
860 gnt_file_sel_set_suggested_filename(sel
, "dump.html");
861 g_signal_connect(G_OBJECT(sel
), "file_selected", G_CALLBACK(dump_file_save
), NULL
);
862 g_signal_connect(G_OBJECT(sel
->cancel
), "activate", G_CALLBACK(dump_file_cancel
), sel
);
863 gnt_widget_show(window
);
868 shift_window(GntWM
*wm
, GntWidget
*widget
, int dir
)
870 GList
*all
= wm
->cws
->list
;
871 GList
*list
= g_list_find(all
, widget
);
876 length
= g_list_length(all
);
877 pos
= g_list_position(all
, list
);
885 else if (pos
> length
)
888 all
= g_list_insert(all
, widget
, pos
);
889 all
= g_list_delete_link(all
, list
);
891 gnt_ws_draw_taskbar(wm
->cws
, FALSE
);
895 shift_left(GntBindable
*bindable
, GList
*null
)
897 GntWM
*wm
= GNT_WM(bindable
);
898 if (wm
->_list
.window
)
901 if(!wm
->cws
->ordered
)
904 shift_window(wm
, wm
->cws
->ordered
->data
, -1);
909 shift_right(GntBindable
*bindable
, GList
*null
)
911 GntWM
*wm
= GNT_WM(bindable
);
913 if (wm
->_list
.window
)
916 if(!wm
->cws
->ordered
)
919 shift_window(wm
, wm
->cws
->ordered
->data
, 1);
924 action_list_activate(GntTree
*tree
, GntWM
*wm
)
926 GntAction
*action
= gnt_tree_get_selection_data(tree
);
928 gnt_widget_destroy(wm
->_list
.window
);
932 compare_action(gconstpointer p1
, gconstpointer p2
)
934 const GntAction
*a1
= p1
;
935 const GntAction
*a2
= p2
;
937 return g_utf8_collate(a1
->label
, a2
->label
);
941 list_actions(GntBindable
*bindable
, GList
*null
)
943 GntWidget
*tree
, *win
;
945 GntWM
*wm
= GNT_WM(bindable
);
947 if (wm
->_list
.window
|| wm
->menu
)
950 if (wm
->acts
== NULL
)
954 wm
->actions
= &wm
->_list
;
956 win
= wm
->actions
->window
;
957 tree
= wm
->actions
->tree
;
959 gnt_box_set_title(GNT_BOX(win
), "Actions");
960 GNT_WIDGET_SET_FLAGS(tree
, GNT_WIDGET_NO_BORDER
);
961 /* XXX: Do we really want this? */
962 gnt_tree_set_compare_func(GNT_TREE(tree
), compare_action
);
964 for (iter
= wm
->acts
; iter
; iter
= iter
->next
) {
965 GntAction
*action
= iter
->data
;
966 gnt_tree_add_row_last(GNT_TREE(tree
), action
,
967 gnt_tree_create_row(GNT_TREE(tree
), action
->label
), NULL
);
969 g_signal_connect(G_OBJECT(tree
), "activate", G_CALLBACK(action_list_activate
), wm
);
970 n
= g_list_length(wm
->acts
);
971 gnt_widget_set_size(tree
, 0, n
);
972 gnt_widget_set_position(win
, 0, getmaxy(stdscr
) - 3 - n
);
974 gnt_widget_show(win
);
980 widestringwidth(wchar_t *wide
)
985 len
= wcstombs(NULL
, wide
, 0) + 1;
986 string
= g_new0(char, len
);
987 wcstombs(string
, wide
, len
);
988 ret
= string
? gnt_util_onscreen_width(string
, NULL
) : 1;
994 /* Returns the onscreen width of the character at the position */
996 reverse_char(WINDOW
*d
, int y
, int x
, gboolean set
)
998 #define DECIDE(ch) (set ? ((ch) | A_REVERSE) : ((ch) & ~A_REVERSE))
1002 ch
= mvwinch(d
, y
, x
);
1003 mvwaddch(d
, y
, x
, DECIDE(ch
));
1008 if (mvwin_wch(d
, y
, x
, &ch
) == OK
) {
1009 wc
= widestringwidth(ch
.chars
);
1010 ch
.attr
= DECIDE(ch
.attr
);
1011 ch
.attr
&= WA_ATTRIBUTES
; /* XXX: This is a workaround for a bug */
1012 mvwadd_wch(d
, y
, x
, &ch
);
1020 window_reverse(GntWidget
*win
, gboolean set
, GntWM
*wm
)
1026 if (GNT_WIDGET_IS_FLAG_SET(win
, GNT_WIDGET_NO_BORDER
))
1030 gnt_widget_get_size(win
, &w
, &h
);
1032 if (gnt_widget_has_shadow(win
)) {
1037 /* the top and bottom */
1038 for (i
= 0; i
< w
; i
+= reverse_char(d
, 0, i
, set
));
1039 for (i
= 0; i
< w
; i
+= reverse_char(d
, h
-1, i
, set
));
1041 /* the left and right */
1042 for (i
= 0; i
< h
; i
+= reverse_char(d
, i
, 0, set
));
1043 for (i
= 0; i
< h
; i
+= reverse_char(d
, i
, w
-1, set
));
1045 gnt_wm_copy_win(win
, g_hash_table_lookup(wm
->nodes
, win
));
1050 ensure_normal_mode(GntWM
*wm
)
1052 if (wm
->mode
!= GNT_KP_MODE_NORMAL
) {
1053 if (wm
->cws
->ordered
)
1054 window_reverse(wm
->cws
->ordered
->data
, FALSE
, wm
);
1055 wm
->mode
= GNT_KP_MODE_NORMAL
;
1060 start_move(GntBindable
*bindable
, GList
*null
)
1062 GntWM
*wm
= GNT_WM(bindable
);
1063 if (wm
->_list
.window
|| wm
->menu
)
1065 if (!wm
->cws
->ordered
)
1068 wm
->mode
= GNT_KP_MODE_MOVE
;
1069 window_reverse(GNT_WIDGET(wm
->cws
->ordered
->data
), TRUE
, wm
);
1075 start_resize(GntBindable
*bindable
, GList
*null
)
1077 GntWM
*wm
= GNT_WM(bindable
);
1078 if (wm
->_list
.window
|| wm
->menu
)
1080 if (!wm
->cws
->ordered
)
1083 wm
->mode
= GNT_KP_MODE_RESIZE
;
1084 window_reverse(GNT_WIDGET(wm
->cws
->ordered
->data
), TRUE
, wm
);
1090 wm_quit(GntBindable
*bindable
, GList
*list
)
1092 GntWM
*wm
= GNT_WM(bindable
);
1095 g_main_loop_quit(wm
->loop
);
1100 return_true(GntWM
*wm
, GntWidget
*w
, int *a
, int *b
)
1106 refresh_screen(GntBindable
*bindable
, GList
*null
)
1108 GntWM
*wm
= GNT_WM(bindable
);
1113 g_hash_table_foreach(wm
->nodes
, (GHFunc
)refresh_node
, GINT_TO_POINTER(TRUE
));
1114 g_signal_emit(wm
, signals
[SIG_TERMINAL_REFRESH
], 0);
1115 gnt_ws_draw_taskbar(wm
->cws
, TRUE
);
1117 curs_set(0); /* endwin resets the cursor to normal */
1123 toggle_clipboard(GntBindable
*bindable
, GList
*n
)
1125 static GntWidget
*clip
;
1129 gnt_widget_destroy(clip
);
1133 getmaxyx(stdscr
, maxy
, maxx
);
1134 text
= gnt_get_clipboard_string();
1135 clip
= gnt_hwindow_new(FALSE
);
1136 GNT_WIDGET_SET_FLAGS(clip
, GNT_WIDGET_TRANSIENT
);
1137 GNT_WIDGET_SET_FLAGS(clip
, GNT_WIDGET_NO_BORDER
);
1138 gnt_box_set_pad(GNT_BOX(clip
), 0);
1139 gnt_box_add_widget(GNT_BOX(clip
), gnt_label_new(" "));
1140 gnt_box_add_widget(GNT_BOX(clip
), gnt_label_new(text
));
1141 gnt_box_add_widget(GNT_BOX(clip
), gnt_label_new(" "));
1142 gnt_widget_set_position(clip
, 0, 0);
1143 gnt_widget_draw(clip
);
1148 static void remove_tag(gpointer wid
, gpointer wim
)
1150 GntWM
*wm
= GNT_WM(wim
);
1151 GntWidget
*w
= GNT_WIDGET(wid
);
1152 wm
->tagged
= g_list_remove(wm
->tagged
, w
);
1153 mvwhline(w
->window
, 0, 1, ACS_HLINE
| gnt_color_pair(GNT_COLOR_NORMAL
), 3);
1158 tag_widget(GntBindable
*b
, GList
*params
)
1160 GntWM
*wm
= GNT_WM(b
);
1163 if (!wm
->cws
->ordered
)
1165 widget
= wm
->cws
->ordered
->data
;
1167 if (g_list_find(wm
->tagged
, widget
)) {
1168 remove_tag(widget
, wm
);
1172 wm
->tagged
= g_list_prepend(wm
->tagged
, widget
);
1173 wbkgdset(widget
->window
, ' ' | gnt_color_pair(GNT_COLOR_HIGHLIGHT
));
1174 mvwprintw(widget
->window
, 0, 1, "[T]");
1175 gnt_widget_draw(widget
);
1180 widget_move_ws(gpointer wid
, gpointer w
)
1182 GntWM
*wm
= GNT_WM(w
);
1183 gnt_wm_widget_move_workspace(wm
, wm
->cws
, GNT_WIDGET(wid
));
1187 place_tagged(GntBindable
*b
, GList
*params
)
1189 GntWM
*wm
= GNT_WM(b
);
1190 g_list_foreach(wm
->tagged
, widget_move_ws
, wm
);
1191 g_list_foreach(wm
->tagged
, remove_tag
, wm
);
1192 g_list_free(wm
->tagged
);
1198 workspace_list(GntBindable
*b
, GList
*params
)
1200 GntWM
*wm
= GNT_WM(b
);
1202 if (wm
->_list
.window
|| wm
->menu
)
1205 list_of_windows(wm
, TRUE
);
1211 workspace_new(GntBindable
*bindable
, GList
*null
)
1213 GntWM
*wm
= GNT_WM(bindable
);
1214 GntWS
*ws
= gnt_ws_new(NULL
);
1215 gnt_wm_add_workspace(wm
, ws
);
1216 gnt_wm_switch_workspace(wm
, g_list_index(wm
->workspaces
, ws
));
1221 ignore_keys_start(GntBindable
*bindable
, GList
*n
)
1223 GntWM
*wm
= GNT_WM(bindable
);
1225 if(!wm
->menu
&& !wm
->_list
.window
&& wm
->mode
== GNT_KP_MODE_NORMAL
){
1233 ignore_keys_end(GntBindable
*bindable
, GList
*n
)
1235 return ignore_keys
? !(ignore_keys
= FALSE
) : FALSE
;
1239 window_next_urgent(GntBindable
*bindable
, GList
*n
)
1241 GntWM
*wm
= GNT_WM(bindable
);
1242 switch_window(wm
, 1, TRUE
);
1247 window_prev_urgent(GntBindable
*bindable
, GList
*n
)
1249 GntWM
*wm
= GNT_WM(bindable
);
1250 switch_window(wm
, -1, TRUE
);
1256 python_script_selected(GntFileSel
*fs
, const char *path
, const char *f
, gpointer n
)
1258 char *dir
= g_path_get_dirname(path
);
1259 FILE *file
= fopen(path
, "r");
1260 PyObject
*pp
= PySys_GetObject("path"), *dirobj
= PyString_FromString(dir
);
1262 PyList_Insert(pp
, 0, dirobj
);
1264 PyRun_SimpleFile(file
, path
);
1267 if (PyErr_Occurred()) {
1272 gnt_widget_destroy(GNT_WIDGET(fs
));
1276 run_python(GntBindable
*bindable
, GList
*n
)
1278 GntWidget
*window
= gnt_file_sel_new();
1279 GntFileSel
*sel
= GNT_FILE_SEL(window
);
1281 g_object_set(G_OBJECT(window
), "vertical", TRUE
, NULL
);
1282 gnt_box_add_widget(GNT_BOX(window
), gnt_label_new("Please select the python script you want to run."));
1283 gnt_box_set_title(GNT_BOX(window
), "Select Python Script...");
1285 g_signal_connect(G_OBJECT(sel
), "file_selected", G_CALLBACK(python_script_selected
), NULL
);
1286 g_signal_connect_swapped(G_OBJECT(sel
->cancel
), "activate", G_CALLBACK(gnt_widget_destroy
), sel
);
1287 gnt_widget_show(window
);
1290 #endif /* USE_PYTHON */
1293 help_for_bindable(GntWM
*wm
, GntBindable
*bindable
)
1295 gboolean ret
= TRUE
;
1296 GntBindableClass
*klass
= GNT_BINDABLE_GET_CLASS(bindable
);
1298 if (klass
->help_window
) {
1299 gnt_wm_raise_window(wm
, GNT_WIDGET(klass
->help_window
));
1301 ret
= gnt_bindable_build_help_window(bindable
);
1307 help_for_wm(GntBindable
*bindable
, GList
*null
)
1309 return help_for_bindable(GNT_WM(bindable
),bindable
);
1313 help_for_window(GntBindable
*bindable
, GList
*null
)
1315 GntWM
*wm
= GNT_WM(bindable
);
1318 if(!wm
->cws
->ordered
)
1321 widget
= wm
->cws
->ordered
->data
;
1323 return help_for_bindable(wm
,GNT_BINDABLE(widget
));
1327 help_for_widget(GntBindable
*bindable
, GList
*null
)
1329 GntWM
*wm
= GNT_WM(bindable
);
1332 if (!wm
->cws
->ordered
)
1335 widget
= wm
->cws
->ordered
->data
;
1336 if (!GNT_IS_BOX(widget
))
1339 return help_for_bindable(wm
, GNT_BINDABLE(GNT_BOX(widget
)->active
));
1343 accumulate_windows(gpointer window
, gpointer node
, gpointer p
)
1345 GList
*list
= *(GList
**)p
;
1346 list
= g_list_prepend(list
, window
);
1351 gnt_wm_destroy(GObject
*obj
)
1353 GntWM
*wm
= GNT_WM(obj
);
1355 g_hash_table_foreach(wm
->nodes
, accumulate_windows
, &list
);
1356 g_list_foreach(list
, (GFunc
)gnt_widget_destroy
, NULL
);
1358 g_hash_table_destroy(wm
->nodes
);
1361 while (wm
->workspaces
) {
1362 g_object_unref(wm
->workspaces
->data
);
1363 wm
->workspaces
= g_list_delete_link(wm
->workspaces
, wm
->workspaces
);
1366 if (started_python
) {
1368 started_python
= FALSE
;
1374 gnt_wm_class_init(GntWMClass
*klass
)
1377 GObjectClass
*gclass
= G_OBJECT_CLASS(klass
);
1380 gclass
->dispose
= gnt_wm_destroy
;
1382 klass
->new_window
= gnt_wm_new_window_real
;
1383 klass
->decorate_window
= NULL
;
1384 klass
->close_window
= NULL
;
1385 klass
->window_resize_confirm
= return_true
;
1386 klass
->window_resized
= gnt_wm_win_resized
;
1387 klass
->window_move_confirm
= return_true
;
1388 klass
->window_moved
= gnt_wm_win_moved
;
1389 klass
->window_update
= NULL
;
1390 klass
->key_pressed
= NULL
;
1391 klass
->mouse_clicked
= NULL
;
1392 klass
->give_focus
= gnt_wm_give_focus
;
1394 signals
[SIG_NEW_WIN
] =
1395 g_signal_new("new_win",
1396 G_TYPE_FROM_CLASS(klass
),
1398 G_STRUCT_OFFSET(GntWMClass
, new_window
),
1400 g_cclosure_marshal_VOID__POINTER
,
1401 G_TYPE_NONE
, 1, G_TYPE_POINTER
);
1402 signals
[SIG_DECORATE_WIN
] =
1403 g_signal_new("decorate_win",
1404 G_TYPE_FROM_CLASS(klass
),
1406 G_STRUCT_OFFSET(GntWMClass
, decorate_window
),
1408 g_cclosure_marshal_VOID__POINTER
,
1409 G_TYPE_NONE
, 1, G_TYPE_POINTER
);
1410 signals
[SIG_CLOSE_WIN
] =
1411 g_signal_new("close_win",
1412 G_TYPE_FROM_CLASS(klass
),
1414 G_STRUCT_OFFSET(GntWMClass
, close_window
),
1416 g_cclosure_marshal_VOID__POINTER
,
1417 G_TYPE_NONE
, 1, G_TYPE_POINTER
);
1418 signals
[SIG_CONFIRM_RESIZE
] =
1419 g_signal_new("confirm_resize",
1420 G_TYPE_FROM_CLASS(klass
),
1422 G_STRUCT_OFFSET(GntWMClass
, window_resize_confirm
),
1423 gnt_boolean_handled_accumulator
, NULL
,
1424 gnt_closure_marshal_BOOLEAN__POINTER_POINTER_POINTER
,
1425 G_TYPE_BOOLEAN
, 3, G_TYPE_POINTER
, G_TYPE_POINTER
, G_TYPE_POINTER
);
1427 signals
[SIG_CONFIRM_MOVE
] =
1428 g_signal_new("confirm_move",
1429 G_TYPE_FROM_CLASS(klass
),
1431 G_STRUCT_OFFSET(GntWMClass
, window_move_confirm
),
1432 gnt_boolean_handled_accumulator
, NULL
,
1433 gnt_closure_marshal_BOOLEAN__POINTER_POINTER_POINTER
,
1434 G_TYPE_BOOLEAN
, 3, G_TYPE_POINTER
, G_TYPE_POINTER
, G_TYPE_POINTER
);
1436 signals
[SIG_RESIZED
] =
1437 g_signal_new("window_resized",
1438 G_TYPE_FROM_CLASS(klass
),
1440 G_STRUCT_OFFSET(GntWMClass
, window_resized
),
1442 g_cclosure_marshal_VOID__POINTER
,
1443 G_TYPE_NONE
, 1, G_TYPE_POINTER
);
1444 signals
[SIG_MOVED
] =
1445 g_signal_new("window_moved",
1446 G_TYPE_FROM_CLASS(klass
),
1448 G_STRUCT_OFFSET(GntWMClass
, window_moved
),
1450 g_cclosure_marshal_VOID__POINTER
,
1451 G_TYPE_NONE
, 1, G_TYPE_POINTER
);
1452 signals
[SIG_UPDATE_WIN
] =
1453 g_signal_new("window_update",
1454 G_TYPE_FROM_CLASS(klass
),
1456 G_STRUCT_OFFSET(GntWMClass
, window_update
),
1458 g_cclosure_marshal_VOID__POINTER
,
1459 G_TYPE_NONE
, 1, G_TYPE_POINTER
);
1461 signals
[SIG_GIVE_FOCUS
] =
1462 g_signal_new("give_focus",
1463 G_TYPE_FROM_CLASS(klass
),
1465 G_STRUCT_OFFSET(GntWMClass
, give_focus
),
1467 g_cclosure_marshal_VOID__POINTER
,
1468 G_TYPE_NONE
, 1, G_TYPE_POINTER
);
1470 signals
[SIG_MOUSE_CLICK
] =
1471 g_signal_new("mouse_clicked",
1472 G_TYPE_FROM_CLASS(klass
),
1474 G_STRUCT_OFFSET(GntWMClass
, mouse_clicked
),
1475 gnt_boolean_handled_accumulator
, NULL
,
1476 gnt_closure_marshal_BOOLEAN__INT_INT_INT_POINTER
,
1477 G_TYPE_BOOLEAN
, 4, G_TYPE_INT
, G_TYPE_INT
, G_TYPE_INT
, G_TYPE_POINTER
);
1479 signals
[SIG_TERMINAL_REFRESH
] =
1480 g_signal_new("terminal-refresh",
1481 G_TYPE_FROM_CLASS(klass
),
1483 G_STRUCT_OFFSET(GntWMClass
, terminal_refresh
),
1485 g_cclosure_marshal_VOID__VOID
,
1488 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "window-next", window_next
,
1490 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "window-prev", window_prev
,
1492 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "window-close", window_close
,
1494 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "window-list", window_list
,
1496 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "dump-screen", dump_screen
,
1498 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "shift-left", shift_left
,
1500 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "shift-right", shift_right
,
1502 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "action-list", list_actions
,
1504 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "start-move", start_move
,
1506 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "start-resize", start_resize
,
1508 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "wm-quit", wm_quit
,
1510 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "refresh-screen", refresh_screen
,
1512 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "switch-window-n", switch_window_n
,
1514 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "window-scroll-down", window_scroll_down
,
1515 "\033" GNT_KEY_CTRL_J
, NULL
);
1516 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "window-scroll-up", window_scroll_up
,
1517 "\033" GNT_KEY_CTRL_K
, NULL
);
1518 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "help-for-widget", help_for_widget
,
1520 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "workspace-new", workspace_new
,
1522 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "workspace-next", workspace_next
,
1524 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "workspace-prev", workspace_prev
,
1526 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "window-tag", tag_widget
,
1528 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "place-tagged", place_tagged
,
1530 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "workspace-list", workspace_list
,
1532 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "toggle-clipboard", toggle_clipboard
,
1534 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "help-for-wm", help_for_wm
,
1536 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "help-for-window", help_for_window
,
1538 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "ignore-keys-start", ignore_keys_start
,
1540 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "ignore-keys-end", ignore_keys_end
,
1541 "\033" GNT_KEY_CTRL_G
, NULL
);
1542 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "window-next-urgent", window_next_urgent
,
1544 snprintf(key
, sizeof(key
), "\033%s", GNT_KEY_BACK_TAB
);
1545 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "window-prev-urgent", window_prev_urgent
,
1546 key
[1] ? key
: NULL
, NULL
);
1548 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "run-python", run_python
,
1550 if (!Py_IsInitialized()) {
1551 Py_SetProgramName("gnt");
1553 started_python
= TRUE
;
1557 gnt_style_read_actions(G_OBJECT_CLASS_TYPE(klass
), GNT_BINDABLE_CLASS(klass
));
1559 /* Make sure Alt+x are detected properly. */
1560 for (i
= '0'; i
<= '9'; i
++) {
1561 char str
[] = "\033X";
1563 gnt_keys_add_combination(str
);
1569 /******************************************************************************
1571 *****************************************************************************/
1573 gnt_wm_get_gtype(void)
1575 static GType type
= 0;
1578 static const GTypeInfo info
= {
1580 NULL
, /* base_init */
1581 NULL
, /* base_finalize */
1582 (GClassInitFunc
)gnt_wm_class_init
,
1584 NULL
, /* class_data */
1586 0, /* n_preallocs */
1587 gnt_wm_init
, /* instance_init */
1588 NULL
/* value_table */
1591 type
= g_type_register_static(GNT_TYPE_BINDABLE
,
1600 gnt_wm_add_workspace(GntWM
*wm
, GntWS
*ws
)
1602 wm
->workspaces
= g_list_append(wm
->workspaces
, ws
);
1606 gnt_wm_switch_workspace(GntWM
*wm
, gint n
)
1608 GntWS
*s
= g_list_nth_data(wm
->workspaces
, n
);
1612 if (wm
->_list
.window
) {
1613 gnt_widget_destroy(wm
->_list
.window
);
1615 ensure_normal_mode(wm
);
1616 gnt_ws_hide(wm
->cws
, wm
->nodes
);
1618 gnt_ws_show(wm
->cws
, wm
->nodes
);
1620 gnt_ws_draw_taskbar(wm
->cws
, TRUE
);
1622 if (wm
->cws
->ordered
) {
1623 gnt_wm_raise_window(wm
, wm
->cws
->ordered
->data
);
1626 if (act
&& g_list_find(act
, wm
->cws
)) {
1627 act
= g_list_remove(act
, wm
->cws
);
1634 gnt_wm_switch_workspace_prev(GntWM
*wm
)
1636 int n
= g_list_index(wm
->workspaces
, wm
->cws
);
1637 return gnt_wm_switch_workspace(wm
, --n
);
1641 gnt_wm_switch_workspace_next(GntWM
*wm
)
1643 int n
= g_list_index(wm
->workspaces
, wm
->cws
);
1644 return gnt_wm_switch_workspace(wm
, ++n
);
1648 workspace_next(GntBindable
*wm
, GList
*n
)
1650 return gnt_wm_switch_workspace_next(GNT_WM(wm
));
1654 workspace_prev(GntBindable
*wm
, GList
*n
)
1656 return gnt_wm_switch_workspace_prev(GNT_WM(wm
));
1660 gnt_wm_widget_move_workspace(GntWM
*wm
, GntWS
*neww
, GntWidget
*widget
)
1662 GntWS
*oldw
= gnt_wm_widget_find_workspace(wm
, widget
);
1664 if (!oldw
|| oldw
== neww
)
1666 node
= g_hash_table_lookup(wm
->nodes
, widget
);
1667 if (node
&& node
->ws
== neww
)
1673 gnt_ws_remove_widget(oldw
, widget
);
1674 gnt_ws_add_widget(neww
, widget
);
1675 if (neww
== wm
->cws
) {
1676 gnt_ws_widget_show(widget
, wm
->nodes
);
1678 gnt_ws_widget_hide(widget
, wm
->nodes
);
1682 static gint
widget_in_workspace(gconstpointer workspace
, gconstpointer wid
)
1684 GntWS
*s
= (GntWS
*)workspace
;
1685 if (s
->list
&& g_list_find(s
->list
, wid
))
1690 GntWS
*gnt_wm_widget_find_workspace(GntWM
*wm
, GntWidget
*widget
)
1692 GList
*l
= g_list_find_custom(wm
->workspaces
, widget
, widget_in_workspace
);
1698 static void free_workspaces(gpointer data
, gpointer n
)
1704 void gnt_wm_set_workspaces(GntWM
*wm
, GList
*workspaces
)
1706 g_list_foreach(wm
->workspaces
, free_workspaces
, NULL
);
1707 wm
->workspaces
= workspaces
;
1708 gnt_wm_switch_workspace(wm
, 0);
1712 update_window_in_list(GntWM
*wm
, GntWidget
*wid
)
1714 GntTextFormatFlags flag
= 0;
1716 if (wm
->windows
== NULL
)
1719 if (wm
->cws
->ordered
&& wid
== wm
->cws
->ordered
->data
)
1720 flag
|= GNT_TEXT_FLAG_DIM
;
1721 else if (GNT_WIDGET_IS_FLAG_SET(wid
, GNT_WIDGET_URGENT
))
1722 flag
|= GNT_TEXT_FLAG_BOLD
;
1724 gnt_tree_set_row_flags(GNT_TREE(wm
->windows
->tree
), wid
, flag
);
1728 match_title(gpointer title
, gpointer n
, gpointer wid_title
)
1730 /* XXX: do any regex magic here. */
1731 if (g_strrstr((gchar
*)wid_title
, (gchar
*)title
))
1736 #if !GLIB_CHECK_VERSION(2,4,0)
1744 table_find_helper(gpointer key
, gpointer value
, gpointer data
)
1746 GHRFunc func
= data
;
1747 if (func(key
, value
, table_find_data
.data
))
1748 table_find_data
.value
= value
;
1752 g_hash_table_find(GHashTable
* table
, GHRFunc func
, gpointer data
)
1754 table_find_data
.data
= data
;
1755 table_find_data
.value
= NULL
;
1756 g_hash_table_foreach(table
, table_find_helper
, func
);
1757 return table_find_data
.value
;
1762 new_widget_find_workspace(GntWM
*wm
, GntWidget
*widget
)
1765 const gchar
*name
, *title
;
1766 title
= GNT_BOX(widget
)->title
;
1768 ret
= g_hash_table_find(wm
->title_places
, match_title
, (gpointer
)title
);
1771 name
= gnt_widget_get_name(widget
);
1773 ret
= g_hash_table_find(wm
->name_places
, match_title
, (gpointer
)name
);
1774 return ret
? ret
: wm
->cws
;
1778 gnt_wm_new_window_real(GntWM
*wm
, GntWidget
*widget
)
1781 gboolean transient
= FALSE
;
1783 if (widget
->window
== NULL
)
1786 node
= g_new0(GntNode
, 1);
1790 g_hash_table_replace(wm
->nodes
, widget
, node
);
1792 refresh_node(widget
, node
, GINT_TO_POINTER(TRUE
));
1794 transient
= !!GNT_WIDGET_IS_FLAG_SET(node
->me
, GNT_WIDGET_TRANSIENT
);
1798 int x
, y
, w
, h
, maxx
, maxy
;
1799 gboolean shadow
= TRUE
;
1801 if (!gnt_widget_has_shadow(widget
))
1805 w
= widget
->priv
.width
+ shadow
;
1806 h
= widget
->priv
.height
+ shadow
;
1808 maxx
= getmaxx(stdscr
);
1809 maxy
= getmaxy(stdscr
) - 1; /* room for the taskbar */
1814 x
= MAX(0, maxx
- w
);
1816 y
= MAX(0, maxy
- h
);
1820 node
->window
= newwin(h
, w
, y
, x
);
1821 gnt_wm_copy_win(widget
, node
);
1825 node
->panel
= new_panel(node
->window
);
1826 set_panel_userptr(node
->panel
, node
);
1829 GntWS
*ws
= wm
->cws
;
1830 if (node
->me
!= wm
->_list
.window
) {
1831 if (GNT_IS_BOX(widget
)) {
1832 ws
= new_widget_find_workspace(wm
, widget
);
1835 ws
->list
= g_list_append(ws
->list
, widget
);
1836 ws
->ordered
= g_list_append(ws
->ordered
, widget
);
1839 if (wm
->event_stack
|| node
->me
== wm
->_list
.window
||
1840 node
->me
== ws
->ordered
->data
) {
1841 gnt_wm_raise_window(wm
, node
->me
);
1843 bottom_panel(node
->panel
); /* New windows should not grab focus */
1844 gnt_widget_set_focus(node
->me
, FALSE
);
1845 gnt_widget_set_urgent(node
->me
);
1847 gnt_ws_widget_hide(widget
, wm
->nodes
);
1852 void gnt_wm_new_window(GntWM
*wm
, GntWidget
*widget
)
1854 while (widget
->parent
)
1855 widget
= widget
->parent
;
1857 if (GNT_WIDGET_IS_FLAG_SET(widget
, GNT_WIDGET_INVISIBLE
) ||
1858 g_hash_table_lookup(wm
->nodes
, widget
)) {
1863 if (GNT_IS_BOX(widget
)) {
1864 const char *title
= GNT_BOX(widget
)->title
;
1865 GntPosition
*p
= NULL
;
1866 if (title
&& (p
= g_hash_table_lookup(wm
->positions
, title
)) != NULL
) {
1867 sanitize_position(widget
, &p
->x
, &p
->y
, TRUE
);
1868 gnt_widget_set_position(widget
, p
->x
, p
->y
);
1869 mvwin(widget
->window
, p
->y
, p
->x
);
1873 g_signal_emit(wm
, signals
[SIG_NEW_WIN
], 0, widget
);
1874 g_signal_emit(wm
, signals
[SIG_DECORATE_WIN
], 0, widget
);
1876 if (wm
->windows
&& !GNT_WIDGET_IS_FLAG_SET(widget
, GNT_WIDGET_TRANSIENT
)) {
1877 if ((GNT_IS_BOX(widget
) && GNT_BOX(widget
)->title
) && wm
->_list
.window
!= widget
1878 && GNT_WIDGET_IS_FLAG_SET(widget
, GNT_WIDGET_CAN_TAKE_FOCUS
)) {
1879 gnt_tree_add_row_last(GNT_TREE(wm
->windows
->tree
), widget
,
1880 gnt_tree_create_row(GNT_TREE(wm
->windows
->tree
), GNT_BOX(widget
)->title
),
1881 g_object_get_data(G_OBJECT(wm
->windows
->tree
), "workspace") ? wm
->cws
: NULL
);
1882 update_window_in_list(wm
, widget
);
1886 gnt_ws_draw_taskbar(wm
->cws
, FALSE
);
1890 void gnt_wm_window_decorate(GntWM
*wm
, GntWidget
*widget
)
1892 g_signal_emit(wm
, signals
[SIG_DECORATE_WIN
], 0, widget
);
1895 void gnt_wm_window_close(GntWM
*wm
, GntWidget
*widget
)
1899 gboolean transient
= !!GNT_WIDGET_IS_FLAG_SET(widget
, GNT_WIDGET_TRANSIENT
);
1901 s
= gnt_wm_widget_find_workspace(wm
, widget
);
1903 if (g_hash_table_lookup(wm
->nodes
, widget
) == NULL
)
1906 g_signal_emit(wm
, signals
[SIG_CLOSE_WIN
], 0, widget
);
1907 g_hash_table_remove(wm
->nodes
, widget
);
1910 gnt_tree_remove(GNT_TREE(wm
->windows
->tree
), widget
);
1914 pos
= g_list_index(s
->list
, widget
);
1917 s
->list
= g_list_remove(s
->list
, widget
);
1918 s
->ordered
= g_list_remove(s
->ordered
, widget
);
1920 if (s
->ordered
&& wm
->cws
== s
)
1921 gnt_wm_raise_window(wm
, s
->ordered
->data
);
1923 } else if (transient
&& wm
->cws
&& wm
->cws
->ordered
) {
1924 gnt_wm_update_window(wm
, wm
->cws
->ordered
->data
);
1927 gnt_ws_draw_taskbar(wm
->cws
, FALSE
);
1931 time_t gnt_wm_get_idle_time()
1933 return time(NULL
) - last_active_time
;
1936 gboolean
gnt_wm_process_input(GntWM
*wm
, const char *keys
)
1938 gboolean ret
= FALSE
;
1940 keys
= gnt_bindable_remap_keys(GNT_BINDABLE(wm
), keys
);
1944 if(keys
&& !strcmp(keys
, "\033" GNT_KEY_CTRL_G
)){
1945 if(gnt_bindable_perform_action_key(GNT_BINDABLE(wm
), keys
)){
1949 return wm
->cws
->ordered
? gnt_widget_key_pressed(GNT_WIDGET(wm
->cws
->ordered
->data
), keys
) : FALSE
;
1952 if (gnt_bindable_perform_action_key(GNT_BINDABLE(wm
), keys
)) {
1956 /* Do some manual checking */
1957 if (wm
->cws
->ordered
&& wm
->mode
!= GNT_KP_MODE_NORMAL
) {
1958 int xmin
= 0, ymin
= 0, xmax
= getmaxx(stdscr
), ymax
= getmaxy(stdscr
) - 1;
1960 GntWidget
*widget
= GNT_WIDGET(wm
->cws
->ordered
->data
);
1963 gnt_widget_get_position(widget
, &x
, &y
);
1964 gnt_widget_get_size(widget
, &w
, &h
);
1968 if (wm
->mode
== GNT_KP_MODE_MOVE
) {
1969 if (strcmp(keys
, GNT_KEY_LEFT
) == 0) {
1972 } else if (strcmp(keys
, GNT_KEY_RIGHT
) == 0) {
1975 } else if (strcmp(keys
, GNT_KEY_UP
) == 0) {
1978 } else if (strcmp(keys
, GNT_KEY_DOWN
) == 0) {
1982 if (ox
!= x
|| oy
!= y
) {
1983 gnt_screen_move_widget(widget
, x
, y
);
1984 window_reverse(widget
, TRUE
, wm
);
1987 } else if (wm
->mode
== GNT_KP_MODE_RESIZE
) {
1988 if (strcmp(keys
, GNT_KEY_LEFT
) == 0) {
1990 } else if (strcmp(keys
, GNT_KEY_RIGHT
) == 0) {
1993 } else if (strcmp(keys
, GNT_KEY_UP
) == 0) {
1995 } else if (strcmp(keys
, GNT_KEY_DOWN
) == 0) {
1999 if (oh
!= h
|| ow
!= w
) {
2000 gnt_screen_resize_widget(widget
, w
, h
);
2001 window_reverse(widget
, TRUE
, wm
);
2005 if (strcmp(keys
, "\r") == 0 || strcmp(keys
, "\033") == 0) {
2006 window_reverse(widget
, FALSE
, wm
);
2007 wm
->mode
= GNT_KP_MODE_NORMAL
;
2012 /* Escape to close the window-list or action-list window */
2013 if (strcmp(keys
, "\033") == 0) {
2014 if (wm
->_list
.window
) {
2015 gnt_widget_destroy(wm
->_list
.window
);
2018 } else if (keys
[0] == '\033' && isdigit(keys
[1]) && keys
[2] == '\0') {
2019 /* Alt+x for quick switch */
2020 int n
= *(keys
+ 1) - '0';
2026 list
= g_list_append(list
, GINT_TO_POINTER(n
- 1));
2027 switch_window_n(GNT_BINDABLE(wm
), list
);
2033 ret
= gnt_widget_key_pressed(GNT_WIDGET(wm
->menu
), keys
);
2034 else if (wm
->_list
.window
)
2035 ret
= gnt_widget_key_pressed(wm
->_list
.window
, keys
);
2036 else if (wm
->cws
->ordered
) {
2037 GntWidget
*win
= wm
->cws
->ordered
->data
;
2038 if (GNT_IS_WINDOW(win
)) {
2039 GntMenu
*menu
= GNT_WINDOW(win
)->menu
;
2041 const char *id
= gnt_window_get_accel_item(GNT_WINDOW(win
), keys
);
2043 GntMenuItem
*item
= gnt_menu_get_item(menu
, id
);
2045 ret
= gnt_menuitem_activate(item
);
2050 ret
= gnt_widget_key_pressed(win
, keys
);
2056 gnt_wm_win_resized(GntWM
*wm
, GntNode
*node
)
2058 /*refresh_node(node->me, node, NULL);*/
2062 gnt_wm_win_moved(GntWM
*wm
, GntNode
*node
)
2064 refresh_node(node
->me
, node
, NULL
);
2067 void gnt_wm_resize_window(GntWM
*wm
, GntWidget
*widget
, int width
, int height
)
2069 gboolean ret
= TRUE
;
2073 while (widget
->parent
)
2074 widget
= widget
->parent
;
2075 node
= g_hash_table_lookup(wm
->nodes
, widget
);
2079 g_signal_emit(wm
, signals
[SIG_CONFIRM_RESIZE
], 0, widget
, &width
, &height
, &ret
);
2081 return; /* resize is not permitted */
2082 hide_panel(node
->panel
);
2083 gnt_widget_set_size(widget
, width
, height
);
2084 gnt_widget_draw(widget
);
2086 maxx
= getmaxx(stdscr
);
2087 maxy
= getmaxy(stdscr
) - 1;
2088 height
= MIN(height
, maxy
);
2089 width
= MIN(width
, maxx
);
2090 wresize(node
->window
, height
, width
);
2091 replace_panel(node
->panel
, node
->window
);
2093 g_signal_emit(wm
, signals
[SIG_RESIZED
], 0, node
);
2095 show_panel(node
->panel
);
2100 write_gdi(gpointer key
, gpointer value
, gpointer data
)
2102 GntPosition
*p
= value
;
2103 fprintf(data
, ".%s = %d;%d\n", (char *)key
, p
->x
, p
->y
);
2107 write_already(gpointer data
)
2113 filename
= g_build_filename(g_get_home_dir(), ".gntpositions", NULL
);
2115 file
= fopen(filename
, "wb");
2117 gnt_warning("error opening file (%s) to save positions", filename
);
2119 fprintf(file
, "[positions]\n");
2120 g_hash_table_foreach(wm
->positions
, write_gdi
, file
);
2125 g_source_remove(write_timeout
);
2131 write_positions_to_file(GntWM
*wm
)
2133 if (write_timeout
) {
2134 g_source_remove(write_timeout
);
2136 write_timeout
= g_timeout_add_seconds(10, write_already
, wm
);
2139 void gnt_wm_move_window(GntWM
*wm
, GntWidget
*widget
, int x
, int y
)
2141 gboolean ret
= TRUE
;
2144 while (widget
->parent
)
2145 widget
= widget
->parent
;
2146 node
= g_hash_table_lookup(wm
->nodes
, widget
);
2150 g_signal_emit(wm
, signals
[SIG_CONFIRM_MOVE
], 0, widget
, &x
, &y
, &ret
);
2152 return; /* resize is not permitted */
2154 gnt_widget_set_position(widget
, x
, y
);
2155 move_panel(node
->panel
, y
, x
);
2157 g_signal_emit(wm
, signals
[SIG_MOVED
], 0, node
);
2158 if (gnt_style_get_bool(GNT_STYLE_REMPOS
, TRUE
) && GNT_IS_BOX(widget
) &&
2159 !GNT_WIDGET_IS_FLAG_SET(widget
, GNT_WIDGET_TRANSIENT
)) {
2160 const char *title
= GNT_BOX(widget
)->title
;
2162 GntPosition
*p
= g_new0(GntPosition
, 1);
2163 GntWidget
*wid
= node
->me
;
2166 g_hash_table_replace(wm
->positions
, g_strdup(title
), p
);
2167 write_positions_to_file(wm
);
2175 gnt_wm_give_focus(GntWM
*wm
, GntWidget
*widget
)
2177 GntNode
*node
= g_hash_table_lookup(wm
->nodes
, widget
);
2182 if (widget
!= wm
->_list
.window
&& !GNT_IS_MENU(widget
) &&
2183 wm
->cws
->ordered
->data
!= widget
) {
2184 GntWidget
*w
= wm
->cws
->ordered
->data
;
2185 wm
->cws
->ordered
= g_list_bring_to_front(wm
->cws
->ordered
, widget
);
2186 gnt_widget_set_focus(w
, FALSE
);
2189 gnt_widget_set_focus(widget
, TRUE
);
2190 GNT_WIDGET_UNSET_FLAGS(widget
, GNT_WIDGET_URGENT
);
2191 gnt_widget_draw(widget
);
2192 top_panel(node
->panel
);
2194 if (wm
->_list
.window
) {
2195 GntNode
*nd
= g_hash_table_lookup(wm
->nodes
, wm
->_list
.window
);
2196 top_panel(nd
->panel
);
2198 gnt_ws_draw_taskbar(wm
->cws
, FALSE
);
2202 void gnt_wm_update_window(GntWM
*wm
, GntWidget
*widget
)
2204 GntNode
*node
= NULL
;
2207 while (widget
->parent
)
2208 widget
= widget
->parent
;
2209 if (!GNT_IS_MENU(widget
)) {
2210 if (!GNT_IS_BOX(widget
))
2212 gnt_box_sync_children(GNT_BOX(widget
));
2215 ws
= gnt_wm_widget_find_workspace(wm
, widget
);
2216 node
= g_hash_table_lookup(wm
->nodes
, widget
);
2218 gnt_wm_new_window(wm
, widget
);
2220 g_signal_emit(wm
, signals
[SIG_UPDATE_WIN
], 0, node
);
2222 if (ws
== wm
->cws
|| GNT_WIDGET_IS_FLAG_SET(widget
, GNT_WIDGET_TRANSIENT
)) {
2223 gnt_wm_copy_win(widget
, node
);
2224 gnt_ws_draw_taskbar(wm
->cws
, FALSE
);
2226 } else if (ws
&& ws
!= wm
->cws
&& GNT_WIDGET_IS_FLAG_SET(widget
, GNT_WIDGET_URGENT
)) {
2227 if (!act
|| (act
&& !g_list_find(act
, ws
)))
2228 act
= g_list_prepend(act
, ws
);
2233 gboolean
gnt_wm_process_click(GntWM
*wm
, GntMouseEvent event
, int x
, int y
, GntWidget
*widget
)
2235 gboolean ret
= TRUE
;
2237 g_signal_emit(wm
, signals
[SIG_MOUSE_CLICK
], 0, event
, x
, y
, widget
, &ret
);
2241 void gnt_wm_raise_window(GntWM
*wm
, GntWidget
*widget
)
2243 GntWS
*ws
= gnt_wm_widget_find_workspace(wm
, widget
);
2245 gnt_wm_switch_workspace(wm
, g_list_index(wm
->workspaces
, ws
));
2246 if (widget
!= wm
->cws
->ordered
->data
) {
2247 GntWidget
*wid
= wm
->cws
->ordered
->data
;
2248 wm
->cws
->ordered
= g_list_bring_to_front(wm
->cws
->ordered
, widget
);
2249 gnt_widget_set_focus(wid
, FALSE
);
2250 gnt_widget_draw(wid
);
2252 gnt_widget_set_focus(widget
, TRUE
);
2253 gnt_widget_draw(widget
);
2254 g_signal_emit(wm
, signals
[SIG_GIVE_FOCUS
], 0, widget
);
2257 void gnt_wm_set_event_stack(GntWM
*wm
, gboolean set
)
2259 wm
->event_stack
= set
;