grim/libgnt
Clone
Summary
Browse
Changes
Graph
Fixed out of source tree building
2016-01-06, James Geboski
22477dc14614
Fixed out of source tree building
This addresses:
- The autogen script not switching to the source directory
- Various missing header include paths
/*
* 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
<string.h>
#include
"gntinternal.h"
#undef GNT_LOG_DOMAIN
#define GNT_LOG_DOMAIN "Bindable"
#include
"gntbindable.h"
#include
"gntstyle.h"
#include
"gnt.h"
#include
"gntutils.h"
#include
"gnttextview.h"
#include
"gnttree.h"
#include
"gntbox.h"
#include
"gntbutton.h"
#include
"gntwindow.h"
#include
"gntlabel.h"
static
GObjectClass
*
parent_class
=
NULL
;
static
struct
{
char
*
okeys
;
/* Old keystrokes */
char
*
keys
;
/* New Keystrokes being bound to the action */
GntBindableClass
*
klass
;
/* Class of the object that's getting keys rebound */
char
*
name
;
/* The name of the action */
GList
*
params
;
/* The list of paramaters */
}
rebind_info
;
static
void
gnt_bindable_free_rebind_info
(
void
)
{
g_free
(
rebind_info
.
name
);
g_free
(
rebind_info
.
keys
);
g_free
(
rebind_info
.
okeys
);
}
static
void
gnt_bindable_rebinding_cancel
(
GntWidget
*
button
,
gpointer
data
)
{
gnt_bindable_free_rebind_info
();
gnt_widget_destroy
(
GNT_WIDGET
(
data
));
}
static
void
gnt_bindable_rebinding_rebind
(
GntWidget
*
button
,
gpointer
data
)
{
if
(
rebind_info
.
keys
)
{
gnt_bindable_register_binding
(
rebind_info
.
klass
,
NULL
,
rebind_info
.
okeys
,
rebind_info
.
params
);
gnt_bindable_register_binding
(
rebind_info
.
klass
,
rebind_info
.
name
,
rebind_info
.
keys
,
rebind_info
.
params
);
}
gnt_bindable_free_rebind_info
();
gnt_widget_destroy
(
GNT_WIDGET
(
data
));
}
static
gboolean
gnt_bindable_rebinding_grab_key
(
GntBindable
*
bindable
,
const
char
*
text
,
gpointer
data
)
{
GntTextView
*
textview
=
GNT_TEXT_VIEW
(
data
);
char
*
new_text
;
const
char
*
tmp
;
if
(
text
&&
*
text
)
{
/* Rebinding tab or enter for something is probably not that great an idea */
if
(
!
strcmp
(
text
,
GNT_KEY_CTRL_I
)
||
!
strcmp
(
text
,
GNT_KEY_ENTER
))
{
return
FALSE
;
}
tmp
=
gnt_key_lookup
(
text
);
new_text
=
g_strdup_printf
(
"KEY:
\"
%s
\"
"
,
tmp
);
gnt_text_view_clear
(
textview
);
gnt_text_view_append_text_with_flags
(
textview
,
new_text
,
GNT_TEXT_FLAG_NORMAL
);
g_free
(
new_text
);
g_free
(
rebind_info
.
keys
);
rebind_info
.
keys
=
g_strdup
(
text
);
return
TRUE
;
}
return
FALSE
;
}
static
void
gnt_bindable_rebinding_activate
(
GntBindable
*
data
,
gpointer
bindable
)
{
const
char
*
widget_name
=
g_type_name
(
G_OBJECT_TYPE
(
bindable
));
char
*
keys
;
GntWidget
*
key_textview
;
GntWidget
*
label
;
GntWidget
*
bind_button
,
*
cancel_button
;
GntWidget
*
button_box
;
GList
*
current_row_data
;
char
*
tmp
;
GntWidget
*
win
=
gnt_window_new
();
GntTree
*
tree
=
GNT_TREE
(
data
);
GntWidget
*
vbox
=
gnt_box_new
(
FALSE
,
TRUE
);
rebind_info
.
klass
=
GNT_BINDABLE_GET_CLASS
(
bindable
);
current_row_data
=
gnt_tree_get_selection_text_list
(
tree
);
rebind_info
.
name
=
g_strdup
(
g_list_nth_data
(
current_row_data
,
1
));
keys
=
gnt_tree_get_selection_data
(
tree
);
rebind_info
.
okeys
=
g_strdup
(
gnt_key_translate
(
keys
));
rebind_info
.
params
=
NULL
;
g_list_foreach
(
current_row_data
,
(
GFunc
)
g_free
,
NULL
);
g_list_free
(
current_row_data
);
gnt_box_set_alignment
(
GNT_BOX
(
vbox
),
GNT_ALIGN_MID
);
gnt_box_set_title
(
GNT_BOX
(
win
),
"Key Capture"
);
tmp
=
g_strdup_printf
(
"Type the new bindings for %s in a %s."
,
rebind_info
.
name
,
widget_name
);
label
=
gnt_label_new
(
tmp
);
g_free
(
tmp
);
gnt_box_add_widget
(
GNT_BOX
(
vbox
),
label
);
tmp
=
g_strdup_printf
(
"KEY:
\"
%s
\"
"
,
keys
);
key_textview
=
gnt_text_view_new
();
gnt_widget_set_size
(
key_textview
,
key_textview
->
priv
.
x
,
2
);
gnt_text_view_append_text_with_flags
(
GNT_TEXT_VIEW
(
key_textview
),
tmp
,
GNT_TEXT_FLAG_NORMAL
);
g_free
(
tmp
);
gnt_widget_set_name
(
key_textview
,
"keystroke"
);
gnt_box_add_widget
(
GNT_BOX
(
vbox
),
key_textview
);
g_signal_connect
(
G_OBJECT
(
win
),
"key_pressed"
,
G_CALLBACK
(
gnt_bindable_rebinding_grab_key
),
key_textview
);
button_box
=
gnt_box_new
(
FALSE
,
FALSE
);
bind_button
=
gnt_button_new
(
"BIND"
);
gnt_widget_set_name
(
bind_button
,
"bind"
);
gnt_box_add_widget
(
GNT_BOX
(
button_box
),
bind_button
);
cancel_button
=
gnt_button_new
(
"Cancel"
);
gnt_widget_set_name
(
cancel_button
,
"cancel"
);
gnt_box_add_widget
(
GNT_BOX
(
button_box
),
cancel_button
);
g_signal_connect
(
G_OBJECT
(
bind_button
),
"activate"
,
G_CALLBACK
(
gnt_bindable_rebinding_rebind
),
win
);
g_signal_connect
(
G_OBJECT
(
cancel_button
),
"activate"
,
G_CALLBACK
(
gnt_bindable_rebinding_cancel
),
win
);
gnt_box_add_widget
(
GNT_BOX
(
vbox
),
button_box
);
gnt_box_add_widget
(
GNT_BOX
(
win
),
vbox
);
gnt_widget_show
(
win
);
}
typedef
struct
{
GHashTable
*
hash
;
GntTree
*
tree
;
}
BindingView
;
static
void
add_binding
(
gpointer
key
,
gpointer
value
,
gpointer
data
)
{
BindingView
*
bv
=
data
;
GntBindableActionParam
*
act
=
value
;
const
char
*
name
=
g_hash_table_lookup
(
bv
->
hash
,
act
->
action
);
if
(
name
&&
*
name
)
{
const
char
*
k
=
gnt_key_lookup
(
key
);
if
(
!
k
)
k
=
key
;
gnt_tree_add_row_after
(
bv
->
tree
,
(
gpointer
)
k
,
gnt_tree_create_row
(
bv
->
tree
,
k
,
name
),
NULL
,
NULL
);
}
}
static
void
add_action
(
gpointer
key
,
gpointer
value
,
gpointer
data
)
{
BindingView
*
bv
=
data
;
g_hash_table_insert
(
bv
->
hash
,
value
,
key
);
}
static
void
gnt_bindable_class_init
(
GntBindableClass
*
klass
)
{
parent_class
=
g_type_class_peek_parent
(
klass
);
klass
->
actions
=
g_hash_table_new_full
(
g_str_hash
,
g_str_equal
,
g_free
,
(
GDestroyNotify
)
gnt_bindable_action_free
);
klass
->
bindings
=
g_hash_table_new_full
(
g_str_hash
,
g_str_equal
,
g_free
,
(
GDestroyNotify
)
gnt_bindable_action_param_free
);
gnt_style_read_actions
(
G_OBJECT_CLASS_TYPE
(
klass
),
GNT_BINDABLE_CLASS
(
klass
));
GNTDEBUG
;
}
static
gpointer
bindable_clone
(
GntBindableAction
*
action
)
{
GntBindableAction
*
ret
=
g_new0
(
GntBindableAction
,
1
);
ret
->
name
=
g_strdup
(
action
->
name
);
ret
->
u
=
action
->
u
;
return
ret
;
}
static
gpointer
binding_clone
(
GntBindableActionParam
*
param
)
{
GntBindableActionParam
*
p
=
g_new0
(
GntBindableActionParam
,
1
);
p
->
list
=
g_list_copy
(
param
->
list
);
p
->
action
=
param
->
action
;
return
p
;
}
static
void
duplicate_hashes
(
GntBindableClass
*
klass
)
{
/* Duplicate the bindings from parent class */
if
(
klass
->
actions
)
{
klass
->
actions
=
gnt_hash_table_duplicate
(
klass
->
actions
,
g_str_hash
,
g_str_equal
,
g_free
,
(
GDestroyNotify
)
gnt_bindable_action_free
,
(
GntDuplicateFunc
)
g_strdup
,
(
GntDuplicateFunc
)
bindable_clone
);
klass
->
bindings
=
gnt_hash_table_duplicate
(
klass
->
bindings
,
g_str_hash
,
g_str_equal
,
g_free
,
(
GDestroyNotify
)
gnt_bindable_action_param_free
,
(
GntDuplicateFunc
)
g_strdup
,
(
GntDuplicateFunc
)
binding_clone
);
}
else
{
klass
->
actions
=
g_hash_table_new_full
(
g_str_hash
,
g_str_equal
,
g_free
,
(
GDestroyNotify
)
gnt_bindable_action_free
);
klass
->
bindings
=
g_hash_table_new_full
(
g_str_hash
,
g_str_equal
,
g_free
,
(
GDestroyNotify
)
gnt_bindable_action_param_free
);
}
GNTDEBUG
;
}
/******************************************************************************
* GntBindable API
*****************************************************************************/
GType
gnt_bindable_get_type
(
void
)
{
static
GType
type
=
0
;
if
(
type
==
0
)
{
static
const
GTypeInfo
info
=
{
sizeof
(
GntBindableClass
),
(
GBaseInitFunc
)
duplicate_hashes
,
/* base_init */
NULL
,
/* base_finalize */
(
GClassInitFunc
)
gnt_bindable_class_init
,
NULL
,
NULL
,
/* class_data */
sizeof
(
GntBindable
),
0
,
/* n_preallocs */
NULL
,
/* instance_init */
NULL
/* value_table */
};
type
=
g_type_register_static
(
G_TYPE_OBJECT
,
"GntBindable"
,
&
info
,
G_TYPE_FLAG_ABSTRACT
);
}
return
type
;
}
/*
* Key Remaps
*/
const
char
*
gnt_bindable_remap_keys
(
GntBindable
*
bindable
,
const
char
*
text
)
{
const
char
*
remap
=
NULL
;
GType
type
=
G_OBJECT_TYPE
(
bindable
);
GntBindableClass
*
klass
=
GNT_BINDABLE_CLASS
(
GNT_BINDABLE_GET_CLASS
(
bindable
));
if
(
klass
->
remaps
==
NULL
)
{
klass
->
remaps
=
g_hash_table_new_full
(
g_str_hash
,
g_str_equal
,
g_free
,
g_free
);
gnt_styles_get_keyremaps
(
type
,
klass
->
remaps
);
}
remap
=
g_hash_table_lookup
(
klass
->
remaps
,
text
);
return
(
remap
?
remap
:
text
);
}
/*
* Actions and Bindings
*/
gboolean
gnt_bindable_perform_action_named
(
GntBindable
*
bindable
,
const
char
*
name
,
...)
{
GntBindableClass
*
klass
=
GNT_BINDABLE_CLASS
(
GNT_BINDABLE_GET_CLASS
(
bindable
));
GList
*
list
=
NULL
;
va_list
args
;
GntBindableAction
*
action
;
void
*
p
;
va_start
(
args
,
name
);
while
((
p
=
va_arg
(
args
,
void
*
))
!=
NULL
)
list
=
g_list_append
(
list
,
p
);
va_end
(
args
);
action
=
g_hash_table_lookup
(
klass
->
actions
,
name
);
if
(
action
&&
action
->
u
.
action
)
{
return
action
->
u
.
action
(
bindable
,
list
);
}
return
FALSE
;
}
gboolean
gnt_bindable_perform_action_key
(
GntBindable
*
bindable
,
const
char
*
keys
)
{
GntBindableClass
*
klass
=
GNT_BINDABLE_CLASS
(
GNT_BINDABLE_GET_CLASS
(
bindable
));
GntBindableActionParam
*
param
=
g_hash_table_lookup
(
klass
->
bindings
,
keys
);
if
(
param
&&
param
->
action
)
{
if
(
param
->
list
)
return
param
->
action
->
u
.
action
(
bindable
,
param
->
list
);
else
return
param
->
action
->
u
.
action_noparam
(
bindable
);
}
return
FALSE
;
}
gboolean
gnt_bindable_check_key
(
GntBindable
*
bindable
,
const
char
*
keys
)
{
GntBindableClass
*
klass
=
GNT_BINDABLE_CLASS
(
GNT_BINDABLE_GET_CLASS
(
bindable
));
GntBindableActionParam
*
param
=
g_hash_table_lookup
(
klass
->
bindings
,
keys
);
return
(
param
&&
param
->
action
);
}
static
void
register_binding
(
GntBindableClass
*
klass
,
const
char
*
name
,
const
char
*
trigger
,
GList
*
list
)
{
GntBindableActionParam
*
param
;
GntBindableAction
*
action
;
if
(
name
==
NULL
||
*
name
==
'\0'
)
{
g_hash_table_remove
(
klass
->
bindings
,
(
char
*
)
trigger
);
gnt_keys_del_combination
(
trigger
);
return
;
}
action
=
g_hash_table_lookup
(
klass
->
actions
,
name
);
if
(
!
action
)
{
gnt_warning
(
"Invalid action name %s for %s"
,
name
,
g_type_name
(
G_OBJECT_CLASS_TYPE
(
klass
)));
if
(
list
)
g_list_free
(
list
);
return
;
}
param
=
g_new0
(
GntBindableActionParam
,
1
);
param
->
action
=
action
;
param
->
list
=
list
;
g_hash_table_replace
(
klass
->
bindings
,
g_strdup
(
trigger
),
param
);
gnt_keys_add_combination
(
trigger
);
}
void
gnt_bindable_register_binding
(
GntBindableClass
*
klass
,
const
char
*
name
,
const
char
*
trigger
,
...)
{
GList
*
list
=
NULL
;
va_list
args
;
void
*
data
;
va_start
(
args
,
trigger
);
while
((
data
=
va_arg
(
args
,
void
*
)))
{
list
=
g_list_append
(
list
,
data
);
}
va_end
(
args
);
register_binding
(
klass
,
name
,
trigger
,
list
);
}
void
gnt_bindable_class_register_action
(
GntBindableClass
*
klass
,
const
char
*
name
,
GntBindableActionCallback
callback
,
const
char
*
trigger
,
...)
{
void
*
data
;
va_list
args
;
GntBindableAction
*
action
=
g_new0
(
GntBindableAction
,
1
);
GList
*
list
;
action
->
name
=
g_strdup
(
name
);
action
->
u
.
action
=
callback
;
g_hash_table_replace
(
klass
->
actions
,
g_strdup
(
name
),
action
);
if
(
trigger
&&
*
trigger
)
{
list
=
NULL
;
va_start
(
args
,
trigger
);
while
((
data
=
va_arg
(
args
,
void
*
)))
{
list
=
g_list_append
(
list
,
data
);
}
va_end
(
args
);
register_binding
(
klass
,
name
,
trigger
,
list
);
}
}
void
gnt_bindable_action_free
(
GntBindableAction
*
action
)
{
g_free
(
action
->
name
);
g_free
(
action
);
}
void
gnt_bindable_action_param_free
(
GntBindableActionParam
*
param
)
{
g_list_free
(
param
->
list
);
/* XXX: There may be a leak here for string parameters */
g_free
(
param
);
}
GntBindable
*
gnt_bindable_bindings_view
(
GntBindable
*
bind
)
{
GntBindable
*
tree
=
GNT_BINDABLE
(
gnt_tree_new_with_columns
(
2
));
GntBindableClass
*
klass
=
GNT_BINDABLE_CLASS
(
GNT_BINDABLE_GET_CLASS
(
bind
));
GHashTable
*
hash
=
g_hash_table_new
(
g_direct_hash
,
g_direct_equal
);
BindingView
bv
=
{
hash
,
GNT_TREE
(
tree
)};
gnt_tree_set_compare_func
(
bv
.
tree
,
(
GCompareFunc
)
g_utf8_collate
);
g_hash_table_foreach
(
klass
->
actions
,
add_action
,
&
bv
);
g_hash_table_foreach
(
klass
->
bindings
,
add_binding
,
&
bv
);
if
(
GNT_TREE
(
tree
)
->
list
==
NULL
)
{
gnt_widget_destroy
(
GNT_WIDGET
(
tree
));
tree
=
NULL
;
}
else
gnt_tree_adjust_columns
(
bv
.
tree
);
g_hash_table_destroy
(
hash
);
return
tree
;
}
static
void
reset_binding_window
(
GntBindableClass
*
window
,
gpointer
k
)
{
GntBindableClass
*
klass
=
GNT_BINDABLE_CLASS
(
k
);
klass
->
help_window
=
NULL
;
}
gboolean
gnt_bindable_build_help_window
(
GntBindable
*
bindable
)
{
GntWidget
*
tree
;
GntBindableClass
*
klass
=
GNT_BINDABLE_GET_CLASS
(
bindable
);
char
*
title
;
tree
=
GNT_WIDGET
(
gnt_bindable_bindings_view
(
bindable
));
klass
->
help_window
=
GNT_BINDABLE
(
gnt_window_new
());
title
=
g_strdup_printf
(
"Bindings for %s"
,
g_type_name
(
G_OBJECT_TYPE
(
bindable
)));
gnt_box_set_title
(
GNT_BOX
(
klass
->
help_window
),
title
);
if
(
tree
)
{
g_signal_connect
(
G_OBJECT
(
tree
),
"activate"
,
G_CALLBACK
(
gnt_bindable_rebinding_activate
),
bindable
);
gnt_box_add_widget
(
GNT_BOX
(
klass
->
help_window
),
tree
);
}
else
gnt_box_add_widget
(
GNT_BOX
(
klass
->
help_window
),
gnt_label_new
(
"This widget has no customizable bindings."
));
g_signal_connect
(
G_OBJECT
(
klass
->
help_window
),
"destroy"
,
G_CALLBACK
(
reset_binding_window
),
klass
);
gnt_widget_show
(
GNT_WIDGET
(
klass
->
help_window
));
g_free
(
title
);
return
TRUE
;
}