[balsa/wip/gtk4] GtkTextView has no populate-menu signal
- From: Peter Bloomfield <peterb src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [balsa/wip/gtk4] GtkTextView has no populate-menu signal
- Date: Fri, 27 Sep 2019 02:12:47 +0000 (UTC)
commit 6d4bc7acdcbdde2e0555e63062ce707028f21dfa
Author: Peter Bloomfield <PeterBloomfield bellsouth net>
Date: Thu Sep 26 22:09:58 2019 -0400
GtkTextView has no populate-menu signal
The replacement is gtk_text_view_set_extra_menu(), which takes a GMenu
argument, so we have to set up functions to provide one.
libbalsa/libbalsa-vfs.c | 123 ++++++++++++++++++++++---
libbalsa/libbalsa-vfs.h | 9 ++
src/balsa-mime-widget-callbacks.c | 19 ++++
src/balsa-mime-widget-callbacks.h | 1 +
src/balsa-mime-widget-text.c | 187 +++++++++++++++++++++++++-------------
5 files changed, 263 insertions(+), 76 deletions(-)
---
diff --git a/libbalsa/libbalsa-vfs.c b/libbalsa/libbalsa-vfs.c
index 0d95ff044..7a15ce850 100644
--- a/libbalsa/libbalsa-vfs.c
+++ b/libbalsa/libbalsa-vfs.c
@@ -579,29 +579,66 @@ libbalsa_vfs_file_unlink(const LibbalsaVfs * file, GError **err)
return result;
}
-
-gboolean
-libbalsa_vfs_launch_app(const LibbalsaVfs * file, GObject * object, GError **err)
+static gboolean
+launch_app(const LibbalsaVfs *file,
+ GAppInfo *app,
+ GError **err)
{
- GAppInfo *app;
+ gboolean result = FALSE;
GList * args;
- gboolean result;
- g_return_val_if_fail(file != NULL, FALSE);
- g_return_val_if_fail(object != NULL, FALSE);
-
- app = G_APP_INFO(g_object_get_data(object, LIBBALSA_VFS_MIME_ACTION));
- if (!app) {
+ if (app == NULL) {
g_set_error(err, LIBBALSA_VFS_ERROR_QUARK, -1,
_("Cannot launch, missing application"));
- return FALSE;
+ return result;
}
+
args = g_list_prepend(NULL, file->priv->gio_gfile);
result = g_app_info_launch(app, args, NULL, err);
g_list_free(args);
+
return result;
}
+gboolean
+libbalsa_vfs_launch_app(const LibbalsaVfs * file, GObject * object, GError **err)
+{
+ GAppInfo *app;
+
+ g_return_val_if_fail(file != NULL, FALSE);
+ g_return_val_if_fail(object != NULL, FALSE);
+
+ app = G_APP_INFO(g_object_get_data(object, LIBBALSA_VFS_MIME_ACTION));
+
+ return launch_app(file, app, err);
+}
+
+gboolean
+libbalsa_vfs_launch_app_gmenu(const LibbalsaVfs *file,
+ const gchar *app_id,
+ GError **err)
+{
+ GList *apps;
+ GList *app_l;
+ GAppInfo *app = NULL;
+
+ g_return_val_if_fail(file != NULL, FALSE);
+ g_return_val_if_fail(app_id != NULL, FALSE);
+
+ apps = g_app_info_get_all();
+
+ for (app_l = apps; app_l != NULL; app_l = app_l->next) {
+ if (g_strcmp0(g_app_info_get_id(app_l->data), app_id) == 0)
+ break;
+ }
+
+ if (app_l != NULL)
+ app = g_object_ref(app_l->data);
+
+ g_list_free_full(apps, g_object_unref);
+
+ return launch_app(file, app, err);
+}
gboolean
libbalsa_vfs_launch_app_for_body(LibBalsaMessageBody * mime_body,
@@ -626,6 +663,29 @@ libbalsa_vfs_launch_app_for_body(LibBalsaMessageBody * mime_body,
return result;
}
+gboolean
+libbalsa_vfs_launch_app_for_body_gmenu(const gchar *app_id,
+ LibBalsaMessageBody *mime_body,
+ GError **err)
+{
+ gchar *uri;
+ LibbalsaVfs * file;
+ gboolean result;
+
+ g_return_val_if_fail(mime_body != NULL, FALSE);
+
+ if (!libbalsa_message_body_save_temporary(mime_body, err))
+ return FALSE;
+
+ uri = g_filename_to_uri(mime_body->temp_filename, NULL, NULL);
+ file = libbalsa_vfs_new_from_uri(uri);
+ g_free(uri);
+ result = libbalsa_vfs_launch_app_gmenu(file, app_id, err);
+ g_object_unref(file);
+
+ return result;
+}
+
gchar *
libbalsa_vfs_content_description(const gchar * mime_type)
@@ -654,6 +714,7 @@ libbalsa_vfs_content_type_of_buffer(const guchar * buffer,
}
+/* fill the passed menu with vfs items */
static void
gio_add_vfs_menu_item(GtkMenu * menu, GAppInfo *app, GCallback callback,
gpointer data)
@@ -670,7 +731,6 @@ gio_add_vfs_menu_item(GtkMenu * menu, GAppInfo *app, GCallback callback,
}
-/* fill the passed menu with vfs items */
void
libbalsa_vfs_fill_menu_by_content_type(GtkMenu * menu,
const gchar * content_type,
@@ -697,6 +757,45 @@ libbalsa_vfs_fill_menu_by_content_type(GtkMenu * menu,
g_list_free_full(app_list, g_object_unref);
}
+
+/* fill the passed GMenu with vfs items */
+static void
+gio_add_vfs_gmenu_item(GMenu * menu, const gchar *action, GAppInfo *app)
+{
+ gchar *menu_label =
+ g_strdup_printf(_("Open with %s"), g_app_info_get_display_name(app));
+ gchar *detailed_action =
+ g_strdup_printf("%s::%s", action, g_app_info_get_id(app));
+
+ g_menu_append(menu, menu_label, detailed_action);
+ g_free(detailed_action);
+ g_free(menu_label);
+}
+
+void
+libbalsa_vfs_fill_gmenu_by_content_type(GMenu * menu,
+ const gchar * action,
+ const gchar * content_type)
+{
+ GList* list;
+ GAppInfo *def_app;
+ GList *app_list;
+
+ if ((def_app = g_app_info_get_default_for_type(content_type, FALSE)))
+ gio_add_vfs_gmenu_item(menu, action, def_app);
+
+ app_list = g_app_info_get_all_for_type(content_type);
+ for (list = app_list; list != NULL; list = list->next) {
+ GAppInfo *app = G_APP_INFO(list->data);
+
+ if (app && g_app_info_should_show(app) &&
+ (!def_app || !g_app_info_equal(app, def_app)))
+ gio_add_vfs_gmenu_item(menu, action, app);
+ }
+ g_clear_object(&def_app);
+ g_list_free_full(app_list, g_object_unref);
+}
+
GtkWidget *
libbalsa_vfs_mime_button(LibBalsaMessageBody * mime_body,
const gchar * content_type,
diff --git a/libbalsa/libbalsa-vfs.h b/libbalsa/libbalsa-vfs.h
index 4a0ad6e5c..b7af02a75 100644
--- a/libbalsa/libbalsa-vfs.h
+++ b/libbalsa/libbalsa-vfs.h
@@ -71,13 +71,22 @@ gint libbalsa_vfs_file_unlink(const LibbalsaVfs *file,
gboolean libbalsa_vfs_launch_app(const LibbalsaVfs *file,
GObject *object,
GError **err);
+gboolean libbalsa_vfs_launch_app_gmenu(const LibbalsaVfs *file,
+ const gchar *app_id,
+ GError **err);
gboolean libbalsa_vfs_launch_app_for_body(LibBalsaMessageBody *mime_body,
GObject *object,
GError **err);
+gboolean libbalsa_vfs_launch_app_for_body_gmenu(const gchar *app_id,
+ LibBalsaMessageBody *mime_body,
+ GError **err);
void libbalsa_vfs_fill_menu_by_content_type(GtkMenu *menu,
const gchar *content_type,
GCallback callback,
gpointer data);
+void libbalsa_vfs_fill_gmenu_by_content_type(GMenu *menu,
+ const gchar *action,
+ const gchar *content_type);
GtkWidget *libbalsa_vfs_mime_button(LibBalsaMessageBody *mime_body,
const gchar *content_type,
GCallback callback,
diff --git a/src/balsa-mime-widget-callbacks.c b/src/balsa-mime-widget-callbacks.c
index a8f5ae150..0373def35 100644
--- a/src/balsa-mime-widget-callbacks.c
+++ b/src/balsa-mime-widget-callbacks.c
@@ -55,6 +55,25 @@ balsa_mime_widget_ctx_menu_cb(GtkWidget * menu_item,
}
+void
+balsa_mime_widget_ctx_gmenu_cb(const gchar *app_id,
+ LibBalsaMessageBody *mime_body)
+{
+ GError *err = NULL;
+ gboolean result;
+
+ g_return_if_fail(mime_body != NULL);
+ result = libbalsa_vfs_launch_app_for_body_gmenu(app_id,
+ mime_body,
+ &err);
+ if (!result)
+ balsa_information(LIBBALSA_INFORMATION_WARNING,
+ _("Could not launch application: %s"),
+ err ? err->message : "Unknown error");
+ g_clear_error(&err);
+}
+
+
/** Pops up a "save part" dialog for a message part.
@param parent_widget the widget located in the window that is to
diff --git a/src/balsa-mime-widget-callbacks.h b/src/balsa-mime-widget-callbacks.h
index dfa7a64ea..5145368a3 100644
--- a/src/balsa-mime-widget-callbacks.h
+++ b/src/balsa-mime-widget-callbacks.h
@@ -28,6 +28,7 @@ G_BEGIN_DECLS
void balsa_mime_widget_ctx_menu_cb(GtkWidget * menu_item, LibBalsaMessageBody * mime_body);
+void balsa_mime_widget_ctx_gmenu_cb(const gchar *app_id, LibBalsaMessageBody *mime_body);
void balsa_mime_widget_ctx_menu_save(GtkWidget * parent_widget,
LibBalsaMessageBody * mime_body);
gboolean balsa_mime_widget_key_press_event(GtkEventControllerKey *key_controller,
diff --git a/src/balsa-mime-widget-text.c b/src/balsa-mime-widget-text.c
index 93c790b8c..d729d539a 100644
--- a/src/balsa-mime-widget-text.c
+++ b/src/balsa-mime-widget-text.c
@@ -33,6 +33,7 @@
#include "balsa-mime-widget.h"
#include "balsa-mime-widget-callbacks.h"
#include "balsa-cite-bar.h"
+#include "libbalsa/application-helpers.h"
#if HAVE_GTKSOURCEVIEW
#include <gtksourceview/gtksource.h>
@@ -43,8 +44,6 @@ static GtkWidget * create_text_widget(const char * content_type);
static void bm_modify_font_from_string(GtkWidget * widget, const char *font);
static GtkTextTag * quote_tag(GtkTextBuffer * buffer, gint level, gint margin);
static void fix_text_widget(GtkWidget *widget, gpointer data);
-static void text_view_populate_popup(GtkWidget *widget, GtkMenu *menu,
- gpointer user_data);
#ifdef HAVE_HTML_WIDGET
static BalsaMimeWidget *bm_widget_new_html(BalsaMessage * bm,
@@ -123,6 +122,12 @@ static void fill_text_buf_cited(BalsaMimeWidgetText *mwt,
const gchar *text_body,
gboolean is_flowed,
gboolean is_plain);
+static gboolean text_view_url_popup(GtkWidget *widget,
+ BalsaMimeWidgetText *mwt);
+static void mwt_set_extra_menu(GtkWidget *widget,
+ BalsaMimeWidgetText *mwt);
+static void structured_phrases_toggle(BalsaMimeWidgetText *mwt,
+ gboolean new_hl);
#define PHRASE_HIGHLIGHT_ON 1
@@ -171,9 +176,74 @@ balsa_mime_widget_text_class_init(BalsaMimeWidgetTextClass * klass)
object_class->finalize = balsa_mime_widget_text_finalize;
}
+static void
+bmwt_launch_app_change_state(GSimpleAction * action,
+ GVariant * state,
+ gpointer user_data)
+{
+ BalsaMimeWidgetText *mwt = user_data;
+ const gchar *app_id;
+
+ app_id = g_variant_get_string(state, NULL);
+ balsa_mime_widget_ctx_gmenu_cb(app_id, mwt->mime_body);
+
+ g_simple_action_set_state(action, state);
+}
+
+static void
+bmwt_save_activated(GSimpleAction * action,
+ GVariant * state,
+ gpointer user_data)
+{
+ BalsaMimeWidgetText *mwt = user_data;
+
+ balsa_mime_widget_ctx_menu_save(GTK_WIDGET(mwt), mwt->mime_body);
+
+ g_simple_action_set_state(action, state);
+}
+
+static void
+bmwt_highlight_change_state(GSimpleAction * action,
+ GVariant * state,
+ gpointer user_data)
+{
+ BalsaMimeWidgetText *mwt = user_data;
+ gboolean new_hl;
+
+ new_hl = g_variant_get_boolean(state);
+ structured_phrases_toggle(mwt, new_hl);
+
+ g_simple_action_set_state(action, state);
+}
+
+static GActionEntry win_entries[] = {
+ {
+ "launch-app",
+ libbalsa_radio_activated,
+ "s",
+ "''",
+ bmwt_launch_app_change_state},
+ {
+ "save-part",
+ bmwt_save_activated},
+ {
+ "highlight-structured-phrases",
+ libbalsa_toggle_activated,
+ NULL,
+ "true",
+ bmwt_highlight_change_state}
+};
+
static void
balsa_mime_widget_text_init(BalsaMimeWidgetText * self)
{
+ GSimpleActionGroup *simple = g_simple_action_group_new();
+
+ g_action_map_add_action_entries(G_ACTION_MAP(simple),
+ win_entries, G_N_ELEMENTS(win_entries),
+ self);
+ gtk_widget_insert_action_group(GTK_WIDGET(self), "win", G_ACTION_GROUP(simple));
+ g_object_unref(simple);
}
/*
@@ -265,7 +335,12 @@ balsa_mime_widget_new_text(BalsaMessage * bm, LibBalsaMessageBody * mime_body,
/* create the mime object and the text/source view widget */
mwt = g_object_new(BALSA_TYPE_MIME_WIDGET_TEXT, NULL);
+ mwt->mime_body = mime_body;
+
mwt->text_widget = widget = create_text_widget(content_type);
+ g_signal_connect(widget, "popup-menu",
+ G_CALLBACK(text_view_url_popup), mwt);
+ mwt_set_extra_menu(widget, mwt);
/* configure text or source view */
gtk_text_view_set_editable(GTK_TEXT_VIEW(widget), FALSE);
@@ -293,10 +368,6 @@ balsa_mime_widget_new_text(BalsaMessage * bm, LibBalsaMessageBody * mime_body,
G_CALLBACK(balsa_mime_widget_key_press_event), bm);
gtk_widget_add_controller(widget, controller);
- mwt->mime_body = mime_body;
- g_signal_connect(G_OBJECT(widget), "populate-popup",
- G_CALLBACK(text_view_populate_popup), mwt);
-
buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget));
fill_text_buf_cited(mwt, widget, ptr,
@@ -462,8 +533,7 @@ quote_tag(GtkTextBuffer * buffer, gint level, gint margin)
return tag;
}
-/* set the gtk_text widget's cursor to a vertical bar
- fix event mask so that pointer motions are reported (if necessary) */
+/* set the gtk_text widget's cursor to a vertical bar */
static void
fix_text_widget(GtkWidget *widget, gpointer data)
{
@@ -477,26 +547,15 @@ fix_text_widget(GtkWidget *widget, gpointer data)
}
static void
-gtk_widget_destroy_insensitive(GtkWidget * widget)
-{
- if (!gtk_widget_get_sensitive(widget) ||
- GTK_IS_SEPARATOR_MENU_ITEM(widget))
- gtk_widget_destroy(widget);
-}
-
-static void
-structured_phrases_toggle(GtkCheckMenuItem *checkmenuitem,
- gpointer user_data)
+structured_phrases_toggle(BalsaMimeWidgetText *mwt,
+ gboolean new_hl)
{
- BalsaMimeWidgetText *mwt = user_data;
GtkTextView * text_view;
GtkTextTagTable * table;
GtkTextTag * tag;
- gboolean new_hl;
text_view = GTK_TEXT_VIEW(mwt->text_widget);
table = gtk_text_buffer_get_tag_table(gtk_text_view_get_buffer(text_view));
- new_hl = gtk_check_menu_item_get_active(checkmenuitem);
if (!table || mwt->phrase_hl == 0 ||
(mwt->phrase_hl == PHRASE_HIGHLIGHT_ON && new_hl) ||
(mwt->phrase_hl == PHRASE_HIGHLIGHT_OFF && !new_hl))
@@ -543,72 +602,72 @@ url_send_cb(GtkWidget * menu_item, message_url_t * uri)
}
static gboolean
-text_view_url_popup(GtkWidget *widget, GtkMenu *menu, message_url_t *url)
+text_view_url_popup(GtkWidget *widget,
+ BalsaMimeWidgetText *mwt)
{
+ message_url_t *url = mwt->current_url;
+ GtkMenu *menu;
GtkWidget *menu_item;
+ GdkEvent *event;
/* check if we are over an url */
if (url == NULL)
return FALSE;
/* build a popup to copy or open the URL */
- gtk_container_foreach(GTK_CONTAINER(menu),
- (GtkCallback)gtk_widget_destroy, NULL);
+ menu = (GtkMenu *) gtk_menu_new();
- menu_item = gtk_menu_item_new_with_label (_("Copy link"));
- g_signal_connect (G_OBJECT (menu_item), "activate",
- G_CALLBACK (url_copy_cb), (gpointer)url);
- gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
+ menu_item = gtk_menu_item_new_with_label(_("Copy link"));
+ g_signal_connect(menu_item, "activate",
+ G_CALLBACK(url_copy_cb), url);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
- menu_item = gtk_menu_item_new_with_label (_("Open link"));
- g_signal_connect (G_OBJECT (menu_item), "activate",
- G_CALLBACK (url_open_cb), (gpointer)url);
- gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
+ menu_item = gtk_menu_item_new_with_label(_("Open link"));
+ g_signal_connect(menu_item, "activate",
+ G_CALLBACK(url_open_cb), url);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
- menu_item = gtk_menu_item_new_with_label (_("Send link…"));
- g_signal_connect (G_OBJECT (menu_item), "activate",
- G_CALLBACK (url_send_cb), (gpointer)url);
+ menu_item = gtk_menu_item_new_with_label(_("Send link…"));
+ g_signal_connect(menu_item, "activate",
+ G_CALLBACK(url_send_cb), url);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
+ event = gtk_get_current_event();
+ if (event != NULL) {
+ gtk_menu_popup_at_pointer(GTK_MENU(menu), event);
+ g_object_unref(event);
+ } else {
+ gtk_menu_popup_at_widget(GTK_MENU(menu), widget,
+ GDK_GRAVITY_CENTER, GDK_GRAVITY_CENTER,
+ NULL);
+ }
+
return TRUE;
}
static void
-text_view_populate_popup(GtkWidget *widget, GtkMenu *menu,
- gpointer user_data)
+mwt_set_extra_menu(GtkWidget *widget,
+ BalsaMimeWidgetText *mwt)
{
- BalsaMimeWidgetText *mwt = user_data;
- GtkWidget *menu_item;
+ GMenu *menu = g_menu_new();
- gtk_widget_hide(GTK_WIDGET(menu));
- gtk_container_foreach(GTK_CONTAINER(menu),
- (GtkCallback) gtk_widget_hide, NULL);
- if (text_view_url_popup(widget, menu, mwt->current_url))
- return;
+ libbalsa_vfs_fill_gmenu_by_content_type(menu,
+ "launch-app",
+ "text/plain");
- gtk_container_foreach(GTK_CONTAINER(menu),
- (GtkCallback)gtk_widget_destroy_insensitive, NULL);
- gtk_menu_shell_append(GTK_MENU_SHELL(menu),
- gtk_separator_menu_item_new ());
- libbalsa_vfs_fill_menu_by_content_type(menu, "text/plain",
- G_CALLBACK (balsa_mime_widget_ctx_menu_cb),
- (gpointer)mwt->mime_body);
-
- menu_item = gtk_menu_item_new_with_label (_("Save…"));
- g_signal_connect (G_OBJECT (menu_item), "activate",
- G_CALLBACK (balsa_mime_widget_ctx_menu_save), mwt->mime_body);
- gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
+ g_menu_append(menu, _("Save…"), "save-part");
if (mwt->phrase_hl != 0) {
- gtk_menu_shell_append(GTK_MENU_SHELL(menu),
- gtk_separator_menu_item_new ());
- menu_item = gtk_check_menu_item_new_with_label (_("Highlight structured phrases"));
- gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM(menu_item),
- mwt->phrase_hl == PHRASE_HIGHLIGHT_ON);
- g_signal_connect (G_OBJECT (menu_item), "toggled",
- G_CALLBACK (structured_phrases_toggle), mwt);
- gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
+ GMenu *section = g_menu_new();
+
+ g_menu_append(section, _("Highlight structured phrases"),
+ "highlight-structured-phrases");
+
+ g_menu_append_section(menu, NULL, G_MENU_MODEL(section));
}
+
+ gtk_text_view_set_extra_menu(GTK_TEXT_VIEW(widget), G_MENU_MODEL(menu));
+ g_object_unref(menu);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]