[balsa/popover: 59/65] Various: Fill some menus with stateless GMenuItems
- From: Peter Bloomfield <peterb src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [balsa/popover: 59/65] Various: Fill some menus with stateless GMenuItems
- Date: Thu, 20 Aug 2020 20:54:34 +0000 (UTC)
commit 2e04b91e93a5ff003190389956c4f2376409249a
Author: Peter Bloomfield <PeterBloomfield bellsouth net>
Date: Fri Jun 26 16:21:52 2020 -0400
Various: Fill some menus with stateless GMenuItems
Fill the open-with menus with stateless GMenuItems, so that they are
rendered without radio buttons.
Instead of passing the app's name as the state of a stateful GMenuItem,
pass the GAppInfo itself as GObject data on a convenient object.
* libbalsa/libbalsa-vfs.c (libbalsa_vfs_launch_app),
(libbalsa_vfs_launch_app_for_body), (gio_add_vfs_menu_item),
(libbalsa_vfs_fill_menu_by_content_type),
(libbalsa_vfs_mime_button):
* libbalsa/libbalsa-vfs.h:
* src/balsa-message.c (open_with_activated), (part_add_actions),
(part_create_menu):
* src/balsa-mime-widget-callbacks.c
(balsa_mime_widget_ctx_menu_launch_app),
(balsa_mime_widget_ctx_menu_cb):
* src/balsa-mime-widget-callbacks.h:
* src/balsa-mime-widget-text.c (open_with_activated),
(text_view_populate_popup), (bmwt_html_open_with_activated),
(bmwt_html_populate_popup_menu), (bmwt_html_button_press_cb):
* src/sendmsg-window.c (attachment_menu_vfs_cb), (add_attachment):
ChangeLog | 34 +++++++++-------
libbalsa/libbalsa-vfs.c | 84 +++++++++++++++++++++++----------------
libbalsa/libbalsa-vfs.h | 9 +++--
src/balsa-message.c | 43 ++++++++++----------
src/balsa-mime-widget-callbacks.c | 4 +-
src/balsa-mime-widget-callbacks.h | 4 +-
src/balsa-mime-widget-text.c | 55 +++++++++++++------------
src/sendmsg-window.c | 16 +++++---
8 files changed, 142 insertions(+), 107 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 58f6ec530..249af9816 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -83,23 +83,29 @@
* src/sendmsg-window.c (attachments_add), (drag_data_quote):
-2020-06-28 Peter Bloomfield <pbloomfield bellsouth net>
+2020-06-26 Peter Bloomfield <pbloomfield bellsouth net>
- compose-window: Make the "Open" option on the urlref-attachment
- context menu work.
+ Various: Fill the open-with menus with stateless GMenuItems, so
+ that they are rendered without radio buttons.
- * src/sendmsg-window.cs
- (on_open_url_cb): Get the top-level window from the compose
- window; getting it from the menu-item leads to a Wayland
- error;
- (add_urlref_attachment): Populate BalsaAttachInfo:file_uri.
+ Instead, pass the GAppInfo as GObject data on a convenient
+ object.
-2020-06-24 Peter Bloomfield <pbloomfield bellsouth net>
-
- mime-widget-text: Actually pop up the context menu when
- right-clicking on an URL.
-
- * src/balsa-mime-widget-text.c (text_view_url_popup):
+ * libbalsa/libbalsa-vfs.c (libbalsa_vfs_launch_app),
+ (libbalsa_vfs_launch_app_for_body), (gio_add_vfs_menu_item),
+ (libbalsa_vfs_fill_menu_by_content_type),
+ (libbalsa_vfs_mime_button):
+ * libbalsa/libbalsa-vfs.h:
+ * src/balsa-message.c (open_with_activated), (part_add_actions),
+ (part_create_menu):
+ * src/balsa-mime-widget-callbacks.c
+ (balsa_mime_widget_ctx_menu_launch_app),
+ (balsa_mime_widget_ctx_menu_cb):
+ * src/balsa-mime-widget-callbacks.h:
+ * src/balsa-mime-widget-text.c (open_with_activated),
+ (text_view_populate_popup), (bmwt_html_open_with_activated),
+ (bmwt_html_populate_popup_menu), (bmwt_html_button_press_cb):
+ * src/sendmsg-window.c (attachment_menu_vfs_cb), (add_attachment):
2020-06-22 Peter Bloomfield <pbloomfield bellsouth net>
diff --git a/libbalsa/libbalsa-vfs.c b/libbalsa/libbalsa-vfs.c
index a66e138ae..eae652d20 100644
--- a/libbalsa/libbalsa-vfs.c
+++ b/libbalsa/libbalsa-vfs.c
@@ -528,26 +528,12 @@ libbalsa_vfs_file_unlink(LibbalsaVfs * file, GError **err)
gboolean
-libbalsa_vfs_launch_app(LibbalsaVfs * file, const gchar *app_name, GError **err)
+libbalsa_vfs_launch_app(LibbalsaVfs * file, GAppInfo *app, GError **err)
{
- GList *app_list;
- GList *list;
- GAppInfo *app = NULL;
GList * args;
gboolean result;
g_return_val_if_fail(LIBBALSA_IS_VFS(file), FALSE);
- g_return_val_if_fail(app_name != NULL, FALSE);
-
- app_list = g_app_info_get_all();
- for (list = app_list; list != NULL; list = list->next) {
- GAppInfo *this_app = G_APP_INFO(list->data);
- if (strcmp(app_name, g_app_info_get_name(this_app)) == 0) {
- app = g_object_ref(this_app);
- break;
- }
- }
- g_list_free_full(app_list, g_object_unref);
if (app == NULL) {
g_set_error(err, LIBBALSA_VFS_ERROR_QUARK, -1,
@@ -558,22 +544,21 @@ libbalsa_vfs_launch_app(LibbalsaVfs * file, const gchar *app_name, GError **err)
args = g_list_prepend(NULL, file->gio_gfile);
result = g_app_info_launch(app, args, NULL, err);
g_list_free(args);
- g_object_unref(app);
return result;
}
gboolean
-libbalsa_vfs_launch_app_for_body(LibBalsaMessageBody * mime_body,
- const gchar *app_name, GError **err)
+libbalsa_vfs_launch_app_for_body(LibBalsaMessageBody *mime_body,
+ GAppInfo *app,
+ GError **err)
{
gchar *uri;
LibbalsaVfs * file;
gboolean result;
g_return_val_if_fail(mime_body != NULL, FALSE);
- g_return_val_if_fail(app_name != NULL, FALSE);
if (!libbalsa_message_body_save_temporary(mime_body, err))
return FALSE;
@@ -582,7 +567,7 @@ libbalsa_vfs_launch_app_for_body(LibBalsaMessageBody * mime_body,
file = libbalsa_vfs_new_from_uri(uri);
g_free(uri);
- result = libbalsa_vfs_launch_app(file, app_name, err);
+ result = libbalsa_vfs_launch_app(file, app, err);
g_object_unref(file);
return result;
@@ -615,26 +600,52 @@ libbalsa_vfs_content_type_of_buffer(const guchar * buffer,
return retval;
}
+/*
+ * GAppInfo support
+ */
static void
gio_add_vfs_menu_item(GMenu *menu,
GAppInfo *app,
- const gchar *action)
+ GActionMap *action_map,
+ const gchar *action_namespace,
+ GCallback callback,
+ GObject *object)
{
- const gchar *name;
+ const gchar *app_name;
gchar *menu_label;
- GMenuItem *menu_item;
+ gchar *action_name;
+ gchar *p;
+ GSimpleAction *action;
- name = g_app_info_get_name(app);
+ app_name = g_app_info_get_name(app);
- menu_label = g_strdup_printf(_("Open with %s"), name);
- menu_item = g_menu_item_new(menu_label, NULL);
- g_free(menu_label);
+ action_name = g_strstrip(g_strdup(app_name));
+
+ for (p = action_name; *p != '\0'; p++) {
+ if (!g_ascii_isalnum(*p))
+ *p = '-';
+ }
+
+ action = g_simple_action_new(action_name, NULL);
+ g_signal_connect(action, "activate", callback, object);
+ g_action_map_add_action(action_map, G_ACTION(action));
+ g_object_unref(action);
- g_menu_item_set_action_and_target(menu_item, action, "s", name);
+ g_object_set_data_full(object, action_name, g_object_ref(app), g_object_unref);
- g_menu_append_item(menu, menu_item);
- g_object_unref(menu_item);
+ if (action_namespace != NULL) {
+ gchar *prefixed_action_name;
+
+ prefixed_action_name = g_strdup_printf("%s.%s", action_namespace, action_name);
+ g_free(action_name);
+ action_name = prefixed_action_name;
+ }
+
+ menu_label = g_strdup_printf(_("Open with %s"), app_name);
+ g_menu_append(menu, menu_label, action_name);
+ g_free(menu_label);
+ g_free(action_name);
}
@@ -642,7 +653,10 @@ gio_add_vfs_menu_item(GMenu *menu,
void
libbalsa_vfs_fill_menu_by_content_type(GMenu *menu,
const gchar *content_type,
- const gchar *action)
+ GActionMap *action_map,
+ const gchar *action_namespace,
+ GCallback callback,
+ GObject *object)
{
GList* list;
GAppInfo *def_app;
@@ -650,7 +664,7 @@ libbalsa_vfs_fill_menu_by_content_type(GMenu *menu,
def_app = g_app_info_get_default_for_type(content_type, FALSE);
if (def_app != NULL)
- gio_add_vfs_menu_item(menu, def_app, action);
+ gio_add_vfs_menu_item(menu, def_app, action_map, action_namespace, callback, object);
app_list = g_app_info_get_all_for_type(content_type);
for (list = app_list; list != NULL; list = list->next) {
@@ -658,7 +672,7 @@ libbalsa_vfs_fill_menu_by_content_type(GMenu *menu,
if (app != NULL && g_app_info_should_show(app) &&
(def_app == NULL || !g_app_info_equal(app, def_app)))
- gio_add_vfs_menu_item(menu, app, action);
+ gio_add_vfs_menu_item(menu, app, action_map, action_namespace, callback, object);
}
g_list_free_full(app_list, g_object_unref);
@@ -670,11 +684,11 @@ GtkWidget *
libbalsa_vfs_mime_button(const gchar * content_type, GCallback callback, gpointer data)
{
GtkWidget *button = NULL;
- gchar *msg;
GAppInfo *app = g_app_info_get_default_for_type(content_type, FALSE);
if (app != NULL) {
const gchar *app_name;
+ gchar *msg;
app_name = g_app_info_get_name(app);
msg = g_strdup_printf(_("Open _part with %s"), app_name);
@@ -682,7 +696,7 @@ libbalsa_vfs_mime_button(const gchar * content_type, GCallback callback, gpointe
g_free(msg);
g_object_set_data_full(G_OBJECT(button), LIBBALSA_VFS_MIME_ACTION,
- g_strdup(app_name), g_free);
+ app, g_object_unref);
g_signal_connect(button, "clicked", callback, data);
}
diff --git a/libbalsa/libbalsa-vfs.h b/libbalsa/libbalsa-vfs.h
index 84ff8f205..b4f3f4608 100644
--- a/libbalsa/libbalsa-vfs.h
+++ b/libbalsa/libbalsa-vfs.h
@@ -70,14 +70,17 @@ gint libbalsa_vfs_file_unlink(LibbalsaVfs * file,
/* application launch helpers */
gboolean libbalsa_vfs_launch_app(LibbalsaVfs *file,
- const gchar *app_name,
+ GAppInfo *app,
GError **err);
gboolean libbalsa_vfs_launch_app_for_body(LibBalsaMessageBody *mime_body,
- const gchar *app_name,
+ GAppInfo *app,
GError **err);
void libbalsa_vfs_fill_menu_by_content_type(GMenu *menu,
const gchar *content_type,
- const gchar *action);
+ GActionMap *action_map,
+ const gchar *action_namespace,
+ GCallback callback,
+ GObject *object);
GtkWidget * libbalsa_vfs_mime_button(const gchar * content_type,
GCallback callback,
gpointer data);
diff --git a/src/balsa-message.c b/src/balsa-message.c
index 650be3c69..2e1d79ffb 100644
--- a/src/balsa-message.c
+++ b/src/balsa-message.c
@@ -1802,16 +1802,19 @@ save_activated(GSimpleAction *action,
}
static void
-open_with_change_state(GSimpleAction *action,
- GVariant *parameter,
- gpointer user_data)
+open_with_activated(GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
{
- const gchar *app = g_variant_get_string(parameter, NULL);
BalsaPartInfo *info = user_data;
+ const gchar *action_name;
+ GAppInfo *app;
+
+ action_name = g_action_get_name(G_ACTION(action));
+ app = g_object_get_data(user_data, action_name);
balsa_mime_widget_ctx_menu_launch_app(app, info->body);
- g_simple_action_set_state(action, parameter);
if (GTK_IS_POPOVER(info->popup_widget))
gtk_popover_popdown((GtkPopover *) info->popup_widget);
}
@@ -1836,15 +1839,13 @@ copy_part_change_state(GSimpleAction *action,
gtk_popover_popdown((GtkPopover *) info->popup_widget);
}
-static void
+static GSimpleActionGroup *
part_add_actions(BalsaMessage *balsa_message,
- const gchar *action_namespace,
gpointer user_data)
{
GSimpleActionGroup *simple;
static const GActionEntry entries[] = {
{"save", save_activated},
- {"open-with", libbalsa_radio_activated, "s", "''", open_with_change_state},
{"copy-part", libbalsa_radio_activated, "s", "''", copy_part_change_state}
};
@@ -1852,10 +1853,7 @@ part_add_actions(BalsaMessage *balsa_message,
g_action_map_add_action_entries(G_ACTION_MAP(simple),
entries, G_N_ELEMENTS(entries),
user_data);
- gtk_widget_insert_action_group(GTK_WIDGET(balsa_message),
- action_namespace,
- G_ACTION_GROUP(simple));
- g_object_unref(simple);
+ return simple;
}
static void
@@ -1867,19 +1865,24 @@ part_create_menu(BalsaMessage *balsa_message, BalsaPartInfo *info)
3) GnomeVFS shortlist applications, with the default one (sometimes
included on shortlist, sometimes not) excluded. */
{
- static int menu_number;
- gchar *namespace;
GMenu *menu;
gchar *content_type;
-
- namespace = g_strdup_printf("menu-%d", ++menu_number);
-
- part_add_actions(balsa_message, namespace, info);
+ GSimpleActionGroup *simple;
+ static int menu_number;
+ gchar *namespace;
menu = g_menu_new();
-
content_type = libbalsa_message_body_get_mime_type (info->body);
- libbalsa_vfs_fill_menu_by_content_type(menu, content_type, "open-with");
+ simple = part_add_actions(balsa_message, info);
+
+ libbalsa_vfs_fill_menu_by_content_type(menu, content_type,
+ G_ACTION_MAP(simple), NULL,
+ G_CALLBACK(open_with_activated),
+ G_OBJECT(info));
+
+ namespace = g_strdup_printf("menu-%d", ++menu_number);
+ gtk_widget_insert_action_group(GTK_WIDGET(balsa_message), namespace, G_ACTION_GROUP(simple));
+ g_object_unref(simple);
g_menu_append(menu, _("Save…"), "save");
diff --git a/src/balsa-mime-widget-callbacks.c b/src/balsa-mime-widget-callbacks.c
index cab4e9e52..e6466f299 100644
--- a/src/balsa-mime-widget-callbacks.c
+++ b/src/balsa-mime-widget-callbacks.c
@@ -37,7 +37,7 @@
void
-balsa_mime_widget_ctx_menu_launch_app(const gchar *app,
+balsa_mime_widget_ctx_menu_launch_app(GAppInfo *app,
LibBalsaMessageBody *mime_body)
{
GError *err = NULL;
@@ -58,7 +58,7 @@ balsa_mime_widget_ctx_menu_cb(GtkWidget *button,
gpointer user_data)
{
LibBalsaMessageBody *mime_body = user_data;
- const gchar *app;
+ GAppInfo *app;
app = g_object_get_data(G_OBJECT(button), LIBBALSA_VFS_MIME_ACTION);
balsa_mime_widget_ctx_menu_launch_app(app, mime_body);
diff --git a/src/balsa-mime-widget-callbacks.h b/src/balsa-mime-widget-callbacks.h
index 670bb78f7..892ca2e1c 100644
--- a/src/balsa-mime-widget-callbacks.h
+++ b/src/balsa-mime-widget-callbacks.h
@@ -27,8 +27,8 @@
G_BEGIN_DECLS
-void balsa_mime_widget_ctx_menu_launch_app(const gchar * app,
- LibBalsaMessageBody * mime_body);
+void balsa_mime_widget_ctx_menu_launch_app(GAppInfo *app,
+ LibBalsaMessageBody *mime_body);
void balsa_mime_widget_ctx_menu_cb(GtkWidget * button,
gpointer user_data);
void balsa_mime_widget_ctx_menu_save(GtkWidget * parent_widget,
diff --git a/src/balsa-mime-widget-text.c b/src/balsa-mime-widget-text.c
index 86fbe8d13..ee54b72d6 100644
--- a/src/balsa-mime-widget-text.c
+++ b/src/balsa-mime-widget-text.c
@@ -602,12 +602,17 @@ text_view_url_popup(GtkWidget *widget, GtkMenu *menu, message_url_t *url)
}
static void
-open_with_change_state(GSimpleAction *action,
- GVariant *parameter,
- gpointer user_data)
+open_with_activated(GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
{
- const gchar *app = g_variant_get_string(parameter, NULL);
- LibBalsaMessageBody *part = user_data;
+ BalsaMimeWidgetText *mwt = user_data;
+ LibBalsaMessageBody *part = mwt->mime_body;
+ const gchar *action_name;
+ GAppInfo *app;
+
+ action_name = g_action_get_name(G_ACTION(action));
+ app = g_object_get_data(user_data, action_name);
balsa_mime_widget_ctx_menu_launch_app(app, part);
}
@@ -619,9 +624,6 @@ text_view_populate_popup(GtkWidget *widget, GtkMenu *menu,
BalsaMimeWidgetText *mwt = user_data;
GtkWidget *menu_item;
GSimpleActionGroup *simple;
- static const GActionEntry text_view_popup_entries[] = {
- {"open-with", libbalsa_radio_activated, "s", "''", open_with_change_state},
- };
GMenu *open_menu;
GtkWidget *submenu;
@@ -642,19 +644,18 @@ text_view_populate_popup(GtkWidget *widget, GtkMenu *menu,
gtk_separator_menu_item_new());
/* Set up the "open-with" action: */
+ open_menu = g_menu_new();
simple = g_simple_action_group_new();
- g_action_map_add_action_entries(G_ACTION_MAP(simple),
- text_view_popup_entries,
- G_N_ELEMENTS(text_view_popup_entries),
- mwt->mime_body);
+ libbalsa_vfs_fill_menu_by_content_type(open_menu, "text/plain",
+ G_ACTION_MAP(simple), "text-view-popup",
+ G_CALLBACK(open_with_activated),
+ G_OBJECT(mwt));
gtk_widget_insert_action_group(GTK_WIDGET(menu),
"text-view-popup",
G_ACTION_GROUP(simple));
+
g_object_unref(simple);
- open_menu = g_menu_new();
- libbalsa_vfs_fill_menu_by_content_type(open_menu, "text/plain",
- "text-view-popup.open-with");
submenu = gtk_menu_new_from_model(G_MENU_MODEL(open_menu));
g_object_unref(open_menu);
@@ -1168,18 +1169,19 @@ bmwt_html_select_all_activated(GSimpleAction *action,
}
static void
-bmwt_html_open_with_change_state(GSimpleAction *action,
- GVariant *parameter,
- gpointer user_data)
+bmwt_html_open_with_activated(GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
{
GtkWidget *html = user_data;
gpointer mime_body = g_object_get_data(G_OBJECT(html), "mime-body");
- GtkWidget *popup_widget = g_object_get_data(G_OBJECT(html), "popup-widget");
+ const gchar *action_name;
+ GAppInfo *app;
- open_with_change_state(action, parameter, mime_body);
+ action_name = g_action_get_name(G_ACTION(action));
+ app = g_object_get_data(user_data, action_name);
- if (GTK_IS_POPOVER(popup_widget))
- gtk_popover_popdown((GtkPopover *) popup_widget);
+ balsa_mime_widget_ctx_menu_launch_app(app, mime_body);
}
static void
@@ -1215,7 +1217,6 @@ bmwt_html_populate_popup_menu(BalsaMessage * bm,
{"zoom-out", bmwt_html_zoom_out_activated},
{"zoom-reset", bmwt_html_zoom_reset_activated},
{"select-all", bmwt_html_select_all_activated},
- {"open-with", libbalsa_radio_activated, "s", "''", bmwt_html_open_with_change_state},
{"save", bmwt_html_save_activated},
{"print", bmwt_html_print_activated}
};
@@ -1234,7 +1235,6 @@ bmwt_html_populate_popup_menu(BalsaMessage * bm,
G_ACTION_GROUP(simple));
print_action = g_action_map_lookup_action(G_ACTION_MAP(simple), "print");
- g_object_unref(simple);
section = g_menu_new();
@@ -1256,7 +1256,10 @@ bmwt_html_populate_popup_menu(BalsaMessage * bm,
open_menu = g_menu_new();
libbalsa_vfs_fill_menu_by_content_type(open_menu, "text/html",
- "open-with");
+ G_ACTION_MAP(simple), NULL,
+ G_CALLBACK(bmwt_html_open_with_activated),
+ G_OBJECT(html));
+ g_object_unref(simple);
g_menu_append_submenu(section, _("Open…"), G_MENU_MODEL(open_menu));
g_object_unref(open_menu);
@@ -1332,7 +1335,7 @@ bmwt_html_button_press_cb(GtkGestureMultiPress *multi_press,
if (gdk_event_triggers_context_menu(event)) {
GtkWidget *html = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture));
- bmwt_html_popup_context_menu(html, bm) ;
+ bmwt_html_popup_context_menu(html, bm);
}
}
diff --git a/src/sendmsg-window.c b/src/sendmsg-window.c
index b15e7849c..ecb5faca5 100644
--- a/src/sendmsg-window.c
+++ b/src/sendmsg-window.c
@@ -1383,11 +1383,15 @@ attachment_menu_vfs_cb(GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
{
- const gchar *app = g_variant_get_string(parameter, NULL);
BalsaAttachInfo *info = user_data;
+ const gchar *action_name;
+ GAppInfo *app;
GError *err = NULL;
gboolean result;
+ action_name = g_action_get_name(G_ACTION(action));
+ app = g_object_get_data(user_data, action_name);
+
result = libbalsa_vfs_launch_app(info->file_uri, app, &err);
if (!result)
balsa_information(LIBBALSA_INFORMATION_WARNING,
@@ -1653,8 +1657,7 @@ add_attachment(BalsaSendmsg * bsmsg, const gchar *filename,
GSimpleActionGroup *simple;
static GActionEntry attachment_entries[] = {
{"new-mode", libbalsa_radio_activated, "i", "1", change_attach_mode},
- {"remove", remove_attachment},
- {"launch-app", libbalsa_radio_activated, "s", "''", attachment_menu_vfs_cb}
+ {"remove", remove_attachment}
};
GMenu *menu;
GMenu *section;
@@ -1759,7 +1762,6 @@ add_attachment(BalsaSendmsg * bsmsg, const gchar *filename,
gtk_widget_insert_action_group(bsmsg->window,
attachment_namespace,
G_ACTION_GROUP(simple));
- g_object_unref(simple);
menu = g_menu_new();
@@ -1803,10 +1805,14 @@ add_attachment(BalsaSendmsg * bsmsg, const gchar *filename,
attached... (only for non-message attachments) */
if (!is_fwd_message) {
section = g_menu_new();
- libbalsa_vfs_fill_menu_by_content_type(section, content_type, "launch-app");
+ libbalsa_vfs_fill_menu_by_content_type(section, content_type,
+ G_ACTION_MAP(simple), NULL,
+ G_CALLBACK(attachment_menu_vfs_cb),
+ G_OBJECT(attach_data));
g_menu_append_section(menu, NULL, G_MENU_MODEL(section));
g_object_unref(section);
}
+ g_object_unref(simple);
attach_data->popup_menu =
libbalsa_popup_widget_new(bsmsg->tree_view, G_MENU_MODEL(menu), attachment_namespace);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]