From 573554b9decf74f3b57ab6d26252700132255525 Mon Sep 17 00:00:00 2001 From: Přemysl Eric Janouch Date: Fri, 15 Oct 2021 12:08:44 +0200 Subject: sdgtk -> sdgui, improve build, mention in README It's finally not horrible. --- CMakeLists.txt | 24 +++-- README.adoc | 5 + src/sdgtk.c | 311 --------------------------------------------------------- src/sdgui.c | 311 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/sdtui.c | 29 +++++- src/utils.c | 28 ------ src/utils.h | 1 - 7 files changed, 358 insertions(+), 351 deletions(-) delete mode 100644 src/sdgtk.c create mode 100644 src/sdgui.c diff --git a/CMakeLists.txt b/CMakeLists.txt index f661cbc..38b0bf7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,6 +78,9 @@ if (WITH_X11) list (APPEND dependencies_LIBRARIES ${xcb_LIBRARIES}) endif () +pkg_check_modules (gtk gtk+-3.0) +option (WITH_GUI "Build a work-in-progress GTK+ UI" ${gtk_FOUND}) + link_directories (${dependencies_LIBRARY_DIRS}) include_directories (${ZLIB_INCLUDE_DIRS} ${icu_INCLUDE_DIRS} ${dependencies_INCLUDE_DIRS} ${Ncursesw_INCLUDE_DIRS} @@ -117,7 +120,7 @@ add_custom_target (docs ALL DEPENDS ${project_MAN_PAGES}) # Project libraries set (project_common_libraries ${ZLIB_LIBRARIES} ${icu_LIBRARIES} - ${dependencies_LIBRARIES} ${Ncursesw_LIBRARIES} termo-static) + ${dependencies_LIBRARIES}) set (project_common_headers ${PROJECT_BINARY_DIR}/config.h @@ -151,17 +154,17 @@ set (project_headers add_definitions (-DGLIB_DISABLE_DEPRECATION_WARNINGS) add_executable (${PROJECT_NAME} ${project_sources} ${project_headers} ${project_common_sources}) -target_link_libraries (${PROJECT_NAME} ${project_common_libraries}) +target_link_libraries (${PROJECT_NAME} ${project_common_libraries} + ${Ncursesw_LIBRARIES} termo-static) -# Experimental GTK+ frontend, we link it with ncurses but we don't care -pkg_check_modules (gtk gtk+-3.0) -if (gtk_FOUND) - add_executable (sdgtk EXCLUDE_FROM_ALL - src/sdgtk.c +# The same for the alternative GTK+ UI +if (WITH_GUI) + add_executable (sdgui + src/sdgui.c src/stardict-view.c ${project_common_sources}) - target_include_directories (sdgtk PUBLIC ${gtk_INCLUDE_DIRS}) - target_link_libraries (sdgtk ${gtk_LIBRARIES} ${project_common_libraries}) + target_include_directories (sdgui PUBLIC ${gtk_INCLUDE_DIRS}) + target_link_libraries (sdgui ${gtk_LIBRARIES} ${project_common_libraries}) endif () # Tools @@ -193,6 +196,9 @@ add_custom_target (dicts DEPENDS ${dicts_targets}) include (GNUInstallDirs) install (TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR}) install (FILES LICENSE DESTINATION ${CMAKE_INSTALL_DOCDIR}) +if (WITH_GUI) + install (TARGETS sdgui DESTINATION ${CMAKE_INSTALL_BINDIR}) +endif () foreach (page ${project_MAN_PAGES}) string (REGEX MATCH "\\.([0-9])$" manpage_suffix "${page}") diff --git a/README.adoc b/README.adoc index 6047f44..727d3a0 100644 --- a/README.adoc +++ b/README.adoc @@ -79,6 +79,11 @@ Linux and/or BSD distributions: Given the entangledness of this codebase, issues with the file format, and general undesirability of terminal UIs, it might be better to start anew. +Graphical UI +------------ +With GTK+ 3 development packages installed, an alternative, work-in-progress +frontend will be built and installed. + Contributing and Support ------------------------ Use https://git.janouch.name/p/sdtui to report any bugs, request features, diff --git a/src/sdgtk.c b/src/sdgtk.c deleted file mode 100644 index 3565bc6..0000000 --- a/src/sdgtk.c +++ /dev/null @@ -1,311 +0,0 @@ -/* - * StarDict GTK+ UI - * - * Copyright (c) 2020 - 2021, Přemysl Eric Janouch - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include -#include - -#include - -#include "config.h" -#include "stardict.h" -#include "utils.h" -#include "stardict-view.h" - -typedef struct dictionary Dictionary; - -struct dictionary -{ - const gchar *filename; ///< Filename - StardictDict *dict; ///< Stardict dictionary data - gchar *name; ///< Name to show - guint position; ///< Current position -}; - -static struct -{ - GtkWidget *window; ///< Top-level window - GtkWidget *notebook; ///< Notebook with tabs - GtkWidget *entry; ///< Search entry widget - GtkWidget *view; ///< Entries view - - gint dictionary; ///< Index of the current dictionary - Dictionary *dictionaries; ///< All open dictionaries - gsize dictionaries_len; ///< Total number of dictionaries - - gboolean watch_selection; ///< Following X11 PRIMARY? -} -g; - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -static gboolean -dictionary_load (Dictionary *self, gchar *filename, GError **e) -{ - self->filename = filename; - if (!(self->dict = stardict_dict_new (self->filename, e))) - return FALSE; - - if (!self->name) - { - self->name = g_strdup (stardict_info_get_book_name - (stardict_dict_get_info (self->dict))); - } - return TRUE; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -static gboolean -init (gchar **filenames, GError **e) -{ - while (filenames[g.dictionaries_len]) - g.dictionaries_len++; - - g.dictionaries = g_malloc0_n (sizeof *g.dictionaries, g.dictionaries_len); - for (gsize i = 0; i < g.dictionaries_len; i++) - { - Dictionary *dict = &g.dictionaries[i]; - if (!dictionary_load (dict, filenames[i], e)) - return FALSE; - } - return TRUE; -} - -static void -search (Dictionary *dict) -{ - GtkEntryBuffer *buf = gtk_entry_get_buffer (GTK_ENTRY (g.entry)); - const gchar *input_utf8 = gtk_entry_buffer_get_text (buf); - - StardictIterator *iterator = - stardict_dict_search (dict->dict, input_utf8, NULL); - dict->position = stardict_iterator_get_offset (iterator); - g_object_unref (iterator); - - stardict_view_set_position (STARDICT_VIEW (g.view), - dict->dict, dict->position); - stardict_view_set_matched (STARDICT_VIEW (g.view), input_utf8); -} - -static void -on_changed (G_GNUC_UNUSED GtkWidget *widget, G_GNUC_UNUSED gpointer data) -{ - search (&g.dictionaries[g.dictionary]); -} - -static void -on_selection_received (G_GNUC_UNUSED GtkClipboard *clipboard, const gchar *text, - G_GNUC_UNUSED gpointer data) -{ - if (!text) - return; - - gtk_entry_set_text (GTK_ENTRY (g.entry), text); - g_signal_emit_by_name (g.entry, - "move-cursor", GTK_MOVEMENT_BUFFER_ENDS, 1, FALSE); -} - -static void -on_selection (GtkClipboard *clipboard, GdkEvent *event, - G_GNUC_UNUSED gpointer data) -{ - if (g.watch_selection - && !gtk_window_has_toplevel_focus (GTK_WINDOW (g.window)) - && event->owner_change.owner != NULL) - gtk_clipboard_request_text (clipboard, on_selection_received, NULL); -} - -static void -on_selection_watch_toggle (GtkCheckMenuItem *item, G_GNUC_UNUSED gpointer data) -{ - g.watch_selection = gtk_check_menu_item_get_active (item); -} - -static void -on_switch_page (G_GNUC_UNUSED GtkWidget *widget, G_GNUC_UNUSED GtkWidget *page, - guint page_num, G_GNUC_UNUSED gpointer data) -{ - g.dictionary = page_num; - search (&g.dictionaries[g.dictionary]); -} - -static gboolean -on_key_press (G_GNUC_UNUSED GtkWidget *widget, GdkEvent *event, - G_GNUC_UNUSED gpointer data) -{ - if (event->key.state == GDK_CONTROL_MASK) - { - if (event->key.keyval == GDK_KEY_Page_Up) - { - gtk_notebook_prev_page (GTK_NOTEBOOK (g.notebook)); - return TRUE; - } - if (event->key.keyval == GDK_KEY_Page_Down) - { - gtk_notebook_next_page (GTK_NOTEBOOK (g.notebook)); - return TRUE; - } - } - if (event->key.state == GDK_MOD1_MASK) - { - if (event->key.keyval >= GDK_KEY_0 - && event->key.keyval <= GDK_KEY_9) - { - gint n = event->key.keyval - GDK_KEY_0; - gtk_notebook_set_current_page - (GTK_NOTEBOOK (g.notebook), n ? (n - 1) : 10); - return TRUE; - } - } - return FALSE; -} - -static void -on_destroy (G_GNUC_UNUSED GtkWidget *widget, G_GNUC_UNUSED gpointer data) -{ - gtk_main_quit (); -} - -static void -die_with_dialog (const gchar *message) -{ - GtkWidget *dialog = gtk_message_dialog_new (NULL, 0, - GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", message); - gtk_dialog_run (GTK_DIALOG (dialog)); - gtk_widget_destroy (dialog); - exit (EXIT_FAILURE); -} - -int -main (int argc, char *argv[]) -{ - if (!setlocale (LC_ALL, "")) - g_printerr ("%s: %s\n", _("Warning"), _("failed to set the locale")); - - bindtextdomain (GETTEXT_PACKAGE, GETTEXT_DIRNAME); - bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); - textdomain (GETTEXT_PACKAGE); - - gchar **filenames = NULL; - GOptionEntry option_entries[] = - { - {G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &filenames, - NULL, N_("FILE...")}, - {}, - }; - - GError *error = NULL; - gtk_init_with_args (&argc, &argv, N_("- StarDict GTK+ UI"), - option_entries, GETTEXT_PACKAGE, &error); - if (error) - { - g_warning ("%s", error->message); - g_error_free (error); - return 1; - } - - if (!filenames) - { - // TODO: eventually just load all dictionaries from configuration - die_with_dialog ("No arguments have been passed."); - } - if (!init (filenames, &error)) - die_with_dialog (error->message); - - // Some Adwaita stupidity - const char *style = "notebook header tab { padding: 2px 8px; margin: 0; }"; - - GdkScreen *screen = gdk_screen_get_default (); - GtkCssProvider *provider = gtk_css_provider_new (); - gtk_css_provider_load_from_data (provider, style, strlen (style), NULL); - gtk_style_context_add_provider_for_screen (screen, - GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); - - g.notebook = gtk_notebook_new (); - g_signal_connect (g.notebook, "switch-page", - G_CALLBACK (on_switch_page), NULL); - gtk_notebook_set_scrollable (GTK_NOTEBOOK (g.notebook), TRUE); - - g.watch_selection = TRUE; - GtkWidget *item = - gtk_check_menu_item_new_with_label (_("Follow selection")); - gtk_check_menu_item_set_active - (GTK_CHECK_MENU_ITEM (item), g.watch_selection); - g_signal_connect (item, "toggled", - G_CALLBACK (on_selection_watch_toggle), NULL); - - GtkWidget *menu = gtk_menu_new (); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); - gtk_widget_show_all (menu); - - GtkWidget *hamburger = gtk_menu_button_new (); - gtk_menu_button_set_direction (GTK_MENU_BUTTON (hamburger), GTK_ARROW_NONE); - gtk_menu_button_set_popup (GTK_MENU_BUTTON (hamburger), menu); - gtk_button_set_relief (GTK_BUTTON (hamburger), GTK_RELIEF_NONE); - gtk_widget_show (hamburger); - - gtk_notebook_set_action_widget - (GTK_NOTEBOOK (g.notebook), hamburger, GTK_PACK_END); - - // FIXME: when the clear icon shows, the widget changes in height - g.entry = gtk_search_entry_new (); - // TODO: attach to the "key-press-event" signal and implement ^W at least, - // though ^U is working already! Note that bindings can be done in CSS - // as well, if we have any extra specially for the editor - g_signal_connect (g.entry, "changed", G_CALLBACK (on_changed), g.view); - // TODO: make the entry have a background colour, rather than transparency - gtk_entry_set_has_frame (GTK_ENTRY (g.entry), FALSE); - - // TODO: supposedly attach to "key-press-event" here and react to - // PageUp/PageDown and up/down arrow keys... either here or in the Entry - g.window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_window_set_default_size (GTK_WINDOW (g.window), 300, 600); - g_signal_connect (g.window, "destroy", - G_CALLBACK (on_destroy), NULL); - g_signal_connect (g.window, "key-press-event", - G_CALLBACK (on_key_press), NULL); - - GtkWidget *superbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 1); - gtk_container_add (GTK_CONTAINER (g.window), superbox); - gtk_container_add (GTK_CONTAINER (superbox), g.notebook); - gtk_container_add (GTK_CONTAINER (superbox), g.entry); - gtk_container_add (GTK_CONTAINER (superbox), - gtk_separator_new (GTK_ORIENTATION_HORIZONTAL)); - - g.view = stardict_view_new (); - gtk_box_pack_end (GTK_BOX (superbox), g.view, TRUE, TRUE, 0); - - for (gsize i = 0; i < g.dictionaries_len; i++) - { - Dictionary *dict = &g.dictionaries[i]; - GtkWidget *dummy = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); - GtkWidget *label = gtk_label_new (dict->name); - gtk_notebook_append_page (GTK_NOTEBOOK (g.notebook), dummy, label); - } - - GtkClipboard *clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY); - g_signal_connect (clipboard, "owner-change", - G_CALLBACK (on_selection), NULL); - - gtk_widget_grab_focus (g.entry); - gtk_widget_show_all (g.window); - gtk_main (); - - g_strfreev (filenames); - return 0; -} diff --git a/src/sdgui.c b/src/sdgui.c new file mode 100644 index 0000000..3565bc6 --- /dev/null +++ b/src/sdgui.c @@ -0,0 +1,311 @@ +/* + * StarDict GTK+ UI + * + * Copyright (c) 2020 - 2021, Přemysl Eric Janouch + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include +#include + +#include + +#include "config.h" +#include "stardict.h" +#include "utils.h" +#include "stardict-view.h" + +typedef struct dictionary Dictionary; + +struct dictionary +{ + const gchar *filename; ///< Filename + StardictDict *dict; ///< Stardict dictionary data + gchar *name; ///< Name to show + guint position; ///< Current position +}; + +static struct +{ + GtkWidget *window; ///< Top-level window + GtkWidget *notebook; ///< Notebook with tabs + GtkWidget *entry; ///< Search entry widget + GtkWidget *view; ///< Entries view + + gint dictionary; ///< Index of the current dictionary + Dictionary *dictionaries; ///< All open dictionaries + gsize dictionaries_len; ///< Total number of dictionaries + + gboolean watch_selection; ///< Following X11 PRIMARY? +} +g; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +static gboolean +dictionary_load (Dictionary *self, gchar *filename, GError **e) +{ + self->filename = filename; + if (!(self->dict = stardict_dict_new (self->filename, e))) + return FALSE; + + if (!self->name) + { + self->name = g_strdup (stardict_info_get_book_name + (stardict_dict_get_info (self->dict))); + } + return TRUE; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +static gboolean +init (gchar **filenames, GError **e) +{ + while (filenames[g.dictionaries_len]) + g.dictionaries_len++; + + g.dictionaries = g_malloc0_n (sizeof *g.dictionaries, g.dictionaries_len); + for (gsize i = 0; i < g.dictionaries_len; i++) + { + Dictionary *dict = &g.dictionaries[i]; + if (!dictionary_load (dict, filenames[i], e)) + return FALSE; + } + return TRUE; +} + +static void +search (Dictionary *dict) +{ + GtkEntryBuffer *buf = gtk_entry_get_buffer (GTK_ENTRY (g.entry)); + const gchar *input_utf8 = gtk_entry_buffer_get_text (buf); + + StardictIterator *iterator = + stardict_dict_search (dict->dict, input_utf8, NULL); + dict->position = stardict_iterator_get_offset (iterator); + g_object_unref (iterator); + + stardict_view_set_position (STARDICT_VIEW (g.view), + dict->dict, dict->position); + stardict_view_set_matched (STARDICT_VIEW (g.view), input_utf8); +} + +static void +on_changed (G_GNUC_UNUSED GtkWidget *widget, G_GNUC_UNUSED gpointer data) +{ + search (&g.dictionaries[g.dictionary]); +} + +static void +on_selection_received (G_GNUC_UNUSED GtkClipboard *clipboard, const gchar *text, + G_GNUC_UNUSED gpointer data) +{ + if (!text) + return; + + gtk_entry_set_text (GTK_ENTRY (g.entry), text); + g_signal_emit_by_name (g.entry, + "move-cursor", GTK_MOVEMENT_BUFFER_ENDS, 1, FALSE); +} + +static void +on_selection (GtkClipboard *clipboard, GdkEvent *event, + G_GNUC_UNUSED gpointer data) +{ + if (g.watch_selection + && !gtk_window_has_toplevel_focus (GTK_WINDOW (g.window)) + && event->owner_change.owner != NULL) + gtk_clipboard_request_text (clipboard, on_selection_received, NULL); +} + +static void +on_selection_watch_toggle (GtkCheckMenuItem *item, G_GNUC_UNUSED gpointer data) +{ + g.watch_selection = gtk_check_menu_item_get_active (item); +} + +static void +on_switch_page (G_GNUC_UNUSED GtkWidget *widget, G_GNUC_UNUSED GtkWidget *page, + guint page_num, G_GNUC_UNUSED gpointer data) +{ + g.dictionary = page_num; + search (&g.dictionaries[g.dictionary]); +} + +static gboolean +on_key_press (G_GNUC_UNUSED GtkWidget *widget, GdkEvent *event, + G_GNUC_UNUSED gpointer data) +{ + if (event->key.state == GDK_CONTROL_MASK) + { + if (event->key.keyval == GDK_KEY_Page_Up) + { + gtk_notebook_prev_page (GTK_NOTEBOOK (g.notebook)); + return TRUE; + } + if (event->key.keyval == GDK_KEY_Page_Down) + { + gtk_notebook_next_page (GTK_NOTEBOOK (g.notebook)); + return TRUE; + } + } + if (event->key.state == GDK_MOD1_MASK) + { + if (event->key.keyval >= GDK_KEY_0 + && event->key.keyval <= GDK_KEY_9) + { + gint n = event->key.keyval - GDK_KEY_0; + gtk_notebook_set_current_page + (GTK_NOTEBOOK (g.notebook), n ? (n - 1) : 10); + return TRUE; + } + } + return FALSE; +} + +static void +on_destroy (G_GNUC_UNUSED GtkWidget *widget, G_GNUC_UNUSED gpointer data) +{ + gtk_main_quit (); +} + +static void +die_with_dialog (const gchar *message) +{ + GtkWidget *dialog = gtk_message_dialog_new (NULL, 0, + GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", message); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + exit (EXIT_FAILURE); +} + +int +main (int argc, char *argv[]) +{ + if (!setlocale (LC_ALL, "")) + g_printerr ("%s: %s\n", _("Warning"), _("failed to set the locale")); + + bindtextdomain (GETTEXT_PACKAGE, GETTEXT_DIRNAME); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + textdomain (GETTEXT_PACKAGE); + + gchar **filenames = NULL; + GOptionEntry option_entries[] = + { + {G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &filenames, + NULL, N_("FILE...")}, + {}, + }; + + GError *error = NULL; + gtk_init_with_args (&argc, &argv, N_("- StarDict GTK+ UI"), + option_entries, GETTEXT_PACKAGE, &error); + if (error) + { + g_warning ("%s", error->message); + g_error_free (error); + return 1; + } + + if (!filenames) + { + // TODO: eventually just load all dictionaries from configuration + die_with_dialog ("No arguments have been passed."); + } + if (!init (filenames, &error)) + die_with_dialog (error->message); + + // Some Adwaita stupidity + const char *style = "notebook header tab { padding: 2px 8px; margin: 0; }"; + + GdkScreen *screen = gdk_screen_get_default (); + GtkCssProvider *provider = gtk_css_provider_new (); + gtk_css_provider_load_from_data (provider, style, strlen (style), NULL); + gtk_style_context_add_provider_for_screen (screen, + GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + + g.notebook = gtk_notebook_new (); + g_signal_connect (g.notebook, "switch-page", + G_CALLBACK (on_switch_page), NULL); + gtk_notebook_set_scrollable (GTK_NOTEBOOK (g.notebook), TRUE); + + g.watch_selection = TRUE; + GtkWidget *item = + gtk_check_menu_item_new_with_label (_("Follow selection")); + gtk_check_menu_item_set_active + (GTK_CHECK_MENU_ITEM (item), g.watch_selection); + g_signal_connect (item, "toggled", + G_CALLBACK (on_selection_watch_toggle), NULL); + + GtkWidget *menu = gtk_menu_new (); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_widget_show_all (menu); + + GtkWidget *hamburger = gtk_menu_button_new (); + gtk_menu_button_set_direction (GTK_MENU_BUTTON (hamburger), GTK_ARROW_NONE); + gtk_menu_button_set_popup (GTK_MENU_BUTTON (hamburger), menu); + gtk_button_set_relief (GTK_BUTTON (hamburger), GTK_RELIEF_NONE); + gtk_widget_show (hamburger); + + gtk_notebook_set_action_widget + (GTK_NOTEBOOK (g.notebook), hamburger, GTK_PACK_END); + + // FIXME: when the clear icon shows, the widget changes in height + g.entry = gtk_search_entry_new (); + // TODO: attach to the "key-press-event" signal and implement ^W at least, + // though ^U is working already! Note that bindings can be done in CSS + // as well, if we have any extra specially for the editor + g_signal_connect (g.entry, "changed", G_CALLBACK (on_changed), g.view); + // TODO: make the entry have a background colour, rather than transparency + gtk_entry_set_has_frame (GTK_ENTRY (g.entry), FALSE); + + // TODO: supposedly attach to "key-press-event" here and react to + // PageUp/PageDown and up/down arrow keys... either here or in the Entry + g.window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_default_size (GTK_WINDOW (g.window), 300, 600); + g_signal_connect (g.window, "destroy", + G_CALLBACK (on_destroy), NULL); + g_signal_connect (g.window, "key-press-event", + G_CALLBACK (on_key_press), NULL); + + GtkWidget *superbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 1); + gtk_container_add (GTK_CONTAINER (g.window), superbox); + gtk_container_add (GTK_CONTAINER (superbox), g.notebook); + gtk_container_add (GTK_CONTAINER (superbox), g.entry); + gtk_container_add (GTK_CONTAINER (superbox), + gtk_separator_new (GTK_ORIENTATION_HORIZONTAL)); + + g.view = stardict_view_new (); + gtk_box_pack_end (GTK_BOX (superbox), g.view, TRUE, TRUE, 0); + + for (gsize i = 0; i < g.dictionaries_len; i++) + { + Dictionary *dict = &g.dictionaries[i]; + GtkWidget *dummy = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); + GtkWidget *label = gtk_label_new (dict->name); + gtk_notebook_append_page (GTK_NOTEBOOK (g.notebook), dummy, label); + } + + GtkClipboard *clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY); + g_signal_connect (clipboard, "owner-change", + G_CALLBACK (on_selection), NULL); + + gtk_widget_grab_focus (g.entry); + gtk_widget_show_all (g.window); + gtk_main (); + + g_strfreev (filenames); + return 0; +} diff --git a/src/sdtui.c b/src/sdtui.c index 3be34f4..1158d05 100644 --- a/src/sdtui.c +++ b/src/sdtui.c @@ -36,8 +36,12 @@ #include #include -#include // input -#include // output +#include // input +#include // output +#include +#ifndef TIOCGWINSZ +#include +#endif // ! TIOCGWINSZ #include "config.h" #include "stardict.h" @@ -62,6 +66,27 @@ unichar_width (gunichar ch) return 1 + g_unichar_iswide (ch); } +void +update_curses_terminal_size (void) +{ +#if defined (HAVE_RESIZETERM) && defined (TIOCGWINSZ) + struct winsize size; + if (!ioctl (STDOUT_FILENO, TIOCGWINSZ, (char *) &size)) + { + char *row = getenv ("LINES"); + char *col = getenv ("COLUMNS"); + unsigned long tmp; + resizeterm ( + (row && xstrtoul (&tmp, row, 10)) ? tmp : size.ws_row, + (col && xstrtoul (&tmp, col, 10)) ? tmp : size.ws_col); + } +#else // HAVE_RESIZETERM && TIOCGWINSZ + // The standard endwin/refresh sequence makes the terminal flicker. + endwin (); + refresh (); +#endif // HAVE_RESIZETERM && TIOCGWINSZ +} + static guint add_read_watch (int fd, GIOFunc func, gpointer user_data) { diff --git a/src/utils.c b/src/utils.c index 275e4e1..3bba022 100644 --- a/src/utils.c +++ b/src/utils.c @@ -23,12 +23,6 @@ #include #include -#include -#include -#ifndef TIOCGWINSZ -#include -#endif // ! TIOCGWINSZ - #include "config.h" #include "utils.h" @@ -101,28 +95,6 @@ xstrtoul (unsigned long *out, const char *s, int base) return errno == 0 && !*end && end != s; } -// Didn't want to have this ugly piece of code in the main source file; -// the standard endwin/refresh sequence makes the terminal flicker. -void -update_curses_terminal_size (void) -{ -#if defined (HAVE_RESIZETERM) && defined (TIOCGWINSZ) - struct winsize size; - if (!ioctl (STDOUT_FILENO, TIOCGWINSZ, (char *) &size)) - { - char *row = getenv ("LINES"); - char *col = getenv ("COLUMNS"); - unsigned long tmp; - resizeterm ( - (row && xstrtoul (&tmp, row, 10)) ? tmp : size.ws_row, - (col && xstrtoul (&tmp, col, 10)) ? tmp : size.ws_col); - } -#else // HAVE_RESIZETERM && TIOCGWINSZ - endwin (); - refresh (); -#endif // HAVE_RESIZETERM && TIOCGWINSZ -} - /// Print a fatal error message and terminate the process immediately. void fatal (const gchar *format, ...) diff --git a/src/utils.h b/src/utils.h index 99ad19a..b47daa9 100644 --- a/src/utils.h +++ b/src/utils.h @@ -41,7 +41,6 @@ gchar *xdxf_to_pango_markup_with_reduced_effort (const gchar *xml); gboolean stream_read_all (GByteArray *ba, GInputStream *is, GError **error); gchar *stream_read_string (GDataInputStream *dis, GError **error); gboolean xstrtoul (unsigned long *out, const char *s, int base); -void update_curses_terminal_size (void); void fatal (const gchar *format, ...) G_GNUC_PRINTF (1, 2) G_GNUC_NORETURN; #endif // ! UTILS_H -- cgit v1.2.3-70-g09d2