qulogic/libgnt
Clone
Summary
Browse
Changes
Graph
Make the combobox a tiny bit friendlier.
v2.7.3
2010-07-05, Sadrul Habib Chowdhury
ac8d8a62c098
Make the combobox a tiny bit friendlier.
Pressing the first letter of an item will now jump to that item (and
popup the dropdown first if necessary). Add some API in libgnt in the
process.
/**
* GNT - The GLib Ncurses Toolkit
*
* GNT is the legal property of its developers, whose names are too numerous
* to list here. Please refer to the COPYRIGHT file distributed with this
* source distribution.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
*/
#include
"config.h"
#ifdef USE_PYTHON
#include
<Python.h>
#else
#define _GNU_SOURCE
#if (defined(__APPLE__) || defined(__unix__)) && !defined(__FreeBSD__) && !defined(__OpenBSD__)
#define _XOPEN_SOURCE_EXTENDED
#endif
#endif
#include
<glib.h>
#if GLIB_CHECK_VERSION(2,6,0)
#
include
<glib/gstdio.h>
#else
#
include
<sys/types.h>
#
include
<sys/stat.h>
#
include
<fcntl.h>
# define g_fopen open
#endif
#include
<ctype.h>
#include
<gmodule.h>
#include
<stdlib.h>
#include
<string.h>
#include
<time.h>
#include
"gntinternal.h"
#undef GNT_LOG_DOMAIN
#define GNT_LOG_DOMAIN "WM"
#include
"gntwm.h"
#include
"gntstyle.h"
#include
"gntmarshal.h"
#include
"gnt.h"
#include
"gntbox.h"
#include
"gntbutton.h"
#include
"gntentry.h"
#include
"gntfilesel.h"
#include
"gntlabel.h"
#include
"gntmenu.h"
#include
"gnttextview.h"
#include
"gnttree.h"
#include
"gntutils.h"
#include
"gntwindow.h"
#define IDLE_CHECK_INTERVAL 5
/* 5 seconds */
enum
{
SIG_NEW_WIN
,
SIG_DECORATE_WIN
,
SIG_CLOSE_WIN
,
SIG_CONFIRM_RESIZE
,
SIG_RESIZED
,
SIG_CONFIRM_MOVE
,
SIG_MOVED
,
SIG_UPDATE_WIN
,
SIG_GIVE_FOCUS
,
SIG_KEY_PRESS
,
SIG_MOUSE_CLICK
,
SIG_TERMINAL_REFRESH
,
SIGS
};
static
guint
signals
[
SIGS
]
=
{
0
};
static
void
gnt_wm_new_window_real
(
GntWM
*
wm
,
GntWidget
*
widget
);
static
void
gnt_wm_win_resized
(
GntWM
*
wm
,
GntNode
*
node
);
static
void
gnt_wm_win_moved
(
GntWM
*
wm
,
GntNode
*
node
);
static
void
gnt_wm_give_focus
(
GntWM
*
wm
,
GntWidget
*
widget
);
static
void
update_window_in_list
(
GntWM
*
wm
,
GntWidget
*
wid
);
static
void
shift_window
(
GntWM
*
wm
,
GntWidget
*
widget
,
int
dir
);
static
gboolean
workspace_next
(
GntBindable
*
wm
,
GList
*
n
);
static
gboolean
workspace_prev
(
GntBindable
*
wm
,
GList
*
n
);
#ifndef NO_WIDECHAR
static
int
widestringwidth
(
wchar_t
*
wide
);
#endif
static
void
ensure_normal_mode
(
GntWM
*
wm
);
static
gboolean
write_already
(
gpointer
data
);
static
int
write_timeout
;
static
time_t
last_active_time
;
static
gboolean
idle_update
;
static
GList
*
act
=
NULL
;
/* list of WS with unseen activitiy */
static
gboolean
ignore_keys
=
FALSE
;
#ifdef USE_PYTHON
static
gboolean
started_python
=
FALSE
;
#endif
static
GList
*
g_list_bring_to_front
(
GList
*
list
,
gpointer
data
)
{
list
=
g_list_remove
(
list
,
data
);
list
=
g_list_prepend
(
list
,
data
);
return
list
;
}
static
void
free_node
(
gpointer
data
)
{
GntNode
*
node
=
data
;
hide_panel
(
node
->
panel
);
del_panel
(
node
->
panel
);
g_free
(
node
);
}
void
gnt_wm_copy_win
(
GntWidget
*
widget
,
GntNode
*
node
)
{
WINDOW
*
src
,
*
dst
;
if
(
!
node
)
return
;
src
=
widget
->
window
;
dst
=
node
->
window
;
copywin
(
src
,
dst
,
node
->
scroll
,
0
,
0
,
0
,
getmaxy
(
dst
)
-
1
,
getmaxx
(
dst
)
-
1
,
0
);
/* Update the hardware cursor */
if
(
GNT_IS_WINDOW
(
widget
)
||
GNT_IS_BOX
(
widget
))
{
GntWidget
*
active
=
GNT_BOX
(
widget
)
->
active
;
if
(
active
)
{
int
curx
=
active
->
priv
.
x
+
getcurx
(
active
->
window
);
int
cury
=
active
->
priv
.
y
+
getcury
(
active
->
window
);
if
(
wmove
(
node
->
window
,
cury
-
widget
->
priv
.
y
,
curx
-
widget
->
priv
.
x
)
!=
OK
)
wmove
(
node
->
window
,
0
,
0
);
}
}
}
/**
* The following is a workaround for a bug in most versions of ncursesw.
* Read about it in: http://article.gmane.org/gmane.comp.lib.ncurses.bugs/2751
*
* In short, if a panel hides one cell of a multi-cell character, then the rest
* of the characters in that line get screwed. The workaround here is to erase
* any such character preemptively.
*
* Caveat: If a wide character is erased, and the panel above it is moved enough
* to expose the entire character, it is not always redrawn.
*/
static
void
work_around_for_ncurses_bug
(
void
)
{
#ifndef NO_WIDECHAR
PANEL
*
panel
=
NULL
;
while
((
panel
=
panel_below
(
panel
))
!=
NULL
)
{
int
sx
,
ex
,
sy
,
ey
,
w
,
y
;
cchar_t
ch
;
PANEL
*
below
=
panel
;
sx
=
panel
->
win
->
_begx
;
ex
=
panel
->
win
->
_maxx
+
sx
;
sy
=
panel
->
win
->
_begy
;
ey
=
panel
->
win
->
_maxy
+
sy
;
while
((
below
=
panel_below
(
below
))
!=
NULL
)
{
if
(
sy
>
below
->
win
->
_begy
+
below
->
win
->
_maxy
||
ey
<
below
->
win
->
_begy
)
continue
;
if
(
sx
>
below
->
win
->
_begx
+
below
->
win
->
_maxx
||
ex
<
below
->
win
->
_begx
)
continue
;
for
(
y
=
MAX
(
sy
,
below
->
win
->
_begy
);
y
<=
MIN
(
ey
,
below
->
win
->
_begy
+
below
->
win
->
_maxy
);
y
++
)
{
if
(
mvwin_wch
(
below
->
win
,
y
-
below
->
win
->
_begy
,
sx
-
1
-
below
->
win
->
_begx
,
&
ch
)
!=
OK
)
goto
right
;
w
=
widestringwidth
(
ch
.
chars
);
if
(
w
>
1
&&
(
ch
.
attr
&
1
))
{
ch
.
chars
[
0
]
=
' '
;
ch
.
attr
&=
~
A_CHARTEXT
;
mvwadd_wch
(
below
->
win
,
y
-
below
->
win
->
_begy
,
sx
-
1
-
below
->
win
->
_begx
,
&
ch
);
touchline
(
below
->
win
,
y
-
below
->
win
->
_begy
,
1
);
}
right
:
if
(
mvwin_wch
(
below
->
win
,
y
-
below
->
win
->
_begy
,
ex
+
1
-
below
->
win
->
_begx
,
&
ch
)
!=
OK
)
continue
;
w
=
widestringwidth
(
ch
.
chars
);
if
(
w
>
1
&&
!
(
ch
.
attr
&
1
))
{
ch
.
chars
[
0
]
=
' '
;
ch
.
attr
&=
~
A_CHARTEXT
;
mvwadd_wch
(
below
->
win
,
y
-
below
->
win
->
_begy
,
ex
+
1
-
below
->
win
->
_begx
,
&
ch
);
touchline
(
below
->
win
,
y
-
below
->
win
->
_begy
,
1
);
}
}
}
}
#endif
}
static
void
update_act_msg
(
void
)
{
GntWidget
*
label
;
GList
*
iter
;
static
GntWidget
*
message
=
NULL
;
GString
*
text
=
g_string_new
(
"act: "
);
if
(
message
)
gnt_widget_destroy
(
message
);
if
(
!
act
)
return
;
for
(
iter
=
act
;
iter
;
iter
=
iter
->
next
)
{
GntWS
*
ws
=
iter
->
data
;
g_string_append_printf
(
text
,
"%s, "
,
gnt_ws_get_name
(
ws
));
}
g_string_erase
(
text
,
text
->
len
-
2
,
2
);
message
=
gnt_vbox_new
(
FALSE
);
label
=
gnt_label_new_with_format
(
text
->
str
,
GNT_TEXT_FLAG_BOLD
|
GNT_TEXT_FLAG_HIGHLIGHT
);
GNT_WIDGET_UNSET_FLAGS
(
GNT_BOX
(
message
),
GNT_WIDGET_CAN_TAKE_FOCUS
);
GNT_WIDGET_SET_FLAGS
(
GNT_BOX
(
message
),
GNT_WIDGET_TRANSIENT
);
gnt_box_add_widget
(
GNT_BOX
(
message
),
label
);
gnt_widget_set_name
(
message
,
"wm-message"
);
gnt_widget_set_position
(
message
,
0
,
0
);
gnt_widget_draw
(
message
);
g_string_free
(
text
,
TRUE
);
}
static
gboolean
update_screen
(
GntWM
*
wm
)
{
if
(
wm
->
mode
==
GNT_KP_MODE_WAIT_ON_CHILD
)
return
TRUE
;
if
(
wm
->
menu
)
{
GntMenu
*
top
=
wm
->
menu
;
while
(
top
)
{
GntNode
*
node
=
g_hash_table_lookup
(
wm
->
nodes
,
top
);
if
(
node
)
top_panel
(
node
->
panel
);
top
=
top
->
submenu
;
}
}
work_around_for_ncurses_bug
();
update_panels
();
doupdate
();
return
TRUE
;
}
static
gboolean
sanitize_position
(
GntWidget
*
widget
,
int
*
x
,
int
*
y
,
gboolean
m
)
{
int
X_MAX
=
getmaxx
(
stdscr
);
int
Y_MAX
=
getmaxy
(
stdscr
)
-
1
;
int
w
,
h
;
int
nx
,
ny
;
gboolean
changed
=
FALSE
;
GntWindowFlags
flags
=
GNT_IS_WINDOW
(
widget
)
?
gnt_window_get_maximize
(
GNT_WINDOW
(
widget
))
:
0
;
gnt_widget_get_size
(
widget
,
&
w
,
&
h
);
if
(
x
)
{
if
(
m
&&
(
flags
&
GNT_WINDOW_MAXIMIZE_X
)
&&
*
x
!=
0
)
{
*
x
=
0
;
changed
=
TRUE
;
}
else
if
(
*
x
+
w
>
X_MAX
)
{
nx
=
MAX
(
0
,
X_MAX
-
w
);
if
(
nx
!=
*
x
)
{
*
x
=
nx
;
changed
=
TRUE
;
}
}
}
if
(
y
)
{
if
(
m
&&
(
flags
&
GNT_WINDOW_MAXIMIZE_Y
)
&&
*
y
!=
0
)
{
*
y
=
0
;
changed
=
TRUE
;
}
else
if
(
*
y
+
h
>
Y_MAX
)
{
ny
=
MAX
(
0
,
Y_MAX
-
h
);
if
(
ny
!=
*
y
)
{
*
y
=
ny
;
changed
=
TRUE
;
}
}
}
return
changed
;
}
static
void
refresh_node
(
GntWidget
*
widget
,
GntNode
*
node
,
gpointer
m
)
{
int
x
,
y
,
w
,
h
;
int
nw
,
nh
;
int
X_MAX
=
getmaxx
(
stdscr
);
int
Y_MAX
=
getmaxy
(
stdscr
)
-
1
;
GntWindowFlags
flags
=
0
;
if
(
m
&&
GNT_IS_WINDOW
(
widget
))
{
flags
=
gnt_window_get_maximize
(
GNT_WINDOW
(
widget
));
}
gnt_widget_get_position
(
widget
,
&
x
,
&
y
);
gnt_widget_get_size
(
widget
,
&
w
,
&
h
);
if
(
sanitize_position
(
widget
,
&
x
,
&
y
,
!!
m
))
gnt_screen_move_widget
(
widget
,
x
,
y
);
if
(
flags
&
GNT_WINDOW_MAXIMIZE_X
)
nw
=
X_MAX
;
else
nw
=
MIN
(
w
,
X_MAX
);
if
(
flags
&
GNT_WINDOW_MAXIMIZE_Y
)
nh
=
Y_MAX
;
else
nh
=
MIN
(
h
,
Y_MAX
);
if
(
nw
!=
w
||
nh
!=
h
)
gnt_screen_resize_widget
(
widget
,
nw
,
nh
);
}
static
void
read_window_positions
(
GntWM
*
wm
)
{
#if GLIB_CHECK_VERSION(2,6,0)
GKeyFile
*
gfile
=
g_key_file_new
();
char
*
filename
=
g_build_filename
(
g_get_home_dir
(),
".gntpositions"
,
NULL
);
GError
*
error
=
NULL
;
char
**
keys
;
gsize
nk
;
if
(
!
g_key_file_load_from_file
(
gfile
,
filename
,
G_KEY_FILE_NONE
,
&
error
))
{
gnt_warning
(
"%s"
,
error
->
message
);
g_error_free
(
error
);
g_free
(
filename
);
return
;
}
keys
=
g_key_file_get_keys
(
gfile
,
"positions"
,
&
nk
,
&
error
);
if
(
error
)
{
gnt_warning
(
"%s"
,
error
->
message
);
g_error_free
(
error
);
error
=
NULL
;
}
else
{
while
(
nk
--
)
{
char
*
title
=
keys
[
nk
];
gsize
l
;
char
**
coords
=
g_key_file_get_string_list
(
gfile
,
"positions"
,
title
,
&
l
,
NULL
);
if
(
l
==
2
)
{
int
x
=
atoi
(
coords
[
0
]);
int
y
=
atoi
(
coords
[
1
]);
GntPosition
*
p
=
g_new0
(
GntPosition
,
1
);
p
->
x
=
x
;
p
->
y
=
y
;
g_hash_table_replace
(
wm
->
positions
,
g_strdup
(
title
+
1
),
p
);
}
else
{
gnt_warning
(
"Invalid number of arguments (%"
G_GSIZE_FORMAT
") for positioning a window."
,
l
);
}
g_strfreev
(
coords
);
}
g_strfreev
(
keys
);
}
g_free
(
filename
);
g_key_file_free
(
gfile
);
#endif
}
static
gboolean
check_idle
(
gpointer
n
)
{
if
(
idle_update
)
{
time
(
&
last_active_time
);
idle_update
=
FALSE
;
}
return
TRUE
;
}
static
void
gnt_wm_init
(
GTypeInstance
*
instance
,
gpointer
class
)
{
GntWM
*
wm
=
GNT_WM
(
instance
);
wm
->
workspaces
=
NULL
;
wm
->
name_places
=
g_hash_table_new_full
(
g_str_hash
,
g_str_equal
,
g_free
,
g_free
);
wm
->
title_places
=
g_hash_table_new_full
(
g_str_hash
,
g_str_equal
,
g_free
,
g_free
);
gnt_style_read_workspaces
(
wm
);
if
(
wm
->
workspaces
==
NULL
)
{
wm
->
cws
=
gnt_ws_new
(
"default"
);
gnt_wm_add_workspace
(
wm
,
wm
->
cws
);
}
else
{
wm
->
cws
=
wm
->
workspaces
->
data
;
}
wm
->
event_stack
=
FALSE
;
wm
->
tagged
=
NULL
;
wm
->
windows
=
NULL
;
wm
->
actions
=
NULL
;
wm
->
nodes
=
g_hash_table_new_full
(
g_direct_hash
,
g_direct_equal
,
NULL
,
free_node
);
wm
->
positions
=
g_hash_table_new_full
(
g_str_hash
,
g_str_equal
,
g_free
,
g_free
);
if
(
gnt_style_get_bool
(
GNT_STYLE_REMPOS
,
TRUE
))
read_window_positions
(
wm
);
g_timeout_add_seconds
(
IDLE_CHECK_INTERVAL
,
check_idle
,
NULL
);
time
(
&
last_active_time
);
gnt_wm_switch_workspace
(
wm
,
0
);
}
static
void
switch_window
(
GntWM
*
wm
,
int
direction
,
gboolean
urgent
)
{
GntWidget
*
w
=
NULL
,
*
wid
=
NULL
;
int
pos
,
orgpos
;
if
(
wm
->
_list
.
window
||
wm
->
menu
)
return
;
if
(
!
wm
->
cws
->
ordered
||
!
wm
->
cws
->
ordered
->
next
)
return
;
if
(
wm
->
mode
!=
GNT_KP_MODE_NORMAL
)
{
ensure_normal_mode
(
wm
);
}
w
=
wm
->
cws
->
ordered
->
data
;
orgpos
=
pos
=
g_list_index
(
wm
->
cws
->
list
,
w
);
do
{
pos
+=
direction
;
if
(
pos
<
0
)
{
wid
=
g_list_last
(
wm
->
cws
->
list
)
->
data
;
pos
=
g_list_length
(
wm
->
cws
->
list
)
-
1
;
}
else
if
(
pos
>=
g_list_length
(
wm
->
cws
->
list
))
{
wid
=
wm
->
cws
->
list
->
data
;
pos
=
0
;
}
else
wid
=
g_list_nth_data
(
wm
->
cws
->
list
,
pos
);
}
while
(
urgent
&&
!
GNT_WIDGET_IS_FLAG_SET
(
wid
,
GNT_WIDGET_URGENT
)
&&
pos
!=
orgpos
);
gnt_wm_raise_window
(
wm
,
wid
);
}
static
gboolean
window_next
(
GntBindable
*
bindable
,
GList
*
null
)
{
GntWM
*
wm
=
GNT_WM
(
bindable
);
switch_window
(
wm
,
1
,
FALSE
);
return
TRUE
;
}
static
gboolean
window_prev
(
GntBindable
*
bindable
,
GList
*
null
)
{
GntWM
*
wm
=
GNT_WM
(
bindable
);
switch_window
(
wm
,
-1
,
FALSE
);
return
TRUE
;
}
static
gboolean
switch_window_n
(
GntBindable
*
bind
,
GList
*
list
)
{
GntWM
*
wm
=
GNT_WM
(
bind
);
GList
*
l
;
int
n
;
if
(
!
wm
->
cws
->
ordered
)
return
TRUE
;
if
(
list
)
n
=
GPOINTER_TO_INT
(
list
->
data
);
else
n
=
0
;
if
((
l
=
g_list_nth
(
wm
->
cws
->
list
,
n
))
!=
NULL
)
{
gnt_wm_raise_window
(
wm
,
l
->
data
);
}
return
TRUE
;
}
static
gboolean
window_scroll_up
(
GntBindable
*
bindable
,
GList
*
null
)
{
GntWM
*
wm
=
GNT_WM
(
bindable
);
GntWidget
*
window
;
GntNode
*
node
;
if
(
!
wm
->
cws
->
ordered
)
return
TRUE
;
window
=
wm
->
cws
->
ordered
->
data
;
node
=
g_hash_table_lookup
(
wm
->
nodes
,
window
);
if
(
!
node
)
return
TRUE
;
if
(
node
->
scroll
)
{
node
->
scroll
--
;
gnt_wm_copy_win
(
window
,
node
);
update_screen
(
wm
);
}
return
TRUE
;
}
static
gboolean
window_scroll_down
(
GntBindable
*
bindable
,
GList
*
null
)
{
GntWM
*
wm
=
GNT_WM
(
bindable
);
GntWidget
*
window
;
GntNode
*
node
;
int
w
,
h
;
if
(
!
wm
->
cws
->
ordered
)
return
TRUE
;
window
=
wm
->
cws
->
ordered
->
data
;
node
=
g_hash_table_lookup
(
wm
->
nodes
,
window
);
if
(
!
node
)
return
TRUE
;
gnt_widget_get_size
(
window
,
&
w
,
&
h
);
if
(
h
-
node
->
scroll
>
getmaxy
(
node
->
window
))
{
node
->
scroll
++
;
gnt_wm_copy_win
(
window
,
node
);
update_screen
(
wm
);
}
return
TRUE
;
}
static
gboolean
window_close
(
GntBindable
*
bindable
,
GList
*
null
)
{
GntWM
*
wm
=
GNT_WM
(
bindable
);
if
(
wm
->
_list
.
window
)
return
TRUE
;
if
(
wm
->
cws
->
ordered
)
{
gnt_widget_destroy
(
wm
->
cws
->
ordered
->
data
);
ensure_normal_mode
(
wm
);
}
return
TRUE
;
}
static
void
destroy__list
(
GntWidget
*
widget
,
GntWM
*
wm
)
{
wm
->
_list
.
window
=
NULL
;
wm
->
_list
.
tree
=
NULL
;
wm
->
windows
=
NULL
;
wm
->
actions
=
NULL
;
update_screen
(
wm
);
}
static
void
setup__list
(
GntWM
*
wm
)
{
GntWidget
*
tree
,
*
win
;
ensure_normal_mode
(
wm
);
win
=
wm
->
_list
.
window
=
gnt_box_new
(
FALSE
,
FALSE
);
gnt_box_set_toplevel
(
GNT_BOX
(
win
),
TRUE
);
gnt_box_set_pad
(
GNT_BOX
(
win
),
0
);
GNT_WIDGET_SET_FLAGS
(
win
,
GNT_WIDGET_TRANSIENT
);
tree
=
wm
->
_list
.
tree
=
gnt_tree_new
();
gnt_box_add_widget
(
GNT_BOX
(
win
),
tree
);
g_signal_connect
(
G_OBJECT
(
win
),
"destroy"
,
G_CALLBACK
(
destroy__list
),
wm
);
}
static
void
window_list_activate
(
GntTree
*
tree
,
GntWM
*
wm
)
{
GntBindable
*
sel
=
gnt_tree_get_selection_data
(
GNT_TREE
(
tree
));
gnt_widget_destroy
(
wm
->
_list
.
window
);
if
(
!
sel
)
return
;
if
(
GNT_IS_WS
(
sel
))
{
gnt_wm_switch_workspace
(
wm
,
g_list_index
(
wm
->
workspaces
,
sel
));
}
else
{
gnt_wm_raise_window
(
wm
,
GNT_WIDGET
(
sel
));
}
}
static
void
populate_window_list
(
GntWM
*
wm
,
gboolean
workspace
)
{
GList
*
iter
;
GntTree
*
tree
=
GNT_TREE
(
wm
->
windows
->
tree
);
if
(
!
workspace
)
{
for
(
iter
=
wm
->
cws
->
list
;
iter
;
iter
=
iter
->
next
)
{
GntBox
*
box
=
GNT_BOX
(
iter
->
data
);
gnt_tree_add_row_last
(
tree
,
box
,
gnt_tree_create_row
(
tree
,
box
->
title
),
NULL
);
update_window_in_list
(
wm
,
GNT_WIDGET
(
box
));
}
}
else
{
GList
*
ws
=
wm
->
workspaces
;
for
(;
ws
;
ws
=
ws
->
next
)
{
gnt_tree_add_row_last
(
tree
,
ws
->
data
,
gnt_tree_create_row
(
tree
,
gnt_ws_get_name
(
GNT_WS
(
ws
->
data
))),
NULL
);
for
(
iter
=
GNT_WS
(
ws
->
data
)
->
list
;
iter
;
iter
=
iter
->
next
)
{
GntBox
*
box
=
GNT_BOX
(
iter
->
data
);
gnt_tree_add_row_last
(
tree
,
box
,
gnt_tree_create_row
(
tree
,
box
->
title
),
ws
->
data
);
update_window_in_list
(
wm
,
GNT_WIDGET
(
box
));
}
}
}
}
static
gboolean
window_list_key_pressed
(
GntWidget
*
widget
,
const
char
*
text
,
GntWM
*
wm
)
{
if
(
text
[
1
]
==
0
&&
wm
->
cws
->
ordered
)
{
GntBindable
*
sel
=
gnt_tree_get_selection_data
(
GNT_TREE
(
widget
));
switch
(
text
[
0
])
{
case
'-'
:
case
','
:
if
(
GNT_IS_WS
(
sel
))
{
/* reorder the workspace. */
}
else
shift_window
(
wm
,
GNT_WIDGET
(
sel
),
-1
);
break
;
case
'='
:
case
'.'
:
if
(
GNT_IS_WS
(
sel
))
{
/* reorder the workspace. */
}
else
shift_window
(
wm
,
GNT_WIDGET
(
sel
),
1
);
break
;
default
:
return
FALSE
;
}
gnt_tree_remove_all
(
GNT_TREE
(
widget
));
populate_window_list
(
wm
,
GPOINTER_TO_INT
(
g_object_get_data
(
G_OBJECT
(
widget
),
"workspace"
)));
gnt_tree_set_selected
(
GNT_TREE
(
widget
),
sel
);
return
TRUE
;
}
return
FALSE
;
}
static
void
list_of_windows
(
GntWM
*
wm
,
gboolean
workspace
)
{
GntWidget
*
tree
,
*
win
;
setup__list
(
wm
);
wm
->
windows
=
&
wm
->
_list
;
win
=
wm
->
windows
->
window
;
tree
=
wm
->
windows
->
tree
;
gnt_box_set_title
(
GNT_BOX
(
win
),
workspace
?
"Workspace List"
:
"Window List"
);
populate_window_list
(
wm
,
workspace
);
if
(
wm
->
cws
->
ordered
)
gnt_tree_set_selected
(
GNT_TREE
(
tree
),
wm
->
cws
->
ordered
->
data
);
else
if
(
workspace
)
gnt_tree_set_selected
(
GNT_TREE
(
tree
),
wm
->
cws
);
g_signal_connect
(
G_OBJECT
(
tree
),
"activate"
,
G_CALLBACK
(
window_list_activate
),
wm
);
g_signal_connect
(
G_OBJECT
(
tree
),
"key_pressed"
,
G_CALLBACK
(
window_list_key_pressed
),
wm
);
g_object_set_data
(
G_OBJECT
(
tree
),
"workspace"
,
GINT_TO_POINTER
(
workspace
));
gnt_tree_set_col_width
(
GNT_TREE
(
tree
),
0
,
getmaxx
(
stdscr
)
/
3
);
gnt_widget_set_size
(
tree
,
0
,
getmaxy
(
stdscr
)
/
2
);
gnt_widget_set_position
(
win
,
getmaxx
(
stdscr
)
/
3
,
getmaxy
(
stdscr
)
/
4
);
gnt_widget_show
(
win
);
}
static
gboolean
window_list
(
GntBindable
*
bindable
,
GList
*
null
)
{
GntWM
*
wm
=
GNT_WM
(
bindable
);
if
(
wm
->
_list
.
window
||
wm
->
menu
)
return
TRUE
;
if
(
!
wm
->
cws
->
ordered
)
return
TRUE
;
list_of_windows
(
wm
,
FALSE
);
return
TRUE
;
}
static
void
dump_file_save
(
GntFileSel
*
fs
,
const
char
*
path
,
const
char
*
f
,
gpointer
n
)
{
FILE
*
file
;
int
x
,
y
;
chtype
old
=
0
,
now
=
0
;
struct
{
char
ascii
;
char
*
unicode
;
}
unis
[]
=
{
{
'q'
,
"─"
},
{
't'
,
"├"
},
{
'u'
,
"┤"
},
{
'x'
,
"│"
},
{
'-'
,
"↑"
},
{
'.'
,
"↓"
},
{
'l'
,
"┌"
},
{
'k'
,
"┐"
},
{
'm'
,
"└"
},
{
'j'
,
"┘"
},
{
'a'
,
"▒"
},
{
'n'
,
"┼"
},
{
'w'
,
"┬"
},
{
'v'
,
"┴"
},
{
'\0'
,
NULL
}
};
gnt_widget_destroy
(
GNT_WIDGET
(
fs
));
if
((
file
=
g_fopen
(
path
,
"w+"
))
==
NULL
)
{
return
;
}
fprintf
(
file
,
"<head>
\n
<meta http-equiv='Content-Type' content='text/html; charset=utf-8' />
\n
</head>
\n
<body>
\n
"
);
fprintf
(
file
,
"<pre>"
);
for
(
y
=
0
;
y
<
getmaxy
(
stdscr
);
y
++
)
{
for
(
x
=
0
;
x
<
getmaxx
(
stdscr
);
x
++
)
{
char
ch
[
2
]
=
{
0
,
0
},
*
print
;
#ifdef NO_WIDECHAR
now
=
mvwinch
(
curscr
,
y
,
x
);
ch
[
0
]
=
now
&
A_CHARTEXT
;
now
^=
ch
[
0
];
#else
cchar_t
wch
;
char
unicode
[
12
];
mvwin_wch
(
curscr
,
y
,
x
,
&
wch
);
now
=
wch
.
attr
;
ch
[
0
]
=
(
char
)(
wch
.
chars
[
0
]
&
0xff
);
#endif
#define CHECK(attr, start, end) \
do \
{ \
if (now & attr) \
{ \
if (!(old & attr)) \
fprintf(file, "%s", start); \
} \
else if (old & attr) \
{ \
fprintf(file, "%s", end); \
} \
} while (0)
CHECK
(
A_BOLD
,
"<b>"
,
"</b>"
);
CHECK
(
A_UNDERLINE
,
"<u>"
,
"</u>"
);
CHECK
(
A_BLINK
,
"<blink>"
,
"</blink>"
);
if
((
now
&
A_COLOR
)
!=
(
old
&
A_COLOR
)
||
(
now
&
A_REVERSE
)
!=
(
old
&
A_REVERSE
))
{
int
ret
;
short
fgp
,
bgp
,
r
,
g
,
b
;
struct
{
int
r
,
g
,
b
;
}
fg
,
bg
;
ret
=
pair_content
(
PAIR_NUMBER
(
now
&
A_COLOR
),
&
fgp
,
&
bgp
);
if
(
fgp
==
-1
)
fgp
=
COLOR_BLACK
;
if
(
bgp
==
-1
)
bgp
=
COLOR_WHITE
;
if
(
now
&
A_REVERSE
)
{
short
tmp
=
fgp
;
fgp
=
bgp
;
bgp
=
tmp
;
}
ret
=
color_content
(
fgp
,
&
r
,
&
g
,
&
b
);
fg
.
r
=
r
;
fg
.
b
=
b
;
fg
.
g
=
g
;
ret
=
color_content
(
bgp
,
&
r
,
&
g
,
&
b
);
bg
.
r
=
r
;
bg
.
b
=
b
;
bg
.
g
=
g
;
#define ADJUST(x) (x = x * 255 / 1000)
ADJUST
(
fg
.
r
);
ADJUST
(
fg
.
g
);
ADJUST
(
fg
.
b
);
ADJUST
(
bg
.
r
);
ADJUST
(
bg
.
b
);
ADJUST
(
bg
.
g
);
if
(
x
)
fprintf
(
file
,
"</span>"
);
fprintf
(
file
,
"<span style=
\"
background:#%02x%02x%02x;color:#%02x%02x%02x
\"
>"
,
bg
.
r
,
bg
.
g
,
bg
.
b
,
fg
.
r
,
fg
.
g
,
fg
.
b
);
}
print
=
ch
;
#ifndef NO_WIDECHAR
if
(
wch
.
chars
[
0
]
>
255
)
{
snprintf
(
unicode
,
sizeof
(
unicode
),
"&#x%x;"
,
(
unsigned
int
)
wch
.
chars
[
0
]);
print
=
unicode
;
}
#endif
if
(
now
&
A_ALTCHARSET
)
{
int
u
;
for
(
u
=
0
;
unis
[
u
].
ascii
;
u
++
)
{
if
(
ch
[
0
]
==
unis
[
u
].
ascii
)
{
print
=
unis
[
u
].
unicode
;
break
;
}
}
if
(
!
unis
[
u
].
ascii
)
print
=
" "
;
}
if
(
ch
[
0
]
==
'&'
)
fprintf
(
file
,
"&"
);
else
if
(
ch
[
0
]
==
'<'
)
fprintf
(
file
,
"<"
);
else
if
(
ch
[
0
]
==
'>'
)
fprintf
(
file
,
">"
);
else
fprintf
(
file
,
"%s"
,
print
);
old
=
now
;
}
fprintf
(
file
,
"</span>
\n
"
);
old
=
0
;
}
fprintf
(
file
,
"</pre>
\n
</body>"
);
fclose
(
file
);
}
static
void
dump_file_cancel
(
GntWidget
*
w
,
GntFileSel
*
fs
)
{
gnt_widget_destroy
(
GNT_WIDGET
(
fs
));
}
static
gboolean
dump_screen
(
GntBindable
*
b
,
GList
*
null
)
{
GntWidget
*
window
=
gnt_file_sel_new
();
GntFileSel
*
sel
=
GNT_FILE_SEL
(
window
);
g_object_set
(
G_OBJECT
(
window
),
"vertical"
,
TRUE
,
NULL
);
gnt_box_add_widget
(
GNT_BOX
(
window
),
gnt_label_new
(
"Please enter the filename to save the screenshot."
));
gnt_box_set_title
(
GNT_BOX
(
window
),
"Save Screenshot..."
);
gnt_file_sel_set_suggested_filename
(
sel
,
"dump.html"
);
g_signal_connect
(
G_OBJECT
(
sel
),
"file_selected"
,
G_CALLBACK
(
dump_file_save
),
NULL
);
g_signal_connect
(
G_OBJECT
(
sel
->
cancel
),
"activate"
,
G_CALLBACK
(
dump_file_cancel
),
sel
);
gnt_widget_show
(
window
);
return
TRUE
;
}
static
void
shift_window
(
GntWM
*
wm
,
GntWidget
*
widget
,
int
dir
)
{
GList
*
all
=
wm
->
cws
->
list
;
GList
*
list
=
g_list_find
(
all
,
widget
);
int
length
,
pos
;
if
(
!
list
)
return
;
length
=
g_list_length
(
all
);
pos
=
g_list_position
(
all
,
list
);
pos
+=
dir
;
if
(
dir
>
0
)
pos
++
;
if
(
pos
<
0
)
pos
=
length
;
else
if
(
pos
>
length
)
pos
=
0
;
all
=
g_list_insert
(
all
,
widget
,
pos
);
all
=
g_list_delete_link
(
all
,
list
);
wm
->
cws
->
list
=
all
;
gnt_ws_draw_taskbar
(
wm
->
cws
,
FALSE
);
if
(
wm
->
cws
->
ordered
)
{
GntWidget
*
w
=
wm
->
cws
->
ordered
->
data
;
GntNode
*
node
=
g_hash_table_lookup
(
wm
->
nodes
,
w
);
top_panel
(
node
->
panel
);
update_panels
();
doupdate
();
}
}
static
gboolean
shift_left
(
GntBindable
*
bindable
,
GList
*
null
)
{
GntWM
*
wm
=
GNT_WM
(
bindable
);
if
(
wm
->
_list
.
window
)
return
TRUE
;
if
(
!
wm
->
cws
->
ordered
)
return
FALSE
;
shift_window
(
wm
,
wm
->
cws
->
ordered
->
data
,
-1
);
return
TRUE
;
}
static
gboolean
shift_right
(
GntBindable
*
bindable
,
GList
*
null
)
{
GntWM
*
wm
=
GNT_WM
(
bindable
);
if
(
wm
->
_list
.
window
)
return
TRUE
;
if
(
!
wm
->
cws
->
ordered
)
return
FALSE
;
shift_window
(
wm
,
wm
->
cws
->
ordered
->
data
,
1
);
return
TRUE
;
}
static
void
action_list_activate
(
GntTree
*
tree
,
GntWM
*
wm
)
{
GntAction
*
action
=
gnt_tree_get_selection_data
(
tree
);
action
->
callback
();
gnt_widget_destroy
(
wm
->
_list
.
window
);
}
static
int
compare_action
(
gconstpointer
p1
,
gconstpointer
p2
)
{
const
GntAction
*
a1
=
p1
;
const
GntAction
*
a2
=
p2
;
return
g_utf8_collate
(
a1
->
label
,
a2
->
label
);
}
static
gboolean
list_actions
(
GntBindable
*
bindable
,
GList
*
null
)
{
GntWidget
*
tree
,
*
win
;
GList
*
iter
;
GntWM
*
wm
=
GNT_WM
(
bindable
);
int
n
;
if
(
wm
->
_list
.
window
||
wm
->
menu
)
return
TRUE
;
if
(
wm
->
acts
==
NULL
)
return
TRUE
;
setup__list
(
wm
);
wm
->
actions
=
&
wm
->
_list
;
win
=
wm
->
actions
->
window
;
tree
=
wm
->
actions
->
tree
;
gnt_box_set_title
(
GNT_BOX
(
win
),
"Actions"
);
GNT_WIDGET_SET_FLAGS
(
tree
,
GNT_WIDGET_NO_BORDER
);
/* XXX: Do we really want this? */
gnt_tree_set_compare_func
(
GNT_TREE
(
tree
),
compare_action
);
for
(
iter
=
wm
->
acts
;
iter
;
iter
=
iter
->
next
)
{
GntAction
*
action
=
iter
->
data
;
gnt_tree_add_row_last
(
GNT_TREE
(
tree
),
action
,
gnt_tree_create_row
(
GNT_TREE
(
tree
),
action
->
label
),
NULL
);
}
g_signal_connect
(
G_OBJECT
(
tree
),
"activate"
,
G_CALLBACK
(
action_list_activate
),
wm
);
n
=
g_list_length
(
wm
->
acts
);
gnt_widget_set_size
(
tree
,
0
,
n
);
gnt_widget_set_position
(
win
,
0
,
getmaxy
(
stdscr
)
-
3
-
n
);
gnt_widget_show
(
win
);
return
TRUE
;
}
#ifndef NO_WIDECHAR
static
int
widestringwidth
(
wchar_t
*
wide
)
{
int
len
,
ret
;
char
*
string
;
len
=
wcstombs
(
NULL
,
wide
,
0
)
+
1
;
string
=
g_new0
(
char
,
len
);
wcstombs
(
string
,
wide
,
len
);
ret
=
string
?
gnt_util_onscreen_width
(
string
,
NULL
)
:
1
;
g_free
(
string
);
return
ret
;
}
#endif
/* Returns the onscreen width of the character at the position */
static
int
reverse_char
(
WINDOW
*
d
,
int
y
,
int
x
,
gboolean
set
)
{
#define DECIDE(ch) (set ? ((ch) | A_REVERSE) : ((ch) & ~A_REVERSE))
#ifdef NO_WIDECHAR
chtype
ch
;
ch
=
mvwinch
(
d
,
y
,
x
);
mvwaddch
(
d
,
y
,
x
,
DECIDE
(
ch
));
return
1
;
#else
cchar_t
ch
;
int
wc
=
1
;
if
(
mvwin_wch
(
d
,
y
,
x
,
&
ch
)
==
OK
)
{
wc
=
widestringwidth
(
ch
.
chars
);
ch
.
attr
=
DECIDE
(
ch
.
attr
);
ch
.
attr
&=
WA_ATTRIBUTES
;
/* XXX: This is a workaround for a bug */
mvwadd_wch
(
d
,
y
,
x
,
&
ch
);
}
return
wc
;
#endif
}
static
void
window_reverse
(
GntWidget
*
win
,
gboolean
set
,
GntWM
*
wm
)
{
int
i
;
int
w
,
h
;
WINDOW
*
d
;
if
(
GNT_WIDGET_IS_FLAG_SET
(
win
,
GNT_WIDGET_NO_BORDER
))
return
;
d
=
win
->
window
;
gnt_widget_get_size
(
win
,
&
w
,
&
h
);
if
(
gnt_widget_has_shadow
(
win
))
{
--
w
;
--
h
;
}
/* the top and bottom */
for
(
i
=
0
;
i
<
w
;
i
+=
reverse_char
(
d
,
0
,
i
,
set
));
for
(
i
=
0
;
i
<
w
;
i
+=
reverse_char
(
d
,
h
-1
,
i
,
set
));
/* the left and right */
for
(
i
=
0
;
i
<
h
;
i
+=
reverse_char
(
d
,
i
,
0
,
set
));
for
(
i
=
0
;
i
<
h
;
i
+=
reverse_char
(
d
,
i
,
w
-1
,
set
));
gnt_wm_copy_win
(
win
,
g_hash_table_lookup
(
wm
->
nodes
,
win
));
update_screen
(
wm
);
}
static
void
ensure_normal_mode
(
GntWM
*
wm
)
{
if
(
wm
->
mode
!=
GNT_KP_MODE_NORMAL
)
{
if
(
wm
->
cws
->
ordered
)
window_reverse
(
wm
->
cws
->
ordered
->
data
,
FALSE
,
wm
);
wm
->
mode
=
GNT_KP_MODE_NORMAL
;
}
}
static
gboolean
start_move
(
GntBindable
*
bindable
,
GList
*
null
)
{
GntWM
*
wm
=
GNT_WM
(
bindable
);
if
(
wm
->
_list
.
window
||
wm
->
menu
)
return
TRUE
;
if
(
!
wm
->
cws
->
ordered
)
return
TRUE
;
wm
->
mode
=
GNT_KP_MODE_MOVE
;
window_reverse
(
GNT_WIDGET
(
wm
->
cws
->
ordered
->
data
),
TRUE
,
wm
);
return
TRUE
;
}
static
gboolean
start_resize
(
GntBindable
*
bindable
,
GList
*
null
)
{
GntWM
*
wm
=
GNT_WM
(
bindable
);
if
(
wm
->
_list
.
window
||
wm
->
menu
)
return
TRUE
;
if
(
!
wm
->
cws
->
ordered
)
return
TRUE
;
wm
->
mode
=
GNT_KP_MODE_RESIZE
;
window_reverse
(
GNT_WIDGET
(
wm
->
cws
->
ordered
->
data
),
TRUE
,
wm
);
return
TRUE
;
}
static
gboolean
wm_quit
(
GntBindable
*
bindable
,
GList
*
list
)
{
GntWM
*
wm
=
GNT_WM
(
bindable
);
if
(
write_timeout
)
write_already
(
wm
);
g_main_loop_quit
(
wm
->
loop
);
return
TRUE
;
}
static
gboolean
return_true
(
GntWM
*
wm
,
GntWidget
*
w
,
int
*
a
,
int
*
b
)
{
return
TRUE
;
}
static
gboolean
refresh_screen
(
GntBindable
*
bindable
,
GList
*
null
)
{
GntWM
*
wm
=
GNT_WM
(
bindable
);
GList
*
iter
;
endwin
();
refresh
();
g_hash_table_foreach
(
wm
->
nodes
,
(
GHFunc
)
refresh_node
,
GINT_TO_POINTER
(
TRUE
));
g_signal_emit
(
wm
,
signals
[
SIG_TERMINAL_REFRESH
],
0
);
for
(
iter
=
g_list_last
(
wm
->
cws
->
ordered
);
iter
;
iter
=
iter
->
prev
)
{
GntWidget
*
w
=
iter
->
data
;
GntNode
*
node
=
g_hash_table_lookup
(
wm
->
nodes
,
w
);
top_panel
(
node
->
panel
);
}
gnt_ws_draw_taskbar
(
wm
->
cws
,
TRUE
);
update_screen
(
wm
);
curs_set
(
0
);
/* endwin resets the cursor to normal */
return
TRUE
;
}
static
gboolean
toggle_clipboard
(
GntBindable
*
bindable
,
GList
*
n
)
{
static
GntWidget
*
clip
;
gchar
*
text
;
int
maxx
,
maxy
;
if
(
clip
)
{
gnt_widget_destroy
(
clip
);
clip
=
NULL
;
return
TRUE
;
}
getmaxyx
(
stdscr
,
maxy
,
maxx
);
text
=
gnt_get_clipboard_string
();
clip
=
gnt_hwindow_new
(
FALSE
);
GNT_WIDGET_SET_FLAGS
(
clip
,
GNT_WIDGET_TRANSIENT
);
GNT_WIDGET_SET_FLAGS
(
clip
,
GNT_WIDGET_NO_BORDER
);
gnt_box_set_pad
(
GNT_BOX
(
clip
),
0
);
gnt_box_add_widget
(
GNT_BOX
(
clip
),
gnt_label_new
(
" "
));
gnt_box_add_widget
(
GNT_BOX
(
clip
),
gnt_label_new
(
text
));
gnt_box_add_widget
(
GNT_BOX
(
clip
),
gnt_label_new
(
" "
));
gnt_widget_set_position
(
clip
,
0
,
0
);
gnt_widget_draw
(
clip
);
g_free
(
text
);
return
TRUE
;
}
static
void
remove_tag
(
gpointer
wid
,
gpointer
wim
)
{
GntWM
*
wm
=
GNT_WM
(
wim
);
GntWidget
*
w
=
GNT_WIDGET
(
wid
);
wm
->
tagged
=
g_list_remove
(
wm
->
tagged
,
w
);
mvwhline
(
w
->
window
,
0
,
1
,
ACS_HLINE
|
gnt_color_pair
(
GNT_COLOR_NORMAL
),
3
);
gnt_widget_draw
(
w
);
}
static
gboolean
tag_widget
(
GntBindable
*
b
,
GList
*
params
)
{
GntWM
*
wm
=
GNT_WM
(
b
);
GntWidget
*
widget
;
if
(
!
wm
->
cws
->
ordered
)
return
FALSE
;
widget
=
wm
->
cws
->
ordered
->
data
;
if
(
g_list_find
(
wm
->
tagged
,
widget
))
{
remove_tag
(
widget
,
wm
);
return
TRUE
;
}
wm
->
tagged
=
g_list_prepend
(
wm
->
tagged
,
widget
);
wbkgdset
(
widget
->
window
,
' '
|
gnt_color_pair
(
GNT_COLOR_HIGHLIGHT
));
mvwprintw
(
widget
->
window
,
0
,
1
,
"[T]"
);
gnt_widget_draw
(
widget
);
return
TRUE
;
}
static
void
widget_move_ws
(
gpointer
wid
,
gpointer
w
)
{
GntWM
*
wm
=
GNT_WM
(
w
);
gnt_wm_widget_move_workspace
(
wm
,
wm
->
cws
,
GNT_WIDGET
(
wid
));
}
static
gboolean
place_tagged
(
GntBindable
*
b
,
GList
*
params
)
{
GntWM
*
wm
=
GNT_WM
(
b
);
g_list_foreach
(
wm
->
tagged
,
widget_move_ws
,
wm
);
g_list_foreach
(
wm
->
tagged
,
remove_tag
,
wm
);
g_list_free
(
wm
->
tagged
);
wm
->
tagged
=
NULL
;
return
TRUE
;
}
static
gboolean
workspace_list
(
GntBindable
*
b
,
GList
*
params
)
{
GntWM
*
wm
=
GNT_WM
(
b
);
if
(
wm
->
_list
.
window
||
wm
->
menu
)
return
TRUE
;
list_of_windows
(
wm
,
TRUE
);
return
TRUE
;
}
static
gboolean
workspace_new
(
GntBindable
*
bindable
,
GList
*
null
)
{
GntWM
*
wm
=
GNT_WM
(
bindable
);
GntWS
*
ws
=
gnt_ws_new
(
NULL
);
gnt_wm_add_workspace
(
wm
,
ws
);
gnt_wm_switch_workspace
(
wm
,
g_list_index
(
wm
->
workspaces
,
ws
));
return
TRUE
;
}
static
gboolean
ignore_keys_start
(
GntBindable
*
bindable
,
GList
*
n
)
{
GntWM
*
wm
=
GNT_WM
(
bindable
);
if
(
!
wm
->
menu
&&
!
wm
->
_list
.
window
&&
wm
->
mode
==
GNT_KP_MODE_NORMAL
){
ignore_keys
=
TRUE
;
return
TRUE
;
}
return
FALSE
;
}
static
gboolean
ignore_keys_end
(
GntBindable
*
bindable
,
GList
*
n
)
{
return
ignore_keys
?
!
(
ignore_keys
=
FALSE
)
:
FALSE
;
}
static
gboolean
window_next_urgent
(
GntBindable
*
bindable
,
GList
*
n
)
{
GntWM
*
wm
=
GNT_WM
(
bindable
);
switch_window
(
wm
,
1
,
TRUE
);
return
TRUE
;
}
static
gboolean
window_prev_urgent
(
GntBindable
*
bindable
,
GList
*
n
)
{
GntWM
*
wm
=
GNT_WM
(
bindable
);
switch_window
(
wm
,
-1
,
TRUE
);
return
TRUE
;
}
#ifdef USE_PYTHON
static
void
python_script_selected
(
GntFileSel
*
fs
,
const
char
*
path
,
const
char
*
f
,
gpointer
n
)
{
char
*
dir
=
g_path_get_dirname
(
path
);
FILE
*
file
=
fopen
(
path
,
"r"
);
PyObject
*
pp
=
PySys_GetObject
(
"path"
),
*
dirobj
=
PyString_FromString
(
dir
);
PyList_Insert
(
pp
,
0
,
dirobj
);
Py_DECREF
(
dirobj
);
PyRun_SimpleFile
(
file
,
path
);
fclose
(
file
);
if
(
PyErr_Occurred
())
{
PyErr_Print
();
}
g_free
(
dir
);
gnt_widget_destroy
(
GNT_WIDGET
(
fs
));
}
static
gboolean
run_python
(
GntBindable
*
bindable
,
GList
*
n
)
{
GntWidget
*
window
=
gnt_file_sel_new
();
GntFileSel
*
sel
=
GNT_FILE_SEL
(
window
);
g_object_set
(
G_OBJECT
(
window
),
"vertical"
,
TRUE
,
NULL
);
gnt_box_add_widget
(
GNT_BOX
(
window
),
gnt_label_new
(
"Please select the python script you want to run."
));
gnt_box_set_title
(
GNT_BOX
(
window
),
"Select Python Script..."
);
g_signal_connect
(
G_OBJECT
(
sel
),
"file_selected"
,
G_CALLBACK
(
python_script_selected
),
NULL
);
g_signal_connect_swapped
(
G_OBJECT
(
sel
->
cancel
),
"activate"
,
G_CALLBACK
(
gnt_widget_destroy
),
sel
);
gnt_widget_show
(
window
);
return
TRUE
;
}
#endif
/* USE_PYTHON */
static
gboolean
help_for_bindable
(
GntWM
*
wm
,
GntBindable
*
bindable
)
{
gboolean
ret
=
TRUE
;
GntBindableClass
*
klass
=
GNT_BINDABLE_GET_CLASS
(
bindable
);
if
(
klass
->
help_window
)
{
gnt_wm_raise_window
(
wm
,
GNT_WIDGET
(
klass
->
help_window
));
}
else
{
ret
=
gnt_bindable_build_help_window
(
bindable
);
}
return
ret
;
}
static
gboolean
help_for_wm
(
GntBindable
*
bindable
,
GList
*
null
)
{
return
help_for_bindable
(
GNT_WM
(
bindable
),
bindable
);
}
static
gboolean
help_for_window
(
GntBindable
*
bindable
,
GList
*
null
)
{
GntWM
*
wm
=
GNT_WM
(
bindable
);
GntWidget
*
widget
;
if
(
!
wm
->
cws
->
ordered
)
return
FALSE
;
widget
=
wm
->
cws
->
ordered
->
data
;
return
help_for_bindable
(
wm
,
GNT_BINDABLE
(
widget
));
}
static
gboolean
help_for_widget
(
GntBindable
*
bindable
,
GList
*
null
)
{
GntWM
*
wm
=
GNT_WM
(
bindable
);
GntWidget
*
widget
;
if
(
!
wm
->
cws
->
ordered
)
return
TRUE
;
widget
=
wm
->
cws
->
ordered
->
data
;
if
(
!
GNT_IS_BOX
(
widget
))
return
TRUE
;
return
help_for_bindable
(
wm
,
GNT_BINDABLE
(
GNT_BOX
(
widget
)
->
active
));
}
static
void
accumulate_windows
(
gpointer
window
,
gpointer
node
,
gpointer
p
)
{
GList
*
list
=
*
(
GList
**
)
p
;
list
=
g_list_prepend
(
list
,
window
);
*
(
GList
**
)
p
=
list
;
}
static
void
gnt_wm_destroy
(
GObject
*
obj
)
{
GntWM
*
wm
=
GNT_WM
(
obj
);
GList
*
list
=
NULL
;
g_hash_table_foreach
(
wm
->
nodes
,
accumulate_windows
,
&
list
);
g_list_foreach
(
list
,
(
GFunc
)
gnt_widget_destroy
,
NULL
);
g_list_free
(
list
);
g_hash_table_destroy
(
wm
->
nodes
);
wm
->
nodes
=
NULL
;
while
(
wm
->
workspaces
)
{
g_object_unref
(
wm
->
workspaces
->
data
);
wm
->
workspaces
=
g_list_delete_link
(
wm
->
workspaces
,
wm
->
workspaces
);
}
#ifdef USE_PYTHON
if
(
started_python
)
{
Py_Finalize
();
started_python
=
FALSE
;
}
#endif
}
static
void
gnt_wm_class_init
(
GntWMClass
*
klass
)
{
int
i
;
GObjectClass
*
gclass
=
G_OBJECT_CLASS
(
klass
);
char
key
[
32
];
gclass
->
dispose
=
gnt_wm_destroy
;
klass
->
new_window
=
gnt_wm_new_window_real
;
klass
->
decorate_window
=
NULL
;
klass
->
close_window
=
NULL
;
klass
->
window_resize_confirm
=
return_true
;
klass
->
window_resized
=
gnt_wm_win_resized
;
klass
->
window_move_confirm
=
return_true
;
klass
->
window_moved
=
gnt_wm_win_moved
;
klass
->
window_update
=
NULL
;
klass
->
key_pressed
=
NULL
;
klass
->
mouse_clicked
=
NULL
;
klass
->
give_focus
=
gnt_wm_give_focus
;
signals
[
SIG_NEW_WIN
]
=
g_signal_new
(
"new_win"
,
G_TYPE_FROM_CLASS
(
klass
),
G_SIGNAL_RUN_LAST
,
G_STRUCT_OFFSET
(
GntWMClass
,
new_window
),
NULL
,
NULL
,
g_cclosure_marshal_VOID__POINTER
,
G_TYPE_NONE
,
1
,
G_TYPE_POINTER
);
signals
[
SIG_DECORATE_WIN
]
=
g_signal_new
(
"decorate_win"
,
G_TYPE_FROM_CLASS
(
klass
),
G_SIGNAL_RUN_LAST
,
G_STRUCT_OFFSET
(
GntWMClass
,
decorate_window
),
NULL
,
NULL
,
g_cclosure_marshal_VOID__POINTER
,
G_TYPE_NONE
,
1
,
G_TYPE_POINTER
);
signals
[
SIG_CLOSE_WIN
]
=
g_signal_new
(
"close_win"
,
G_TYPE_FROM_CLASS
(
klass
),
G_SIGNAL_RUN_LAST
,
G_STRUCT_OFFSET
(
GntWMClass
,
close_window
),
NULL
,
NULL
,
g_cclosure_marshal_VOID__POINTER
,
G_TYPE_NONE
,
1
,
G_TYPE_POINTER
);
signals
[
SIG_CONFIRM_RESIZE
]
=
g_signal_new
(
"confirm_resize"
,
G_TYPE_FROM_CLASS
(
klass
),
G_SIGNAL_RUN_LAST
,
G_STRUCT_OFFSET
(
GntWMClass
,
window_resize_confirm
),
gnt_boolean_handled_accumulator
,
NULL
,
gnt_closure_marshal_BOOLEAN__POINTER_POINTER_POINTER
,
G_TYPE_BOOLEAN
,
3
,
G_TYPE_POINTER
,
G_TYPE_POINTER
,
G_TYPE_POINTER
);
signals
[
SIG_CONFIRM_MOVE
]
=
g_signal_new
(
"confirm_move"
,
G_TYPE_FROM_CLASS
(
klass
),
G_SIGNAL_RUN_LAST
,
G_STRUCT_OFFSET
(
GntWMClass
,
window_move_confirm
),
gnt_boolean_handled_accumulator
,
NULL
,
gnt_closure_marshal_BOOLEAN__POINTER_POINTER_POINTER
,
G_TYPE_BOOLEAN
,
3
,
G_TYPE_POINTER
,
G_TYPE_POINTER
,
G_TYPE_POINTER
);
signals
[
SIG_RESIZED
]
=
g_signal_new
(
"window_resized"
,
G_TYPE_FROM_CLASS
(
klass
),
G_SIGNAL_RUN_LAST
,
G_STRUCT_OFFSET
(
GntWMClass
,
window_resized
),
NULL
,
NULL
,
g_cclosure_marshal_VOID__POINTER
,
G_TYPE_NONE
,
1
,
G_TYPE_POINTER
);
signals
[
SIG_MOVED
]
=
g_signal_new
(
"window_moved"
,
G_TYPE_FROM_CLASS
(
klass
),
G_SIGNAL_RUN_LAST
,
G_STRUCT_OFFSET
(
GntWMClass
,
window_moved
),
NULL
,
NULL
,
g_cclosure_marshal_VOID__POINTER
,
G_TYPE_NONE
,
1
,
G_TYPE_POINTER
);
signals
[
SIG_UPDATE_WIN
]
=
g_signal_new
(
"window_update"
,
G_TYPE_FROM_CLASS
(
klass
),
G_SIGNAL_RUN_LAST
,
G_STRUCT_OFFSET
(
GntWMClass
,
window_update
),
NULL
,
NULL
,
g_cclosure_marshal_VOID__POINTER
,
G_TYPE_NONE
,
1
,
G_TYPE_POINTER
);
signals
[
SIG_GIVE_FOCUS
]
=
g_signal_new
(
"give_focus"
,
G_TYPE_FROM_CLASS
(
klass
),
G_SIGNAL_RUN_LAST
,
G_STRUCT_OFFSET
(
GntWMClass
,
give_focus
),
NULL
,
NULL
,
g_cclosure_marshal_VOID__POINTER
,
G_TYPE_NONE
,
1
,
G_TYPE_POINTER
);
signals
[
SIG_MOUSE_CLICK
]
=
g_signal_new
(
"mouse_clicked"
,
G_TYPE_FROM_CLASS
(
klass
),
G_SIGNAL_RUN_LAST
,
G_STRUCT_OFFSET
(
GntWMClass
,
mouse_clicked
),
gnt_boolean_handled_accumulator
,
NULL
,
gnt_closure_marshal_BOOLEAN__INT_INT_INT_POINTER
,
G_TYPE_BOOLEAN
,
4
,
G_TYPE_INT
,
G_TYPE_INT
,
G_TYPE_INT
,
G_TYPE_POINTER
);
signals
[
SIG_TERMINAL_REFRESH
]
=
g_signal_new
(
"terminal-refresh"
,
G_TYPE_FROM_CLASS
(
klass
),
G_SIGNAL_RUN_LAST
,
G_STRUCT_OFFSET
(
GntWMClass
,
terminal_refresh
),
NULL
,
NULL
,
g_cclosure_marshal_VOID__VOID
,
G_TYPE_NONE
,
0
);
gnt_bindable_class_register_action
(
GNT_BINDABLE_CLASS
(
klass
),
"window-next"
,
window_next
,
"
\033
"
"n"
,
NULL
);
gnt_bindable_class_register_action
(
GNT_BINDABLE_CLASS
(
klass
),
"window-prev"
,
window_prev
,
"
\033
"
"p"
,
NULL
);
gnt_bindable_class_register_action
(
GNT_BINDABLE_CLASS
(
klass
),
"window-close"
,
window_close
,
"
\033
"
"c"
,
NULL
);
gnt_bindable_class_register_action
(
GNT_BINDABLE_CLASS
(
klass
),
"window-list"
,
window_list
,
"
\033
"
"w"
,
NULL
);
gnt_bindable_class_register_action
(
GNT_BINDABLE_CLASS
(
klass
),
"dump-screen"
,
dump_screen
,
"
\033
"
"D"
,
NULL
);
gnt_bindable_class_register_action
(
GNT_BINDABLE_CLASS
(
klass
),
"shift-left"
,
shift_left
,
"
\033
"
","
,
NULL
);
gnt_bindable_class_register_action
(
GNT_BINDABLE_CLASS
(
klass
),
"shift-right"
,
shift_right
,
"
\033
"
"."
,
NULL
);
gnt_bindable_class_register_action
(
GNT_BINDABLE_CLASS
(
klass
),
"action-list"
,
list_actions
,
"
\033
"
"a"
,
NULL
);
gnt_bindable_class_register_action
(
GNT_BINDABLE_CLASS
(
klass
),
"start-move"
,
start_move
,
"
\033
"
"m"
,
NULL
);
gnt_bindable_class_register_action
(
GNT_BINDABLE_CLASS
(
klass
),
"start-resize"
,
start_resize
,
"
\033
"
"r"
,
NULL
);
gnt_bindable_class_register_action
(
GNT_BINDABLE_CLASS
(
klass
),
"wm-quit"
,
wm_quit
,
"
\033
"
"q"
,
NULL
);
gnt_bindable_class_register_action
(
GNT_BINDABLE_CLASS
(
klass
),
"refresh-screen"
,
refresh_screen
,
"
\033
"
"l"
,
NULL
);
gnt_bindable_class_register_action
(
GNT_BINDABLE_CLASS
(
klass
),
"switch-window-n"
,
switch_window_n
,
NULL
,
NULL
);
gnt_bindable_class_register_action
(
GNT_BINDABLE_CLASS
(
klass
),
"window-scroll-down"
,
window_scroll_down
,
"
\033
"
GNT_KEY_CTRL_J
,
NULL
);
gnt_bindable_class_register_action
(
GNT_BINDABLE_CLASS
(
klass
),
"window-scroll-up"
,
window_scroll_up
,
"
\033
"
GNT_KEY_CTRL_K
,
NULL
);
gnt_bindable_class_register_action
(
GNT_BINDABLE_CLASS
(
klass
),
"help-for-widget"
,
help_for_widget
,
"
\033
"
"/"
,
NULL
);
gnt_bindable_class_register_action
(
GNT_BINDABLE_CLASS
(
klass
),
"workspace-new"
,
workspace_new
,
GNT_KEY_F9
,
NULL
);
gnt_bindable_class_register_action
(
GNT_BINDABLE_CLASS
(
klass
),
"workspace-next"
,
workspace_next
,
"
\033
"
">"
,
NULL
);
gnt_bindable_class_register_action
(
GNT_BINDABLE_CLASS
(
klass
),
"workspace-prev"
,
workspace_prev
,
"
\033
"
"<"
,
NULL
);
gnt_bindable_class_register_action
(
GNT_BINDABLE_CLASS
(
klass
),
"window-tag"
,
tag_widget
,
"
\033
"
"t"
,
NULL
);
gnt_bindable_class_register_action
(
GNT_BINDABLE_CLASS
(
klass
),
"place-tagged"
,
place_tagged
,
"
\033
"
"T"
,
NULL
);
gnt_bindable_class_register_action
(
GNT_BINDABLE_CLASS
(
klass
),
"workspace-list"
,
workspace_list
,
"
\033
"
"s"
,
NULL
);
gnt_bindable_class_register_action
(
GNT_BINDABLE_CLASS
(
klass
),
"toggle-clipboard"
,
toggle_clipboard
,
"
\033
"
"C"
,
NULL
);
gnt_bindable_class_register_action
(
GNT_BINDABLE_CLASS
(
klass
),
"help-for-wm"
,
help_for_wm
,
"
\033
"
"
\\
"
,
NULL
);
gnt_bindable_class_register_action
(
GNT_BINDABLE_CLASS
(
klass
),
"help-for-window"
,
help_for_window
,
"
\033
"
"|"
,
NULL
);
gnt_bindable_class_register_action
(
GNT_BINDABLE_CLASS
(
klass
),
"ignore-keys-start"
,
ignore_keys_start
,
NULL
,
NULL
);
gnt_bindable_class_register_action
(
GNT_BINDABLE_CLASS
(
klass
),
"ignore-keys-end"
,
ignore_keys_end
,
"
\033
"
GNT_KEY_CTRL_G
,
NULL
);
gnt_bindable_class_register_action
(
GNT_BINDABLE_CLASS
(
klass
),
"window-next-urgent"
,
window_next_urgent
,
"
\033
"
"
\t
"
,
NULL
);
snprintf
(
key
,
sizeof
(
key
),
"
\033
%s"
,
GNT_KEY_BACK_TAB
);
gnt_bindable_class_register_action
(
GNT_BINDABLE_CLASS
(
klass
),
"window-prev-urgent"
,
window_prev_urgent
,
key
[
1
]
?
key
:
NULL
,
NULL
);
#ifdef USE_PYTHON
gnt_bindable_class_register_action
(
GNT_BINDABLE_CLASS
(
klass
),
"run-python"
,
run_python
,
GNT_KEY_F3
,
NULL
);
if
(
!
Py_IsInitialized
())
{
Py_SetProgramName
(
"gnt"
);
Py_Initialize
();
started_python
=
TRUE
;
}
#endif
gnt_style_read_actions
(
G_OBJECT_CLASS_TYPE
(
klass
),
GNT_BINDABLE_CLASS
(
klass
));
/* Make sure Alt+x are detected properly. */
for
(
i
=
'0'
;
i
<=
'9'
;
i
++
)
{
char
str
[]
=
"
\033
X"
;
str
[
1
]
=
i
;
gnt_keys_add_combination
(
str
);
}
GNTDEBUG
;
}
/******************************************************************************
* GntWM API
*****************************************************************************/
GType
gnt_wm_get_gtype
(
void
)
{
static
GType
type
=
0
;
if
(
type
==
0
)
{
static
const
GTypeInfo
info
=
{
sizeof
(
GntWMClass
),
NULL
,
/* base_init */
NULL
,
/* base_finalize */
(
GClassInitFunc
)
gnt_wm_class_init
,
NULL
,
NULL
,
/* class_data */
sizeof
(
GntWM
),
0
,
/* n_preallocs */
gnt_wm_init
,
/* instance_init */
NULL
/* value_table */
};
type
=
g_type_register_static
(
GNT_TYPE_BINDABLE
,
"GntWM"
,
&
info
,
0
);
}
return
type
;
}
void
gnt_wm_add_workspace
(
GntWM
*
wm
,
GntWS
*
ws
)
{
wm
->
workspaces
=
g_list_append
(
wm
->
workspaces
,
ws
);
}
gboolean
gnt_wm_switch_workspace
(
GntWM
*
wm
,
gint
n
)
{
GntWS
*
s
=
g_list_nth_data
(
wm
->
workspaces
,
n
);
if
(
!
s
)
return
FALSE
;
if
(
wm
->
_list
.
window
)
{
gnt_widget_destroy
(
wm
->
_list
.
window
);
}
ensure_normal_mode
(
wm
);
gnt_ws_hide
(
wm
->
cws
,
wm
->
nodes
);
wm
->
cws
=
s
;
gnt_ws_show
(
wm
->
cws
,
wm
->
nodes
);
gnt_ws_draw_taskbar
(
wm
->
cws
,
TRUE
);
update_screen
(
wm
);
if
(
wm
->
cws
->
ordered
)
{
gnt_wm_raise_window
(
wm
,
wm
->
cws
->
ordered
->
data
);
}
if
(
act
&&
g_list_find
(
act
,
wm
->
cws
))
{
act
=
g_list_remove
(
act
,
wm
->
cws
);
update_act_msg
();
}
return
TRUE
;
}
gboolean
gnt_wm_switch_workspace_prev
(
GntWM
*
wm
)
{
int
n
=
g_list_index
(
wm
->
workspaces
,
wm
->
cws
);
return
gnt_wm_switch_workspace
(
wm
,
--
n
);
}
gboolean
gnt_wm_switch_workspace_next
(
GntWM
*
wm
)
{
int
n
=
g_list_index
(
wm
->
workspaces
,
wm
->
cws
);
return
gnt_wm_switch_workspace
(
wm
,
++
n
);
}
static
gboolean
workspace_next
(
GntBindable
*
wm
,
GList
*
n
)
{
return
gnt_wm_switch_workspace_next
(
GNT_WM
(
wm
));
}
static
gboolean
workspace_prev
(
GntBindable
*
wm
,
GList
*
n
)
{
return
gnt_wm_switch_workspace_prev
(
GNT_WM
(
wm
));
}
void
gnt_wm_widget_move_workspace
(
GntWM
*
wm
,
GntWS
*
neww
,
GntWidget
*
widget
)
{
GntWS
*
oldw
=
gnt_wm_widget_find_workspace
(
wm
,
widget
);
GntNode
*
node
;
if
(
!
oldw
||
oldw
==
neww
)
return
;
node
=
g_hash_table_lookup
(
wm
->
nodes
,
widget
);
if
(
node
&&
node
->
ws
==
neww
)
return
;
if
(
node
)
node
->
ws
=
neww
;
gnt_ws_remove_widget
(
oldw
,
widget
);
gnt_ws_add_widget
(
neww
,
widget
);
if
(
neww
==
wm
->
cws
)
{
gnt_ws_widget_show
(
widget
,
wm
->
nodes
);
}
else
{
gnt_ws_widget_hide
(
widget
,
wm
->
nodes
);
}
}
static
gint
widget_in_workspace
(
gconstpointer
workspace
,
gconstpointer
wid
)
{
GntWS
*
s
=
(
GntWS
*
)
workspace
;
if
(
s
->
list
&&
g_list_find
(
s
->
list
,
wid
))
return
0
;
return
1
;
}
GntWS
*
gnt_wm_widget_find_workspace
(
GntWM
*
wm
,
GntWidget
*
widget
)
{
GList
*
l
=
g_list_find_custom
(
wm
->
workspaces
,
widget
,
widget_in_workspace
);
if
(
l
)
return
l
->
data
;
return
NULL
;
}
static
void
free_workspaces
(
gpointer
data
,
gpointer
n
)
{
GntWS
*
s
=
data
;
g_free
(
s
->
name
);
}
void
gnt_wm_set_workspaces
(
GntWM
*
wm
,
GList
*
workspaces
)
{
g_list_foreach
(
wm
->
workspaces
,
free_workspaces
,
NULL
);
wm
->
workspaces
=
workspaces
;
gnt_wm_switch_workspace
(
wm
,
0
);
}
static
void
update_window_in_list
(
GntWM
*
wm
,
GntWidget
*
wid
)
{
GntTextFormatFlags
flag
=
0
;
if
(
wm
->
windows
==
NULL
)
return
;
if
(
wm
->
cws
->
ordered
&&
wid
==
wm
->
cws
->
ordered
->
data
)
flag
|=
GNT_TEXT_FLAG_DIM
;
else
if
(
GNT_WIDGET_IS_FLAG_SET
(
wid
,
GNT_WIDGET_URGENT
))
flag
|=
GNT_TEXT_FLAG_BOLD
;
gnt_tree_set_row_flags
(
GNT_TREE
(
wm
->
windows
->
tree
),
wid
,
flag
);
}
static
gboolean
match_title
(
gpointer
title
,
gpointer
n
,
gpointer
wid_title
)
{
/* XXX: do any regex magic here. */
if
(
g_strrstr
((
gchar
*
)
wid_title
,
(
gchar
*
)
title
))
return
TRUE
;
return
FALSE
;
}
#if !GLIB_CHECK_VERSION(2,4,0)
struct
{
gpointer
data
;
gpointer
value
;
}
table_find_data
;
static
void
table_find_helper
(
gpointer
key
,
gpointer
value
,
gpointer
data
)
{
GHRFunc
func
=
data
;
if
(
func
(
key
,
value
,
table_find_data
.
data
))
table_find_data
.
value
=
value
;
}
static
gpointer
g_hash_table_find
(
GHashTable
*
table
,
GHRFunc
func
,
gpointer
data
)
{
table_find_data
.
data
=
data
;
table_find_data
.
value
=
NULL
;
g_hash_table_foreach
(
table
,
table_find_helper
,
func
);
return
table_find_data
.
value
;
}
#endif
static
GntWS
*
new_widget_find_workspace
(
GntWM
*
wm
,
GntWidget
*
widget
)
{
GntWS
*
ret
=
NULL
;
const
gchar
*
name
,
*
title
;
title
=
GNT_BOX
(
widget
)
->
title
;
if
(
title
)
ret
=
g_hash_table_find
(
wm
->
title_places
,
match_title
,
(
gpointer
)
title
);
if
(
ret
)
return
ret
;
name
=
gnt_widget_get_name
(
widget
);
if
(
name
)
ret
=
g_hash_table_find
(
wm
->
name_places
,
match_title
,
(
gpointer
)
name
);
return
ret
?
ret
:
wm
->
cws
;
}
static
void
gnt_wm_new_window_real
(
GntWM
*
wm
,
GntWidget
*
widget
)
{
GntNode
*
node
;
gboolean
transient
=
FALSE
;
if
(
widget
->
window
==
NULL
)
return
;
node
=
g_new0
(
GntNode
,
1
);
node
->
me
=
widget
;
node
->
scroll
=
0
;
g_hash_table_replace
(
wm
->
nodes
,
widget
,
node
);
refresh_node
(
widget
,
node
,
GINT_TO_POINTER
(
TRUE
));
transient
=
!!
GNT_WIDGET_IS_FLAG_SET
(
node
->
me
,
GNT_WIDGET_TRANSIENT
);
#if 1
{
int
x
,
y
,
w
,
h
,
maxx
,
maxy
;
gboolean
shadow
=
TRUE
;
if
(
!
gnt_widget_has_shadow
(
widget
))
shadow
=
FALSE
;
x
=
widget
->
priv
.
x
;
y
=
widget
->
priv
.
y
;
w
=
widget
->
priv
.
width
+
shadow
;
h
=
widget
->
priv
.
height
+
shadow
;
maxx
=
getmaxx
(
stdscr
);
maxy
=
getmaxy
(
stdscr
)
-
1
;
/* room for the taskbar */
x
=
MAX
(
0
,
x
);
y
=
MAX
(
0
,
y
);
if
(
x
+
w
>=
maxx
)
x
=
MAX
(
0
,
maxx
-
w
);
if
(
y
+
h
>=
maxy
)
y
=
MAX
(
0
,
maxy
-
h
);
w
=
MIN
(
w
,
maxx
);
h
=
MIN
(
h
,
maxy
);
node
->
window
=
newwin
(
h
,
w
,
y
,
x
);
gnt_wm_copy_win
(
widget
,
node
);
}
#endif
node
->
panel
=
new_panel
(
node
->
window
);
set_panel_userptr
(
node
->
panel
,
node
);
if
(
!
transient
)
{
GntWS
*
ws
=
wm
->
cws
;
if
(
node
->
me
!=
wm
->
_list
.
window
)
{
if
(
GNT_IS_BOX
(
widget
))
{
ws
=
new_widget_find_workspace
(
wm
,
widget
);
}
node
->
ws
=
ws
;
ws
->
list
=
g_list_append
(
ws
->
list
,
widget
);
ws
->
ordered
=
g_list_append
(
ws
->
ordered
,
widget
);
}
if
(
wm
->
event_stack
||
node
->
me
==
wm
->
_list
.
window
||
node
->
me
==
ws
->
ordered
->
data
)
{
gnt_wm_raise_window
(
wm
,
node
->
me
);
}
else
{
bottom_panel
(
node
->
panel
);
/* New windows should not grab focus */
gnt_widget_set_focus
(
node
->
me
,
FALSE
);
gnt_widget_set_urgent
(
node
->
me
);
if
(
wm
->
cws
!=
ws
)
gnt_ws_widget_hide
(
widget
,
wm
->
nodes
);
}
}
}
void
gnt_wm_new_window
(
GntWM
*
wm
,
GntWidget
*
widget
)
{
while
(
widget
->
parent
)
widget
=
widget
->
parent
;
if
(
GNT_WIDGET_IS_FLAG_SET
(
widget
,
GNT_WIDGET_INVISIBLE
)
||
g_hash_table_lookup
(
wm
->
nodes
,
widget
))
{
update_screen
(
wm
);
return
;
}
if
(
GNT_IS_BOX
(
widget
))
{
const
char
*
title
=
GNT_BOX
(
widget
)
->
title
;
GntPosition
*
p
=
NULL
;
if
(
title
&&
(
p
=
g_hash_table_lookup
(
wm
->
positions
,
title
))
!=
NULL
)
{
sanitize_position
(
widget
,
&
p
->
x
,
&
p
->
y
,
TRUE
);
gnt_widget_set_position
(
widget
,
p
->
x
,
p
->
y
);
mvwin
(
widget
->
window
,
p
->
y
,
p
->
x
);
}
}
g_signal_emit
(
wm
,
signals
[
SIG_NEW_WIN
],
0
,
widget
);
g_signal_emit
(
wm
,
signals
[
SIG_DECORATE_WIN
],
0
,
widget
);
if
(
wm
->
windows
&&
!
GNT_WIDGET_IS_FLAG_SET
(
widget
,
GNT_WIDGET_TRANSIENT
))
{
if
((
GNT_IS_BOX
(
widget
)
&&
GNT_BOX
(
widget
)
->
title
)
&&
wm
->
_list
.
window
!=
widget
&&
GNT_WIDGET_IS_FLAG_SET
(
widget
,
GNT_WIDGET_CAN_TAKE_FOCUS
))
{
gnt_tree_add_row_last
(
GNT_TREE
(
wm
->
windows
->
tree
),
widget
,
gnt_tree_create_row
(
GNT_TREE
(
wm
->
windows
->
tree
),
GNT_BOX
(
widget
)
->
title
),
g_object_get_data
(
G_OBJECT
(
wm
->
windows
->
tree
),
"workspace"
)
?
wm
->
cws
:
NULL
);
update_window_in_list
(
wm
,
widget
);
}
}
gnt_ws_draw_taskbar
(
wm
->
cws
,
FALSE
);
update_screen
(
wm
);
}
void
gnt_wm_window_decorate
(
GntWM
*
wm
,
GntWidget
*
widget
)
{
g_signal_emit
(
wm
,
signals
[
SIG_DECORATE_WIN
],
0
,
widget
);
}
void
gnt_wm_window_close
(
GntWM
*
wm
,
GntWidget
*
widget
)
{
GntWS
*
s
;
int
pos
;
gboolean
transient
=
!!
GNT_WIDGET_IS_FLAG_SET
(
widget
,
GNT_WIDGET_TRANSIENT
);
s
=
gnt_wm_widget_find_workspace
(
wm
,
widget
);
if
(
g_hash_table_lookup
(
wm
->
nodes
,
widget
)
==
NULL
)
return
;
g_signal_emit
(
wm
,
signals
[
SIG_CLOSE_WIN
],
0
,
widget
);
g_hash_table_remove
(
wm
->
nodes
,
widget
);
if
(
wm
->
windows
)
{
gnt_tree_remove
(
GNT_TREE
(
wm
->
windows
->
tree
),
widget
);
}
if
(
s
)
{
pos
=
g_list_index
(
s
->
list
,
widget
);
if
(
pos
!=
-1
)
{
s
->
list
=
g_list_remove
(
s
->
list
,
widget
);
s
->
ordered
=
g_list_remove
(
s
->
ordered
,
widget
);
if
(
s
->
ordered
&&
wm
->
cws
==
s
)
gnt_wm_raise_window
(
wm
,
s
->
ordered
->
data
);
}
}
else
if
(
transient
&&
wm
->
cws
&&
wm
->
cws
->
ordered
)
{
gnt_wm_update_window
(
wm
,
wm
->
cws
->
ordered
->
data
);
}
gnt_ws_draw_taskbar
(
wm
->
cws
,
FALSE
);
update_screen
(
wm
);
}
time_t
gnt_wm_get_idle_time
()
{
return
time
(
NULL
)
-
last_active_time
;
}
gboolean
gnt_wm_process_input
(
GntWM
*
wm
,
const
char
*
keys
)
{
gboolean
ret
=
FALSE
;
keys
=
gnt_bindable_remap_keys
(
GNT_BINDABLE
(
wm
),
keys
);
idle_update
=
TRUE
;
if
(
ignore_keys
){
if
(
keys
&&
!
strcmp
(
keys
,
"
\033
"
GNT_KEY_CTRL_G
)){
if
(
gnt_bindable_perform_action_key
(
GNT_BINDABLE
(
wm
),
keys
)){
return
TRUE
;
}
}
return
wm
->
cws
->
ordered
?
gnt_widget_key_pressed
(
GNT_WIDGET
(
wm
->
cws
->
ordered
->
data
),
keys
)
:
FALSE
;
}
if
(
gnt_bindable_perform_action_key
(
GNT_BINDABLE
(
wm
),
keys
))
{
return
TRUE
;
}
/* Do some manual checking */
if
(
wm
->
cws
->
ordered
&&
wm
->
mode
!=
GNT_KP_MODE_NORMAL
)
{
int
xmin
=
0
,
ymin
=
0
,
xmax
=
getmaxx
(
stdscr
),
ymax
=
getmaxy
(
stdscr
)
-
1
;
int
x
,
y
,
w
,
h
;
GntWidget
*
widget
=
GNT_WIDGET
(
wm
->
cws
->
ordered
->
data
);
int
ox
,
oy
,
ow
,
oh
;
gnt_widget_get_position
(
widget
,
&
x
,
&
y
);
gnt_widget_get_size
(
widget
,
&
w
,
&
h
);
ox
=
x
;
oy
=
y
;
ow
=
w
;
oh
=
h
;
if
(
wm
->
mode
==
GNT_KP_MODE_MOVE
)
{
if
(
strcmp
(
keys
,
GNT_KEY_LEFT
)
==
0
)
{
if
(
x
>
xmin
)
x
--
;
}
else
if
(
strcmp
(
keys
,
GNT_KEY_RIGHT
)
==
0
)
{
if
(
x
+
w
<
xmax
)
x
++
;
}
else
if
(
strcmp
(
keys
,
GNT_KEY_UP
)
==
0
)
{
if
(
y
>
ymin
)
y
--
;
}
else
if
(
strcmp
(
keys
,
GNT_KEY_DOWN
)
==
0
)
{
if
(
y
+
h
<
ymax
)
y
++
;
}
if
(
ox
!=
x
||
oy
!=
y
)
{
gnt_screen_move_widget
(
widget
,
x
,
y
);
window_reverse
(
widget
,
TRUE
,
wm
);
return
TRUE
;
}
}
else
if
(
wm
->
mode
==
GNT_KP_MODE_RESIZE
)
{
if
(
strcmp
(
keys
,
GNT_KEY_LEFT
)
==
0
)
{
w
--
;
}
else
if
(
strcmp
(
keys
,
GNT_KEY_RIGHT
)
==
0
)
{
if
(
x
+
w
<
xmax
)
w
++
;
}
else
if
(
strcmp
(
keys
,
GNT_KEY_UP
)
==
0
)
{
h
--
;
}
else
if
(
strcmp
(
keys
,
GNT_KEY_DOWN
)
==
0
)
{
if
(
y
+
h
<
ymax
)
h
++
;
}
if
(
oh
!=
h
||
ow
!=
w
)
{
gnt_screen_resize_widget
(
widget
,
w
,
h
);
window_reverse
(
widget
,
TRUE
,
wm
);
return
TRUE
;
}
}
if
(
strcmp
(
keys
,
"
\r
"
)
==
0
||
strcmp
(
keys
,
"
\033
"
)
==
0
)
{
window_reverse
(
widget
,
FALSE
,
wm
);
wm
->
mode
=
GNT_KP_MODE_NORMAL
;
}
return
TRUE
;
}
/* Escape to close the window-list or action-list window */
if
(
strcmp
(
keys
,
"
\033
"
)
==
0
)
{
if
(
wm
->
_list
.
window
)
{
gnt_widget_destroy
(
wm
->
_list
.
window
);
return
TRUE
;
}
}
else
if
(
keys
[
0
]
==
'\033'
&&
isdigit
(
keys
[
1
])
&&
keys
[
2
]
==
'\0'
)
{
/* Alt+x for quick switch */
int
n
=
*
(
keys
+
1
)
-
'0'
;
GList
*
list
=
NULL
;
if
(
n
==
0
)
n
=
10
;
list
=
g_list_append
(
list
,
GINT_TO_POINTER
(
n
-
1
));
switch_window_n
(
GNT_BINDABLE
(
wm
),
list
);
g_list_free
(
list
);
return
TRUE
;
}
if
(
wm
->
menu
)
ret
=
gnt_widget_key_pressed
(
GNT_WIDGET
(
wm
->
menu
),
keys
);
else
if
(
wm
->
_list
.
window
)
ret
=
gnt_widget_key_pressed
(
wm
->
_list
.
window
,
keys
);
else
if
(
wm
->
cws
->
ordered
)
{
GntWidget
*
win
=
wm
->
cws
->
ordered
->
data
;
if
(
GNT_IS_WINDOW
(
win
))
{
GntMenu
*
menu
=
GNT_WINDOW
(
win
)
->
menu
;
if
(
menu
)
{
const
char
*
id
=
gnt_window_get_accel_item
(
GNT_WINDOW
(
win
),
keys
);
if
(
id
)
{
GntMenuItem
*
item
=
gnt_menu_get_item
(
menu
,
id
);
if
(
item
)
ret
=
gnt_menuitem_activate
(
item
);
}
}
}
if
(
!
ret
)
ret
=
gnt_widget_key_pressed
(
win
,
keys
);
}
return
ret
;
}
static
void
gnt_wm_win_resized
(
GntWM
*
wm
,
GntNode
*
node
)
{
/*refresh_node(node->me, node, NULL);*/
}
static
void
gnt_wm_win_moved
(
GntWM
*
wm
,
GntNode
*
node
)
{
refresh_node
(
node
->
me
,
node
,
NULL
);
}
void
gnt_wm_resize_window
(
GntWM
*
wm
,
GntWidget
*
widget
,
int
width
,
int
height
)
{
gboolean
ret
=
TRUE
;
GntNode
*
node
;
int
maxx
,
maxy
;
while
(
widget
->
parent
)
widget
=
widget
->
parent
;
node
=
g_hash_table_lookup
(
wm
->
nodes
,
widget
);
if
(
!
node
)
return
;
g_signal_emit
(
wm
,
signals
[
SIG_CONFIRM_RESIZE
],
0
,
widget
,
&
width
,
&
height
,
&
ret
);
if
(
!
ret
)
return
;
/* resize is not permitted */
hide_panel
(
node
->
panel
);
gnt_widget_set_size
(
widget
,
width
,
height
);
gnt_widget_draw
(
widget
);
maxx
=
getmaxx
(
stdscr
);
maxy
=
getmaxy
(
stdscr
)
-
1
;
height
=
MIN
(
height
,
maxy
);
width
=
MIN
(
width
,
maxx
);
wresize
(
node
->
window
,
height
,
width
);
replace_panel
(
node
->
panel
,
node
->
window
);
g_signal_emit
(
wm
,
signals
[
SIG_RESIZED
],
0
,
node
);
show_panel
(
node
->
panel
);
update_screen
(
wm
);
}
static
void
write_gdi
(
gpointer
key
,
gpointer
value
,
gpointer
data
)
{
GntPosition
*
p
=
value
;
fprintf
(
data
,
".%s = %d;%d
\n
"
,
(
char
*
)
key
,
p
->
x
,
p
->
y
);
}
static
gboolean
write_already
(
gpointer
data
)
{
GntWM
*
wm
=
data
;
FILE
*
file
;
char
*
filename
;
filename
=
g_build_filename
(
g_get_home_dir
(),
".gntpositions"
,
NULL
);
file
=
fopen
(
filename
,
"wb"
);
if
(
file
==
NULL
)
{
gnt_warning
(
"error opening file (%s) to save positions"
,
filename
);
}
else
{
fprintf
(
file
,
"[positions]
\n
"
);
g_hash_table_foreach
(
wm
->
positions
,
write_gdi
,
file
);
fclose
(
file
);
}
g_free
(
filename
);
g_source_remove
(
write_timeout
);
write_timeout
=
0
;
return
FALSE
;
}
static
void
write_positions_to_file
(
GntWM
*
wm
)
{
if
(
write_timeout
)
{
g_source_remove
(
write_timeout
);
}
write_timeout
=
g_timeout_add_seconds
(
10
,
write_already
,
wm
);
}
void
gnt_wm_move_window
(
GntWM
*
wm
,
GntWidget
*
widget
,
int
x
,
int
y
)
{
gboolean
ret
=
TRUE
;
GntNode
*
node
;
while
(
widget
->
parent
)
widget
=
widget
->
parent
;
node
=
g_hash_table_lookup
(
wm
->
nodes
,
widget
);
if
(
!
node
)
return
;
g_signal_emit
(
wm
,
signals
[
SIG_CONFIRM_MOVE
],
0
,
widget
,
&
x
,
&
y
,
&
ret
);
if
(
!
ret
)
return
;
/* resize is not permitted */
gnt_widget_set_position
(
widget
,
x
,
y
);
move_panel
(
node
->
panel
,
y
,
x
);
g_signal_emit
(
wm
,
signals
[
SIG_MOVED
],
0
,
node
);
if
(
gnt_style_get_bool
(
GNT_STYLE_REMPOS
,
TRUE
)
&&
GNT_IS_BOX
(
widget
)
&&
!
GNT_WIDGET_IS_FLAG_SET
(
widget
,
GNT_WIDGET_TRANSIENT
))
{
const
char
*
title
=
GNT_BOX
(
widget
)
->
title
;
if
(
title
)
{
GntPosition
*
p
=
g_new0
(
GntPosition
,
1
);
GntWidget
*
wid
=
node
->
me
;
p
->
x
=
wid
->
priv
.
x
;
p
->
y
=
wid
->
priv
.
y
;
g_hash_table_replace
(
wm
->
positions
,
g_strdup
(
title
),
p
);
write_positions_to_file
(
wm
);
}
}
update_screen
(
wm
);
}
static
void
gnt_wm_give_focus
(
GntWM
*
wm
,
GntWidget
*
widget
)
{
GntNode
*
node
=
g_hash_table_lookup
(
wm
->
nodes
,
widget
);
if
(
!
node
)
return
;
if
(
widget
!=
wm
->
_list
.
window
&&
!
GNT_IS_MENU
(
widget
)
&&
wm
->
cws
->
ordered
->
data
!=
widget
)
{
GntWidget
*
w
=
wm
->
cws
->
ordered
->
data
;
wm
->
cws
->
ordered
=
g_list_bring_to_front
(
wm
->
cws
->
ordered
,
widget
);
gnt_widget_set_focus
(
w
,
FALSE
);
}
gnt_widget_set_focus
(
widget
,
TRUE
);
GNT_WIDGET_UNSET_FLAGS
(
widget
,
GNT_WIDGET_URGENT
);
gnt_widget_draw
(
widget
);
top_panel
(
node
->
panel
);
if
(
wm
->
_list
.
window
)
{
GntNode
*
nd
=
g_hash_table_lookup
(
wm
->
nodes
,
wm
->
_list
.
window
);
top_panel
(
nd
->
panel
);
}
gnt_ws_draw_taskbar
(
wm
->
cws
,
FALSE
);
update_screen
(
wm
);
}
void
gnt_wm_update_window
(
GntWM
*
wm
,
GntWidget
*
widget
)
{
GntNode
*
node
=
NULL
;
GntWS
*
ws
;
while
(
widget
->
parent
)
widget
=
widget
->
parent
;
if
(
!
GNT_IS_MENU
(
widget
))
{
if
(
!
GNT_IS_BOX
(
widget
))
return
;
gnt_box_sync_children
(
GNT_BOX
(
widget
));
}
ws
=
gnt_wm_widget_find_workspace
(
wm
,
widget
);
node
=
g_hash_table_lookup
(
wm
->
nodes
,
widget
);
if
(
node
==
NULL
)
{
gnt_wm_new_window
(
wm
,
widget
);
}
else
g_signal_emit
(
wm
,
signals
[
SIG_UPDATE_WIN
],
0
,
node
);
if
(
ws
==
wm
->
cws
||
GNT_WIDGET_IS_FLAG_SET
(
widget
,
GNT_WIDGET_TRANSIENT
))
{
gnt_wm_copy_win
(
widget
,
node
);
gnt_ws_draw_taskbar
(
wm
->
cws
,
FALSE
);
update_screen
(
wm
);
}
else
if
(
ws
&&
ws
!=
wm
->
cws
&&
GNT_WIDGET_IS_FLAG_SET
(
widget
,
GNT_WIDGET_URGENT
))
{
if
(
!
act
||
(
act
&&
!
g_list_find
(
act
,
ws
)))
act
=
g_list_prepend
(
act
,
ws
);
update_act_msg
();
}
}
gboolean
gnt_wm_process_click
(
GntWM
*
wm
,
GntMouseEvent
event
,
int
x
,
int
y
,
GntWidget
*
widget
)
{
gboolean
ret
=
TRUE
;
idle_update
=
TRUE
;
g_signal_emit
(
wm
,
signals
[
SIG_MOUSE_CLICK
],
0
,
event
,
x
,
y
,
widget
,
&
ret
);
return
ret
;
}
void
gnt_wm_raise_window
(
GntWM
*
wm
,
GntWidget
*
widget
)
{
GntWS
*
ws
=
gnt_wm_widget_find_workspace
(
wm
,
widget
);
if
(
wm
->
cws
!=
ws
)
gnt_wm_switch_workspace
(
wm
,
g_list_index
(
wm
->
workspaces
,
ws
));
if
(
widget
!=
wm
->
cws
->
ordered
->
data
)
{
GntWidget
*
wid
=
wm
->
cws
->
ordered
->
data
;
wm
->
cws
->
ordered
=
g_list_bring_to_front
(
wm
->
cws
->
ordered
,
widget
);
gnt_widget_set_focus
(
wid
,
FALSE
);
gnt_widget_draw
(
wid
);
}
gnt_widget_set_focus
(
widget
,
TRUE
);
gnt_widget_draw
(
widget
);
g_signal_emit
(
wm
,
signals
[
SIG_GIVE_FOCUS
],
0
,
widget
);
}
void
gnt_wm_set_event_stack
(
GntWM
*
wm
,
gboolean
set
)
{
wm
->
event_stack
=
set
;
}