Bug 418954 - Add a separate entry combo for port numbers
Adds a new EPortEntry widget which appears alongside "host" entry boxes so users don't have to know about the "host:port" syntax to specify a custom port number. Currently only used in the mail account editor, but we'll generalize it futher so it can be used everywhere.
This commit is contained in:
@ -56,6 +56,7 @@
|
||||
#include "e-util/e-signature-utils.h"
|
||||
#include "e-util/e-util-private.h"
|
||||
#include "widgets/misc/e-signature-editor.h"
|
||||
#include "widgets/misc/e-port-entry.h"
|
||||
|
||||
#include "e-mail-local.h"
|
||||
#include "e-mail-session.h"
|
||||
@ -106,6 +107,8 @@ typedef struct _EMAccountEditorService {
|
||||
GtkLabel *description;
|
||||
GtkLabel *hostlabel;
|
||||
GtkEntry *hostname;
|
||||
GtkLabel *portlabel;
|
||||
EPortEntry *port;
|
||||
GtkLabel *userlabel;
|
||||
GtkEntry *username;
|
||||
GtkEntry *path;
|
||||
@ -1229,28 +1232,23 @@ smime_encrypt_key_clear (GtkWidget *w, EMAccountEditor *emae)
|
||||
#endif
|
||||
|
||||
static void
|
||||
emae_url_set_hostport (CamelURL *url, const gchar *txt)
|
||||
emae_url_set_host (CamelURL *url, const gchar *txt)
|
||||
{
|
||||
const gchar *port;
|
||||
gchar *host;
|
||||
|
||||
/* FIXME: what if this was a raw IPv6 address? */
|
||||
if (txt && (port = strchr (txt, ':'))) {
|
||||
camel_url_set_port (url, atoi (port+1));
|
||||
if (txt && *txt) {
|
||||
host = g_strdup (txt);
|
||||
host[port-txt] = 0;
|
||||
} else {
|
||||
/* "" is converted to NULL, but if we set NULL on the url,
|
||||
camel_url_to_string strips lots of details */
|
||||
host = g_strdup ((txt?txt:""));
|
||||
camel_url_set_port (url, 0);
|
||||
}
|
||||
|
||||
g_strstrip (host);
|
||||
if (txt && *txt)
|
||||
g_strstrip (host);
|
||||
camel_url_set_host (url, host);
|
||||
g_free (host);
|
||||
}
|
||||
}
|
||||
|
||||
g_free (host);
|
||||
static void
|
||||
emae_url_set_port (CamelURL *url, const gchar *port)
|
||||
{
|
||||
if (port && *port)
|
||||
camel_url_set_port (url, atoi (port));
|
||||
}
|
||||
|
||||
/* This is used to map a funciton which will set on the url a string value.
|
||||
@ -1263,7 +1261,8 @@ struct _provider_host_info {
|
||||
};
|
||||
|
||||
static struct _provider_host_info emae_source_host_info[] = {
|
||||
{ CAMEL_URL_PART_HOST, emae_url_set_hostport, { G_STRUCT_OFFSET (EMAccountEditorService, hostname), G_STRUCT_OFFSET (EMAccountEditorService, hostlabel), }, },
|
||||
{ CAMEL_URL_PART_HOST, emae_url_set_host, { G_STRUCT_OFFSET (EMAccountEditorService, hostname), G_STRUCT_OFFSET (EMAccountEditorService, hostlabel), }, },
|
||||
{ CAMEL_URL_PART_HOST, emae_url_set_port, { G_STRUCT_OFFSET (EMAccountEditorService, port), G_STRUCT_OFFSET (EMAccountEditorService, portlabel), }, },
|
||||
{ CAMEL_URL_PART_USER, camel_url_set_user, { G_STRUCT_OFFSET (EMAccountEditorService, username), G_STRUCT_OFFSET (EMAccountEditorService, userlabel), } },
|
||||
{ CAMEL_URL_PART_PATH, camel_url_set_path, { G_STRUCT_OFFSET (EMAccountEditorService, path), G_STRUCT_OFFSET (EMAccountEditorService, pathlabel), G_STRUCT_OFFSET (EMAccountEditorService, pathentry) }, },
|
||||
{ CAMEL_URL_PART_AUTH, NULL, { 0, G_STRUCT_OFFSET (EMAccountEditorService, auth_frame), }, },
|
||||
@ -1271,7 +1270,8 @@ static struct _provider_host_info emae_source_host_info[] = {
|
||||
};
|
||||
|
||||
static struct _provider_host_info emae_transport_host_info[] = {
|
||||
{ CAMEL_URL_PART_HOST, emae_url_set_hostport, { G_STRUCT_OFFSET (EMAccountEditorService, hostname), G_STRUCT_OFFSET (EMAccountEditorService, hostlabel), }, },
|
||||
{ CAMEL_URL_PART_HOST, emae_url_set_host, { G_STRUCT_OFFSET (EMAccountEditorService, hostname), G_STRUCT_OFFSET (EMAccountEditorService, hostlabel), }, },
|
||||
{ CAMEL_URL_PART_HOST, emae_url_set_port, { G_STRUCT_OFFSET (EMAccountEditorService, port), G_STRUCT_OFFSET (EMAccountEditorService, portlabel), }, },
|
||||
{ CAMEL_URL_PART_USER, camel_url_set_user, { G_STRUCT_OFFSET (EMAccountEditorService, username), G_STRUCT_OFFSET (EMAccountEditorService, userlabel), } },
|
||||
{ CAMEL_URL_PART_AUTH, NULL, { 0, G_STRUCT_OFFSET (EMAccountEditorService, auth_frame), }, },
|
||||
{ 0 },
|
||||
@ -1292,6 +1292,8 @@ static struct _service_info {
|
||||
const gchar *description;
|
||||
const gchar *hostname;
|
||||
const gchar *hostlabel;
|
||||
const gchar *port;
|
||||
const gchar *portlabel;
|
||||
const gchar *username;
|
||||
const gchar *userlabel;
|
||||
const gchar *path;
|
||||
@ -1325,6 +1327,8 @@ static struct _service_info {
|
||||
"source_description",
|
||||
"source_host",
|
||||
"source_host_label",
|
||||
"source_port",
|
||||
"source_port_label",
|
||||
"source_user",
|
||||
"source_user_label",
|
||||
"source_path",
|
||||
@ -1356,6 +1360,8 @@ static struct _service_info {
|
||||
"transport_description",
|
||||
"transport_host",
|
||||
"transport_host_label",
|
||||
"transport_port",
|
||||
"transport_port_label",
|
||||
"transport_user",
|
||||
"transport_user_label",
|
||||
NULL,
|
||||
@ -1400,16 +1406,23 @@ emae_uri_changed (EMAccountEditorService *service, CamelURL *url)
|
||||
}
|
||||
|
||||
static void
|
||||
emae_service_url_changed (EMAccountEditorService *service, void (*setval)(CamelURL *, const gchar *), GtkEntry *entry)
|
||||
emae_service_url_changed (EMAccountEditorService *service, void (*setval)(CamelURL *, const gchar *), GtkWidget *entry)
|
||||
{
|
||||
GtkComboBox *dropdown;
|
||||
gint id;
|
||||
GtkTreeModel *model;
|
||||
GtkTreeIter iter;
|
||||
CamelServiceAuthType *authtype;
|
||||
gchar *text;
|
||||
|
||||
CamelURL *url = emae_account_url (service->emae, emae_service_info[service->type].account_uri_key);
|
||||
gchar *text = g_strdup (gtk_entry_get_text (entry));
|
||||
|
||||
if (GTK_IS_ENTRY (entry))
|
||||
text = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
|
||||
else if (E_IS_PORT_ENTRY (entry)) {
|
||||
text = g_strdup_printf ("%i", e_port_entry_get_port (E_PORT_ENTRY (entry)));
|
||||
} else
|
||||
return;
|
||||
|
||||
g_strstrip (text);
|
||||
|
||||
@ -1471,13 +1484,19 @@ emae_service_url_path_changed (EMAccountEditorService *service, void (*setval)(C
|
||||
static void
|
||||
emae_hostname_changed (GtkEntry *entry, EMAccountEditorService *service)
|
||||
{
|
||||
emae_service_url_changed (service, emae_url_set_hostport, entry);
|
||||
emae_service_url_changed (service, emae_url_set_host, GTK_WIDGET (entry));
|
||||
}
|
||||
|
||||
static void
|
||||
emae_port_changed (EPortEntry *pentry, EMAccountEditorService *service)
|
||||
{
|
||||
emae_service_url_changed (service, emae_url_set_port, GTK_WIDGET (pentry));
|
||||
}
|
||||
|
||||
static void
|
||||
emae_username_changed (GtkEntry *entry, EMAccountEditorService *service)
|
||||
{
|
||||
emae_service_url_changed (service, camel_url_set_user, entry);
|
||||
emae_service_url_changed (service, camel_url_set_user, GTK_WIDGET (entry));
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1502,7 +1521,11 @@ emae_ssl_update (EMAccountEditorService *service, CamelURL *url)
|
||||
gtk_tree_model_get (model, &iter, 1, &ssl, -1);
|
||||
if (!strcmp (ssl, "none"))
|
||||
ssl = NULL;
|
||||
|
||||
e_port_entry_security_port_changed (service->port, ssl);
|
||||
|
||||
camel_url_set_param (url, "use_ssl", ssl);
|
||||
camel_url_set_port (url, e_port_entry_get_port (service->port));
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1524,6 +1547,7 @@ emae_service_provider_changed (EMAccountEditorService *service)
|
||||
{
|
||||
EAccount *account;
|
||||
gint i, j;
|
||||
gint old_port;
|
||||
void (*show)(GtkWidget *);
|
||||
CamelURL *url = emae_account_url (service->emae, emae_service_info[service->type].account_uri_key);
|
||||
|
||||
@ -1549,6 +1573,9 @@ emae_service_provider_changed (EMAccountEditorService *service)
|
||||
enable = e_account_writable (account, emae_service_info[service->type].save_passwd_key);
|
||||
gtk_widget_set_sensitive ((GtkWidget *)service->remember, enable);
|
||||
|
||||
if (service->port && service->provider->port_entries)
|
||||
e_port_entry_set_camel_entries (service->port, service->provider->port_entries);
|
||||
|
||||
for (i=0;emae_service_info[service->type].host_info[i].flag;i++) {
|
||||
GtkWidget *w;
|
||||
gint hide;
|
||||
@ -1565,8 +1592,13 @@ emae_service_provider_changed (EMAccountEditorService *service)
|
||||
if (dwidget == NULL && enable)
|
||||
dwidget = w;
|
||||
|
||||
if (info->setval && !hide)
|
||||
info->setval (url, enable?gtk_entry_get_text ((GtkEntry *)w):NULL);
|
||||
if (info->setval && !hide) {
|
||||
if (GTK_IS_ENTRY (w))
|
||||
info->setval (url, enable?gtk_entry_get_text ((GtkEntry *)w):NULL);
|
||||
else if (E_IS_PORT_ENTRY (w))
|
||||
info->setval (url, enable?g_strdup_printf("%i",
|
||||
e_port_entry_get_port (E_PORT_ENTRY (w))):NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1599,6 +1631,7 @@ emae_service_provider_changed (EMAccountEditorService *service)
|
||||
gtk_widget_hide ((GtkWidget *)service->needs_auth);
|
||||
}
|
||||
#ifdef HAVE_SSL
|
||||
old_port = url->port;
|
||||
gtk_widget_hide (service->no_ssl);
|
||||
if (service->provider->flags & CAMEL_PROVIDER_SUPPORTS_SSL) {
|
||||
emae_ssl_update (service, url);
|
||||
@ -1614,6 +1647,13 @@ emae_service_provider_changed (EMAccountEditorService *service)
|
||||
gtk_widget_show (service->no_ssl);
|
||||
camel_url_set_param (url, "use_ssl", NULL);
|
||||
#endif
|
||||
|
||||
/* This must be done AFTER use_ssl is set; changing use_ssl overwrites
|
||||
the old port, which could be SSL port, but also could be some special
|
||||
port and we would otherwise lost it */
|
||||
if (url->port)
|
||||
e_port_entry_set_port (service->port, old_port);
|
||||
|
||||
} else {
|
||||
camel_url_set_protocol (url, NULL);
|
||||
gtk_label_set_text (service->description, "");
|
||||
@ -1978,12 +2018,17 @@ emae_setup_service (EMAccountEditor *emae, EMAccountEditorService *service, GtkB
|
||||
account = em_account_editor_get_modified_account (emae);
|
||||
uri = e_account_get_string (account, info->account_uri_key);
|
||||
|
||||
service->provider = uri?camel_provider_get (uri, NULL):NULL;
|
||||
service->provider = uri ? camel_provider_get (uri, NULL) : NULL;
|
||||
|
||||
/* Extract all widgets we need from the builder file. */
|
||||
|
||||
service->frame = e_builder_get_widget (builder, info->frame);
|
||||
service->container = e_builder_get_widget (builder, info->container);
|
||||
service->description = GTK_LABEL (e_builder_get_widget (builder, info->description));
|
||||
service->hostname = GTK_ENTRY (e_builder_get_widget (builder, info->hostname));
|
||||
service->hostlabel = (GtkLabel *)e_builder_get_widget (builder, info->hostlabel);
|
||||
service->port = E_PORT_ENTRY (e_builder_get_widget (builder, info->port));
|
||||
service->portlabel = (GtkLabel *)e_builder_get_widget (builder, info->portlabel);
|
||||
service->username = GTK_ENTRY (e_builder_get_widget (builder, info->username));
|
||||
service->userlabel = (GtkLabel *)e_builder_get_widget (builder, info->userlabel);
|
||||
if (info->pathentry) {
|
||||
@ -1997,19 +2042,36 @@ emae_setup_service (EMAccountEditor *emae, EMAccountEditorService *service, GtkB
|
||||
service->use_ssl = (GtkComboBox *)e_builder_get_widget (builder, info->use_ssl);
|
||||
service->no_ssl = e_builder_get_widget (builder, info->ssl_disabled);
|
||||
|
||||
service->auth_frame = e_builder_get_widget (builder, info->auth_frame);
|
||||
service->check_supported = (GtkButton *)e_builder_get_widget (builder, info->authtype_check);
|
||||
service->authtype = (GtkComboBox *)e_builder_get_widget (builder, info->authtype);
|
||||
service->providers = (GtkComboBox *)e_builder_get_widget (builder, info->type_dropdown);
|
||||
|
||||
service->remember = emae_account_toggle (emae, info->remember_password, info->save_passwd_key, builder);
|
||||
|
||||
if (info->needs_auth)
|
||||
service->needs_auth = (GtkToggleButton *)e_builder_get_widget (builder, info->needs_auth);
|
||||
else
|
||||
service->needs_auth = NULL;
|
||||
|
||||
service->auth_changed_id = 0;
|
||||
|
||||
/* Do this first. Otherwise subsequent changes get clobbered. */
|
||||
emae_service_provider_changed (service);
|
||||
|
||||
/* configure ui for current settings */
|
||||
if (url->host) {
|
||||
if (url->port) {
|
||||
gchar *host = g_strdup_printf ("%s:%d", url->host, url->port);
|
||||
|
||||
gtk_entry_set_text (service->hostname, host);
|
||||
g_free (host);
|
||||
} else
|
||||
gtk_entry_set_text (service->hostname, url->host);
|
||||
gtk_entry_set_text (service->hostname, url->host);
|
||||
}
|
||||
|
||||
if (url->user && *url->user) {
|
||||
gtk_entry_set_text (service->username, url->user);
|
||||
}
|
||||
|
||||
if (url->port) {
|
||||
e_port_entry_set_port (service->port, url->port);
|
||||
}
|
||||
|
||||
if (service->pathentry) {
|
||||
GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
|
||||
|
||||
@ -2035,29 +2097,21 @@ emae_setup_service (EMAccountEditor *emae, EMAccountEditorService *service, GtkB
|
||||
}
|
||||
|
||||
g_signal_connect (service->hostname, "changed", G_CALLBACK (emae_hostname_changed), service);
|
||||
g_signal_connect (service->port, "changed", G_CALLBACK (emae_port_changed), service);
|
||||
g_signal_connect (service->username, "changed", G_CALLBACK (emae_username_changed), service);
|
||||
if (service->pathentry)
|
||||
g_signal_connect (GTK_FILE_CHOOSER (service->pathentry), "selection-changed", G_CALLBACK (emae_path_changed), service);
|
||||
|
||||
g_signal_connect (service->use_ssl, "changed", G_CALLBACK(emae_ssl_changed), service);
|
||||
|
||||
service->auth_frame = e_builder_get_widget (builder, info->auth_frame);
|
||||
service->remember = emae_account_toggle (emae, info->remember_password, info->save_passwd_key, builder);
|
||||
service->check_supported = (GtkButton *)e_builder_get_widget (builder, info->authtype_check);
|
||||
service->authtype = (GtkComboBox *)e_builder_get_widget (builder, info->authtype);
|
||||
/* old authtype will be destroyed when we exit */
|
||||
service->auth_changed_id = 0;
|
||||
service->providers = (GtkComboBox *)e_builder_get_widget (builder, info->type_dropdown);
|
||||
emae_refresh_providers (emae, service);
|
||||
emae_refresh_authtype (emae, service);
|
||||
|
||||
if (info->needs_auth) {
|
||||
service->needs_auth = (GtkToggleButton *)e_builder_get_widget (builder, info->needs_auth);
|
||||
if (service->needs_auth != NULL) {
|
||||
gtk_toggle_button_set_active (service->needs_auth, url->authmech != NULL);
|
||||
g_signal_connect (service->needs_auth, "toggled", G_CALLBACK(emae_needs_auth), service);
|
||||
emae_needs_auth (service->needs_auth, service);
|
||||
} else {
|
||||
service->needs_auth = NULL;
|
||||
}
|
||||
|
||||
if (!e_account_writable (account, info->account_uri_key))
|
||||
@ -2065,8 +2119,6 @@ emae_setup_service (EMAccountEditor *emae, EMAccountEditorService *service, GtkB
|
||||
else
|
||||
gtk_widget_set_sensitive (service->container, TRUE);
|
||||
|
||||
emae_service_provider_changed (service);
|
||||
|
||||
camel_url_free (url);
|
||||
}
|
||||
|
||||
@ -3346,7 +3398,7 @@ emae_service_complete (EMAccountEditor *emae, EMAccountEditorService *service)
|
||||
return FALSE;
|
||||
|
||||
if (CAMEL_PROVIDER_NEEDS (service->provider, CAMEL_URL_PART_HOST)) {
|
||||
if (url->host == NULL || url->host[0] == 0)
|
||||
if (url->host == NULL || url->host[0] == 0 || !e_port_entry_is_valid (service->port))
|
||||
ok = FALSE;
|
||||
}
|
||||
/* We only need the user if the service needs auth as well, i think */
|
||||
|
||||
@ -625,7 +625,7 @@ For example: "Work" or "Personal"</property>
|
||||
<object class="GtkTable" id="source-config-table">
|
||||
<property name="visible">True</property>
|
||||
<property name="n_rows">3</property>
|
||||
<property name="n_columns">2</property>
|
||||
<property name="n_columns">4</property>
|
||||
<property name="column_spacing">12</property>
|
||||
<property name="row_spacing">6</property>
|
||||
<child>
|
||||
@ -637,6 +637,25 @@ For example: "Work" or "Personal"</property>
|
||||
<property name="mnemonic_widget">source_host</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="top_attach">0</property>
|
||||
<property name="bottom_attach">1</property>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="x_options">GTK_FILL</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="source_port_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="label">_Port:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="mnemonic_widget">source_port</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="top_attach">0</property>
|
||||
<property name="bottom_attach">1</property>
|
||||
<property name="left_attach">2</property>
|
||||
<property name="x_options">GTK_FILL</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
@ -651,7 +670,6 @@ For example: "Work" or "Personal"</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
<property name="x_options">GTK_FILL</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
@ -664,8 +682,20 @@ For example: "Work" or "Personal"</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="y_options"></property>
|
||||
<property name="top_attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="EPortEntry" type-func="e_port_entry_get_type" id="source_port">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="has-entry">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">3</property>
|
||||
<property name="top_attach">0</property>
|
||||
<property name="x_options"></property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
@ -676,7 +706,7 @@ For example: "Work" or "Personal"</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="right_attach">4</property>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
<property name="y_options"></property>
|
||||
@ -1053,7 +1083,7 @@ For example: "Work" or "Personal"</property>
|
||||
<object class="GtkTable" id="transport-server-table">
|
||||
<property name="visible">True</property>
|
||||
<property name="n_rows">2</property>
|
||||
<property name="n_columns">2</property>
|
||||
<property name="n_columns">4</property>
|
||||
<property name="column_spacing">12</property>
|
||||
<property name="row_spacing">6</property>
|
||||
<child>
|
||||
@ -1062,7 +1092,6 @@ For example: "Work" or "Personal"</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="label" translatable="yes">_Server:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="justify">right</property>
|
||||
<property name="mnemonic_widget">transport_host</property>
|
||||
</object>
|
||||
<packing>
|
||||
@ -1070,6 +1099,20 @@ For example: "Work" or "Personal"</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="transport_port_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Port:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="justify">right</property>
|
||||
<property name="mnemonic_widget">transport_port</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">2</property>
|
||||
<property name="x_options">GTK_FILL</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="transport_host">
|
||||
<property name="visible">True</property>
|
||||
@ -1082,6 +1125,18 @@ For example: "Work" or "Personal"</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="EPortEntry" type-func="e_port_entry_get_type" id="transport_port">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="has-entry">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">3</property>
|
||||
<property name="x_options"></property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="transport_needs_auth">
|
||||
<property name="label" translatable="yes">Ser_ver requires authentication</property>
|
||||
@ -1092,6 +1147,7 @@ For example: "Work" or "Personal"</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
|
||||
@ -47,6 +47,7 @@ widgetsinclude_HEADERS = \
|
||||
e-picture-gallery.h \
|
||||
e-popup-action.h \
|
||||
e-popup-menu.h \
|
||||
e-port-entry.h \
|
||||
e-preferences-window.h \
|
||||
e-preview-pane.h \
|
||||
e-printable.h \
|
||||
@ -126,6 +127,7 @@ libemiscwidgets_la_SOURCES = \
|
||||
e-picture-gallery.c \
|
||||
e-popup-action.c \
|
||||
e-popup-menu.c \
|
||||
e-port-entry.c \
|
||||
e-preferences-window.c \
|
||||
e-preview-pane.c \
|
||||
e-printable.c \
|
||||
|
||||
474
widgets/misc/e-port-entry.c
Normal file
474
widgets/misc/e-port-entry.c
Normal file
@ -0,0 +1,474 @@
|
||||
/*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with the program; if not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
* Authors:
|
||||
* Dan Vratil <dvratil@redhat.com>
|
||||
*/
|
||||
|
||||
#include "e-port-entry.h"
|
||||
|
||||
#include <config.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <glib.h>
|
||||
|
||||
struct _EPortEntryPrivate {
|
||||
guint port;
|
||||
gboolean is_valid;
|
||||
};
|
||||
|
||||
enum {
|
||||
PORT_NUM_COLUMN,
|
||||
PORT_DESC_COLUMN,
|
||||
PORT_IS_SSL_COLUMN
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_IS_VALID,
|
||||
PROP_PORT
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (
|
||||
EPortEntry,
|
||||
e_port_entry,
|
||||
GTK_TYPE_COMBO_BOX)
|
||||
|
||||
static void
|
||||
port_entry_set_is_valid (EPortEntry *port_entry,
|
||||
gboolean is_valid)
|
||||
{
|
||||
g_return_if_fail (E_IS_PORT_ENTRY (port_entry));
|
||||
|
||||
port_entry->priv->is_valid = is_valid;
|
||||
|
||||
g_object_notify (G_OBJECT (port_entry), "is-valid");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns number of port currently selected in the widget, no matter
|
||||
* what value is in the PORT property
|
||||
*/
|
||||
static gint
|
||||
port_entry_get_model_active_port (EPortEntry *port_entry)
|
||||
{
|
||||
const gchar *port;
|
||||
|
||||
port = gtk_combo_box_get_active_id (GTK_COMBO_BOX (port_entry));
|
||||
|
||||
if (!port) {
|
||||
GtkWidget *entry = gtk_bin_get_child (GTK_BIN (port_entry));
|
||||
port = gtk_entry_get_text (GTK_ENTRY (entry));
|
||||
}
|
||||
|
||||
return atoi (port);
|
||||
}
|
||||
|
||||
static void
|
||||
port_entry_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
switch (property_id) {
|
||||
case PROP_IS_VALID:
|
||||
port_entry_set_is_valid (
|
||||
E_PORT_ENTRY (object),
|
||||
g_value_get_boolean (value));
|
||||
return;
|
||||
case PROP_PORT:
|
||||
e_port_entry_set_port (
|
||||
E_PORT_ENTRY (object),
|
||||
g_value_get_uint (value));
|
||||
return;
|
||||
}
|
||||
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
}
|
||||
|
||||
static void
|
||||
port_entry_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
switch (property_id) {
|
||||
case PROP_IS_VALID:
|
||||
g_value_set_boolean (
|
||||
value, e_port_entry_is_valid (
|
||||
E_PORT_ENTRY (object)));
|
||||
return;
|
||||
case PROP_PORT:
|
||||
g_value_set_uint (
|
||||
value, e_port_entry_get_port (
|
||||
E_PORT_ENTRY (object)));
|
||||
return;
|
||||
}
|
||||
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
}
|
||||
|
||||
static void
|
||||
port_entry_port_changed (EPortEntry *port_entry)
|
||||
{
|
||||
GtkTreeModel *model;
|
||||
GtkTreeIter iter;
|
||||
const gchar *port;
|
||||
const gchar *tooltip;
|
||||
|
||||
g_return_if_fail (E_IS_PORT_ENTRY (port_entry));
|
||||
|
||||
model = gtk_combo_box_get_model (GTK_COMBO_BOX (port_entry));
|
||||
g_return_if_fail (model);
|
||||
|
||||
if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (port_entry), &iter)) {
|
||||
GtkWidget *entry = gtk_bin_get_child (GTK_BIN (port_entry));
|
||||
port = gtk_entry_get_text (GTK_ENTRY (entry));
|
||||
|
||||
/* Try if user just haven't happened to enter a default port */
|
||||
gtk_combo_box_set_active_id (GTK_COMBO_BOX (port_entry), port);
|
||||
} else {
|
||||
gtk_tree_model_get (model, &iter, PORT_NUM_COLUMN, &port, -1);
|
||||
}
|
||||
|
||||
if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (port_entry), &iter)) {
|
||||
gtk_tree_model_get (model, &iter, PORT_DESC_COLUMN, &tooltip, -1);
|
||||
gtk_widget_set_tooltip_text (GTK_WIDGET (port_entry), tooltip);
|
||||
} else {
|
||||
gtk_widget_set_has_tooltip (GTK_WIDGET (port_entry), FALSE);
|
||||
}
|
||||
|
||||
if (port == NULL || *port == '\0') {
|
||||
port_entry->priv->port = 0;
|
||||
port_entry_set_is_valid (port_entry, FALSE);
|
||||
} else {
|
||||
port_entry->priv->port = atoi (port);
|
||||
if ((port_entry->priv->port <= 0) ||
|
||||
(port_entry->priv->port > G_MAXUINT16)) {
|
||||
port_entry->priv->port = 0;
|
||||
port_entry_set_is_valid (port_entry, FALSE);
|
||||
} else {
|
||||
port_entry_set_is_valid (port_entry, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
g_object_notify (G_OBJECT (port_entry), "port");
|
||||
}
|
||||
|
||||
static void
|
||||
port_entry_get_preferred_width (GtkWidget *widget,
|
||||
gint *minimum_size,
|
||||
gint *natural_size)
|
||||
{
|
||||
PangoContext *context;
|
||||
PangoFontMetrics *metrics;
|
||||
PangoFontDescription *font_desc;
|
||||
GtkStyleContext *style_context;
|
||||
GtkStateFlags state;
|
||||
gint digit_width;
|
||||
gint parent_entry_width_min;
|
||||
gint parent_width_min;
|
||||
GtkWidget *entry;
|
||||
|
||||
style_context = gtk_widget_get_style_context (widget);
|
||||
state = gtk_widget_get_state_flags (widget);
|
||||
gtk_style_context_get (
|
||||
style_context, state, "font", &font_desc, NULL);
|
||||
context = gtk_widget_get_pango_context (GTK_WIDGET (widget));
|
||||
metrics = pango_context_get_metrics (
|
||||
context, font_desc, pango_context_get_language (context));
|
||||
|
||||
digit_width = PANGO_PIXELS (
|
||||
pango_font_metrics_get_approximate_digit_width (metrics));
|
||||
|
||||
/* Preferred width of the entry */
|
||||
entry = gtk_bin_get_child (GTK_BIN (widget));
|
||||
gtk_widget_get_preferred_width (entry, NULL, &parent_entry_width_min);
|
||||
|
||||
/* Preferred width of a standard combobox */
|
||||
GTK_WIDGET_CLASS (e_port_entry_parent_class)->
|
||||
get_preferred_width (widget, &parent_width_min, NULL);
|
||||
|
||||
/* 6 * digit_width - port number has max 5
|
||||
* digits + extra free space for better look */
|
||||
if (minimum_size != NULL)
|
||||
*minimum_size =
|
||||
parent_width_min - parent_entry_width_min +
|
||||
6 * digit_width;
|
||||
|
||||
if (natural_size != NULL)
|
||||
*natural_size =
|
||||
parent_width_min - parent_entry_width_min +
|
||||
6 * digit_width;
|
||||
|
||||
pango_font_metrics_unref (metrics);
|
||||
pango_font_description_free (font_desc);
|
||||
}
|
||||
|
||||
static void
|
||||
e_port_entry_class_init (EPortEntryClass *class)
|
||||
{
|
||||
GObjectClass *object_class;
|
||||
GtkWidgetClass *widget_class;
|
||||
|
||||
g_type_class_add_private (class, sizeof (EPortEntryPrivate));
|
||||
|
||||
object_class = G_OBJECT_CLASS (class);
|
||||
object_class->set_property = port_entry_set_property;
|
||||
object_class->get_property = port_entry_get_property;
|
||||
|
||||
widget_class = GTK_WIDGET_CLASS (class);
|
||||
widget_class->get_preferred_width = port_entry_get_preferred_width;
|
||||
|
||||
g_object_class_install_property (
|
||||
object_class,
|
||||
PROP_IS_VALID,
|
||||
g_param_spec_boolean (
|
||||
"is-valid",
|
||||
NULL,
|
||||
NULL,
|
||||
FALSE,
|
||||
G_PARAM_READABLE));
|
||||
|
||||
g_object_class_install_property (
|
||||
object_class,
|
||||
PROP_PORT,
|
||||
g_param_spec_uint (
|
||||
"port",
|
||||
NULL,
|
||||
NULL,
|
||||
0, /* Min port, 0 = invalid port */
|
||||
G_MAXUINT16, /* Max port */
|
||||
0,
|
||||
G_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static void
|
||||
e_port_entry_init (EPortEntry *port_entry)
|
||||
{
|
||||
GtkCellRenderer *renderer;
|
||||
GtkListStore *store;
|
||||
|
||||
port_entry->priv = G_TYPE_INSTANCE_GET_PRIVATE (
|
||||
port_entry, E_TYPE_PORT_ENTRY, EPortEntryPrivate);
|
||||
port_entry->priv->port = 0;
|
||||
port_entry->priv->is_valid = FALSE;
|
||||
|
||||
store = gtk_list_store_new (
|
||||
3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN);
|
||||
|
||||
gtk_combo_box_set_model (
|
||||
GTK_COMBO_BOX (port_entry), GTK_TREE_MODEL (store));
|
||||
gtk_combo_box_set_entry_text_column (
|
||||
GTK_COMBO_BOX (port_entry), PORT_NUM_COLUMN);
|
||||
gtk_combo_box_set_id_column (
|
||||
GTK_COMBO_BOX (port_entry), PORT_NUM_COLUMN);
|
||||
|
||||
renderer = gtk_cell_renderer_text_new ();
|
||||
gtk_cell_renderer_set_sensitive (renderer, TRUE);
|
||||
gtk_cell_layout_pack_start (
|
||||
GTK_CELL_LAYOUT (port_entry), renderer, FALSE);
|
||||
gtk_cell_layout_add_attribute (
|
||||
GTK_CELL_LAYOUT (port_entry),
|
||||
renderer, "text", PORT_NUM_COLUMN);
|
||||
|
||||
renderer = gtk_cell_renderer_text_new ();
|
||||
gtk_cell_renderer_set_sensitive (renderer, FALSE);
|
||||
gtk_cell_layout_pack_start (
|
||||
GTK_CELL_LAYOUT (port_entry), renderer, TRUE);
|
||||
gtk_cell_layout_add_attribute (
|
||||
GTK_CELL_LAYOUT (port_entry),
|
||||
renderer, "text", PORT_DESC_COLUMN);
|
||||
|
||||
/* Update the port property when port is changed */
|
||||
g_signal_connect (
|
||||
port_entry, "changed",
|
||||
G_CALLBACK (port_entry_port_changed), NULL);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
e_port_entry_new (void)
|
||||
{
|
||||
return g_object_new (
|
||||
E_TYPE_PORT_ENTRY, "has-entry", TRUE, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
e_port_entry_set_camel_entries (EPortEntry *port_entry,
|
||||
CamelProviderPortEntry *entries)
|
||||
{
|
||||
GtkTreeIter iter;
|
||||
GtkTreeModel *model;
|
||||
GtkListStore *store;
|
||||
gint i = 0;
|
||||
|
||||
g_return_if_fail (E_IS_PORT_ENTRY (port_entry));
|
||||
g_return_if_fail (entries);
|
||||
|
||||
model = gtk_combo_box_get_model (GTK_COMBO_BOX (port_entry));
|
||||
store = GTK_LIST_STORE (model);
|
||||
|
||||
gtk_list_store_clear (store);
|
||||
|
||||
while (entries[i].port > 0) {
|
||||
gchar *port_string;
|
||||
|
||||
port_string = g_strdup_printf ("%i", entries[i].port);
|
||||
|
||||
gtk_list_store_append (store, &iter);
|
||||
gtk_list_store_set (
|
||||
store, &iter,
|
||||
PORT_NUM_COLUMN, port_string,
|
||||
PORT_DESC_COLUMN, entries[i].desc,
|
||||
PORT_IS_SSL_COLUMN, entries[i].is_ssl,
|
||||
-1);
|
||||
i++;
|
||||
|
||||
g_free (port_string);
|
||||
}
|
||||
|
||||
/* Activate the first port */
|
||||
if (i > 0)
|
||||
e_port_entry_set_port (port_entry, entries[0].port);
|
||||
}
|
||||
|
||||
void
|
||||
e_port_entry_security_port_changed (EPortEntry *port_entry,
|
||||
gchar *ssl)
|
||||
{
|
||||
g_return_if_fail (E_IS_PORT_ENTRY (port_entry));
|
||||
g_return_if_fail (ssl != NULL);
|
||||
|
||||
if (strcmp (ssl, "always") == 0) {
|
||||
e_port_entry_activate_secured_port (port_entry, 0);
|
||||
} else {
|
||||
e_port_entry_activate_nonsecured_port (port_entry, 0);
|
||||
}
|
||||
}
|
||||
|
||||
gint
|
||||
e_port_entry_get_port (EPortEntry *port_entry)
|
||||
{
|
||||
g_return_val_if_fail (E_IS_PORT_ENTRY (port_entry), 0);
|
||||
|
||||
return port_entry->priv->port;
|
||||
}
|
||||
|
||||
void
|
||||
e_port_entry_set_port (EPortEntry *port_entry,
|
||||
gint port)
|
||||
{
|
||||
g_return_if_fail (E_IS_PORT_ENTRY (port_entry));
|
||||
|
||||
port_entry->priv->port = port;
|
||||
if ((port <= 0) || (port > G_MAXUINT16))
|
||||
port_entry_set_is_valid (port_entry, FALSE);
|
||||
else {
|
||||
gchar *port_string;
|
||||
|
||||
port_string = g_strdup_printf ("%i", port);
|
||||
|
||||
gtk_combo_box_set_active_id (
|
||||
GTK_COMBO_BOX (port_entry), port_string);
|
||||
|
||||
if (port_entry_get_model_active_port (port_entry) != port) {
|
||||
GtkWidget *entry;
|
||||
|
||||
entry = gtk_bin_get_child (GTK_BIN (port_entry));
|
||||
gtk_entry_set_text (GTK_ENTRY (entry), port_string);
|
||||
}
|
||||
|
||||
port_entry_set_is_valid (port_entry, TRUE);
|
||||
|
||||
g_free (port_string);
|
||||
}
|
||||
|
||||
g_object_notify (G_OBJECT (port_entry), "port");
|
||||
}
|
||||
|
||||
gboolean
|
||||
e_port_entry_is_valid (EPortEntry *port_entry)
|
||||
{
|
||||
g_return_val_if_fail (E_IS_PORT_ENTRY (port_entry), FALSE);
|
||||
|
||||
return port_entry->priv->is_valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* If there are more then one secured port in the model, you can specify
|
||||
* which of the secured ports should be activated by specifying the index.
|
||||
* The index counts only for secured ports, so if you have 5 ports of which
|
||||
* ports 1, 3 and 5 are secured, the association is 0=>1, 1=>3, 2=>5
|
||||
*/
|
||||
void
|
||||
e_port_entry_activate_secured_port (EPortEntry *port_entry,
|
||||
gint index)
|
||||
{
|
||||
GtkTreeModel *model;
|
||||
GtkTreeIter iter;
|
||||
gboolean is_ssl;
|
||||
gint iters = 0;
|
||||
|
||||
g_return_if_fail (E_IS_PORT_ENTRY (port_entry));
|
||||
|
||||
model = gtk_combo_box_get_model (GTK_COMBO_BOX (port_entry));
|
||||
|
||||
if (!gtk_tree_model_get_iter_first (model, &iter))
|
||||
return;
|
||||
|
||||
do {
|
||||
gtk_tree_model_get (
|
||||
model, &iter, PORT_IS_SSL_COLUMN, &is_ssl, -1);
|
||||
if (is_ssl && (iters == index)) {
|
||||
gtk_combo_box_set_active_iter (
|
||||
GTK_COMBO_BOX (port_entry), &iter);
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_ssl)
|
||||
iters++;
|
||||
|
||||
} while (gtk_tree_model_iter_next (model, &iter));
|
||||
}
|
||||
|
||||
/**
|
||||
* If there are more then one unsecured port in the model, you can specify
|
||||
* which of the unsecured ports should be activated by specifiying the index.
|
||||
* The index counts only for unsecured ports, so if you have 5 ports, of which
|
||||
* ports 2 and 4 are unsecured, the associtation is 0=>2, 1=>4
|
||||
*/
|
||||
void
|
||||
e_port_entry_activate_nonsecured_port (EPortEntry *port_entry,
|
||||
gint index)
|
||||
{
|
||||
GtkTreeModel *model;
|
||||
GtkTreeIter iter;
|
||||
gboolean is_ssl;
|
||||
gint iters = 0;
|
||||
|
||||
g_return_if_fail (E_IS_PORT_ENTRY (port_entry));
|
||||
|
||||
model = gtk_combo_box_get_model (GTK_COMBO_BOX (port_entry));
|
||||
|
||||
if (!gtk_tree_model_get_iter_first (model, &iter))
|
||||
return;
|
||||
|
||||
do {
|
||||
gtk_tree_model_get (model, &iter, PORT_IS_SSL_COLUMN, &is_ssl, -1);
|
||||
if (!is_ssl && (iters == index)) {
|
||||
gtk_combo_box_set_active_iter (
|
||||
GTK_COMBO_BOX (port_entry), &iter);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_ssl)
|
||||
iters++;
|
||||
|
||||
} while (gtk_tree_model_iter_next (model, &iter));
|
||||
}
|
||||
82
widgets/misc/e-port-entry.h
Normal file
82
widgets/misc/e-port-entry.h
Normal file
@ -0,0 +1,82 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
|
||||
|
||||
/*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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 02110-1301
|
||||
* USA
|
||||
*
|
||||
* Authors:
|
||||
* Dan Vratil <dvratil@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef E_PORT_ENTRY_H
|
||||
#define E_PORT_ENTRY_H
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <camel/camel.h>
|
||||
|
||||
/* Standard GObject macros */
|
||||
#define E_TYPE_PORT_ENTRY \
|
||||
(e_port_entry_get_type ())
|
||||
#define E_PORT_ENTRY(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST \
|
||||
((obj), E_TYPE_PORT_ENTRY, EPortEntry))
|
||||
#define E_PORT_ENTRY_CLASS(cls) \
|
||||
(G_TYPE_CHECK_CLASS_CAST \
|
||||
((cls), E_TYPE_PORT_ENTRY, EPortEntryClass))
|
||||
#define E_IS_PORT_ENTRY(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE \
|
||||
((obj), E_TYPE_PORT_ENTRY))
|
||||
#define E_IS_PORT_ENTRY_CLASS(cls) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE \
|
||||
((cls), E_TYPE_PORT_ENTRY))
|
||||
#define E_PORT_ENTRY_GET_CLASS(obj) \
|
||||
(G_TYPE_INSTANCE_GET_CLASS \
|
||||
((obj), E_TYPE_PORT_ENTRY, EPortEntryClass))
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _EPortEntry EPortEntry;
|
||||
typedef struct _EPortEntryClass EPortEntryClass;
|
||||
typedef struct _EPortEntryPrivate EPortEntryPrivate;
|
||||
|
||||
struct _EPortEntry {
|
||||
GtkComboBox parent;
|
||||
EPortEntryPrivate *priv;
|
||||
};
|
||||
|
||||
struct _EPortEntryClass {
|
||||
GtkComboBoxClass parent_class;
|
||||
};
|
||||
|
||||
GType e_port_entry_get_type (void) G_GNUC_CONST;
|
||||
GtkWidget * e_port_entry_new (void);
|
||||
void e_port_entry_set_camel_entries (EPortEntry *pentry,
|
||||
CamelProviderPortEntry *entries);
|
||||
void e_port_entry_security_port_changed
|
||||
(EPortEntry *pentry,
|
||||
gchar *ssl);
|
||||
gint e_port_entry_get_port (EPortEntry *pentry);
|
||||
void e_port_entry_set_port (EPortEntry *pentry, gint port);
|
||||
gboolean e_port_entry_is_valid (EPortEntry *pentry);
|
||||
void e_port_entry_activate_secured_port
|
||||
(EPortEntry *pentry,
|
||||
gint index);
|
||||
void e_port_entry_activate_nonsecured_port
|
||||
(EPortEntry *pentry,
|
||||
gint index);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* E_PORT_ENTRY_H */
|
||||
Reference in New Issue
Block a user