Replace dynamic exports with codegen for GtkBuilder callbacks

This prevents having to export those callbacks and put them in the
global namespace. Also, use inline shell script in Makefile.am instead
of a Python script which should be more portable (by default) and gets
rid of the helper script.
This commit is contained in:
Matthew Brush 2014-10-19 13:49:58 -07:00 committed by Thomas Martitz
parent eb36500ac4
commit 1d64d5211f
8 changed files with 61 additions and 259 deletions

View File

@ -24,25 +24,14 @@ dnl `__attribute__((visibility(...)))` extension and use it if so.
])
CFLAGS="${libgeany_backup_cflags}"
dnl Try and see if we can use our list of dynamically exported symbols with
dnl the linker and use it if so.
AC_MSG_CHECKING([whether linker supports --dynamic-list])
libgeany_backup_ldflags=$LDFLAGS
LDFLAGS=-Wl,--dynamic-list="${srcdir}/src/dynamicsymbols.list"
AC_LINK_IFELSE([
AC_LANG_PROGRAM([], [])
], [
LIBGEANY_LIBS="-Wl,--dynamic-list=\"\$(top_srcdir)/src/dynamicsymbols.list\""
AC_MSG_RESULT([yes])
], [
LIBGEANY_LIBS=""
AC_MSG_RESULT([no])
])
LDFLAGS="${libgeany_backup_ldflags}"
LIBGEANY_LIBS="${LIBGEANY_LIBS} -version-info ${libgeany_current}:${libgeany_revision}:${libgeany_age}"
LIBGEANY_LIBS="-version-info ${libgeany_current}:${libgeany_revision}:${libgeany_age}"
AC_SUBST([LIBGEANY_CFLAGS])
AC_SUBST([LIBGEANY_LIBS])
dnl Check for utilities needed to do codegen
AC_PATH_PROG([SORT], [sort], [
AC_MSG_ERROR([The 'sort' utility is required, is it installed?])])
AC_PATH_PROG([UNIQ], [uniq], [
AC_MSG_ERROR([The 'uniq' utility is required, is it installed?])])
])

View File

@ -1,73 +0,0 @@
#!/usr/bin/env python
"""
Script to parse GtkBuilder XML file for signal handler references and list
them in a linker file for which symbols to dynamically export.
"""
import optparse
import os
import re
import sys
from xml.etree import ElementTree as ET
def find_handlers(xml_filename, excludes=[]):
def is_excluded(name, excludes):
for exclude in excludes:
m = re.match(exclude, name)
if m:
return True
return False
tree = ET.parse(xml_filename)
root = tree.getroot()
handlers = []
signals = root.findall(".//signal")
for signal in signals:
handler = signal.attrib["handler"]
if not is_excluded(handler, excludes):
handlers.append(handler)
return sorted(handlers)
def write_dynamic_list(handlers, output_file):
output_file.write("""\
/* This file was auto-generated by the `%s' script, do not edit. */
{
""" % os.path.basename(__file__))
for handler in handlers:
output_file.write("\t%s;\n" % handler)
output_file.write("};\n")
def main(args):
p = optparse.OptionParser(usage="%prog [-o FILE] XMLFILE")
p.add_option("-o", "--output", metavar="FILE", dest="output_file",
default="-", help="write the output to this file (default `-' for stdin)")
opts, args = p.parse_args(args)
output_file = None
try:
if opts.output_file == "-":
output_file = sys.stdout
else:
output_file = open(opts.output_file, 'w')
args = args[1:]
if len(args) == 0:
p.error("invalid XMLFILE argument, expecting a filename, got none")
elif len(args) > 1:
p.error("too many XMLFILE arguments, expecting a single filename")
handlers = find_handlers(args[0], ["gtk_.+"])
write_dynamic_list(handlers, output_file)
finally:
if output_file is not None and output_file is not sys.stdout:
output_file.close()
return 0
if __name__ == "__main__":
sys.exit(main(sys.argv))

View File

@ -11,7 +11,7 @@ EXTRA_DIST = \
pluginprivate.h \
projectprivate.h \
makefile.win32 \
$(top_srcdir)/src/dynamicsymbols.list
$(srcdir)/signalconn.c.in
bin_PROGRAMS = geany
lib_LTLIBRARIES = libgeany.la
@ -173,10 +173,20 @@ AM_CFLAGS = -DGEANY_DATADIR=\""$(datadir)"\" \
clean-local:
# Helper rule to rebuild the dynamicsymbols.list file when handlers are
# added to data/geany.glade. Run `make dynamic-symbols' from the src builddir.
$(top_srcdir)/src/dynamicsymbols.list: $(top_srcdir)/data/geany.glade
-python $(top_srcdir)/scripts/dynamicsymbols.py -o $@ $(top_srcdir)/data/geany.glade
dynamic-symbols: $(top_srcdir)/src/dynamicsymbols.list
endif
callbacks.c: signalconn.c
glade_file=$(top_srcdir)/data/geany.glade
template_file=$(srcdir)/signalconn.c.in
signalconn.c: $(glade_file) $(template_file)
$(AM_V_GEN)( \
echo '/* This file is auto-generated, do not edit. */' && \
$(SED) -n '/@callback_map@/q;p' "$(template_file)" && \
$(SED) -n 's/^.*handler="\([^"]\+\)".*$$/\tg_hash_table_insert(hash, "\1", G_CALLBACK(\1));/p' "$(glade_file)" \
| $(SORT) | $(UNIQ) && \
$(SED) -n '/@callback_map@/{:l;n;p;b l}' "$(template_file)" \
) > $@ || { $(RM) $@ && exit 1; }
CLEANFILES = signalconn.c

View File

@ -1988,3 +1988,5 @@ GEANY_EXPORT_SYMBOL void on_detect_width_from_file_activate(GtkMenuItem *menuite
ui_document_show_hide(doc);
}
}
#include "signalconn.c"

View File

@ -26,6 +26,9 @@
G_BEGIN_DECLS
/* Defined in auto-generated code in signalconn.c */
void callbacks_connect(GtkBuilder *builder);
extern gboolean ignore_callback;
void on_new1_activate(GtkMenuItem *menuitem, gpointer user_data);

View File

@ -1,161 +0,0 @@
/* This file was auto-generated by the `dynamicsymbols.py' script, do not edit. */
{
on_button_customize_toolbar_clicked;
on_change_font1_activate;
on_clone1_activate;
on_close1_activate;
on_close_all1_activate;
on_close_other_documents1_activate;
on_comments_bsd_activate;
on_comments_changelog_activate;
on_comments_changelog_activate;
on_comments_fileheader_activate;
on_comments_fileheader_activate;
on_comments_function_activate;
on_comments_function_activate;
on_comments_gpl_activate;
on_comments_multiline_activate;
on_context_action1_activate;
on_copy1_activate;
on_copy1_activate;
on_copy_current_lines1_activate;
on_count_words1_activate;
on_cr_activate;
on_crlf_activate;
on_customize_toolbar1_activate;
on_cut1_activate;
on_cut1_activate;
on_cut_current_lines1_activate;
on_debug_messages1_activate;
on_delete1_activate;
on_delete1_activate;
on_delete_current_lines1_activate;
on_detect_type_from_file_activate;
on_detect_width_from_file_activate;
on_duplicate_line_or_selection1_activate;
on_edit1_activate;
on_escape_key_press_event;
on_file1_activate;
on_file_properties_activate;
on_find1_activate;
on_find_document_usage1_activate;
on_find_document_usage1_activate;
on_find_in_files1_activate;
on_find_next1_activate;
on_find_nextsel1_activate;
on_find_previous1_activate;
on_find_prevsel1_activate;
on_find_usage1_activate;
on_find_usage1_activate;
on_fullscreen1_toggled;
on_go_to_line_activate;
on_go_to_next_marker1_activate;
on_go_to_previous_marker1_activate;
on_goto_tag_declaration1;
on_goto_tag_definition1;
on_goto_tag_definition1;
on_help1_activate;
on_help_menu_item_bug_report_activate;
on_help_menu_item_donate_activate;
on_help_menu_item_wiki_activate;
on_help_shortcuts1_activate;
on_hide_toolbar1_activate;
on_indent_width_activate;
on_indent_width_activate;
on_indent_width_activate;
on_indent_width_activate;
on_indent_width_activate;
on_indent_width_activate;
on_indent_width_activate;
on_indent_width_activate;
on_info1_activate;
on_insert_alternative_white_space1_activate;
on_insert_alternative_white_space1_activate;
on_lf_activate;
on_line_breaking1_activate;
on_line_wrapping1_toggled;
on_load_tags1_activate;
on_mark_all1_activate;
on_markers_margin1_toggled;
on_menu_color_schemes_activate;
on_menu_comment_line1_activate;
on_menu_comments_bsd_activate;
on_menu_comments_gpl_activate;
on_menu_comments_multiline_activate;
on_menu_decrease_indent1_activate;
on_menu_fold_all1_activate;
on_menu_increase_indent1_activate;
on_menu_open_selected_file1_activate;
on_menu_open_selected_file1_activate;
on_menu_project1_activate;
on_menu_reload_configuration1_activate;
on_menu_remove_indicators1_activate;
on_menu_select_all1_activate;
on_menu_select_all1_activate;
on_menu_show_indentation_guides1_toggled;
on_menu_show_line_endings1_toggled;
on_menu_show_sidebar1_toggled;
on_menu_show_white_space1_toggled;
on_menu_toggle_all_additional_widgets1_activate;
on_menu_toggle_line_commentation1_activate;
on_menu_uncomment_line1_activate;
on_menu_unfold_all1_activate;
on_menu_write_unicode_bom1_toggled;
on_motion_event;
on_move_lines_down1_activate;
on_move_lines_up1_activate;
on_new1_activate;
on_next_message1_activate;
on_normal_size1_activate;
on_notebook1_switch_page_after;
on_open1_activate;
on_page_setup1_activate;
on_paste1_activate;
on_paste1_activate;
on_plugin_preferences1_activate;
on_preferences1_activate;
on_previous_message1_activate;
on_print1_activate;
on_project_close1_activate;
on_project_new1_activate;
on_project_open1_activate;
on_project_properties1_activate;
on_quit1_activate;
on_redo1_activate;
on_redo1_activate;
on_reflow_lines_block1_activate;
on_remove_markers1_activate;
on_replace1_activate;
on_replace_spaces_activate;
on_replace_tabs_activate;
on_reset_indentation1_activate;
on_save1_activate;
on_save_all1_activate;
on_save_as1_activate;
on_search1_activate;
on_select_current_lines1_activate;
on_select_current_paragraph1_activate;
on_send_selection_to_vte1_activate;
on_set_file_readonly1_toggled;
on_show_color_chooser1_activate;
on_show_line_numbers1_toggled;
on_show_messages_window1_toggled;
on_show_toolbar1_toggled;
on_smart_line_indent1_activate;
on_spaces1_activate;
on_strip_trailing_spaces1_activate;
on_tabs1_activate;
on_tabs_and_spaces1_activate;
on_toggle_case1_activate;
on_toolbutton_reload_clicked;
on_tv_notebook_switch_page;
on_tv_notebook_switch_page_after;
on_undo1_activate;
on_undo1_activate;
on_use_auto_indentation1_toggled;
on_website1_activate;
on_window_delete_event;
on_window_state_event;
on_zoom_in1_activate;
on_zoom_out1_activate;
};

32
src/signalconn.c.in Normal file
View File

@ -0,0 +1,32 @@
static void builder_connect_func(GtkBuilder *builder, GObject *object,
const gchar *signal_name, const gchar *handler_name, GObject *connect_obj,
GConnectFlags flags, gpointer user_data)
{
GHashTable *hash = user_data;
GCallback callback;
callback = g_hash_table_lookup(hash, handler_name);
g_return_if_fail(callback);
if (connect_obj == NULL)
g_signal_connect_data(object, signal_name, callback, NULL, NULL, flags);
else
g_signal_connect_object(object, signal_name, callback, connect_obj, flags);
}
void callbacks_connect(GtkBuilder *builder)
{
GHashTable *hash;
g_return_if_fail(GTK_IS_BUILDER(builder));
hash = g_hash_table_new(g_str_hash, g_str_equal);
@callback_map@
gtk_builder_connect_signals_full(builder, builder_connect_func, hash);
g_hash_table_destroy(hash);
}

View File

@ -2448,7 +2448,7 @@ void ui_init_builder(void)
}
g_free(interface_file);
gtk_builder_connect_signals(builder, NULL);
callbacks_connect(builder);
edit_menu1 = GTK_WIDGET(gtk_builder_get_object(builder, "edit_menu1"));
prefs_dialog = GTK_WIDGET(gtk_builder_get_object(builder, "prefs_dialog"));