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
)
115 src
= widget
->window
;
117 shadow
= gnt_widget_has_shadow(widget
) ? 1 : 0;
118 copywin(src
, dst
, node
->scroll
, 0, 0, 0, getmaxy(dst
) - 1, getmaxx(dst
) - 1, 0);
122 * The following is a workaround for a bug in most versions of ncursesw.
123 * Read about it in: http://article.gmane.org/gmane.comp.lib.ncurses.bugs/2751
125 * In short, if a panel hides one cell of a multi-cell character, then the rest
126 * of the characters in that line get screwed. The workaround here is to erase
127 * any such character preemptively.
129 * Caveat: If a wide character is erased, and the panel above it is moved enough
130 * to expose the entire character, it is not always redrawn.
133 work_around_for_ncurses_bug()
137 while ((panel
= panel_below(panel
)) != NULL
) {
138 int sx
, ex
, sy
, ey
, w
, y
;
140 PANEL
*below
= panel
;
142 sx
= panel
->win
->_begx
;
143 ex
= panel
->win
->_maxx
+ sx
;
144 sy
= panel
->win
->_begy
;
145 ey
= panel
->win
->_maxy
+ sy
;
147 while ((below
= panel_below(below
)) != NULL
) {
148 if (sy
> below
->win
->_begy
+ below
->win
->_maxy
||
149 ey
< below
->win
->_begy
)
151 if (sx
> below
->win
->_begx
+ below
->win
->_maxx
||
152 ex
< below
->win
->_begx
)
154 for (y
= MAX(sy
, below
->win
->_begy
); y
<= MIN(ey
, below
->win
->_begy
+ below
->win
->_maxy
); y
++) {
155 if (mvwin_wch(below
->win
, y
- below
->win
->_begy
, sx
- 1 - below
->win
->_begx
, &ch
) != OK
)
157 w
= widestringwidth(ch
.chars
);
158 if (w
> 1 && (ch
.attr
& 1)) {
160 ch
.attr
&= ~ A_CHARTEXT
;
161 mvwadd_wch(below
->win
, y
- below
->win
->_begy
, sx
- 1 - below
->win
->_begx
, &ch
);
162 touchline(below
->win
, y
- below
->win
->_begy
, 1);
165 if (mvwin_wch(below
->win
, y
- below
->win
->_begy
, ex
+ 1 - below
->win
->_begx
, &ch
) != OK
)
167 w
= widestringwidth(ch
.chars
);
168 if (w
> 1 && !(ch
.attr
& 1)) {
170 ch
.attr
&= ~ A_CHARTEXT
;
171 mvwadd_wch(below
->win
, y
- below
->win
->_begy
, ex
+ 1 - below
->win
->_begx
, &ch
);
172 touchline(below
->win
, y
- below
->win
->_begy
, 1);
185 static GntWidget
*message
= NULL
;
186 GString
*text
= g_string_new("act: ");
188 gnt_widget_destroy(message
);
189 if (g_list_length(act
) == 0)
191 for (iter
= act
; iter
; iter
= iter
->next
) {
192 GntWS
*ws
= iter
->data
;
193 g_string_append_printf(text
, "%s, ", gnt_ws_get_name(ws
));
195 g_string_erase(text
, text
->len
- 2, 2);
196 message
= gnt_vbox_new(FALSE
);
197 label
= gnt_label_new_with_format(text
->str
, GNT_TEXT_FLAG_BOLD
| GNT_TEXT_FLAG_HIGHLIGHT
);
198 GNT_WIDGET_UNSET_FLAGS(GNT_BOX(message
), GNT_WIDGET_CAN_TAKE_FOCUS
);
199 GNT_WIDGET_SET_FLAGS(GNT_BOX(message
), GNT_WIDGET_TRANSIENT
);
200 gnt_box_add_widget(GNT_BOX(message
), label
);
201 gnt_widget_set_name(message
, "wm-message");
202 gnt_widget_set_position(message
, 0, 0);
203 gnt_widget_draw(message
);
204 g_string_free(text
, TRUE
);
208 update_screen(GntWM
*wm
)
210 if (wm
->mode
== GNT_KP_MODE_WAIT_ON_CHILD
)
214 GntMenu
*top
= wm
->menu
;
216 GntNode
*node
= g_hash_table_lookup(wm
->nodes
, top
);
218 top_panel(node
->panel
);
222 work_around_for_ncurses_bug();
229 sanitize_position(GntWidget
*widget
, int *x
, int *y
)
231 int X_MAX
= getmaxx(stdscr
);
232 int Y_MAX
= getmaxy(stdscr
) - 1;
235 gboolean changed
= FALSE
;
237 gnt_widget_get_size(widget
, &w
, &h
);
239 if (*x
+ w
> X_MAX
) {
240 nx
= MAX(0, X_MAX
- w
);
248 if (*y
+ h
> Y_MAX
) {
249 ny
= MAX(0, Y_MAX
- h
);
260 refresh_node(GntWidget
*widget
, GntNode
*node
, gpointer null
)
265 int X_MAX
= getmaxx(stdscr
);
266 int Y_MAX
= getmaxy(stdscr
) - 1;
268 gnt_widget_get_position(widget
, &x
, &y
);
269 gnt_widget_get_size(widget
, &w
, &h
);
271 if (sanitize_position(widget
, &x
, &y
))
272 gnt_screen_move_widget(widget
, x
, y
);
276 if (nw
!= w
|| nh
!= h
)
277 gnt_screen_resize_widget(widget
, nw
, nh
);
281 read_window_positions(GntWM
*wm
)
283 #if GLIB_CHECK_VERSION(2,6,0)
284 GKeyFile
*gfile
= g_key_file_new();
285 char *filename
= g_build_filename(g_get_home_dir(), ".gntpositions", NULL
);
286 GError
*error
= NULL
;
290 if (!g_key_file_load_from_file(gfile
, filename
, G_KEY_FILE_NONE
, &error
)) {
291 g_printerr("GntWM: %s\n", error
->message
);
297 keys
= g_key_file_get_keys(gfile
, "positions", &nk
, &error
);
299 g_printerr("GntWM: %s\n", error
->message
);
304 char *title
= keys
[nk
];
306 char **coords
= g_key_file_get_string_list(gfile
, "positions", title
, &l
, NULL
);
308 int x
= atoi(coords
[0]);
309 int y
= atoi(coords
[1]);
310 GntPosition
*p
= g_new0(GntPosition
, 1);
313 g_hash_table_replace(wm
->positions
, g_strdup(title
+ 1), p
);
315 g_printerr("GntWM: Invalid number of arguments for positioing a window.\n");
323 g_key_file_free(gfile
);
327 static gboolean
check_idle(gpointer n
)
330 time(&last_active_time
);
337 gnt_wm_init(GTypeInstance
*instance
, gpointer
class)
339 GntWM
*wm
= GNT_WM(instance
);
340 wm
->workspaces
= NULL
;
341 wm
->name_places
= g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, g_free
);
342 wm
->title_places
= g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, g_free
);
343 gnt_style_read_workspaces(wm
);
344 if (wm
->workspaces
== NULL
) {
345 wm
->cws
= gnt_ws_new("default");
346 gnt_wm_add_workspace(wm
, wm
->cws
);
348 wm
->cws
= wm
->workspaces
->data
;
350 wm
->event_stack
= FALSE
;
354 wm
->nodes
= g_hash_table_new_full(g_direct_hash
, g_direct_equal
, NULL
, free_node
);
355 wm
->positions
= g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, g_free
);
356 if (gnt_style_get_bool(GNT_STYLE_REMPOS
, TRUE
))
357 read_window_positions(wm
);
358 g_timeout_add(IDLE_CHECK_INTERVAL
* 1000, check_idle
, NULL
);
359 time(&last_active_time
);
360 gnt_wm_switch_workspace(wm
, 0);
364 switch_window(GntWM
*wm
, int direction
)
366 GntWidget
*w
= NULL
, *wid
= NULL
;
369 if (wm
->_list
.window
|| wm
->menu
)
372 if (!wm
->cws
->ordered
|| !wm
->cws
->ordered
->next
)
375 w
= wm
->cws
->ordered
->data
;
376 pos
= g_list_index(wm
->cws
->list
, w
);
380 wid
= g_list_last(wm
->cws
->list
)->data
;
381 else if (pos
>= g_list_length(wm
->cws
->list
))
382 wid
= wm
->cws
->list
->data
;
384 wid
= g_list_nth_data(wm
->cws
->list
, pos
);
386 gnt_wm_raise_window(wm
, wid
);
390 window_next(GntBindable
*bindable
, GList
*null
)
392 GntWM
*wm
= GNT_WM(bindable
);
393 switch_window(wm
, 1);
398 window_prev(GntBindable
*bindable
, GList
*null
)
400 GntWM
*wm
= GNT_WM(bindable
);
401 switch_window(wm
, -1);
406 switch_window_n(GntBindable
*bind
, GList
*list
)
408 GntWM
*wm
= GNT_WM(bind
);
412 if (!wm
->cws
->ordered
)
416 n
= GPOINTER_TO_INT(list
->data
);
420 if ((l
= g_list_nth(wm
->cws
->list
, n
)) != NULL
)
422 gnt_wm_raise_window(wm
, l
->data
);
429 window_scroll_up(GntBindable
*bindable
, GList
*null
)
431 GntWM
*wm
= GNT_WM(bindable
);
435 if (!wm
->cws
->ordered
)
438 window
= wm
->cws
->ordered
->data
;
439 node
= g_hash_table_lookup(wm
->nodes
, window
);
445 gnt_wm_copy_win(window
, node
);
452 window_scroll_down(GntBindable
*bindable
, GList
*null
)
454 GntWM
*wm
= GNT_WM(bindable
);
459 if (!wm
->cws
->ordered
)
462 window
= wm
->cws
->ordered
->data
;
463 node
= g_hash_table_lookup(wm
->nodes
, window
);
467 gnt_widget_get_size(window
, &w
, &h
);
468 if (h
- node
->scroll
> getmaxy(node
->window
)) {
470 gnt_wm_copy_win(window
, node
);
477 window_close(GntBindable
*bindable
, GList
*null
)
479 GntWM
*wm
= GNT_WM(bindable
);
481 if (wm
->_list
.window
)
484 if (wm
->cws
->ordered
) {
485 gnt_widget_destroy(wm
->cws
->ordered
->data
);
492 destroy__list(GntWidget
*widget
, GntWM
*wm
)
494 wm
->_list
.window
= NULL
;
495 wm
->_list
.tree
= NULL
;
502 setup__list(GntWM
*wm
)
504 GntWidget
*tree
, *win
;
505 win
= wm
->_list
.window
= gnt_box_new(FALSE
, FALSE
);
506 gnt_box_set_toplevel(GNT_BOX(win
), TRUE
);
507 gnt_box_set_pad(GNT_BOX(win
), 0);
508 GNT_WIDGET_SET_FLAGS(win
, GNT_WIDGET_TRANSIENT
);
510 tree
= wm
->_list
.tree
= gnt_tree_new();
511 gnt_box_add_widget(GNT_BOX(win
), tree
);
513 g_signal_connect(G_OBJECT(win
), "destroy", G_CALLBACK(destroy__list
), wm
);
517 window_list_activate(GntTree
*tree
, GntWM
*wm
)
519 GntBindable
*sel
= gnt_tree_get_selection_data(GNT_TREE(tree
));
521 gnt_widget_destroy(wm
->_list
.window
);
526 if (GNT_IS_WS(sel
)) {
527 gnt_wm_switch_workspace(wm
, g_list_index(wm
->workspaces
, sel
));
529 gnt_wm_raise_window(wm
, GNT_WIDGET(sel
));
534 populate_window_list(GntWM
*wm
, gboolean workspace
)
537 GntTree
*tree
= GNT_TREE(wm
->windows
->tree
);
539 for (iter
= wm
->cws
->list
; iter
; iter
= iter
->next
) {
540 GntBox
*box
= GNT_BOX(iter
->data
);
542 gnt_tree_add_row_last(tree
, box
,
543 gnt_tree_create_row(tree
, box
->title
), NULL
);
544 update_window_in_list(wm
, GNT_WIDGET(box
));
547 GList
*ws
= wm
->workspaces
;
548 for (; ws
; ws
= ws
->next
) {
549 gnt_tree_add_row_last(tree
, ws
->data
,
550 gnt_tree_create_row(tree
, gnt_ws_get_name(GNT_WS(ws
->data
))), NULL
);
551 for (iter
= GNT_WS(ws
->data
)->list
; iter
; iter
= iter
->next
) {
552 GntBox
*box
= GNT_BOX(iter
->data
);
554 gnt_tree_add_row_last(tree
, box
,
555 gnt_tree_create_row(tree
, box
->title
), ws
->data
);
556 update_window_in_list(wm
, GNT_WIDGET(box
));
563 window_list_key_pressed(GntWidget
*widget
, const char *text
, GntWM
*wm
)
565 if (text
[1] == 0 && wm
->cws
->ordered
) {
566 GntBindable
*sel
= gnt_tree_get_selection_data(GNT_TREE(widget
));
570 if (GNT_IS_WS(sel
)) {
571 /* reorder the workspace. */
573 shift_window(wm
, GNT_WIDGET(sel
), -1);
577 if (GNT_IS_WS(sel
)) {
578 /* reorder the workspace. */
580 shift_window(wm
, GNT_WIDGET(sel
), 1);
585 gnt_tree_remove_all(GNT_TREE(widget
));
586 populate_window_list(wm
, GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget
), "workspace")));
587 gnt_tree_set_selected(GNT_TREE(widget
), sel
);
594 list_of_windows(GntWM
*wm
, gboolean workspace
)
596 GntWidget
*tree
, *win
;
598 wm
->windows
= &wm
->_list
;
600 win
= wm
->windows
->window
;
601 tree
= wm
->windows
->tree
;
603 gnt_box_set_title(GNT_BOX(win
), workspace
? "Workspace List" : "Window List");
605 populate_window_list(wm
, workspace
);
607 if (wm
->cws
->ordered
)
608 gnt_tree_set_selected(GNT_TREE(tree
), wm
->cws
->ordered
->data
);
610 gnt_tree_set_selected(GNT_TREE(tree
), wm
->cws
);
612 g_signal_connect(G_OBJECT(tree
), "activate", G_CALLBACK(window_list_activate
), wm
);
613 g_signal_connect(G_OBJECT(tree
), "key_pressed", G_CALLBACK(window_list_key_pressed
), wm
);
614 g_object_set_data(G_OBJECT(tree
), "workspace", GINT_TO_POINTER(workspace
));
616 gnt_tree_set_col_width(GNT_TREE(tree
), 0, getmaxx(stdscr
) / 3);
617 gnt_widget_set_size(tree
, 0, getmaxy(stdscr
) / 2);
618 gnt_widget_set_position(win
, getmaxx(stdscr
) / 3, getmaxy(stdscr
) / 4);
620 gnt_widget_show(win
);
624 window_list(GntBindable
*bindable
, GList
*null
)
626 GntWM
*wm
= GNT_WM(bindable
);
628 if (wm
->_list
.window
|| wm
->menu
)
631 if (!wm
->cws
->ordered
)
634 list_of_windows(wm
, FALSE
);
640 dump_screen(GntBindable
*bindable
, GList
*null
)
643 chtype old
= 0, now
= 0;
644 FILE *file
= fopen("dump.html", "w");
666 fprintf(file
, "<head>\n <meta http-equiv='Content-Type' content='text/html; charset=utf-8' />\n</head>\n<body>\n");
667 fprintf(file
, "<pre>");
668 for (y
= 0; y
< getmaxy(stdscr
); y
++) {
669 for (x
= 0; x
< getmaxx(stdscr
); x
++) {
670 char ch
[2] = {0, 0}, *print
;
672 now
= mvwinch(curscr
, y
, x
);
673 ch
[0] = now
& A_CHARTEXT
;
678 mvwin_wch(curscr
, y
, x
, &wch
);
680 ch
[0] = (char)(wch
.chars
[0] & 0xff);
683 #define CHECK(attr, start, end) \
689 fprintf(file, "%s", start); \
691 else if (old & attr) \
693 fprintf(file, "%s", end); \
697 CHECK(A_BOLD
, "<b>", "</b>");
698 CHECK(A_UNDERLINE
, "<u>", "</u>");
699 CHECK(A_BLINK
, "<blink>", "</blink>");
701 if ((now
& A_COLOR
) != (old
& A_COLOR
) ||
702 (now
& A_REVERSE
) != (old
& A_REVERSE
))
705 short fgp
, bgp
, r
, g
, b
;
711 ret
= pair_content(PAIR_NUMBER(now
& A_COLOR
), &fgp
, &bgp
);
722 ret
= color_content(fgp
, &r
, &g
, &b
);
723 fg
.r
= r
; fg
.b
= b
; fg
.g
= g
;
724 ret
= color_content(bgp
, &r
, &g
, &b
);
725 bg
.r
= r
; bg
.b
= b
; bg
.g
= g
;
726 #define ADJUST(x) (x = x * 255 / 1000)
734 if (x
) fprintf(file
, "</span>");
735 fprintf(file
, "<span style=\"background:#%02x%02x%02x;color:#%02x%02x%02x\">",
736 bg
.r
, bg
.g
, bg
.b
, fg
.r
, fg
.g
, fg
.b
);
740 if (wch
.chars
[0] > 255) {
741 snprintf(unicode
, sizeof(unicode
), "&#x%x;", (unsigned int)wch
.chars
[0]);
745 if (now
& A_ALTCHARSET
)
748 for (u
= 0; unis
[u
].ascii
; u
++) {
749 if (ch
[0] == unis
[u
].ascii
) {
750 print
= unis
[u
].unicode
;
758 fprintf(file
, "&");
759 else if (ch
[0] == '<')
760 fprintf(file
, "<");
761 else if (ch
[0] == '>')
762 fprintf(file
, ">");
764 fprintf(file
, "%s", print
);
767 fprintf(file
, "</span>\n");
770 fprintf(file
, "</pre>\n</body>");
776 shift_window(GntWM
*wm
, GntWidget
*widget
, int dir
)
778 GList
*all
= wm
->cws
->list
;
779 GList
*list
= g_list_find(all
, widget
);
784 length
= g_list_length(all
);
785 pos
= g_list_position(all
, list
);
793 else if (pos
> length
)
796 all
= g_list_insert(all
, widget
, pos
);
797 all
= g_list_delete_link(all
, list
);
799 gnt_ws_draw_taskbar(wm
->cws
, FALSE
);
803 shift_left(GntBindable
*bindable
, GList
*null
)
805 GntWM
*wm
= GNT_WM(bindable
);
806 if (wm
->_list
.window
)
809 if(!wm
->cws
->ordered
)
812 shift_window(wm
, wm
->cws
->ordered
->data
, -1);
817 shift_right(GntBindable
*bindable
, GList
*null
)
819 GntWM
*wm
= GNT_WM(bindable
);
821 if (wm
->_list
.window
)
824 if(!wm
->cws
->ordered
)
827 shift_window(wm
, wm
->cws
->ordered
->data
, 1);
832 action_list_activate(GntTree
*tree
, GntWM
*wm
)
834 GntAction
*action
= gnt_tree_get_selection_data(tree
);
836 gnt_widget_destroy(wm
->_list
.window
);
840 compare_action(gconstpointer p1
, gconstpointer p2
)
842 const GntAction
*a1
= p1
;
843 const GntAction
*a2
= p2
;
845 return g_utf8_collate(a1
->label
, a2
->label
);
849 list_actions(GntBindable
*bindable
, GList
*null
)
851 GntWidget
*tree
, *win
;
853 GntWM
*wm
= GNT_WM(bindable
);
854 if (wm
->_list
.window
|| wm
->menu
)
857 if (wm
->acts
== NULL
)
861 wm
->actions
= &wm
->_list
;
863 win
= wm
->actions
->window
;
864 tree
= wm
->actions
->tree
;
866 gnt_box_set_title(GNT_BOX(win
), "Actions");
867 GNT_WIDGET_SET_FLAGS(tree
, GNT_WIDGET_NO_BORDER
);
868 /* XXX: Do we really want this? */
869 gnt_tree_set_compare_func(GNT_TREE(tree
), compare_action
);
871 for (iter
= wm
->acts
; iter
; iter
= iter
->next
) {
872 GntAction
*action
= iter
->data
;
873 gnt_tree_add_row_last(GNT_TREE(tree
), action
,
874 gnt_tree_create_row(GNT_TREE(tree
), action
->label
), NULL
);
876 g_signal_connect(G_OBJECT(tree
), "activate", G_CALLBACK(action_list_activate
), wm
);
877 gnt_widget_set_size(tree
, 0, g_list_length(wm
->acts
));
878 gnt_widget_set_position(win
, 0, getmaxy(stdscr
) - 3 - g_list_length(wm
->acts
));
880 gnt_widget_show(win
);
886 widestringwidth(wchar_t *wide
)
891 len
= wcstombs(NULL
, wide
, 0) + 1;
892 string
= g_new0(char, len
);
893 wcstombs(string
, wide
, len
);
894 ret
= string
? gnt_util_onscreen_width(string
, NULL
) : 1;
900 /* Returns the onscreen width of the character at the position */
902 reverse_char(WINDOW
*d
, int y
, int x
, gboolean set
)
904 #define DECIDE(ch) (set ? ((ch) | A_REVERSE) : ((ch) & ~A_REVERSE))
908 ch
= mvwinch(d
, y
, x
);
909 mvwaddch(d
, y
, x
, DECIDE(ch
));
914 if (mvwin_wch(d
, y
, x
, &ch
) == OK
) {
915 wc
= widestringwidth(ch
.chars
);
916 ch
.attr
= DECIDE(ch
.attr
);
917 ch
.attr
&= WA_ATTRIBUTES
; /* XXX: This is a workaround for a bug */
918 mvwadd_wch(d
, y
, x
, &ch
);
926 window_reverse(GntWidget
*win
, gboolean set
, GntWM
*wm
)
932 if (GNT_WIDGET_IS_FLAG_SET(win
, GNT_WIDGET_NO_BORDER
))
936 gnt_widget_get_size(win
, &w
, &h
);
938 if (gnt_widget_has_shadow(win
)) {
943 /* the top and bottom */
944 for (i
= 0; i
< w
; i
+= reverse_char(d
, 0, i
, set
));
945 for (i
= 0; i
< w
; i
+= reverse_char(d
, h
-1, i
, set
));
947 /* the left and right */
948 for (i
= 0; i
< h
; i
+= reverse_char(d
, i
, 0, set
));
949 for (i
= 0; i
< h
; i
+= reverse_char(d
, i
, w
-1, set
));
951 gnt_wm_copy_win(win
, g_hash_table_lookup(wm
->nodes
, win
));
956 start_move(GntBindable
*bindable
, GList
*null
)
958 GntWM
*wm
= GNT_WM(bindable
);
959 if (wm
->_list
.window
|| wm
->menu
)
961 if (!wm
->cws
->ordered
)
964 wm
->mode
= GNT_KP_MODE_MOVE
;
965 window_reverse(GNT_WIDGET(wm
->cws
->ordered
->data
), TRUE
, wm
);
971 start_resize(GntBindable
*bindable
, GList
*null
)
973 GntWM
*wm
= GNT_WM(bindable
);
974 if (wm
->_list
.window
|| wm
->menu
)
976 if (!wm
->cws
->ordered
)
979 wm
->mode
= GNT_KP_MODE_RESIZE
;
980 window_reverse(GNT_WIDGET(wm
->cws
->ordered
->data
), TRUE
, wm
);
986 wm_quit(GntBindable
*bindable
, GList
*list
)
988 GntWM
*wm
= GNT_WM(bindable
);
991 g_main_loop_quit(wm
->loop
);
996 return_true(GntWM
*wm
, GntWidget
*w
, int *a
, int *b
)
1002 refresh_screen(GntBindable
*bindable
, GList
*null
)
1004 GntWM
*wm
= GNT_WM(bindable
);
1008 g_hash_table_foreach(wm
->nodes
, (GHFunc
)refresh_node
, NULL
);
1010 g_signal_emit(wm
, signals
[SIG_TERMINAL_REFRESH
], 0);
1012 gnt_ws_draw_taskbar(wm
->cws
, TRUE
);
1013 curs_set(0); /* endwin resets the cursor to normal */
1019 toggle_clipboard(GntBindable
*bindable
, GList
*n
)
1021 static GntWidget
*clip
;
1025 gnt_widget_destroy(clip
);
1029 getmaxyx(stdscr
, maxy
, maxx
);
1030 text
= gnt_get_clipboard_string();
1031 clip
= gnt_hwindow_new(FALSE
);
1032 GNT_WIDGET_SET_FLAGS(clip
, GNT_WIDGET_TRANSIENT
);
1033 GNT_WIDGET_SET_FLAGS(clip
, GNT_WIDGET_NO_BORDER
);
1034 gnt_box_set_pad(GNT_BOX(clip
), 0);
1035 gnt_box_add_widget(GNT_BOX(clip
), gnt_label_new(" "));
1036 gnt_box_add_widget(GNT_BOX(clip
), gnt_label_new(text
));
1037 gnt_box_add_widget(GNT_BOX(clip
), gnt_label_new(" "));
1038 gnt_widget_set_position(clip
, 0, 0);
1039 gnt_widget_draw(clip
);
1044 static void remove_tag(gpointer wid
, gpointer wim
)
1046 GntWM
*wm
= GNT_WM(wim
);
1047 GntWidget
*w
= GNT_WIDGET(wid
);
1048 wm
->tagged
= g_list_remove(wm
->tagged
, w
);
1049 mvwhline(w
->window
, 0, 1, ACS_HLINE
| gnt_color_pair(GNT_COLOR_NORMAL
), 3);
1054 tag_widget(GntBindable
*b
, GList
*params
)
1056 GntWM
*wm
= GNT_WM(b
);
1059 if (!wm
->cws
->ordered
)
1061 widget
= wm
->cws
->ordered
->data
;
1063 if (g_list_find(wm
->tagged
, widget
)) {
1064 remove_tag(widget
, wm
);
1068 wm
->tagged
= g_list_prepend(wm
->tagged
, widget
);
1069 wbkgdset(widget
->window
, ' ' | gnt_color_pair(GNT_COLOR_HIGHLIGHT
));
1070 mvwprintw(widget
->window
, 0, 1, "[T]");
1071 gnt_widget_draw(widget
);
1076 widget_move_ws(gpointer wid
, gpointer w
)
1078 GntWM
*wm
= GNT_WM(w
);
1079 gnt_wm_widget_move_workspace(wm
, wm
->cws
, GNT_WIDGET(wid
));
1083 place_tagged(GntBindable
*b
, GList
*params
)
1085 GntWM
*wm
= GNT_WM(b
);
1086 g_list_foreach(wm
->tagged
, widget_move_ws
, wm
);
1087 g_list_foreach(wm
->tagged
, remove_tag
, wm
);
1088 g_list_free(wm
->tagged
);
1094 workspace_list(GntBindable
*b
, GList
*params
)
1096 GntWM
*wm
= GNT_WM(b
);
1098 if (wm
->_list
.window
|| wm
->menu
)
1101 list_of_windows(wm
, TRUE
);
1107 workspace_new(GntBindable
*bindable
, GList
*null
)
1109 GntWM
*wm
= GNT_WM(bindable
);
1110 GntWS
*ws
= gnt_ws_new(NULL
);
1111 gnt_wm_add_workspace(wm
, ws
);
1112 gnt_wm_switch_workspace(wm
, g_list_index(wm
->workspaces
, ws
));
1117 ignore_keys_start(GntBindable
*bindable
, GList
*n
)
1119 GntWM
*wm
= GNT_WM(bindable
);
1121 if(!wm
->menu
&& !wm
->_list
.window
&& wm
->mode
== GNT_KP_MODE_NORMAL
){
1129 ignore_keys_end(GntBindable
*bindable
, GList
*n
)
1131 return ignore_keys
? !(ignore_keys
= FALSE
) : FALSE
;
1135 help_for_bindable(GntWM
*wm
, GntBindable
*bindable
)
1137 gboolean ret
= TRUE
;
1138 GntBindableClass
*klass
= GNT_BINDABLE_GET_CLASS(bindable
);
1140 if (klass
->help_window
) {
1141 gnt_wm_raise_window(wm
, GNT_WIDGET(klass
->help_window
));
1143 ret
= gnt_bindable_build_help_window(bindable
);
1149 help_for_wm(GntBindable
*bindable
, GList
*null
)
1151 return help_for_bindable(GNT_WM(bindable
),bindable
);
1155 help_for_window(GntBindable
*bindable
, GList
*null
)
1157 GntWM
*wm
= GNT_WM(bindable
);
1160 if(!wm
->cws
->ordered
)
1163 widget
= wm
->cws
->ordered
->data
;
1165 return help_for_bindable(wm
,GNT_BINDABLE(widget
));
1169 help_for_widget(GntBindable
*bindable
, GList
*null
)
1171 GntWM
*wm
= GNT_WM(bindable
);
1174 if (!wm
->cws
->ordered
)
1177 widget
= wm
->cws
->ordered
->data
;
1178 if (!GNT_IS_BOX(widget
))
1181 return help_for_bindable(wm
, GNT_BINDABLE(GNT_BOX(widget
)->active
));
1185 accumulate_windows(gpointer window
, gpointer node
, gpointer p
)
1187 GList
*list
= *(GList
**)p
;
1188 list
= g_list_prepend(list
, window
);
1193 gnt_wm_destroy(GObject
*obj
)
1195 GntWM
*wm
= GNT_WM(obj
);
1197 g_hash_table_foreach(wm
->nodes
, accumulate_windows
, &list
);
1198 g_list_foreach(list
, (GFunc
)gnt_widget_destroy
, NULL
);
1200 g_hash_table_destroy(wm
->nodes
);
1203 while (wm
->workspaces
) {
1204 g_object_unref(wm
->workspaces
->data
);
1205 wm
->workspaces
= g_list_delete_link(wm
->workspaces
, wm
->workspaces
);
1210 gnt_wm_class_init(GntWMClass
*klass
)
1213 GObjectClass
*gclass
= G_OBJECT_CLASS(klass
);
1215 gclass
->dispose
= gnt_wm_destroy
;
1217 klass
->new_window
= gnt_wm_new_window_real
;
1218 klass
->decorate_window
= NULL
;
1219 klass
->close_window
= NULL
;
1220 klass
->window_resize_confirm
= return_true
;
1221 klass
->window_resized
= gnt_wm_win_resized
;
1222 klass
->window_move_confirm
= return_true
;
1223 klass
->window_moved
= gnt_wm_win_moved
;
1224 klass
->window_update
= NULL
;
1225 klass
->key_pressed
= NULL
;
1226 klass
->mouse_clicked
= NULL
;
1227 klass
->give_focus
= gnt_wm_give_focus
;
1229 signals
[SIG_NEW_WIN
] =
1230 g_signal_new("new_win",
1231 G_TYPE_FROM_CLASS(klass
),
1233 G_STRUCT_OFFSET(GntWMClass
, new_window
),
1235 g_cclosure_marshal_VOID__POINTER
,
1236 G_TYPE_NONE
, 1, G_TYPE_POINTER
);
1237 signals
[SIG_DECORATE_WIN
] =
1238 g_signal_new("decorate_win",
1239 G_TYPE_FROM_CLASS(klass
),
1241 G_STRUCT_OFFSET(GntWMClass
, decorate_window
),
1243 g_cclosure_marshal_VOID__POINTER
,
1244 G_TYPE_NONE
, 1, G_TYPE_POINTER
);
1245 signals
[SIG_CLOSE_WIN
] =
1246 g_signal_new("close_win",
1247 G_TYPE_FROM_CLASS(klass
),
1249 G_STRUCT_OFFSET(GntWMClass
, close_window
),
1251 g_cclosure_marshal_VOID__POINTER
,
1252 G_TYPE_NONE
, 1, G_TYPE_POINTER
);
1253 signals
[SIG_CONFIRM_RESIZE
] =
1254 g_signal_new("confirm_resize",
1255 G_TYPE_FROM_CLASS(klass
),
1257 G_STRUCT_OFFSET(GntWMClass
, window_resize_confirm
),
1258 gnt_boolean_handled_accumulator
, NULL
,
1259 gnt_closure_marshal_BOOLEAN__POINTER_POINTER_POINTER
,
1260 G_TYPE_BOOLEAN
, 3, G_TYPE_POINTER
, G_TYPE_POINTER
, G_TYPE_POINTER
);
1262 signals
[SIG_CONFIRM_MOVE
] =
1263 g_signal_new("confirm_move",
1264 G_TYPE_FROM_CLASS(klass
),
1266 G_STRUCT_OFFSET(GntWMClass
, window_move_confirm
),
1267 gnt_boolean_handled_accumulator
, NULL
,
1268 gnt_closure_marshal_BOOLEAN__POINTER_POINTER_POINTER
,
1269 G_TYPE_BOOLEAN
, 3, G_TYPE_POINTER
, G_TYPE_POINTER
, G_TYPE_POINTER
);
1271 signals
[SIG_RESIZED
] =
1272 g_signal_new("window_resized",
1273 G_TYPE_FROM_CLASS(klass
),
1275 G_STRUCT_OFFSET(GntWMClass
, window_resized
),
1277 g_cclosure_marshal_VOID__POINTER
,
1278 G_TYPE_NONE
, 1, G_TYPE_POINTER
);
1279 signals
[SIG_MOVED
] =
1280 g_signal_new("window_moved",
1281 G_TYPE_FROM_CLASS(klass
),
1283 G_STRUCT_OFFSET(GntWMClass
, window_moved
),
1285 g_cclosure_marshal_VOID__POINTER
,
1286 G_TYPE_NONE
, 1, G_TYPE_POINTER
);
1287 signals
[SIG_UPDATE_WIN
] =
1288 g_signal_new("window_update",
1289 G_TYPE_FROM_CLASS(klass
),
1291 G_STRUCT_OFFSET(GntWMClass
, window_update
),
1293 g_cclosure_marshal_VOID__POINTER
,
1294 G_TYPE_NONE
, 1, G_TYPE_POINTER
);
1296 signals
[SIG_GIVE_FOCUS
] =
1297 g_signal_new("give_focus",
1298 G_TYPE_FROM_CLASS(klass
),
1300 G_STRUCT_OFFSET(GntWMClass
, give_focus
),
1302 g_cclosure_marshal_VOID__POINTER
,
1303 G_TYPE_NONE
, 1, G_TYPE_POINTER
);
1305 signals
[SIG_MOUSE_CLICK
] =
1306 g_signal_new("mouse_clicked",
1307 G_TYPE_FROM_CLASS(klass
),
1309 G_STRUCT_OFFSET(GntWMClass
, mouse_clicked
),
1310 gnt_boolean_handled_accumulator
, NULL
,
1311 gnt_closure_marshal_BOOLEAN__INT_INT_INT_POINTER
,
1312 G_TYPE_BOOLEAN
, 4, G_TYPE_INT
, G_TYPE_INT
, G_TYPE_INT
, G_TYPE_POINTER
);
1314 signals
[SIG_TERMINAL_REFRESH
] =
1315 g_signal_new("terminal-refresh",
1316 G_TYPE_FROM_CLASS(klass
),
1318 G_STRUCT_OFFSET(GntWMClass
, terminal_refresh
),
1320 g_cclosure_marshal_VOID__VOID
,
1323 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "window-next", window_next
,
1325 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "window-prev", window_prev
,
1327 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "window-close", window_close
,
1329 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "window-list", window_list
,
1331 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "dump-screen", dump_screen
,
1333 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "shift-left", shift_left
,
1335 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "shift-right", shift_right
,
1337 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "action-list", list_actions
,
1339 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "start-move", start_move
,
1341 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "start-resize", start_resize
,
1343 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "wm-quit", wm_quit
,
1345 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "refresh-screen", refresh_screen
,
1347 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "switch-window-n", switch_window_n
,
1349 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "window-scroll-down", window_scroll_down
,
1350 "\033" GNT_KEY_CTRL_J
, NULL
);
1351 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "window-scroll-up", window_scroll_up
,
1352 "\033" GNT_KEY_CTRL_K
, NULL
);
1353 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "help-for-widget", help_for_widget
,
1355 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "workspace-new", workspace_new
,
1357 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "workspace-next", workspace_next
,
1359 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "workspace-prev", workspace_prev
,
1361 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "window-tag", tag_widget
,
1363 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "place-tagged", place_tagged
,
1365 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "workspace-list", workspace_list
,
1367 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "toggle-clipboard", toggle_clipboard
,
1369 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "help-for-wm", help_for_wm
,
1371 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "help-for-window", help_for_window
,
1373 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "ignore-keys-start", ignore_keys_start
,
1374 GNT_KEY_CTRL_G
, NULL
);
1375 gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass
), "ignore-keys-end", ignore_keys_end
,
1376 "\033" GNT_KEY_CTRL_G
, NULL
);
1378 gnt_style_read_actions(G_OBJECT_CLASS_TYPE(klass
), GNT_BINDABLE_CLASS(klass
));
1380 /* Make sure Alt+x are detected properly. */
1381 for (i
= '0'; i
<= '9'; i
++) {
1382 char str
[] = "\033X";
1384 gnt_keys_add_combination(str
);
1390 /******************************************************************************
1392 *****************************************************************************/
1394 gnt_wm_get_gtype(void)
1396 static GType type
= 0;
1399 static const GTypeInfo info
= {
1401 NULL
, /* base_init */
1402 NULL
, /* base_finalize */
1403 (GClassInitFunc
)gnt_wm_class_init
,
1405 NULL
, /* class_data */
1407 0, /* n_preallocs */
1408 gnt_wm_init
, /* instance_init */
1409 NULL
/* value_table */
1412 type
= g_type_register_static(GNT_TYPE_BINDABLE
,
1421 gnt_wm_add_workspace(GntWM
*wm
, GntWS
*ws
)
1423 wm
->workspaces
= g_list_append(wm
->workspaces
, ws
);
1427 gnt_wm_switch_workspace(GntWM
*wm
, gint n
)
1429 GntWS
*s
= g_list_nth_data(wm
->workspaces
, n
);
1433 if (wm
->_list
.window
) {
1434 gnt_widget_destroy(wm
->_list
.window
);
1436 gnt_ws_hide(wm
->cws
, wm
->nodes
);
1438 gnt_ws_show(wm
->cws
, wm
->nodes
);
1440 gnt_ws_draw_taskbar(wm
->cws
, TRUE
);
1442 if (wm
->cws
->ordered
) {
1443 gnt_wm_raise_window(wm
, wm
->cws
->ordered
->data
);
1446 if (act
&& g_list_find(act
, wm
->cws
)) {
1447 act
= g_list_remove(act
, wm
->cws
);
1454 gnt_wm_switch_workspace_prev(GntWM
*wm
)
1456 int n
= g_list_index(wm
->workspaces
, wm
->cws
);
1457 return gnt_wm_switch_workspace(wm
, --n
);
1461 gnt_wm_switch_workspace_next(GntWM
*wm
)
1463 int n
= g_list_index(wm
->workspaces
, wm
->cws
);
1464 return gnt_wm_switch_workspace(wm
, ++n
);
1468 workspace_next(GntBindable
*wm
, GList
*n
)
1470 return gnt_wm_switch_workspace_next(GNT_WM(wm
));
1474 workspace_prev(GntBindable
*wm
, GList
*n
)
1476 return gnt_wm_switch_workspace_prev(GNT_WM(wm
));
1480 gnt_wm_widget_move_workspace(GntWM
*wm
, GntWS
*neww
, GntWidget
*widget
)
1482 GntWS
*oldw
= gnt_wm_widget_find_workspace(wm
, widget
);
1484 if (!oldw
|| oldw
== neww
)
1486 node
= g_hash_table_lookup(wm
->nodes
, widget
);
1487 if (node
&& node
->ws
== neww
)
1493 gnt_ws_remove_widget(oldw
, widget
);
1494 gnt_ws_add_widget(neww
, widget
);
1495 if (neww
== wm
->cws
) {
1496 gnt_ws_widget_show(widget
, wm
->nodes
);
1498 gnt_ws_widget_hide(widget
, wm
->nodes
);
1502 static gint
widget_in_workspace(gconstpointer workspace
, gconstpointer wid
)
1504 GntWS
*s
= (GntWS
*)workspace
;
1505 if (s
->list
&& g_list_find(s
->list
, wid
))
1510 GntWS
*gnt_wm_widget_find_workspace(GntWM
*wm
, GntWidget
*widget
)
1512 GList
*l
= g_list_find_custom(wm
->workspaces
, widget
, widget_in_workspace
);
1518 static void free_workspaces(gpointer data
, gpointer n
)
1524 void gnt_wm_set_workspaces(GntWM
*wm
, GList
*workspaces
)
1526 g_list_foreach(wm
->workspaces
, free_workspaces
, NULL
);
1527 wm
->workspaces
= workspaces
;
1528 gnt_wm_switch_workspace(wm
, 0);
1532 update_window_in_list(GntWM
*wm
, GntWidget
*wid
)
1534 GntTextFormatFlags flag
= 0;
1536 if (wm
->windows
== NULL
)
1539 if (wm
->cws
->ordered
&& wid
== wm
->cws
->ordered
->data
)
1540 flag
|= GNT_TEXT_FLAG_DIM
;
1541 else if (GNT_WIDGET_IS_FLAG_SET(wid
, GNT_WIDGET_URGENT
))
1542 flag
|= GNT_TEXT_FLAG_BOLD
;
1544 gnt_tree_set_row_flags(GNT_TREE(wm
->windows
->tree
), wid
, flag
);
1548 match_title(gpointer title
, gpointer n
, gpointer wid_title
)
1550 /* XXX: do any regex magic here. */
1551 if (g_strrstr((gchar
*)wid_title
, (gchar
*)title
))
1556 #if !GLIB_CHECK_VERSION(2,4,0)
1564 table_find_helper(gpointer key
, gpointer value
, gpointer data
)
1566 GHRFunc func
= data
;
1567 if (func(key
, value
, table_find_data
.data
))
1568 table_find_data
.value
= value
;
1572 g_hash_table_find(GHashTable
* table
, GHRFunc func
, gpointer data
)
1574 table_find_data
.data
= data
;
1575 table_find_data
.value
= NULL
;
1576 g_hash_table_foreach(table
, table_find_helper
, func
);
1577 return table_find_data
.value
;
1582 new_widget_find_workspace(GntWM
*wm
, GntWidget
*widget
)
1585 const gchar
*name
, *title
;
1586 title
= GNT_BOX(widget
)->title
;
1588 ret
= g_hash_table_find(wm
->title_places
, match_title
, (gpointer
)title
);
1591 name
= gnt_widget_get_name(widget
);
1593 ret
= g_hash_table_find(wm
->name_places
, match_title
, (gpointer
)name
);
1594 return ret
? ret
: wm
->cws
;
1598 gnt_wm_new_window_real(GntWM
*wm
, GntWidget
*widget
)
1601 gboolean transient
= FALSE
;
1603 if (widget
->window
== NULL
)
1606 node
= g_new0(GntNode
, 1);
1610 g_hash_table_replace(wm
->nodes
, widget
, node
);
1612 refresh_node(widget
, node
, NULL
);
1614 transient
= !!GNT_WIDGET_IS_FLAG_SET(node
->me
, GNT_WIDGET_TRANSIENT
);
1618 int x
, y
, w
, h
, maxx
, maxy
;
1619 gboolean shadow
= TRUE
;
1621 if (!gnt_widget_has_shadow(widget
))
1625 w
= widget
->priv
.width
;
1626 h
= widget
->priv
.height
;
1628 getmaxyx(stdscr
, maxy
, maxx
);
1629 maxy
-= 1; /* room for the taskbar */
1636 x
= MAX(0, maxx
- w
);
1638 y
= MAX(0, maxy
- h
);
1642 node
->window
= newwin(h
+ shadow
, w
+ shadow
, y
, x
);
1643 gnt_wm_copy_win(widget
, node
);
1647 node
->panel
= new_panel(node
->window
);
1648 set_panel_userptr(node
->panel
, node
);
1651 GntWS
*ws
= wm
->cws
;
1652 if (node
->me
!= wm
->_list
.window
) {
1653 if (GNT_IS_BOX(widget
)) {
1654 ws
= new_widget_find_workspace(wm
, widget
);
1657 ws
->list
= g_list_append(ws
->list
, widget
);
1658 ws
->ordered
= g_list_append(ws
->ordered
, widget
);
1661 if (wm
->event_stack
|| node
->me
== wm
->_list
.window
||
1662 node
->me
== ws
->ordered
->data
) {
1663 gnt_wm_raise_window(wm
, node
->me
);
1665 bottom_panel(node
->panel
); /* New windows should not grab focus */
1666 gnt_widget_set_focus(node
->me
, FALSE
);
1667 gnt_widget_set_urgent(node
->me
);
1669 gnt_ws_widget_hide(widget
, wm
->nodes
);
1674 void gnt_wm_new_window(GntWM
*wm
, GntWidget
*widget
)
1676 while (widget
->parent
)
1677 widget
= widget
->parent
;
1679 if (GNT_WIDGET_IS_FLAG_SET(widget
, GNT_WIDGET_INVISIBLE
) ||
1680 g_hash_table_lookup(wm
->nodes
, widget
)) {
1685 if (GNT_IS_BOX(widget
)) {
1686 const char *title
= GNT_BOX(widget
)->title
;
1687 GntPosition
*p
= NULL
;
1688 if (title
&& (p
= g_hash_table_lookup(wm
->positions
, title
)) != NULL
) {
1689 sanitize_position(widget
, &p
->x
, &p
->y
);
1690 gnt_widget_set_position(widget
, p
->x
, p
->y
);
1691 mvwin(widget
->window
, p
->y
, p
->x
);
1695 g_signal_emit(wm
, signals
[SIG_NEW_WIN
], 0, widget
);
1696 g_signal_emit(wm
, signals
[SIG_DECORATE_WIN
], 0, widget
);
1698 if (wm
->windows
&& !GNT_WIDGET_IS_FLAG_SET(widget
, GNT_WIDGET_TRANSIENT
)) {
1699 if ((GNT_IS_BOX(widget
) && GNT_BOX(widget
)->title
) && wm
->_list
.window
!= widget
1700 && GNT_WIDGET_IS_FLAG_SET(widget
, GNT_WIDGET_CAN_TAKE_FOCUS
)) {
1701 gnt_tree_add_row_last(GNT_TREE(wm
->windows
->tree
), widget
,
1702 gnt_tree_create_row(GNT_TREE(wm
->windows
->tree
), GNT_BOX(widget
)->title
),
1703 g_object_get_data(G_OBJECT(wm
->windows
->tree
), "workspace") ? wm
->cws
: NULL
);
1704 update_window_in_list(wm
, widget
);
1709 gnt_ws_draw_taskbar(wm
->cws
, FALSE
);
1712 void gnt_wm_window_decorate(GntWM
*wm
, GntWidget
*widget
)
1714 g_signal_emit(wm
, signals
[SIG_DECORATE_WIN
], 0, widget
);
1717 void gnt_wm_window_close(GntWM
*wm
, GntWidget
*widget
)
1722 s
= gnt_wm_widget_find_workspace(wm
, widget
);
1724 if (g_hash_table_lookup(wm
->nodes
, widget
) == NULL
)
1727 g_signal_emit(wm
, signals
[SIG_CLOSE_WIN
], 0, widget
);
1728 g_hash_table_remove(wm
->nodes
, widget
);
1731 gnt_tree_remove(GNT_TREE(wm
->windows
->tree
), widget
);
1735 pos
= g_list_index(s
->list
, widget
);
1738 s
->list
= g_list_remove(s
->list
, widget
);
1739 s
->ordered
= g_list_remove(s
->ordered
, widget
);
1741 if (s
->ordered
&& wm
->cws
== s
)
1742 gnt_wm_raise_window(wm
, s
->ordered
->data
);
1747 gnt_ws_draw_taskbar(wm
->cws
, FALSE
);
1750 time_t gnt_wm_get_idle_time()
1752 return time(NULL
) - last_active_time
;
1755 gboolean
gnt_wm_process_input(GntWM
*wm
, const char *keys
)
1757 gboolean ret
= FALSE
;
1759 keys
= gnt_bindable_remap_keys(GNT_BINDABLE(wm
), keys
);
1763 if(keys
&& !strcmp(keys
, "\033" GNT_KEY_CTRL_G
)){
1764 if(gnt_bindable_perform_action_key(GNT_BINDABLE(wm
), keys
)){
1768 return wm
->cws
->ordered
? gnt_widget_key_pressed(GNT_WIDGET(wm
->cws
->ordered
->data
), keys
) : FALSE
;
1771 if (gnt_bindable_perform_action_key(GNT_BINDABLE(wm
), keys
)) {
1775 /* Do some manual checking */
1776 if (wm
->cws
->ordered
&& wm
->mode
!= GNT_KP_MODE_NORMAL
) {
1777 int xmin
= 0, ymin
= 0, xmax
= getmaxx(stdscr
), ymax
= getmaxy(stdscr
) - 1;
1779 GntWidget
*widget
= GNT_WIDGET(wm
->cws
->ordered
->data
);
1782 gnt_widget_get_position(widget
, &x
, &y
);
1783 gnt_widget_get_size(widget
, &w
, &h
);
1787 if (wm
->mode
== GNT_KP_MODE_MOVE
) {
1788 if (strcmp(keys
, GNT_KEY_LEFT
) == 0) {
1791 } else if (strcmp(keys
, GNT_KEY_RIGHT
) == 0) {
1794 } else if (strcmp(keys
, GNT_KEY_UP
) == 0) {
1797 } else if (strcmp(keys
, GNT_KEY_DOWN
) == 0) {
1801 if (ox
!= x
|| oy
!= y
) {
1802 gnt_screen_move_widget(widget
, x
, y
);
1803 window_reverse(widget
, TRUE
, wm
);
1806 } else if (wm
->mode
== GNT_KP_MODE_RESIZE
) {
1807 if (strcmp(keys
, GNT_KEY_LEFT
) == 0) {
1809 } else if (strcmp(keys
, GNT_KEY_RIGHT
) == 0) {
1812 } else if (strcmp(keys
, GNT_KEY_UP
) == 0) {
1814 } else if (strcmp(keys
, GNT_KEY_DOWN
) == 0) {
1818 if (oh
!= h
|| ow
!= w
) {
1819 gnt_screen_resize_widget(widget
, w
, h
);
1820 window_reverse(widget
, TRUE
, wm
);
1824 if (strcmp(keys
, "\r") == 0 || strcmp(keys
, "\033") == 0) {
1825 window_reverse(widget
, FALSE
, wm
);
1826 wm
->mode
= GNT_KP_MODE_NORMAL
;
1831 /* Escape to close the window-list or action-list window */
1832 if (strcmp(keys
, "\033") == 0) {
1833 if (wm
->_list
.window
) {
1834 gnt_widget_destroy(wm
->_list
.window
);
1837 } else if (keys
[0] == '\033' && isdigit(keys
[1]) && keys
[2] == '\0') {
1838 /* Alt+x for quick switch */
1839 int n
= *(keys
+ 1) - '0';
1845 list
= g_list_append(list
, GINT_TO_POINTER(n
- 1));
1846 switch_window_n(GNT_BINDABLE(wm
), list
);
1852 ret
= gnt_widget_key_pressed(GNT_WIDGET(wm
->menu
), keys
);
1853 else if (wm
->_list
.window
)
1854 ret
= gnt_widget_key_pressed(wm
->_list
.window
, keys
);
1855 else if (wm
->cws
->ordered
) {
1856 GntWidget
*win
= wm
->cws
->ordered
->data
;
1857 if (GNT_IS_WINDOW(win
)) {
1858 GntMenu
*menu
= GNT_WINDOW(win
)->menu
;
1860 const char *id
= gnt_window_get_accel_item(GNT_WINDOW(win
), keys
);
1862 ret
= (gnt_menu_get_item(menu
, id
) != NULL
);
1866 ret
= gnt_widget_key_pressed(win
, keys
);
1872 gnt_wm_win_resized(GntWM
*wm
, GntNode
*node
)
1874 /*refresh_node(node->me, node, NULL);*/
1878 gnt_wm_win_moved(GntWM
*wm
, GntNode
*node
)
1880 refresh_node(node
->me
, node
, NULL
);
1883 void gnt_wm_resize_window(GntWM
*wm
, GntWidget
*widget
, int width
, int height
)
1885 gboolean ret
= TRUE
;
1890 while (widget
->parent
)
1891 widget
= widget
->parent
;
1892 node
= g_hash_table_lookup(wm
->nodes
, widget
);
1896 g_signal_emit(wm
, signals
[SIG_CONFIRM_RESIZE
], 0, widget
, &width
, &height
, &ret
);
1898 return; /* resize is not permitted */
1899 hide_panel(node
->panel
);
1900 gnt_widget_set_size(widget
, width
, height
);
1901 gnt_widget_draw(widget
);
1903 shadow
= gnt_widget_has_shadow(widget
) ? 1 : 0;
1904 maxx
= getmaxx(stdscr
) - shadow
;
1905 maxy
= getmaxy(stdscr
) - 1 - shadow
;
1906 height
= MIN(height
, maxy
);
1907 width
= MIN(width
, maxx
);
1908 wresize(node
->window
, height
, width
);
1909 replace_panel(node
->panel
, node
->window
);
1911 g_signal_emit(wm
, signals
[SIG_RESIZED
], 0, node
);
1913 show_panel(node
->panel
);
1918 write_gdi(gpointer key
, gpointer value
, gpointer data
)
1920 GntPosition
*p
= value
;
1921 fprintf(data
, ".%s = %d;%d\n", (char *)key
, p
->x
, p
->y
);
1925 write_already(gpointer data
)
1931 filename
= g_build_filename(g_get_home_dir(), ".gntpositions", NULL
);
1933 file
= fopen(filename
, "wb");
1935 g_printerr("GntWM: error opening file to save positions\n");
1937 fprintf(file
, "[positions]\n");
1938 g_hash_table_foreach(wm
->positions
, write_gdi
, file
);
1943 g_source_remove(write_timeout
);
1949 write_positions_to_file(GntWM
*wm
)
1951 if (write_timeout
) {
1952 g_source_remove(write_timeout
);
1954 write_timeout
= g_timeout_add(10000, write_already
, wm
);
1957 void gnt_wm_move_window(GntWM
*wm
, GntWidget
*widget
, int x
, int y
)
1959 gboolean ret
= TRUE
;
1962 while (widget
->parent
)
1963 widget
= widget
->parent
;
1964 node
= g_hash_table_lookup(wm
->nodes
, widget
);
1968 g_signal_emit(wm
, signals
[SIG_CONFIRM_MOVE
], 0, widget
, &x
, &y
, &ret
);
1970 return; /* resize is not permitted */
1972 gnt_widget_set_position(widget
, x
, y
);
1973 move_panel(node
->panel
, y
, x
);
1975 g_signal_emit(wm
, signals
[SIG_MOVED
], 0, node
);
1976 if (gnt_style_get_bool(GNT_STYLE_REMPOS
, TRUE
) && GNT_IS_BOX(widget
) &&
1977 !GNT_WIDGET_IS_FLAG_SET(widget
, GNT_WIDGET_TRANSIENT
)) {
1978 const char *title
= GNT_BOX(widget
)->title
;
1980 GntPosition
*p
= g_new0(GntPosition
, 1);
1981 GntWidget
*wid
= node
->me
;
1984 g_hash_table_replace(wm
->positions
, g_strdup(title
), p
);
1985 write_positions_to_file(wm
);
1993 gnt_wm_give_focus(GntWM
*wm
, GntWidget
*widget
)
1995 GntNode
*node
= g_hash_table_lookup(wm
->nodes
, widget
);
2000 if (widget
!= wm
->_list
.window
&& !GNT_IS_MENU(widget
) &&
2001 wm
->cws
->ordered
->data
!= widget
) {
2002 GntWidget
*w
= wm
->cws
->ordered
->data
;
2003 wm
->cws
->ordered
= g_list_bring_to_front(wm
->cws
->ordered
, widget
);
2004 gnt_widget_set_focus(w
, FALSE
);
2007 gnt_widget_set_focus(widget
, TRUE
);
2008 GNT_WIDGET_UNSET_FLAGS(widget
, GNT_WIDGET_URGENT
);
2009 gnt_widget_draw(widget
);
2010 top_panel(node
->panel
);
2012 if (wm
->_list
.window
) {
2013 GntNode
*nd
= g_hash_table_lookup(wm
->nodes
, wm
->_list
.window
);
2014 top_panel(nd
->panel
);
2017 gnt_ws_draw_taskbar(wm
->cws
, FALSE
);
2020 void gnt_wm_update_window(GntWM
*wm
, GntWidget
*widget
)
2022 GntNode
*node
= NULL
;
2025 while (widget
->parent
)
2026 widget
= widget
->parent
;
2027 if (!GNT_IS_MENU(widget
)) {
2028 if (!GNT_IS_BOX(widget
))
2030 gnt_box_sync_children(GNT_BOX(widget
));
2033 ws
= gnt_wm_widget_find_workspace(wm
, widget
);
2034 node
= g_hash_table_lookup(wm
->nodes
, widget
);
2036 gnt_wm_new_window(wm
, widget
);
2038 g_signal_emit(wm
, signals
[SIG_UPDATE_WIN
], 0, node
);
2040 if (ws
== wm
->cws
|| GNT_WIDGET_IS_FLAG_SET(widget
, GNT_WIDGET_TRANSIENT
)) {
2041 gnt_wm_copy_win(widget
, node
);
2043 gnt_ws_draw_taskbar(wm
->cws
, FALSE
);
2044 } else if (ws
&& ws
!= wm
->cws
&& GNT_WIDGET_IS_FLAG_SET(widget
, GNT_WIDGET_URGENT
)) {
2045 if (!act
|| (act
&& !g_list_find(act
, ws
)))
2046 act
= g_list_prepend(act
, ws
);
2051 gboolean
gnt_wm_process_click(GntWM
*wm
, GntMouseEvent event
, int x
, int y
, GntWidget
*widget
)
2053 gboolean ret
= TRUE
;
2055 g_signal_emit(wm
, signals
[SIG_MOUSE_CLICK
], 0, event
, x
, y
, widget
, &ret
);
2059 void gnt_wm_raise_window(GntWM
*wm
, GntWidget
*widget
)
2061 GntWS
*ws
= gnt_wm_widget_find_workspace(wm
, widget
);
2063 gnt_wm_switch_workspace(wm
, g_list_index(wm
->workspaces
, ws
));
2064 if (widget
!= wm
->cws
->ordered
->data
) {
2065 GntWidget
*wid
= wm
->cws
->ordered
->data
;
2066 wm
->cws
->ordered
= g_list_bring_to_front(wm
->cws
->ordered
, widget
);
2067 gnt_widget_set_focus(wid
, FALSE
);
2068 gnt_widget_draw(wid
);
2070 gnt_widget_set_focus(widget
, TRUE
);
2071 gnt_widget_draw(widget
);
2072 g_signal_emit(wm
, signals
[SIG_GIVE_FOCUS
], 0, widget
);
2075 void gnt_wm_set_event_stack(GntWM
*wm
, gboolean set
)
2077 wm
->event_stack
= set
;