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__)
30 #define _XOPEN_SOURCE_EXTENDED
35 #include <glib/gstdio.h>
44 #include "gntmarshal.h"
47 #include "gntbutton.h"
49 #include "gntfilesel.h"
52 #include "gnttextview.h"
55 #include "gntwindow.h"
57 #define IDLE_CHECK_INTERVAL 5 /* 5 seconds */
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
);
87 static int widestringwidth(wchar_t *wide
);
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
;
99 g_list_bring_to_front(GList
*list
, gpointer data
)
101 list
= g_list_remove(list
, data
);
102 list
= g_list_prepend(list
, data
);
107 free_node(gpointer data
)
109 GntNode
*node
= data
;
110 hide_panel(node
->panel
);
111 del_panel(node
->panel
);
116 gnt_wm_copy_win(GntWidget
*widget
, GntNode
*node
)
121 src
= widget
->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.
138 work_around_for_ncurses_bug(void)
142 while ((panel
= panel_below(panel
)) != NULL
) {
143 int sx
, ex
, sy
, ey
, w
, y
;
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
)
156 if (sx
> below
->win
->_begx
+ below
->win
->_maxx
||
157 ex
< below
->win
->_begx
)
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
)
162 w
= widestringwidth(ch
.chars
);
163 if (w
> 1 && (ch
.attr
& 1)) {
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);
170 if (mvwin_wch(below
->win
, y
- below
->win
->_begy
, ex
+ 1 - below
->win
->_begx
, &ch
) != OK
)
172 w
= widestringwidth(ch
.chars
);
173 if (w
> 1 && !(ch
.attr
& 1)) {
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);
190 static GntWidget
*message
= NULL
;
191 GString
*text
= g_string_new("act: ");
193 gnt_widget_destroy(message
);
194 if (g_list_length(act
) == 0)
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
);
213 update_screen(GntWM
*wm
)
215 if (wm
->mode
== GNT_KP_MODE_WAIT_ON_CHILD
)
219 GntMenu
*top
= wm
->menu
;
221 GntNode
*node
= g_hash_table_lookup(wm
->nodes
, top
);
223 top_panel(node
->panel
);
227 work_around_for_ncurses_bug();
234 sanitize_position(GntWidget
*widget
, int *x
, int *y
, gboolean m
)
236 int X_MAX
= getmaxx(stdscr
);
237 int Y_MAX
= getmaxy(stdscr
) - 1;
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
);
246 if (m
&& (flags
& GNT_WINDOW_MAXIMIZE_X
) && *x
!= 0) {
249 } else if (*x
+ w
> X_MAX
) {
250 nx
= MAX(0, X_MAX
- w
);
258 if (m
&& (flags
& GNT_WINDOW_MAXIMIZE_Y
) && *y
!= 0) {
261 } else if (*y
+ h
> Y_MAX
) {
262 ny
= MAX(0, Y_MAX
- h
);
273 refresh_node(GntWidget
*widget
, GntNode
*node
, gpointer m
)
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
)
298 if (flags
& GNT_WINDOW_MAXIMIZE_Y
)
303 if (nw
!= w
|| nh
!= h
)
304 gnt_screen_resize_widget(widget
, nw
, nh
);
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
;
317 if (!g_key_file_load_from_file(gfile
, filename
, G_KEY_FILE_NONE
, &error
)) {
318 g_printerr("GntWM: %s\n", error
->message
);
324 keys
= g_key_file_get_keys(gfile
, "positions", &nk
, &error
);
326 g_printerr("GntWM: %s\n", error
->message
);
331 char *title
= keys
[nk
];
333 char **coords
= g_key_file_get_string_list(gfile
, "positions", title
, &l
, NULL
);
335 int x
= atoi(coords
[0]);
336 int y
= atoi(coords
[1]);
337 GntPosition
*p
= g_new0(GntPosition
, 1);
340 g_hash_table_replace(wm
->positions
, g_strdup(title
+ 1), p
);
342 g_printerr("GntWM: Invalid number of arguments for positioing a window.\n");
350 g_key_file_free(gfile
);
354 static gboolean
check_idle(gpointer n
)
357 time(&last_active_time
);
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
);
375 wm
->cws
= wm
->workspaces
->data
;
377 wm
->event_stack
= FALSE
;
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);
391 switch_window(GntWM
*wm
, int direction
, gboolean urgent
)
393 GntWidget
*w
= NULL
, *wid
= NULL
;
396 if (wm
->_list
.window
|| wm
->menu
)
399 if (!wm
->cws
->ordered
|| !wm
->cws
->ordered
->next
)
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
);
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
;
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
);
426 window_next(GntBindable
*bindable
, GList
*null
)
428 GntWM
*wm
= GNT_WM(bindable
);
429 switch_window(wm
, 1, FALSE
);
434 window_prev(GntBindable
*bindable
, GList
*null
)
436 GntWM
*wm
= GNT_WM(bindable
);
437 switch_window(wm
, -1, FALSE
);
442 switch_window_n(GntBindable
*bind
, GList
*list
)
444 GntWM
*wm
= GNT_WM(bind
);
448 if (!wm
->cws
->ordered
)
452 n
= GPOINTER_TO_INT(list
->data
);
456 if ((l
= g_list_nth(wm
->cws
->list
, n
)) != NULL
)
458 gnt_wm_raise_window(wm
, l
->data
);
465 window_scroll_up(GntBindable
*bindable
, GList
*null
)
467 GntWM
*wm
= GNT_WM(bindable
);
471 if (!wm
->cws
->ordered
)
474 window
= wm
->cws
->ordered
->data
;
475 node
= g_hash_table_lookup(wm
->nodes
, window
);
481 gnt_wm_copy_win(window
, node
);
488 window_scroll_down(GntBindable
*bindable
, GList
*null
)
490 GntWM
*wm
= GNT_WM(bindable
);
495 if (!wm
->cws
->ordered
)
498 window
= wm
->cws
->ordered
->data
;
499 node
= g_hash_table_lookup(wm
->nodes
, window
);
503 gnt_widget_get_size(window
, &w
, &h
);
504 if (h
- node
->scroll
> getmaxy(node
->window
)) {
506 gnt_wm_copy_win(window
, node
);
513 window_close(GntBindable
*bindable
, GList
*null
)
515 GntWM
*wm
= GNT_WM(bindable
);
517 if (wm
->_list
.window
)
520 if (wm
->cws
->ordered
) {
521 gnt_widget_destroy(wm
->cws
->ordered
->data
);
522 ensure_normal_mode(wm
);
529 destroy__list(GntWidget
*widget
, GntWM
*wm
)
531 wm
->_list
.window
= NULL
;
532 wm
->_list
.tree
= NULL
;
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
);
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
);
564 if (GNT_IS_WS(sel
)) {
565 gnt_wm_switch_workspace(wm
, g_list_index(wm
->workspaces
, sel
));
567 gnt_wm_raise_window(wm
, GNT_WIDGET(sel
));
572 populate_window_list(GntWM
*wm
, gboolean workspace
)
575 GntTree
*tree
= GNT_TREE(wm
->windows
->tree
);
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
));
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
));
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
));
608 if (GNT_IS_WS(sel
)) {
609 /* reorder the workspace. */
611 shift_window(wm
, GNT_WIDGET(sel
), -1);
615 if (GNT_IS_WS(sel
)) {
616 /* reorder the workspace. */
618 shift_window(wm
, GNT_WIDGET(sel
), 1);
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
);
632 list_of_windows(GntWM
*wm
, gboolean workspace
)
634 GntWidget
*tree
, *win
;
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
);
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
);
662 window_list(GntBindable
*bindable
, GList
*null
)
664 GntWM
*wm
= GNT_WM(bindable
);
666 if (wm
->_list
.window
|| wm
->menu
)
669 if (!wm
->cws
->ordered
)
672 list_of_windows(wm
, FALSE
);
678 dump_file_save(GntFileSel
*fs
, const char *path
, const char *f
, gpointer n
)
682 chtype old
= 0, now
= 0;
704 gnt_widget_destroy(GNT_WIDGET(fs
));
706 if ((file
= g_fopen(path
, "w+")) == NULL
) {
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
;
716 now
= mvwinch(curscr
, y
, x
);
717 ch
[0] = now
& A_CHARTEXT
;
722 mvwin_wch(curscr
, y
, x
, &wch
);
724 ch
[0] = (char)(wch
.chars
[0] & 0xff);
727 #define CHECK(attr, start, end) \
733 fprintf(file, "%s", start); \
735 else if (old & attr) \
737 fprintf(file, "%s", end); \
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
))
749 short fgp
, bgp
, r
, g
, b
;
755 ret
= pair_content(PAIR_NUMBER(now
& A_COLOR
), &fgp
, &bgp
);
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)
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
);
784 if (wch
.chars
[0] > 255) {
785 snprintf(unicode
, sizeof(unicode
), "&#x%x;", (unsigned int)wch
.chars
[0]);
789 if (now
& A_ALTCHARSET
)
792 for (u
= 0; unis
[u
].ascii
; u
++) {
793 if (ch
[0] == unis
[u
].ascii
) {
794 print
= unis
[u
].unicode
;
802 fprintf(file
, "&");
803 else if (ch
[0] == '<')
804 fprintf(file
, "<");
805 else if (ch
[0] == '>')
806 fprintf(file
, ">");
808 fprintf(file
, "%s", print
);
811 fprintf(file
, "</span>\n");
814 fprintf(file
, "</pre>\n</body>");
819 dump_file_cancel(GntWidget
*w
, GntFileSel
*fs
)
821 gnt_widget_destroy(GNT_WIDGET(fs
));
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
);
842 shift_window(GntWM
*wm
, GntWidget
*widget
, int dir
)
844 GList
*all
= wm
->cws
->list
;
845 GList
*list
= g_list_find(all
, widget
);
850 length
= g_list_length(all
);
851 pos
= g_list_position(all
, list
);
859 else if (pos
> length
)
862 all
= g_list_insert(all
, widget
, pos
);
863 all
= g_list_delete_link(all
, list
);
865 gnt_ws_draw_taskbar(wm
->cws
, FALSE
);
869 shift_left(GntBindable
*bindable
, GList
*null
)
871 GntWM
*wm
= GNT_WM(bindable
);
872 if (wm
->_list
.window
)
875 if(!wm
->cws
->ordered
)
878 shift_window(wm
, wm
->cws
->ordered
->data
, -1);
883 shift_right(GntBindable
*bindable
, GList
*null
)
885 GntWM
*wm
= GNT_WM(bindable
);
887 if (wm
->_list
.window
)
890 if(!wm
->cws
->ordered
)
893 shift_window(wm
, wm
->cws
->ordered
->data
, 1);
898 action_list_activate(GntTree
*tree
, GntWM
*wm
)
900 GntAction
*action
= gnt_tree_get_selection_data(tree
);
902 gnt_widget_destroy(wm
->_list
.window
);
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
);
915 list_actions(GntBindable
*bindable
, GList
*null
)
917 GntWidget
*tree
, *win
;
919 GntWM
*wm
= GNT_WM(bindable
);
920 if (wm
->_list
.window
|| wm
->menu
)
923 if (wm
->acts
== NULL
)
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
);
952 widestringwidth(wchar_t *wide
)
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;
966 /* Returns the onscreen width of the character at the position */
968 reverse_char(WINDOW
*d
, int y
, int x
, gboolean set
)
970 #define DECIDE(ch) (set ? ((ch) | A_REVERSE) : ((ch) & ~A_REVERSE))
974 ch
= mvwinch(d
, y
, x
);
975 mvwaddch(d
, y
, x
, DECIDE(ch
));
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
);
992 window_reverse(GntWidget
*win
, gboolean set
, GntWM
*wm
)
998 if (GNT_WIDGET_IS_FLAG_SET(win
, GNT_WIDGET_NO_BORDER
))
1002 gnt_widget_get_size(win
, &w
, &h
);
1004 if (gnt_widget_has_shadow(win
)) {
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
));
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
;
1032 start_move(GntBindable
*bindable
, GList
*null
)
1034 GntWM
*wm
= GNT_WM(bindable
);
1035 if (wm
->_list
.window
|| wm
->menu
)
1037 if (!wm
->cws
->ordered
)
1040 wm
->mode
= GNT_KP_MODE_MOVE
;
1041 window_reverse(GNT_WIDGET(wm
->cws
->ordered
->data
), TRUE
, wm
);
1047 start_resize(GntBindable
*bindable
, GList
*null
)
1049 GntWM
*wm
= GNT_WM(bindable
);
1050 if (wm
->_list
.window
|| wm
->menu
)
1052 if (!wm
->cws
->ordered
)
1055 wm
->mode
= GNT_KP_MODE_RESIZE
;
1056 window_reverse(GNT_WIDGET(wm
->cws
->ordered
->data
), TRUE
, wm
);
1062 wm_quit(GntBindable
*bindable
, GList
*list
)
1064 GntWM
*wm
= GNT_WM(bindable
);
1067 g_main_loop_quit(wm
->loop
);
1072 return_true(GntWM
*wm
, GntWidget
*w
, int *a
, int *b
)
1078 refresh_screen(GntBindable
*bindable
, GList
*null
)
1080 GntWM
*wm
= GNT_WM(bindable
);
1085 g_hash_table_foreach(wm
->nodes
, (GHFunc
)refresh_node
, GINT_TO_POINTER(TRUE
));
1086 g_signal_emit(wm
, signals
[SIG_TERMINAL_REFRESH
], 0);
1088 gnt_ws_draw_taskbar(wm
->cws
, TRUE
);
1089 curs_set(0); /* endwin resets the cursor to normal */
1095 toggle_clipboard(GntBindable
*bindable
, GList
*n
)
1097 static GntWidget
*clip
;
1101 gnt_widget_destroy(clip
);
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
);
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);
1130 tag_widget(GntBindable
*b
, GList
*params
)
1132 GntWM
*wm
= GNT_WM(b
);
1135 if (!wm
->cws
->ordered
)
1137 widget
= wm
->cws
->ordered
->data
;
1139 if (g_list_find(wm
->tagged
, widget
)) {
1140 remove_tag(widget
, wm
);
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
);
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
));
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
);
1170 workspace_list(GntBindable
*b
, GList
*params
)
1172 GntWM
*wm
= GNT_WM(b
);
1174 if (wm
->_list
.window
|| wm
->menu
)
1177 list_of_windows(wm
, TRUE
);
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
));
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
){
1205 ignore_keys_end(GntBindable
*bindable
, GList
*n
)
1207 return ignore_keys
? !(ignore_keys
= FALSE
) : FALSE
;
1211 window_next_urgent(GntBindable
*bindable
, GList
*n
)
1213 GntWM
*wm
= GNT_WM(bindable
);
1214 switch_window(wm
, 1, TRUE
);
1219 window_prev_urgent(GntBindable
*bindable
, GList
*n
)
1221 GntWM
*wm
= GNT_WM(bindable
);
1222 switch_window(wm
, -1, TRUE
);
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
);
1236 PyRun_SimpleFile(file
, path
);
1239 if (PyErr_Occurred()) {
1244 gnt_widget_destroy(GNT_WIDGET(fs
));
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
);
1262 #endif /* USE_PYTHON */
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
));
1273 ret
= gnt_bindable_build_help_window(bindable
);
1279 help_for_wm(GntBindable
*bindable
, GList
*null
)
1281 return help_for_bindable(GNT_WM(bindable
),bindable
);
1285 help_for_window(GntBindable
*bindable
, GList
*null
)
1287 GntWM
*wm
= GNT_WM(bindable
);
1290 if(!wm
->cws
->ordered
)
1293 widget
= wm
->cws
->ordered
->data
;
1295 return help_for_bindable(wm
,GNT_BINDABLE(widget
));
1299 help_for_widget(GntBindable
*bindable
, GList
*null
)
1301 GntWM
*wm
= GNT_WM(bindable
);
1304 if (!wm
->cws
->ordered
)
1307 widget
= wm
->cws
->ordered
->data
;
1308 if (!GNT_IS_BOX(widget
))
1311 return help_for_bindable(wm
, GNT_BINDABLE(GNT_BOX(widget
)->active
));
1315 accumulate_windows(gpointer window
, gpointer node
, gpointer p
)
1317 GList
*list
= *(GList
**)p
;
1318 list
= g_list_prepend(list
, window
);
1323 gnt_wm_destroy(GObject
*obj
)
1325 GntWM
*wm
= GNT_WM(obj
);
1327 g_hash_table_foreach(wm
->nodes
, accumulate_windows
, &list
);
1328 g_list_foreach(list
, (GFunc
)gnt_widget_destroy
, NULL
);
1330 g_hash_table_destroy(wm
->nodes
);
1333 while (wm
->workspaces
) {
1334 g_object_unref(wm
->workspaces
->data
);
1335 wm
->workspaces
= g_list_delete_link(wm
->workspaces
, wm
->workspaces
);
1343 gnt_wm_class_init(GntWMClass
*klass
)
1346 GObjectClass
*gclass
= G_OBJECT_CLASS(klass
);
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
),
1367 G_STRUCT_OFFSET(GntWMClass
, new_window
),
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
),
1375 G_STRUCT_OFFSET(GntWMClass
, decorate_window
),
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
),
1383 G_STRUCT_OFFSET(GntWMClass
, close_window
),
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
),
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
),
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
),
1409 G_STRUCT_OFFSET(GntWMClass
, window_resized
),
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
),
1417 G_STRUCT_OFFSET(GntWMClass
, window_moved
),
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
),
1425 G_STRUCT_OFFSET(GntWMClass
, window_update
),
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
),
1434 G_STRUCT_OFFSET(GntWMClass
, give_focus
),
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
),
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
),
1452 G_STRUCT_OFFSET(GntWMClass
, terminal_refresh
),
1454 g_cclosure_marshal_VOID__VOID
,
1457 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "window-next", window_next
,
1459 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "window-prev", window_prev
,
1461 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "window-close", window_close
,
1463 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "window-list", window_list
,
1465 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "dump-screen", dump_screen
,
1467 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "shift-left", shift_left
,
1469 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "shift-right", shift_right
,
1471 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "action-list", list_actions
,
1473 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "start-move", start_move
,
1475 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "start-resize", start_resize
,
1477 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "wm-quit", wm_quit
,
1479 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "refresh-screen", refresh_screen
,
1481 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "switch-window-n", switch_window_n
,
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
,
1489 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "workspace-new", workspace_new
,
1491 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "workspace-next", workspace_next
,
1493 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "workspace-prev", workspace_prev
,
1495 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "window-tag", tag_widget
,
1497 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "place-tagged", place_tagged
,
1499 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "workspace-list", workspace_list
,
1501 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "toggle-clipboard", toggle_clipboard
,
1503 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "help-for-wm", help_for_wm
,
1505 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "help-for-window", help_for_window
,
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
,
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
);
1517 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "run-python", run_python
,
1519 Py_SetProgramName("gnt");
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";
1529 gnt_keys_add_combination(str
);
1535 /******************************************************************************
1537 *****************************************************************************/
1539 gnt_wm_get_gtype(void)
1541 static GType type
= 0;
1544 static const GTypeInfo info
= {
1546 NULL
, /* base_init */
1547 NULL
, /* base_finalize */
1548 (GClassInitFunc
)gnt_wm_class_init
,
1550 NULL
, /* class_data */
1552 0, /* n_preallocs */
1553 gnt_wm_init
, /* instance_init */
1554 NULL
/* value_table */
1557 type
= g_type_register_static(GNT_TYPE_BINDABLE
,
1566 gnt_wm_add_workspace(GntWM
*wm
, GntWS
*ws
)
1568 wm
->workspaces
= g_list_append(wm
->workspaces
, ws
);
1572 gnt_wm_switch_workspace(GntWM
*wm
, gint n
)
1574 GntWS
*s
= g_list_nth_data(wm
->workspaces
, n
);
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
);
1584 gnt_ws_show(wm
->cws
, wm
->nodes
);
1586 gnt_ws_draw_taskbar(wm
->cws
, TRUE
);
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
);
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
);
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
);
1614 workspace_next(GntBindable
*wm
, GList
*n
)
1616 return gnt_wm_switch_workspace_next(GNT_WM(wm
));
1620 workspace_prev(GntBindable
*wm
, GList
*n
)
1622 return gnt_wm_switch_workspace_prev(GNT_WM(wm
));
1626 gnt_wm_widget_move_workspace(GntWM
*wm
, GntWS
*neww
, GntWidget
*widget
)
1628 GntWS
*oldw
= gnt_wm_widget_find_workspace(wm
, widget
);
1630 if (!oldw
|| oldw
== neww
)
1632 node
= g_hash_table_lookup(wm
->nodes
, widget
);
1633 if (node
&& 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
);
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
))
1656 GntWS
*gnt_wm_widget_find_workspace(GntWM
*wm
, GntWidget
*widget
)
1658 GList
*l
= g_list_find_custom(wm
->workspaces
, widget
, widget_in_workspace
);
1664 static void free_workspaces(gpointer data
, gpointer n
)
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);
1678 update_window_in_list(GntWM
*wm
, GntWidget
*wid
)
1680 GntTextFormatFlags flag
= 0;
1682 if (wm
->windows
== NULL
)
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
);
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
))
1702 #if !GLIB_CHECK_VERSION(2,4,0)
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
;
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
;
1728 new_widget_find_workspace(GntWM
*wm
, GntWidget
*widget
)
1731 const gchar
*name
, *title
;
1732 title
= GNT_BOX(widget
)->title
;
1734 ret
= g_hash_table_find(wm
->title_places
, match_title
, (gpointer
)title
);
1737 name
= gnt_widget_get_name(widget
);
1739 ret
= g_hash_table_find(wm
->name_places
, match_title
, (gpointer
)name
);
1740 return ret
? ret
: wm
->cws
;
1744 gnt_wm_new_window_real(GntWM
*wm
, GntWidget
*widget
)
1747 gboolean transient
= FALSE
;
1749 if (widget
->window
== NULL
)
1752 node
= g_new0(GntNode
, 1);
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
);
1764 int x
, y
, w
, h
, maxx
, maxy
;
1765 gboolean shadow
= TRUE
;
1767 if (!gnt_widget_has_shadow(widget
))
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 */
1780 x
= MAX(0, maxx
- w
);
1782 y
= MAX(0, maxy
- h
);
1786 node
->window
= newwin(h
, w
, y
, x
);
1787 gnt_wm_copy_win(widget
, node
);
1791 node
->panel
= new_panel(node
->window
);
1792 set_panel_userptr(node
->panel
, node
);
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
);
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
);
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
);
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
)) {
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
);
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
)
1866 s
= gnt_wm_widget_find_workspace(wm
, widget
);
1868 if (g_hash_table_lookup(wm
->nodes
, widget
) == NULL
)
1871 g_signal_emit(wm
, signals
[SIG_CLOSE_WIN
], 0, widget
);
1872 g_hash_table_remove(wm
->nodes
, widget
);
1875 gnt_tree_remove(GNT_TREE(wm
->windows
->tree
), widget
);
1879 pos
= g_list_index(s
->list
, widget
);
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
);
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
);
1907 if(keys
&& !strcmp(keys
, "\033" GNT_KEY_CTRL_G
)){
1908 if(gnt_bindable_perform_action_key(GNT_BINDABLE(wm
), keys
)){
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
)) {
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;
1923 GntWidget
*widget
= GNT_WIDGET(wm
->cws
->ordered
->data
);
1926 gnt_widget_get_position(widget
, &x
, &y
);
1927 gnt_widget_get_size(widget
, &w
, &h
);
1931 if (wm
->mode
== GNT_KP_MODE_MOVE
) {
1932 if (strcmp(keys
, GNT_KEY_LEFT
) == 0) {
1935 } else if (strcmp(keys
, GNT_KEY_RIGHT
) == 0) {
1938 } else if (strcmp(keys
, GNT_KEY_UP
) == 0) {
1941 } else if (strcmp(keys
, GNT_KEY_DOWN
) == 0) {
1945 if (ox
!= x
|| oy
!= y
) {
1946 gnt_screen_move_widget(widget
, x
, y
);
1947 window_reverse(widget
, TRUE
, wm
);
1950 } else if (wm
->mode
== GNT_KP_MODE_RESIZE
) {
1951 if (strcmp(keys
, GNT_KEY_LEFT
) == 0) {
1953 } else if (strcmp(keys
, GNT_KEY_RIGHT
) == 0) {
1956 } else if (strcmp(keys
, GNT_KEY_UP
) == 0) {
1958 } else if (strcmp(keys
, GNT_KEY_DOWN
) == 0) {
1962 if (oh
!= h
|| ow
!= w
) {
1963 gnt_screen_resize_widget(widget
, w
, h
);
1964 window_reverse(widget
, TRUE
, wm
);
1968 if (strcmp(keys
, "\r") == 0 || strcmp(keys
, "\033") == 0) {
1969 window_reverse(widget
, FALSE
, wm
);
1970 wm
->mode
= GNT_KP_MODE_NORMAL
;
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
);
1981 } else if (keys
[0] == '\033' && isdigit(keys
[1]) && keys
[2] == '\0') {
1982 /* Alt+x for quick switch */
1983 int n
= *(keys
+ 1) - '0';
1989 list
= g_list_append(list
, GINT_TO_POINTER(n
- 1));
1990 switch_window_n(GNT_BINDABLE(wm
), list
);
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
;
2004 const char *id
= gnt_window_get_accel_item(GNT_WINDOW(win
), keys
);
2006 GntMenuItem
*item
= gnt_menu_get_item(menu
, id
);
2008 ret
= gnt_menuitem_activate(item
);
2013 ret
= gnt_widget_key_pressed(win
, keys
);
2019 gnt_wm_win_resized(GntWM
*wm
, GntNode
*node
)
2021 /*refresh_node(node->me, node, NULL);*/
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
;
2036 while (widget
->parent
)
2037 widget
= widget
->parent
;
2038 node
= g_hash_table_lookup(wm
->nodes
, widget
);
2042 g_signal_emit(wm
, signals
[SIG_CONFIRM_RESIZE
], 0, widget
, &width
, &height
, &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
);
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
);
2070 write_already(gpointer data
)
2076 filename
= g_build_filename(g_get_home_dir(), ".gntpositions", NULL
);
2078 file
= fopen(filename
, "wb");
2080 g_printerr("GntWM: error opening file to save positions\n");
2082 fprintf(file
, "[positions]\n");
2083 g_hash_table_foreach(wm
->positions
, write_gdi
, file
);
2088 g_source_remove(write_timeout
);
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
;
2107 while (widget
->parent
)
2108 widget
= widget
->parent
;
2109 node
= g_hash_table_lookup(wm
->nodes
, widget
);
2113 g_signal_emit(wm
, signals
[SIG_CONFIRM_MOVE
], 0, widget
, &x
, &y
, &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
;
2125 GntPosition
*p
= g_new0(GntPosition
, 1);
2126 GntWidget
*wid
= node
->me
;
2129 g_hash_table_replace(wm
->positions
, g_strdup(title
), p
);
2130 write_positions_to_file(wm
);
2138 gnt_wm_give_focus(GntWM
*wm
, GntWidget
*widget
)
2140 GntNode
*node
= g_hash_table_lookup(wm
->nodes
, widget
);
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
);
2162 gnt_ws_draw_taskbar(wm
->cws
, FALSE
);
2165 void gnt_wm_update_window(GntWM
*wm
, GntWidget
*widget
)
2167 GntNode
*node
= NULL
;
2170 while (widget
->parent
)
2171 widget
= widget
->parent
;
2172 if (!GNT_IS_MENU(widget
)) {
2173 if (!GNT_IS_BOX(widget
))
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
);
2181 gnt_wm_new_window(wm
, widget
);
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
);
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
);
2196 gboolean
gnt_wm_process_click(GntWM
*wm
, GntMouseEvent event
, int x
, int y
, GntWidget
*widget
)
2198 gboolean ret
= TRUE
;
2200 g_signal_emit(wm
, signals
[SIG_MOUSE_CLICK
], 0, event
, x
, y
, widget
, &ret
);
2204 void gnt_wm_raise_window(GntWM
*wm
, GntWidget
*widget
)
2206 GntWS
*ws
= gnt_wm_widget_find_workspace(wm
, widget
);
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
;