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
24 #if defined(__APPLE__) || defined(__unix__)
25 #define _XOPEN_SOURCE_EXTENDED
39 #include "gntmarshal.h"
42 #include "gntbutton.h"
46 #include "gnttextview.h"
49 #include "gntwindow.h"
51 #define IDLE_CHECK_INTERVAL 5 /* 5 seconds */
70 static guint signals
[SIGS
] = { 0 };
71 static void gnt_wm_new_window_real(GntWM
*wm
, GntWidget
*widget
);
72 static void gnt_wm_win_resized(GntWM
*wm
, GntNode
*node
);
73 static void gnt_wm_win_moved(GntWM
*wm
, GntNode
*node
);
74 static void gnt_wm_give_focus(GntWM
*wm
, GntWidget
*widget
);
75 static void update_window_in_list(GntWM
*wm
, GntWidget
*wid
);
76 static void shift_window(GntWM
*wm
, GntWidget
*widget
, int dir
);
77 static gboolean
workspace_next(GntBindable
*wm
, GList
*n
);
78 static gboolean
workspace_prev(GntBindable
*wm
, GList
*n
);
81 static int widestringwidth(wchar_t *wide
);
84 static gboolean
write_already(gpointer data
);
85 static int write_timeout
;
86 static time_t last_active_time
;
87 static gboolean idle_update
;
88 static GList
*act
= NULL
; /* list of WS with unseen activitiy */
89 static gboolean ignore_keys
= FALSE
;
92 g_list_bring_to_front(GList
*list
, gpointer data
)
94 list
= g_list_remove(list
, data
);
95 list
= g_list_prepend(list
, data
);
100 free_node(gpointer data
)
102 GntNode
*node
= data
;
103 hide_panel(node
->panel
);
104 del_panel(node
->panel
);
109 gnt_wm_copy_win(GntWidget
*widget
, GntNode
*node
)
114 src
= widget
->window
;
116 copywin(src
, dst
, node
->scroll
, 0, 0, 0, getmaxy(dst
) - 1, getmaxx(dst
) - 1, 0);
120 * The following is a workaround for a bug in most versions of ncursesw.
121 * Read about it in: http://article.gmane.org/gmane.comp.lib.ncurses.bugs/2751
123 * In short, if a panel hides one cell of a multi-cell character, then the rest
124 * of the characters in that line get screwed. The workaround here is to erase
125 * any such character preemptively.
127 * Caveat: If a wide character is erased, and the panel above it is moved enough
128 * to expose the entire character, it is not always redrawn.
131 work_around_for_ncurses_bug()
135 while ((panel
= panel_below(panel
)) != NULL
) {
136 int sx
, ex
, sy
, ey
, w
, y
;
138 PANEL
*below
= panel
;
140 sx
= panel
->win
->_begx
;
141 ex
= panel
->win
->_maxx
+ sx
;
142 sy
= panel
->win
->_begy
;
143 ey
= panel
->win
->_maxy
+ sy
;
145 while ((below
= panel_below(below
)) != NULL
) {
146 if (sy
> below
->win
->_begy
+ below
->win
->_maxy
||
147 ey
< below
->win
->_begy
)
149 if (sx
> below
->win
->_begx
+ below
->win
->_maxx
||
150 ex
< below
->win
->_begx
)
152 for (y
= MAX(sy
, below
->win
->_begy
); y
<= MIN(ey
, below
->win
->_begy
+ below
->win
->_maxy
); y
++) {
153 if (mvwin_wch(below
->win
, y
- below
->win
->_begy
, sx
- 1 - below
->win
->_begx
, &ch
) != OK
)
155 w
= widestringwidth(ch
.chars
);
156 if (w
> 1 && (ch
.attr
& 1)) {
158 ch
.attr
&= ~ A_CHARTEXT
;
159 mvwadd_wch(below
->win
, y
- below
->win
->_begy
, sx
- 1 - below
->win
->_begx
, &ch
);
160 touchline(below
->win
, y
- below
->win
->_begy
, 1);
163 if (mvwin_wch(below
->win
, y
- below
->win
->_begy
, ex
+ 1 - below
->win
->_begx
, &ch
) != OK
)
165 w
= widestringwidth(ch
.chars
);
166 if (w
> 1 && !(ch
.attr
& 1)) {
168 ch
.attr
&= ~ A_CHARTEXT
;
169 mvwadd_wch(below
->win
, y
- below
->win
->_begy
, ex
+ 1 - below
->win
->_begx
, &ch
);
170 touchline(below
->win
, y
- below
->win
->_begy
, 1);
183 static GntWidget
*message
= NULL
;
184 GString
*text
= g_string_new("act: ");
186 gnt_widget_destroy(message
);
187 if (g_list_length(act
) == 0)
189 for (iter
= act
; iter
; iter
= iter
->next
) {
190 GntWS
*ws
= iter
->data
;
191 g_string_append_printf(text
, "%s, ", gnt_ws_get_name(ws
));
193 g_string_erase(text
, text
->len
- 2, 2);
194 message
= gnt_vbox_new(FALSE
);
195 label
= gnt_label_new_with_format(text
->str
, GNT_TEXT_FLAG_BOLD
| GNT_TEXT_FLAG_HIGHLIGHT
);
196 GNT_WIDGET_UNSET_FLAGS(GNT_BOX(message
), GNT_WIDGET_CAN_TAKE_FOCUS
);
197 GNT_WIDGET_SET_FLAGS(GNT_BOX(message
), GNT_WIDGET_TRANSIENT
);
198 gnt_box_add_widget(GNT_BOX(message
), label
);
199 gnt_widget_set_name(message
, "wm-message");
200 gnt_widget_set_position(message
, 0, 0);
201 gnt_widget_draw(message
);
202 g_string_free(text
, TRUE
);
206 update_screen(GntWM
*wm
)
208 if (wm
->mode
== GNT_KP_MODE_WAIT_ON_CHILD
)
212 GntMenu
*top
= wm
->menu
;
214 GntNode
*node
= g_hash_table_lookup(wm
->nodes
, top
);
216 top_panel(node
->panel
);
220 work_around_for_ncurses_bug();
227 sanitize_position(GntWidget
*widget
, int *x
, int *y
)
229 int X_MAX
= getmaxx(stdscr
);
230 int Y_MAX
= getmaxy(stdscr
) - 1;
233 gboolean changed
= FALSE
;
235 gnt_widget_get_size(widget
, &w
, &h
);
237 if (*x
+ w
> X_MAX
) {
238 nx
= MAX(0, X_MAX
- w
);
246 if (*y
+ h
> Y_MAX
) {
247 ny
= MAX(0, Y_MAX
- h
);
258 refresh_node(GntWidget
*widget
, GntNode
*node
, gpointer null
)
263 int X_MAX
= getmaxx(stdscr
);
264 int Y_MAX
= getmaxy(stdscr
) - 1;
266 gnt_widget_get_position(widget
, &x
, &y
);
267 gnt_widget_get_size(widget
, &w
, &h
);
269 if (sanitize_position(widget
, &x
, &y
))
270 gnt_screen_move_widget(widget
, x
, y
);
274 if (nw
!= w
|| nh
!= h
)
275 gnt_screen_resize_widget(widget
, nw
, nh
);
279 read_window_positions(GntWM
*wm
)
281 #if GLIB_CHECK_VERSION(2,6,0)
282 GKeyFile
*gfile
= g_key_file_new();
283 char *filename
= g_build_filename(g_get_home_dir(), ".gntpositions", NULL
);
284 GError
*error
= NULL
;
288 if (!g_key_file_load_from_file(gfile
, filename
, G_KEY_FILE_NONE
, &error
)) {
289 g_printerr("GntWM: %s\n", error
->message
);
295 keys
= g_key_file_get_keys(gfile
, "positions", &nk
, &error
);
297 g_printerr("GntWM: %s\n", error
->message
);
302 char *title
= keys
[nk
];
304 char **coords
= g_key_file_get_string_list(gfile
, "positions", title
, &l
, NULL
);
306 int x
= atoi(coords
[0]);
307 int y
= atoi(coords
[1]);
308 GntPosition
*p
= g_new0(GntPosition
, 1);
311 g_hash_table_replace(wm
->positions
, g_strdup(title
+ 1), p
);
313 g_printerr("GntWM: Invalid number of arguments for positioing a window.\n");
321 g_key_file_free(gfile
);
325 static gboolean
check_idle(gpointer n
)
328 time(&last_active_time
);
335 gnt_wm_init(GTypeInstance
*instance
, gpointer
class)
337 GntWM
*wm
= GNT_WM(instance
);
338 wm
->workspaces
= NULL
;
339 wm
->name_places
= g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, g_free
);
340 wm
->title_places
= g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, g_free
);
341 gnt_style_read_workspaces(wm
);
342 if (wm
->workspaces
== NULL
) {
343 wm
->cws
= gnt_ws_new("default");
344 gnt_wm_add_workspace(wm
, wm
->cws
);
346 wm
->cws
= wm
->workspaces
->data
;
348 wm
->event_stack
= FALSE
;
352 wm
->nodes
= g_hash_table_new_full(g_direct_hash
, g_direct_equal
, NULL
, free_node
);
353 wm
->positions
= g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, g_free
);
354 if (gnt_style_get_bool(GNT_STYLE_REMPOS
, TRUE
))
355 read_window_positions(wm
);
356 g_timeout_add(IDLE_CHECK_INTERVAL
* 1000, check_idle
, NULL
);
357 time(&last_active_time
);
358 gnt_wm_switch_workspace(wm
, 0);
362 switch_window(GntWM
*wm
, int direction
)
364 GntWidget
*w
= NULL
, *wid
= NULL
;
367 if (wm
->_list
.window
|| wm
->menu
)
370 if (!wm
->cws
->ordered
|| !wm
->cws
->ordered
->next
)
373 w
= wm
->cws
->ordered
->data
;
374 pos
= g_list_index(wm
->cws
->list
, w
);
378 wid
= g_list_last(wm
->cws
->list
)->data
;
379 else if (pos
>= g_list_length(wm
->cws
->list
))
380 wid
= wm
->cws
->list
->data
;
382 wid
= g_list_nth_data(wm
->cws
->list
, pos
);
384 gnt_wm_raise_window(wm
, wid
);
388 window_next(GntBindable
*bindable
, GList
*null
)
390 GntWM
*wm
= GNT_WM(bindable
);
391 switch_window(wm
, 1);
396 window_prev(GntBindable
*bindable
, GList
*null
)
398 GntWM
*wm
= GNT_WM(bindable
);
399 switch_window(wm
, -1);
404 switch_window_n(GntBindable
*bind
, GList
*list
)
406 GntWM
*wm
= GNT_WM(bind
);
410 if (!wm
->cws
->ordered
)
414 n
= GPOINTER_TO_INT(list
->data
);
418 if ((l
= g_list_nth(wm
->cws
->list
, n
)) != NULL
)
420 gnt_wm_raise_window(wm
, l
->data
);
427 window_scroll_up(GntBindable
*bindable
, GList
*null
)
429 GntWM
*wm
= GNT_WM(bindable
);
433 if (!wm
->cws
->ordered
)
436 window
= wm
->cws
->ordered
->data
;
437 node
= g_hash_table_lookup(wm
->nodes
, window
);
443 gnt_wm_copy_win(window
, node
);
450 window_scroll_down(GntBindable
*bindable
, GList
*null
)
452 GntWM
*wm
= GNT_WM(bindable
);
457 if (!wm
->cws
->ordered
)
460 window
= wm
->cws
->ordered
->data
;
461 node
= g_hash_table_lookup(wm
->nodes
, window
);
465 gnt_widget_get_size(window
, &w
, &h
);
466 if (h
- node
->scroll
> getmaxy(node
->window
)) {
468 gnt_wm_copy_win(window
, node
);
475 window_close(GntBindable
*bindable
, GList
*null
)
477 GntWM
*wm
= GNT_WM(bindable
);
479 if (wm
->_list
.window
)
482 if (wm
->cws
->ordered
) {
483 gnt_widget_destroy(wm
->cws
->ordered
->data
);
490 destroy__list(GntWidget
*widget
, GntWM
*wm
)
492 wm
->_list
.window
= NULL
;
493 wm
->_list
.tree
= NULL
;
500 setup__list(GntWM
*wm
)
502 GntWidget
*tree
, *win
;
503 win
= wm
->_list
.window
= gnt_box_new(FALSE
, FALSE
);
504 gnt_box_set_toplevel(GNT_BOX(win
), TRUE
);
505 gnt_box_set_pad(GNT_BOX(win
), 0);
506 GNT_WIDGET_SET_FLAGS(win
, GNT_WIDGET_TRANSIENT
);
508 tree
= wm
->_list
.tree
= gnt_tree_new();
509 gnt_box_add_widget(GNT_BOX(win
), tree
);
511 g_signal_connect(G_OBJECT(win
), "destroy", G_CALLBACK(destroy__list
), wm
);
515 window_list_activate(GntTree
*tree
, GntWM
*wm
)
517 GntBindable
*sel
= gnt_tree_get_selection_data(GNT_TREE(tree
));
519 gnt_widget_destroy(wm
->_list
.window
);
524 if (GNT_IS_WS(sel
)) {
525 gnt_wm_switch_workspace(wm
, g_list_index(wm
->workspaces
, sel
));
527 gnt_wm_raise_window(wm
, GNT_WIDGET(sel
));
532 populate_window_list(GntWM
*wm
, gboolean workspace
)
535 GntTree
*tree
= GNT_TREE(wm
->windows
->tree
);
537 for (iter
= wm
->cws
->list
; iter
; iter
= iter
->next
) {
538 GntBox
*box
= GNT_BOX(iter
->data
);
540 gnt_tree_add_row_last(tree
, box
,
541 gnt_tree_create_row(tree
, box
->title
), NULL
);
542 update_window_in_list(wm
, GNT_WIDGET(box
));
545 GList
*ws
= wm
->workspaces
;
546 for (; ws
; ws
= ws
->next
) {
547 gnt_tree_add_row_last(tree
, ws
->data
,
548 gnt_tree_create_row(tree
, gnt_ws_get_name(GNT_WS(ws
->data
))), NULL
);
549 for (iter
= GNT_WS(ws
->data
)->list
; iter
; iter
= iter
->next
) {
550 GntBox
*box
= GNT_BOX(iter
->data
);
552 gnt_tree_add_row_last(tree
, box
,
553 gnt_tree_create_row(tree
, box
->title
), ws
->data
);
554 update_window_in_list(wm
, GNT_WIDGET(box
));
561 window_list_key_pressed(GntWidget
*widget
, const char *text
, GntWM
*wm
)
563 if (text
[1] == 0 && wm
->cws
->ordered
) {
564 GntBindable
*sel
= gnt_tree_get_selection_data(GNT_TREE(widget
));
568 if (GNT_IS_WS(sel
)) {
569 /* reorder the workspace. */
571 shift_window(wm
, GNT_WIDGET(sel
), -1);
575 if (GNT_IS_WS(sel
)) {
576 /* reorder the workspace. */
578 shift_window(wm
, GNT_WIDGET(sel
), 1);
583 gnt_tree_remove_all(GNT_TREE(widget
));
584 populate_window_list(wm
, GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget
), "workspace")));
585 gnt_tree_set_selected(GNT_TREE(widget
), sel
);
592 list_of_windows(GntWM
*wm
, gboolean workspace
)
594 GntWidget
*tree
, *win
;
596 wm
->windows
= &wm
->_list
;
598 win
= wm
->windows
->window
;
599 tree
= wm
->windows
->tree
;
601 gnt_box_set_title(GNT_BOX(win
), workspace
? "Workspace List" : "Window List");
603 populate_window_list(wm
, workspace
);
605 if (wm
->cws
->ordered
)
606 gnt_tree_set_selected(GNT_TREE(tree
), wm
->cws
->ordered
->data
);
608 gnt_tree_set_selected(GNT_TREE(tree
), wm
->cws
);
610 g_signal_connect(G_OBJECT(tree
), "activate", G_CALLBACK(window_list_activate
), wm
);
611 g_signal_connect(G_OBJECT(tree
), "key_pressed", G_CALLBACK(window_list_key_pressed
), wm
);
612 g_object_set_data(G_OBJECT(tree
), "workspace", GINT_TO_POINTER(workspace
));
614 gnt_tree_set_col_width(GNT_TREE(tree
), 0, getmaxx(stdscr
) / 3);
615 gnt_widget_set_size(tree
, 0, getmaxy(stdscr
) / 2);
616 gnt_widget_set_position(win
, getmaxx(stdscr
) / 3, getmaxy(stdscr
) / 4);
618 gnt_widget_show(win
);
622 window_list(GntBindable
*bindable
, GList
*null
)
624 GntWM
*wm
= GNT_WM(bindable
);
626 if (wm
->_list
.window
|| wm
->menu
)
629 if (!wm
->cws
->ordered
)
632 list_of_windows(wm
, FALSE
);
638 dump_screen(GntBindable
*bindable
, GList
*null
)
641 chtype old
= 0, now
= 0;
642 FILE *file
= fopen("dump.html", "w");
664 fprintf(file
, "<head>\n <meta http-equiv='Content-Type' content='text/html; charset=utf-8' />\n</head>\n<body>\n");
665 fprintf(file
, "<pre>");
666 for (y
= 0; y
< getmaxy(stdscr
); y
++) {
667 for (x
= 0; x
< getmaxx(stdscr
); x
++) {
668 char ch
[2] = {0, 0}, *print
;
670 now
= mvwinch(curscr
, y
, x
);
671 ch
[0] = now
& A_CHARTEXT
;
676 mvwin_wch(curscr
, y
, x
, &wch
);
678 ch
[0] = (char)(wch
.chars
[0] & 0xff);
681 #define CHECK(attr, start, end) \
687 fprintf(file, "%s", start); \
689 else if (old & attr) \
691 fprintf(file, "%s", end); \
695 CHECK(A_BOLD
, "<b>", "</b>");
696 CHECK(A_UNDERLINE
, "<u>", "</u>");
697 CHECK(A_BLINK
, "<blink>", "</blink>");
699 if ((now
& A_COLOR
) != (old
& A_COLOR
) ||
700 (now
& A_REVERSE
) != (old
& A_REVERSE
))
703 short fgp
, bgp
, r
, g
, b
;
709 ret
= pair_content(PAIR_NUMBER(now
& A_COLOR
), &fgp
, &bgp
);
720 ret
= color_content(fgp
, &r
, &g
, &b
);
721 fg
.r
= r
; fg
.b
= b
; fg
.g
= g
;
722 ret
= color_content(bgp
, &r
, &g
, &b
);
723 bg
.r
= r
; bg
.b
= b
; bg
.g
= g
;
724 #define ADJUST(x) (x = x * 255 / 1000)
732 if (x
) fprintf(file
, "</span>");
733 fprintf(file
, "<span style=\"background:#%02x%02x%02x;color:#%02x%02x%02x\">",
734 bg
.r
, bg
.g
, bg
.b
, fg
.r
, fg
.g
, fg
.b
);
738 if (wch
.chars
[0] > 255) {
739 snprintf(unicode
, sizeof(unicode
), "&#x%x;", (unsigned int)wch
.chars
[0]);
743 if (now
& A_ALTCHARSET
)
746 for (u
= 0; unis
[u
].ascii
; u
++) {
747 if (ch
[0] == unis
[u
].ascii
) {
748 print
= unis
[u
].unicode
;
756 fprintf(file
, "&");
757 else if (ch
[0] == '<')
758 fprintf(file
, "<");
759 else if (ch
[0] == '>')
760 fprintf(file
, ">");
762 fprintf(file
, "%s", print
);
765 fprintf(file
, "</span>\n");
768 fprintf(file
, "</pre>\n</body>");
774 shift_window(GntWM
*wm
, GntWidget
*widget
, int dir
)
776 GList
*all
= wm
->cws
->list
;
777 GList
*list
= g_list_find(all
, widget
);
782 length
= g_list_length(all
);
783 pos
= g_list_position(all
, list
);
791 else if (pos
> length
)
794 all
= g_list_insert(all
, widget
, pos
);
795 all
= g_list_delete_link(all
, list
);
797 gnt_ws_draw_taskbar(wm
->cws
, FALSE
);
801 shift_left(GntBindable
*bindable
, GList
*null
)
803 GntWM
*wm
= GNT_WM(bindable
);
804 if (wm
->_list
.window
)
807 if(!wm
->cws
->ordered
)
810 shift_window(wm
, wm
->cws
->ordered
->data
, -1);
815 shift_right(GntBindable
*bindable
, GList
*null
)
817 GntWM
*wm
= GNT_WM(bindable
);
819 if (wm
->_list
.window
)
822 if(!wm
->cws
->ordered
)
825 shift_window(wm
, wm
->cws
->ordered
->data
, 1);
830 action_list_activate(GntTree
*tree
, GntWM
*wm
)
832 GntAction
*action
= gnt_tree_get_selection_data(tree
);
834 gnt_widget_destroy(wm
->_list
.window
);
838 compare_action(gconstpointer p1
, gconstpointer p2
)
840 const GntAction
*a1
= p1
;
841 const GntAction
*a2
= p2
;
843 return g_utf8_collate(a1
->label
, a2
->label
);
847 list_actions(GntBindable
*bindable
, GList
*null
)
849 GntWidget
*tree
, *win
;
851 GntWM
*wm
= GNT_WM(bindable
);
852 if (wm
->_list
.window
|| wm
->menu
)
855 if (wm
->acts
== NULL
)
859 wm
->actions
= &wm
->_list
;
861 win
= wm
->actions
->window
;
862 tree
= wm
->actions
->tree
;
864 gnt_box_set_title(GNT_BOX(win
), "Actions");
865 GNT_WIDGET_SET_FLAGS(tree
, GNT_WIDGET_NO_BORDER
);
866 /* XXX: Do we really want this? */
867 gnt_tree_set_compare_func(GNT_TREE(tree
), compare_action
);
869 for (iter
= wm
->acts
; iter
; iter
= iter
->next
) {
870 GntAction
*action
= iter
->data
;
871 gnt_tree_add_row_last(GNT_TREE(tree
), action
,
872 gnt_tree_create_row(GNT_TREE(tree
), action
->label
), NULL
);
874 g_signal_connect(G_OBJECT(tree
), "activate", G_CALLBACK(action_list_activate
), wm
);
875 gnt_widget_set_size(tree
, 0, g_list_length(wm
->acts
));
876 gnt_widget_set_position(win
, 0, getmaxy(stdscr
) - 3 - g_list_length(wm
->acts
));
878 gnt_widget_show(win
);
884 widestringwidth(wchar_t *wide
)
889 len
= wcstombs(NULL
, wide
, 0) + 1;
890 string
= g_new0(char, len
);
891 wcstombs(string
, wide
, len
);
892 ret
= string
? gnt_util_onscreen_width(string
, NULL
) : 1;
898 /* Returns the onscreen width of the character at the position */
900 reverse_char(WINDOW
*d
, int y
, int x
, gboolean set
)
902 #define DECIDE(ch) (set ? ((ch) | A_REVERSE) : ((ch) & ~A_REVERSE))
906 ch
= mvwinch(d
, y
, x
);
907 mvwaddch(d
, y
, x
, DECIDE(ch
));
912 if (mvwin_wch(d
, y
, x
, &ch
) == OK
) {
913 wc
= widestringwidth(ch
.chars
);
914 ch
.attr
= DECIDE(ch
.attr
);
915 ch
.attr
&= WA_ATTRIBUTES
; /* XXX: This is a workaround for a bug */
916 mvwadd_wch(d
, y
, x
, &ch
);
924 window_reverse(GntWidget
*win
, gboolean set
, GntWM
*wm
)
930 if (GNT_WIDGET_IS_FLAG_SET(win
, GNT_WIDGET_NO_BORDER
))
934 gnt_widget_get_size(win
, &w
, &h
);
936 if (gnt_widget_has_shadow(win
)) {
941 /* the top and bottom */
942 for (i
= 0; i
< w
; i
+= reverse_char(d
, 0, i
, set
));
943 for (i
= 0; i
< w
; i
+= reverse_char(d
, h
-1, i
, set
));
945 /* the left and right */
946 for (i
= 0; i
< h
; i
+= reverse_char(d
, i
, 0, set
));
947 for (i
= 0; i
< h
; i
+= reverse_char(d
, i
, w
-1, set
));
949 gnt_wm_copy_win(win
, g_hash_table_lookup(wm
->nodes
, win
));
954 start_move(GntBindable
*bindable
, GList
*null
)
956 GntWM
*wm
= GNT_WM(bindable
);
957 if (wm
->_list
.window
|| wm
->menu
)
959 if (!wm
->cws
->ordered
)
962 wm
->mode
= GNT_KP_MODE_MOVE
;
963 window_reverse(GNT_WIDGET(wm
->cws
->ordered
->data
), TRUE
, wm
);
969 start_resize(GntBindable
*bindable
, GList
*null
)
971 GntWM
*wm
= GNT_WM(bindable
);
972 if (wm
->_list
.window
|| wm
->menu
)
974 if (!wm
->cws
->ordered
)
977 wm
->mode
= GNT_KP_MODE_RESIZE
;
978 window_reverse(GNT_WIDGET(wm
->cws
->ordered
->data
), TRUE
, wm
);
984 wm_quit(GntBindable
*bindable
, GList
*list
)
986 GntWM
*wm
= GNT_WM(bindable
);
989 g_main_loop_quit(wm
->loop
);
994 return_true(GntWM
*wm
, GntWidget
*w
, int *a
, int *b
)
1000 refresh_screen(GntBindable
*bindable
, GList
*null
)
1002 GntWM
*wm
= GNT_WM(bindable
);
1007 g_hash_table_foreach(wm
->nodes
, (GHFunc
)refresh_node
, GINT_TO_POINTER(TRUE
));
1008 g_signal_emit(wm
, signals
[SIG_TERMINAL_REFRESH
], 0);
1010 gnt_ws_draw_taskbar(wm
->cws
, TRUE
);
1011 curs_set(0); /* endwin resets the cursor to normal */
1017 toggle_clipboard(GntBindable
*bindable
, GList
*n
)
1019 static GntWidget
*clip
;
1023 gnt_widget_destroy(clip
);
1027 getmaxyx(stdscr
, maxy
, maxx
);
1028 text
= gnt_get_clipboard_string();
1029 clip
= gnt_hwindow_new(FALSE
);
1030 GNT_WIDGET_SET_FLAGS(clip
, GNT_WIDGET_TRANSIENT
);
1031 GNT_WIDGET_SET_FLAGS(clip
, GNT_WIDGET_NO_BORDER
);
1032 gnt_box_set_pad(GNT_BOX(clip
), 0);
1033 gnt_box_add_widget(GNT_BOX(clip
), gnt_label_new(" "));
1034 gnt_box_add_widget(GNT_BOX(clip
), gnt_label_new(text
));
1035 gnt_box_add_widget(GNT_BOX(clip
), gnt_label_new(" "));
1036 gnt_widget_set_position(clip
, 0, 0);
1037 gnt_widget_draw(clip
);
1042 static void remove_tag(gpointer wid
, gpointer wim
)
1044 GntWM
*wm
= GNT_WM(wim
);
1045 GntWidget
*w
= GNT_WIDGET(wid
);
1046 wm
->tagged
= g_list_remove(wm
->tagged
, w
);
1047 mvwhline(w
->window
, 0, 1, ACS_HLINE
| gnt_color_pair(GNT_COLOR_NORMAL
), 3);
1052 tag_widget(GntBindable
*b
, GList
*params
)
1054 GntWM
*wm
= GNT_WM(b
);
1057 if (!wm
->cws
->ordered
)
1059 widget
= wm
->cws
->ordered
->data
;
1061 if (g_list_find(wm
->tagged
, widget
)) {
1062 remove_tag(widget
, wm
);
1066 wm
->tagged
= g_list_prepend(wm
->tagged
, widget
);
1067 wbkgdset(widget
->window
, ' ' | gnt_color_pair(GNT_COLOR_HIGHLIGHT
));
1068 mvwprintw(widget
->window
, 0, 1, "[T]");
1069 gnt_widget_draw(widget
);
1074 widget_move_ws(gpointer wid
, gpointer w
)
1076 GntWM
*wm
= GNT_WM(w
);
1077 gnt_wm_widget_move_workspace(wm
, wm
->cws
, GNT_WIDGET(wid
));
1081 place_tagged(GntBindable
*b
, GList
*params
)
1083 GntWM
*wm
= GNT_WM(b
);
1084 g_list_foreach(wm
->tagged
, widget_move_ws
, wm
);
1085 g_list_foreach(wm
->tagged
, remove_tag
, wm
);
1086 g_list_free(wm
->tagged
);
1092 workspace_list(GntBindable
*b
, GList
*params
)
1094 GntWM
*wm
= GNT_WM(b
);
1096 if (wm
->_list
.window
|| wm
->menu
)
1099 list_of_windows(wm
, TRUE
);
1105 workspace_new(GntBindable
*bindable
, GList
*null
)
1107 GntWM
*wm
= GNT_WM(bindable
);
1108 GntWS
*ws
= gnt_ws_new(NULL
);
1109 gnt_wm_add_workspace(wm
, ws
);
1110 gnt_wm_switch_workspace(wm
, g_list_index(wm
->workspaces
, ws
));
1115 ignore_keys_start(GntBindable
*bindable
, GList
*n
)
1117 GntWM
*wm
= GNT_WM(bindable
);
1119 if(!wm
->menu
&& !wm
->_list
.window
&& wm
->mode
== GNT_KP_MODE_NORMAL
){
1127 ignore_keys_end(GntBindable
*bindable
, GList
*n
)
1129 return ignore_keys
? !(ignore_keys
= FALSE
) : FALSE
;
1133 help_for_bindable(GntWM
*wm
, GntBindable
*bindable
)
1135 gboolean ret
= TRUE
;
1136 GntBindableClass
*klass
= GNT_BINDABLE_GET_CLASS(bindable
);
1138 if (klass
->help_window
) {
1139 gnt_wm_raise_window(wm
, GNT_WIDGET(klass
->help_window
));
1141 ret
= gnt_bindable_build_help_window(bindable
);
1147 help_for_wm(GntBindable
*bindable
, GList
*null
)
1149 return help_for_bindable(GNT_WM(bindable
),bindable
);
1153 help_for_window(GntBindable
*bindable
, GList
*null
)
1155 GntWM
*wm
= GNT_WM(bindable
);
1158 if(!wm
->cws
->ordered
)
1161 widget
= wm
->cws
->ordered
->data
;
1163 return help_for_bindable(wm
,GNT_BINDABLE(widget
));
1167 help_for_widget(GntBindable
*bindable
, GList
*null
)
1169 GntWM
*wm
= GNT_WM(bindable
);
1172 if (!wm
->cws
->ordered
)
1175 widget
= wm
->cws
->ordered
->data
;
1176 if (!GNT_IS_BOX(widget
))
1179 return help_for_bindable(wm
, GNT_BINDABLE(GNT_BOX(widget
)->active
));
1183 accumulate_windows(gpointer window
, gpointer node
, gpointer p
)
1185 GList
*list
= *(GList
**)p
;
1186 list
= g_list_prepend(list
, window
);
1191 gnt_wm_destroy(GObject
*obj
)
1193 GntWM
*wm
= GNT_WM(obj
);
1195 g_hash_table_foreach(wm
->nodes
, accumulate_windows
, &list
);
1196 g_list_foreach(list
, (GFunc
)gnt_widget_destroy
, NULL
);
1198 g_hash_table_destroy(wm
->nodes
);
1201 while (wm
->workspaces
) {
1202 g_object_unref(wm
->workspaces
->data
);
1203 wm
->workspaces
= g_list_delete_link(wm
->workspaces
, wm
->workspaces
);
1208 gnt_wm_class_init(GntWMClass
*klass
)
1211 GObjectClass
*gclass
= G_OBJECT_CLASS(klass
);
1213 gclass
->dispose
= gnt_wm_destroy
;
1215 klass
->new_window
= gnt_wm_new_window_real
;
1216 klass
->decorate_window
= NULL
;
1217 klass
->close_window
= NULL
;
1218 klass
->window_resize_confirm
= return_true
;
1219 klass
->window_resized
= gnt_wm_win_resized
;
1220 klass
->window_move_confirm
= return_true
;
1221 klass
->window_moved
= gnt_wm_win_moved
;
1222 klass
->window_update
= NULL
;
1223 klass
->key_pressed
= NULL
;
1224 klass
->mouse_clicked
= NULL
;
1225 klass
->give_focus
= gnt_wm_give_focus
;
1227 signals
[SIG_NEW_WIN
] =
1228 g_signal_new("new_win",
1229 G_TYPE_FROM_CLASS(klass
),
1231 G_STRUCT_OFFSET(GntWMClass
, new_window
),
1233 g_cclosure_marshal_VOID__POINTER
,
1234 G_TYPE_NONE
, 1, G_TYPE_POINTER
);
1235 signals
[SIG_DECORATE_WIN
] =
1236 g_signal_new("decorate_win",
1237 G_TYPE_FROM_CLASS(klass
),
1239 G_STRUCT_OFFSET(GntWMClass
, decorate_window
),
1241 g_cclosure_marshal_VOID__POINTER
,
1242 G_TYPE_NONE
, 1, G_TYPE_POINTER
);
1243 signals
[SIG_CLOSE_WIN
] =
1244 g_signal_new("close_win",
1245 G_TYPE_FROM_CLASS(klass
),
1247 G_STRUCT_OFFSET(GntWMClass
, close_window
),
1249 g_cclosure_marshal_VOID__POINTER
,
1250 G_TYPE_NONE
, 1, G_TYPE_POINTER
);
1251 signals
[SIG_CONFIRM_RESIZE
] =
1252 g_signal_new("confirm_resize",
1253 G_TYPE_FROM_CLASS(klass
),
1255 G_STRUCT_OFFSET(GntWMClass
, window_resize_confirm
),
1256 gnt_boolean_handled_accumulator
, NULL
,
1257 gnt_closure_marshal_BOOLEAN__POINTER_POINTER_POINTER
,
1258 G_TYPE_BOOLEAN
, 3, G_TYPE_POINTER
, G_TYPE_POINTER
, G_TYPE_POINTER
);
1260 signals
[SIG_CONFIRM_MOVE
] =
1261 g_signal_new("confirm_move",
1262 G_TYPE_FROM_CLASS(klass
),
1264 G_STRUCT_OFFSET(GntWMClass
, window_move_confirm
),
1265 gnt_boolean_handled_accumulator
, NULL
,
1266 gnt_closure_marshal_BOOLEAN__POINTER_POINTER_POINTER
,
1267 G_TYPE_BOOLEAN
, 3, G_TYPE_POINTER
, G_TYPE_POINTER
, G_TYPE_POINTER
);
1269 signals
[SIG_RESIZED
] =
1270 g_signal_new("window_resized",
1271 G_TYPE_FROM_CLASS(klass
),
1273 G_STRUCT_OFFSET(GntWMClass
, window_resized
),
1275 g_cclosure_marshal_VOID__POINTER
,
1276 G_TYPE_NONE
, 1, G_TYPE_POINTER
);
1277 signals
[SIG_MOVED
] =
1278 g_signal_new("window_moved",
1279 G_TYPE_FROM_CLASS(klass
),
1281 G_STRUCT_OFFSET(GntWMClass
, window_moved
),
1283 g_cclosure_marshal_VOID__POINTER
,
1284 G_TYPE_NONE
, 1, G_TYPE_POINTER
);
1285 signals
[SIG_UPDATE_WIN
] =
1286 g_signal_new("window_update",
1287 G_TYPE_FROM_CLASS(klass
),
1289 G_STRUCT_OFFSET(GntWMClass
, window_update
),
1291 g_cclosure_marshal_VOID__POINTER
,
1292 G_TYPE_NONE
, 1, G_TYPE_POINTER
);
1294 signals
[SIG_GIVE_FOCUS
] =
1295 g_signal_new("give_focus",
1296 G_TYPE_FROM_CLASS(klass
),
1298 G_STRUCT_OFFSET(GntWMClass
, give_focus
),
1300 g_cclosure_marshal_VOID__POINTER
,
1301 G_TYPE_NONE
, 1, G_TYPE_POINTER
);
1303 signals
[SIG_MOUSE_CLICK
] =
1304 g_signal_new("mouse_clicked",
1305 G_TYPE_FROM_CLASS(klass
),
1307 G_STRUCT_OFFSET(GntWMClass
, mouse_clicked
),
1308 gnt_boolean_handled_accumulator
, NULL
,
1309 gnt_closure_marshal_BOOLEAN__INT_INT_INT_POINTER
,
1310 G_TYPE_BOOLEAN
, 4, G_TYPE_INT
, G_TYPE_INT
, G_TYPE_INT
, G_TYPE_POINTER
);
1312 signals
[SIG_TERMINAL_REFRESH
] =
1313 g_signal_new("terminal-refresh",
1314 G_TYPE_FROM_CLASS(klass
),
1316 G_STRUCT_OFFSET(GntWMClass
, terminal_refresh
),
1318 g_cclosure_marshal_VOID__VOID
,
1321 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "window-next", window_next
,
1323 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "window-prev", window_prev
,
1325 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "window-close", window_close
,
1327 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "window-list", window_list
,
1329 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "dump-screen", dump_screen
,
1331 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "shift-left", shift_left
,
1333 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "shift-right", shift_right
,
1335 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "action-list", list_actions
,
1337 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "start-move", start_move
,
1339 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "start-resize", start_resize
,
1341 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "wm-quit", wm_quit
,
1343 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "refresh-screen", refresh_screen
,
1345 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "switch-window-n", switch_window_n
,
1347 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "window-scroll-down", window_scroll_down
,
1348 "\033" GNT_KEY_CTRL_J
, NULL
);
1349 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "window-scroll-up", window_scroll_up
,
1350 "\033" GNT_KEY_CTRL_K
, NULL
);
1351 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "help-for-widget", help_for_widget
,
1353 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "workspace-new", workspace_new
,
1355 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "workspace-next", workspace_next
,
1357 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "workspace-prev", workspace_prev
,
1359 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "window-tag", tag_widget
,
1361 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "place-tagged", place_tagged
,
1363 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "workspace-list", workspace_list
,
1365 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "toggle-clipboard", toggle_clipboard
,
1367 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "help-for-wm", help_for_wm
,
1369 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "help-for-window", help_for_window
,
1371 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "ignore-keys-start", ignore_keys_start
,
1372 GNT_KEY_CTRL_G
, NULL
);
1373 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "ignore-keys-end", ignore_keys_end
,
1374 "\033" GNT_KEY_CTRL_G
, NULL
);
1376 gnt_style_read_actions(G_OBJECT_CLASS_TYPE(klass
), GNT_BINDABLE_CLASS(klass
));
1378 /* Make sure Alt+x are detected properly. */
1379 for (i
= '0'; i
<= '9'; i
++) {
1380 char str
[] = "\033X";
1382 gnt_keys_add_combination(str
);
1388 /******************************************************************************
1390 *****************************************************************************/
1392 gnt_wm_get_gtype(void)
1394 static GType type
= 0;
1397 static const GTypeInfo info
= {
1399 NULL
, /* base_init */
1400 NULL
, /* base_finalize */
1401 (GClassInitFunc
)gnt_wm_class_init
,
1403 NULL
, /* class_data */
1405 0, /* n_preallocs */
1406 gnt_wm_init
, /* instance_init */
1407 NULL
/* value_table */
1410 type
= g_type_register_static(GNT_TYPE_BINDABLE
,
1419 gnt_wm_add_workspace(GntWM
*wm
, GntWS
*ws
)
1421 wm
->workspaces
= g_list_append(wm
->workspaces
, ws
);
1425 gnt_wm_switch_workspace(GntWM
*wm
, gint n
)
1427 GntWS
*s
= g_list_nth_data(wm
->workspaces
, n
);
1431 if (wm
->_list
.window
) {
1432 gnt_widget_destroy(wm
->_list
.window
);
1434 gnt_ws_hide(wm
->cws
, wm
->nodes
);
1436 gnt_ws_show(wm
->cws
, wm
->nodes
);
1438 gnt_ws_draw_taskbar(wm
->cws
, TRUE
);
1440 if (wm
->cws
->ordered
) {
1441 gnt_wm_raise_window(wm
, wm
->cws
->ordered
->data
);
1444 if (act
&& g_list_find(act
, wm
->cws
)) {
1445 act
= g_list_remove(act
, wm
->cws
);
1452 gnt_wm_switch_workspace_prev(GntWM
*wm
)
1454 int n
= g_list_index(wm
->workspaces
, wm
->cws
);
1455 return gnt_wm_switch_workspace(wm
, --n
);
1459 gnt_wm_switch_workspace_next(GntWM
*wm
)
1461 int n
= g_list_index(wm
->workspaces
, wm
->cws
);
1462 return gnt_wm_switch_workspace(wm
, ++n
);
1466 workspace_next(GntBindable
*wm
, GList
*n
)
1468 return gnt_wm_switch_workspace_next(GNT_WM(wm
));
1472 workspace_prev(GntBindable
*wm
, GList
*n
)
1474 return gnt_wm_switch_workspace_prev(GNT_WM(wm
));
1478 gnt_wm_widget_move_workspace(GntWM
*wm
, GntWS
*neww
, GntWidget
*widget
)
1480 GntWS
*oldw
= gnt_wm_widget_find_workspace(wm
, widget
);
1482 if (!oldw
|| oldw
== neww
)
1484 node
= g_hash_table_lookup(wm
->nodes
, widget
);
1485 if (node
&& node
->ws
== neww
)
1491 gnt_ws_remove_widget(oldw
, widget
);
1492 gnt_ws_add_widget(neww
, widget
);
1493 if (neww
== wm
->cws
) {
1494 gnt_ws_widget_show(widget
, wm
->nodes
);
1496 gnt_ws_widget_hide(widget
, wm
->nodes
);
1500 static gint
widget_in_workspace(gconstpointer workspace
, gconstpointer wid
)
1502 GntWS
*s
= (GntWS
*)workspace
;
1503 if (s
->list
&& g_list_find(s
->list
, wid
))
1508 GntWS
*gnt_wm_widget_find_workspace(GntWM
*wm
, GntWidget
*widget
)
1510 GList
*l
= g_list_find_custom(wm
->workspaces
, widget
, widget_in_workspace
);
1516 static void free_workspaces(gpointer data
, gpointer n
)
1522 void gnt_wm_set_workspaces(GntWM
*wm
, GList
*workspaces
)
1524 g_list_foreach(wm
->workspaces
, free_workspaces
, NULL
);
1525 wm
->workspaces
= workspaces
;
1526 gnt_wm_switch_workspace(wm
, 0);
1530 update_window_in_list(GntWM
*wm
, GntWidget
*wid
)
1532 GntTextFormatFlags flag
= 0;
1534 if (wm
->windows
== NULL
)
1537 if (wm
->cws
->ordered
&& wid
== wm
->cws
->ordered
->data
)
1538 flag
|= GNT_TEXT_FLAG_DIM
;
1539 else if (GNT_WIDGET_IS_FLAG_SET(wid
, GNT_WIDGET_URGENT
))
1540 flag
|= GNT_TEXT_FLAG_BOLD
;
1542 gnt_tree_set_row_flags(GNT_TREE(wm
->windows
->tree
), wid
, flag
);
1546 match_title(gpointer title
, gpointer n
, gpointer wid_title
)
1548 /* XXX: do any regex magic here. */
1549 if (g_strrstr((gchar
*)wid_title
, (gchar
*)title
))
1554 #if !GLIB_CHECK_VERSION(2,4,0)
1562 table_find_helper(gpointer key
, gpointer value
, gpointer data
)
1564 GHRFunc func
= data
;
1565 if (func(key
, value
, table_find_data
.data
))
1566 table_find_data
.value
= value
;
1570 g_hash_table_find(GHashTable
* table
, GHRFunc func
, gpointer data
)
1572 table_find_data
.data
= data
;
1573 table_find_data
.value
= NULL
;
1574 g_hash_table_foreach(table
, table_find_helper
, func
);
1575 return table_find_data
.value
;
1580 new_widget_find_workspace(GntWM
*wm
, GntWidget
*widget
)
1583 const gchar
*name
, *title
;
1584 title
= GNT_BOX(widget
)->title
;
1586 ret
= g_hash_table_find(wm
->title_places
, match_title
, (gpointer
)title
);
1589 name
= gnt_widget_get_name(widget
);
1591 ret
= g_hash_table_find(wm
->name_places
, match_title
, (gpointer
)name
);
1592 return ret
? ret
: wm
->cws
;
1596 gnt_wm_new_window_real(GntWM
*wm
, GntWidget
*widget
)
1599 gboolean transient
= FALSE
;
1601 if (widget
->window
== NULL
)
1604 node
= g_new0(GntNode
, 1);
1608 g_hash_table_replace(wm
->nodes
, widget
, node
);
1610 refresh_node(widget
, node
, NULL
);
1612 transient
= !!GNT_WIDGET_IS_FLAG_SET(node
->me
, GNT_WIDGET_TRANSIENT
);
1616 int x
, y
, w
, h
, maxx
, maxy
;
1617 gboolean shadow
= TRUE
;
1619 if (!gnt_widget_has_shadow(widget
))
1623 w
= widget
->priv
.width
+ shadow
;
1624 h
= widget
->priv
.height
+ shadow
;
1626 maxx
= getmaxx(stdscr
);
1627 maxy
= getmaxy(stdscr
) - 1; /* room for the taskbar */
1632 x
= MAX(0, maxx
- w
);
1634 y
= MAX(0, maxy
- h
);
1638 node
->window
= newwin(h
, w
, y
, x
);
1639 gnt_wm_copy_win(widget
, node
);
1643 node
->panel
= new_panel(node
->window
);
1644 set_panel_userptr(node
->panel
, node
);
1647 GntWS
*ws
= wm
->cws
;
1648 if (node
->me
!= wm
->_list
.window
) {
1649 if (GNT_IS_BOX(widget
)) {
1650 ws
= new_widget_find_workspace(wm
, widget
);
1653 ws
->list
= g_list_append(ws
->list
, widget
);
1654 ws
->ordered
= g_list_append(ws
->ordered
, widget
);
1657 if (wm
->event_stack
|| node
->me
== wm
->_list
.window
||
1658 node
->me
== ws
->ordered
->data
) {
1659 gnt_wm_raise_window(wm
, node
->me
);
1661 bottom_panel(node
->panel
); /* New windows should not grab focus */
1662 gnt_widget_set_focus(node
->me
, FALSE
);
1663 gnt_widget_set_urgent(node
->me
);
1665 gnt_ws_widget_hide(widget
, wm
->nodes
);
1670 void gnt_wm_new_window(GntWM
*wm
, GntWidget
*widget
)
1672 while (widget
->parent
)
1673 widget
= widget
->parent
;
1675 if (GNT_WIDGET_IS_FLAG_SET(widget
, GNT_WIDGET_INVISIBLE
) ||
1676 g_hash_table_lookup(wm
->nodes
, widget
)) {
1681 if (GNT_IS_BOX(widget
)) {
1682 const char *title
= GNT_BOX(widget
)->title
;
1683 GntPosition
*p
= NULL
;
1684 if (title
&& (p
= g_hash_table_lookup(wm
->positions
, title
)) != NULL
) {
1685 sanitize_position(widget
, &p
->x
, &p
->y
);
1686 gnt_widget_set_position(widget
, p
->x
, p
->y
);
1687 mvwin(widget
->window
, p
->y
, p
->x
);
1691 g_signal_emit(wm
, signals
[SIG_NEW_WIN
], 0, widget
);
1692 g_signal_emit(wm
, signals
[SIG_DECORATE_WIN
], 0, widget
);
1694 if (wm
->windows
&& !GNT_WIDGET_IS_FLAG_SET(widget
, GNT_WIDGET_TRANSIENT
)) {
1695 if ((GNT_IS_BOX(widget
) && GNT_BOX(widget
)->title
) && wm
->_list
.window
!= widget
1696 && GNT_WIDGET_IS_FLAG_SET(widget
, GNT_WIDGET_CAN_TAKE_FOCUS
)) {
1697 gnt_tree_add_row_last(GNT_TREE(wm
->windows
->tree
), widget
,
1698 gnt_tree_create_row(GNT_TREE(wm
->windows
->tree
), GNT_BOX(widget
)->title
),
1699 g_object_get_data(G_OBJECT(wm
->windows
->tree
), "workspace") ? wm
->cws
: NULL
);
1700 update_window_in_list(wm
, widget
);
1705 gnt_ws_draw_taskbar(wm
->cws
, FALSE
);
1708 void gnt_wm_window_decorate(GntWM
*wm
, GntWidget
*widget
)
1710 g_signal_emit(wm
, signals
[SIG_DECORATE_WIN
], 0, widget
);
1713 void gnt_wm_window_close(GntWM
*wm
, GntWidget
*widget
)
1718 s
= gnt_wm_widget_find_workspace(wm
, widget
);
1720 if (g_hash_table_lookup(wm
->nodes
, widget
) == NULL
)
1723 g_signal_emit(wm
, signals
[SIG_CLOSE_WIN
], 0, widget
);
1724 g_hash_table_remove(wm
->nodes
, widget
);
1727 gnt_tree_remove(GNT_TREE(wm
->windows
->tree
), widget
);
1731 pos
= g_list_index(s
->list
, widget
);
1734 s
->list
= g_list_remove(s
->list
, widget
);
1735 s
->ordered
= g_list_remove(s
->ordered
, widget
);
1737 if (s
->ordered
&& wm
->cws
== s
)
1738 gnt_wm_raise_window(wm
, s
->ordered
->data
);
1743 gnt_ws_draw_taskbar(wm
->cws
, FALSE
);
1746 time_t gnt_wm_get_idle_time()
1748 return time(NULL
) - last_active_time
;
1751 gboolean
gnt_wm_process_input(GntWM
*wm
, const char *keys
)
1753 gboolean ret
= FALSE
;
1755 keys
= gnt_bindable_remap_keys(GNT_BINDABLE(wm
), keys
);
1759 if(keys
&& !strcmp(keys
, "\033" GNT_KEY_CTRL_G
)){
1760 if(gnt_bindable_perform_action_key(GNT_BINDABLE(wm
), keys
)){
1764 return wm
->cws
->ordered
? gnt_widget_key_pressed(GNT_WIDGET(wm
->cws
->ordered
->data
), keys
) : FALSE
;
1767 if (gnt_bindable_perform_action_key(GNT_BINDABLE(wm
), keys
)) {
1771 /* Do some manual checking */
1772 if (wm
->cws
->ordered
&& wm
->mode
!= GNT_KP_MODE_NORMAL
) {
1773 int xmin
= 0, ymin
= 0, xmax
= getmaxx(stdscr
), ymax
= getmaxy(stdscr
) - 1;
1775 GntWidget
*widget
= GNT_WIDGET(wm
->cws
->ordered
->data
);
1778 gnt_widget_get_position(widget
, &x
, &y
);
1779 gnt_widget_get_size(widget
, &w
, &h
);
1783 if (wm
->mode
== GNT_KP_MODE_MOVE
) {
1784 if (strcmp(keys
, GNT_KEY_LEFT
) == 0) {
1787 } else if (strcmp(keys
, GNT_KEY_RIGHT
) == 0) {
1790 } else if (strcmp(keys
, GNT_KEY_UP
) == 0) {
1793 } else if (strcmp(keys
, GNT_KEY_DOWN
) == 0) {
1797 if (ox
!= x
|| oy
!= y
) {
1798 gnt_screen_move_widget(widget
, x
, y
);
1799 window_reverse(widget
, TRUE
, wm
);
1802 } else if (wm
->mode
== GNT_KP_MODE_RESIZE
) {
1803 if (strcmp(keys
, GNT_KEY_LEFT
) == 0) {
1805 } else if (strcmp(keys
, GNT_KEY_RIGHT
) == 0) {
1808 } else if (strcmp(keys
, GNT_KEY_UP
) == 0) {
1810 } else if (strcmp(keys
, GNT_KEY_DOWN
) == 0) {
1814 if (oh
!= h
|| ow
!= w
) {
1815 gnt_screen_resize_widget(widget
, w
, h
);
1816 window_reverse(widget
, TRUE
, wm
);
1820 if (strcmp(keys
, "\r") == 0 || strcmp(keys
, "\033") == 0) {
1821 window_reverse(widget
, FALSE
, wm
);
1822 wm
->mode
= GNT_KP_MODE_NORMAL
;
1827 /* Escape to close the window-list or action-list window */
1828 if (strcmp(keys
, "\033") == 0) {
1829 if (wm
->_list
.window
) {
1830 gnt_widget_destroy(wm
->_list
.window
);
1833 } else if (keys
[0] == '\033' && isdigit(keys
[1]) && keys
[2] == '\0') {
1834 /* Alt+x for quick switch */
1835 int n
= *(keys
+ 1) - '0';
1841 list
= g_list_append(list
, GINT_TO_POINTER(n
- 1));
1842 switch_window_n(GNT_BINDABLE(wm
), list
);
1848 ret
= gnt_widget_key_pressed(GNT_WIDGET(wm
->menu
), keys
);
1849 else if (wm
->_list
.window
)
1850 ret
= gnt_widget_key_pressed(wm
->_list
.window
, keys
);
1851 else if (wm
->cws
->ordered
) {
1852 GntWidget
*win
= wm
->cws
->ordered
->data
;
1853 if (GNT_IS_WINDOW(win
)) {
1854 GntMenu
*menu
= GNT_WINDOW(win
)->menu
;
1856 const char *id
= gnt_window_get_accel_item(GNT_WINDOW(win
), keys
);
1858 ret
= (gnt_menu_get_item(menu
, id
) != NULL
);
1862 ret
= gnt_widget_key_pressed(win
, keys
);
1868 gnt_wm_win_resized(GntWM
*wm
, GntNode
*node
)
1870 /*refresh_node(node->me, node, NULL);*/
1874 gnt_wm_win_moved(GntWM
*wm
, GntNode
*node
)
1876 refresh_node(node
->me
, node
, NULL
);
1879 void gnt_wm_resize_window(GntWM
*wm
, GntWidget
*widget
, int width
, int height
)
1881 gboolean ret
= TRUE
;
1885 while (widget
->parent
)
1886 widget
= widget
->parent
;
1887 node
= g_hash_table_lookup(wm
->nodes
, widget
);
1891 g_signal_emit(wm
, signals
[SIG_CONFIRM_RESIZE
], 0, widget
, &width
, &height
, &ret
);
1893 return; /* resize is not permitted */
1894 hide_panel(node
->panel
);
1895 gnt_widget_set_size(widget
, width
, height
);
1896 gnt_widget_draw(widget
);
1898 maxx
= getmaxx(stdscr
);
1899 maxy
= getmaxy(stdscr
) - 1;
1900 height
= MIN(height
, maxy
);
1901 width
= MIN(width
, maxx
);
1902 wresize(node
->window
, height
, width
);
1903 replace_panel(node
->panel
, node
->window
);
1905 g_signal_emit(wm
, signals
[SIG_RESIZED
], 0, node
);
1907 show_panel(node
->panel
);
1912 write_gdi(gpointer key
, gpointer value
, gpointer data
)
1914 GntPosition
*p
= value
;
1915 fprintf(data
, ".%s = %d;%d\n", (char *)key
, p
->x
, p
->y
);
1919 write_already(gpointer data
)
1925 filename
= g_build_filename(g_get_home_dir(), ".gntpositions", NULL
);
1927 file
= fopen(filename
, "wb");
1929 g_printerr("GntWM: error opening file to save positions\n");
1931 fprintf(file
, "[positions]\n");
1932 g_hash_table_foreach(wm
->positions
, write_gdi
, file
);
1937 g_source_remove(write_timeout
);
1943 write_positions_to_file(GntWM
*wm
)
1945 if (write_timeout
) {
1946 g_source_remove(write_timeout
);
1948 write_timeout
= g_timeout_add(10000, write_already
, wm
);
1951 void gnt_wm_move_window(GntWM
*wm
, GntWidget
*widget
, int x
, int y
)
1953 gboolean ret
= TRUE
;
1956 while (widget
->parent
)
1957 widget
= widget
->parent
;
1958 node
= g_hash_table_lookup(wm
->nodes
, widget
);
1962 g_signal_emit(wm
, signals
[SIG_CONFIRM_MOVE
], 0, widget
, &x
, &y
, &ret
);
1964 return; /* resize is not permitted */
1966 gnt_widget_set_position(widget
, x
, y
);
1967 move_panel(node
->panel
, y
, x
);
1969 g_signal_emit(wm
, signals
[SIG_MOVED
], 0, node
);
1970 if (gnt_style_get_bool(GNT_STYLE_REMPOS
, TRUE
) && GNT_IS_BOX(widget
) &&
1971 !GNT_WIDGET_IS_FLAG_SET(widget
, GNT_WIDGET_TRANSIENT
)) {
1972 const char *title
= GNT_BOX(widget
)->title
;
1974 GntPosition
*p
= g_new0(GntPosition
, 1);
1975 GntWidget
*wid
= node
->me
;
1978 g_hash_table_replace(wm
->positions
, g_strdup(title
), p
);
1979 write_positions_to_file(wm
);
1987 gnt_wm_give_focus(GntWM
*wm
, GntWidget
*widget
)
1989 GntNode
*node
= g_hash_table_lookup(wm
->nodes
, widget
);
1994 if (widget
!= wm
->_list
.window
&& !GNT_IS_MENU(widget
) &&
1995 wm
->cws
->ordered
->data
!= widget
) {
1996 GntWidget
*w
= wm
->cws
->ordered
->data
;
1997 wm
->cws
->ordered
= g_list_bring_to_front(wm
->cws
->ordered
, widget
);
1998 gnt_widget_set_focus(w
, FALSE
);
2001 gnt_widget_set_focus(widget
, TRUE
);
2002 GNT_WIDGET_UNSET_FLAGS(widget
, GNT_WIDGET_URGENT
);
2003 gnt_widget_draw(widget
);
2004 top_panel(node
->panel
);
2006 if (wm
->_list
.window
) {
2007 GntNode
*nd
= g_hash_table_lookup(wm
->nodes
, wm
->_list
.window
);
2008 top_panel(nd
->panel
);
2011 gnt_ws_draw_taskbar(wm
->cws
, FALSE
);
2014 void gnt_wm_update_window(GntWM
*wm
, GntWidget
*widget
)
2016 GntNode
*node
= NULL
;
2019 while (widget
->parent
)
2020 widget
= widget
->parent
;
2021 if (!GNT_IS_MENU(widget
)) {
2022 if (!GNT_IS_BOX(widget
))
2024 gnt_box_sync_children(GNT_BOX(widget
));
2027 ws
= gnt_wm_widget_find_workspace(wm
, widget
);
2028 node
= g_hash_table_lookup(wm
->nodes
, widget
);
2030 gnt_wm_new_window(wm
, widget
);
2032 g_signal_emit(wm
, signals
[SIG_UPDATE_WIN
], 0, node
);
2034 if (ws
== wm
->cws
|| GNT_WIDGET_IS_FLAG_SET(widget
, GNT_WIDGET_TRANSIENT
)) {
2035 gnt_wm_copy_win(widget
, node
);
2037 gnt_ws_draw_taskbar(wm
->cws
, FALSE
);
2038 } else if (ws
&& ws
!= wm
->cws
&& GNT_WIDGET_IS_FLAG_SET(widget
, GNT_WIDGET_URGENT
)) {
2039 if (!act
|| (act
&& !g_list_find(act
, ws
)))
2040 act
= g_list_prepend(act
, ws
);
2045 gboolean
gnt_wm_process_click(GntWM
*wm
, GntMouseEvent event
, int x
, int y
, GntWidget
*widget
)
2047 gboolean ret
= TRUE
;
2049 g_signal_emit(wm
, signals
[SIG_MOUSE_CLICK
], 0, event
, x
, y
, widget
, &ret
);
2053 void gnt_wm_raise_window(GntWM
*wm
, GntWidget
*widget
)
2055 GntWS
*ws
= gnt_wm_widget_find_workspace(wm
, widget
);
2057 gnt_wm_switch_workspace(wm
, g_list_index(wm
->workspaces
, ws
));
2058 if (widget
!= wm
->cws
->ordered
->data
) {
2059 GntWidget
*wid
= wm
->cws
->ordered
->data
;
2060 wm
->cws
->ordered
= g_list_bring_to_front(wm
->cws
->ordered
, widget
);
2061 gnt_widget_set_focus(wid
, FALSE
);
2062 gnt_widget_draw(wid
);
2064 gnt_widget_set_focus(widget
, TRUE
);
2065 gnt_widget_draw(widget
);
2066 g_signal_emit(wm
, signals
[SIG_GIVE_FOCUS
], 0, widget
);
2069 void gnt_wm_set_event_stack(GntWM
*wm
, gboolean set
)
2071 wm
->event_stack
= set
;