mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-05-08 13:38:43 +02:00
Currently libnm headers include <linux/if_{ether,infiniband,vlan}.h>.
These are public headers, that means we drag in the linux header to all
users of <NetworkManager.h>.
Often the linux headers work badly together with certain headers from libc.
Depending on the libc version, you have to order linux headers in the right
order with respect to libc headers.
We should do better about libnm headers. As a first step, assume that
the linux headers don't get included by libnm, and explicitly include
them where they are needed.
445 lines
17 KiB
C
445 lines
17 KiB
C
/* SPDX-License-Identifier: GPL-2.0+ */
|
|
/*
|
|
* Copyright (C) 2013 Red Hat, Inc.
|
|
*/
|
|
|
|
/**
|
|
* SECTION:nmt-page-bond
|
|
* @short_description: The editor page for Bond connections
|
|
*
|
|
* Note that this is fairly different from most of the other editor
|
|
* pages, because #NMSettingBond doesn't have properties, so we
|
|
* can't just use #GBinding.
|
|
*/
|
|
|
|
#include "nm-default.h"
|
|
|
|
#include "nmt-page-bond.h"
|
|
|
|
#include <linux/if_ether.h>
|
|
#include <linux/if_infiniband.h>
|
|
|
|
#include "nm-libnm-core-intern/nm-libnm-core-utils.h"
|
|
#include "nmt-mac-entry.h"
|
|
#include "nmt-address-list.h"
|
|
#include "nmt-slave-list.h"
|
|
|
|
G_DEFINE_TYPE(NmtPageBond, nmt_page_bond, NMT_TYPE_EDITOR_PAGE_DEVICE)
|
|
|
|
#define NMT_PAGE_BOND_GET_PRIVATE(o) \
|
|
(G_TYPE_INSTANCE_GET_PRIVATE((o), NMT_TYPE_PAGE_BOND, NmtPageBondPrivate))
|
|
|
|
typedef enum {
|
|
NMT_PAGE_BOND_MONITORING_UNKNOWN = -1,
|
|
NMT_PAGE_BOND_MONITORING_MII = 0,
|
|
NMT_PAGE_BOND_MONITORING_ARP = 1,
|
|
} NmtPageBondMonitoringMode;
|
|
|
|
typedef struct {
|
|
NmtSlaveList *slaves;
|
|
|
|
/* Note: when adding new options to the UI also ensure they are
|
|
* initialized in bond_connection_setup_func()
|
|
*/
|
|
NmtNewtPopup * mode;
|
|
NmtNewtEntry * primary;
|
|
NmtNewtPopup * monitoring;
|
|
NmtNewtEntry * miimon;
|
|
NmtNewtEntry * updelay;
|
|
NmtNewtEntry * downdelay;
|
|
NmtNewtEntry * arp_interval;
|
|
NmtAddressList *arp_ip_target;
|
|
|
|
NmtPageBondMonitoringMode monitoring_mode;
|
|
|
|
NMSettingBond *s_bond;
|
|
GType slave_type;
|
|
gboolean updating;
|
|
} NmtPageBondPrivate;
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void arp_ip_target_widget_changed(GObject *object, GParamSpec *pspec, gpointer user_data);
|
|
|
|
/*****************************************************************************/
|
|
|
|
NmtEditorPage *
|
|
nmt_page_bond_new(NMConnection *conn, NmtDeviceEntry *deventry)
|
|
{
|
|
return g_object_new(NMT_TYPE_PAGE_BOND, "connection", conn, "device-entry", deventry, NULL);
|
|
}
|
|
|
|
static void
|
|
nmt_page_bond_init(NmtPageBond *bond)
|
|
{
|
|
NmtPageBondPrivate *priv = NMT_PAGE_BOND_GET_PRIVATE(bond);
|
|
|
|
priv->monitoring_mode = NMT_PAGE_BOND_MONITORING_UNKNOWN;
|
|
priv->slave_type = G_TYPE_NONE;
|
|
}
|
|
|
|
static NmtNewtPopupEntry bond_mode[] = {
|
|
{N_("Round-robin"), "balance-rr"},
|
|
{N_("Active Backup"), "active-backup"},
|
|
{N_("XOR"), "balance-xor"},
|
|
{N_("Broadcast"), "broadcast"},
|
|
{N_("802.3ad"), "802.3ad"},
|
|
{N_("Adaptive Transmit Load Balancing (tlb)"), "balance-tlb"},
|
|
{N_("Adaptive Load Balancing (alb)"), "balance-alb"},
|
|
{NULL, NULL}};
|
|
|
|
/* NB: the ordering/numbering here corresponds to NmtPageBondMonitoringMode */
|
|
static NmtNewtPopupEntry bond_monitoring[] = {{N_("MII (recommended)"), "mii"},
|
|
{N_("ARP"), "arp"},
|
|
{NULL, NULL}};
|
|
|
|
static void
|
|
bond_options_changed(GObject *object, GParamSpec *pspec, gpointer user_data)
|
|
{
|
|
NMSettingBond * s_bond = NM_SETTING_BOND(object);
|
|
NmtPageBond * bond = NMT_PAGE_BOND(user_data);
|
|
NmtPageBondPrivate * priv = NMT_PAGE_BOND_GET_PRIVATE(bond);
|
|
gs_free const char **ips = NULL;
|
|
const char * val;
|
|
gboolean visible_mii;
|
|
NMBondMode mode;
|
|
|
|
if (priv->updating)
|
|
return;
|
|
|
|
priv->updating = TRUE;
|
|
|
|
val = nm_setting_bond_get_option_by_name(s_bond, NM_SETTING_BOND_OPTION_MODE);
|
|
nmt_newt_popup_set_active_id(priv->mode, val);
|
|
|
|
mode = _nm_setting_bond_mode_from_string(val ?: "");
|
|
|
|
val = nm_setting_bond_get_option_by_name(s_bond, NM_SETTING_BOND_OPTION_PRIMARY);
|
|
nmt_newt_entry_set_text(priv->primary, val);
|
|
|
|
nmt_newt_widget_set_visible(NMT_NEWT_WIDGET(priv->primary), mode == NM_BOND_MODE_ACTIVEBACKUP);
|
|
|
|
if (priv->monitoring_mode == NMT_PAGE_BOND_MONITORING_UNKNOWN) {
|
|
val = nm_setting_bond_get_option_by_name(s_bond, NM_SETTING_BOND_OPTION_ARP_INTERVAL);
|
|
if (_nm_utils_ascii_str_to_int64(val, 10, 0, G_MAXINT, 0) > 0)
|
|
priv->monitoring_mode = NMT_PAGE_BOND_MONITORING_ARP;
|
|
else
|
|
priv->monitoring_mode = NMT_PAGE_BOND_MONITORING_MII;
|
|
}
|
|
nmt_newt_popup_set_active(priv->monitoring, priv->monitoring_mode);
|
|
|
|
val = nm_setting_bond_get_option_by_name(s_bond, NM_SETTING_BOND_OPTION_MIIMON);
|
|
nmt_newt_entry_set_text(priv->miimon, val ?: "0");
|
|
|
|
val = nm_setting_bond_get_option_by_name(s_bond, NM_SETTING_BOND_OPTION_UPDELAY);
|
|
nmt_newt_entry_set_text(priv->updelay, val ?: "0");
|
|
|
|
val = nm_setting_bond_get_option_by_name(s_bond, NM_SETTING_BOND_OPTION_DOWNDELAY);
|
|
nmt_newt_entry_set_text(priv->downdelay, val ?: "0");
|
|
|
|
val = nm_setting_bond_get_option_by_name(s_bond, NM_SETTING_BOND_OPTION_ARP_INTERVAL);
|
|
nmt_newt_entry_set_text(priv->arp_interval, val ?: "0");
|
|
|
|
val = nm_setting_bond_get_option_by_name(s_bond, NM_SETTING_BOND_OPTION_ARP_IP_TARGET);
|
|
ips = nm_utils_bond_option_arp_ip_targets_split(val);
|
|
g_object_set(G_OBJECT(priv->arp_ip_target),
|
|
"strings",
|
|
ips ?: NM_PTRARRAY_EMPTY(const char *),
|
|
NULL);
|
|
|
|
visible_mii = (priv->monitoring_mode == NMT_PAGE_BOND_MONITORING_MII);
|
|
|
|
nmt_newt_widget_set_visible(NMT_NEWT_WIDGET(priv->miimon), visible_mii);
|
|
nmt_newt_widget_set_visible(NMT_NEWT_WIDGET(priv->updelay), visible_mii);
|
|
nmt_newt_widget_set_visible(NMT_NEWT_WIDGET(priv->downdelay), visible_mii);
|
|
nmt_newt_widget_set_visible(NMT_NEWT_WIDGET(priv->arp_interval), !visible_mii);
|
|
nmt_newt_widget_set_visible(NMT_NEWT_WIDGET(priv->arp_ip_target), !visible_mii);
|
|
|
|
priv->updating = FALSE;
|
|
}
|
|
|
|
static void
|
|
slaves_changed(GObject *object, GParamSpec *pspec, gpointer user_data)
|
|
{
|
|
NmtPageBond * bond = NMT_PAGE_BOND(user_data);
|
|
NmtPageBondPrivate *priv = NMT_PAGE_BOND_GET_PRIVATE(bond);
|
|
GPtrArray * slaves;
|
|
|
|
g_object_get(object, "connections", &slaves, NULL);
|
|
if (slaves->len == 0) {
|
|
if (priv->slave_type == G_TYPE_NONE)
|
|
return;
|
|
priv->slave_type = G_TYPE_NONE;
|
|
} else {
|
|
NMConnection *slave = slaves->pdata[0];
|
|
|
|
if (priv->slave_type != G_TYPE_NONE)
|
|
return;
|
|
|
|
if (nm_connection_is_type(slave, NM_SETTING_INFINIBAND_SETTING_NAME))
|
|
priv->slave_type = NM_TYPE_SETTING_INFINIBAND;
|
|
else
|
|
priv->slave_type = NM_TYPE_SETTING_WIRED;
|
|
}
|
|
|
|
if (priv->slave_type == NM_TYPE_SETTING_INFINIBAND) {
|
|
nmt_newt_popup_set_active_id(priv->mode, "active-backup");
|
|
nmt_newt_component_set_sensitive(NMT_NEWT_COMPONENT(priv->mode), FALSE);
|
|
} else
|
|
nmt_newt_component_set_sensitive(NMT_NEWT_COMPONENT(priv->mode), TRUE);
|
|
}
|
|
|
|
static void
|
|
_bond_add_option(NMSettingBond *s_bond, const char *option, const char *value)
|
|
{
|
|
if (nm_str_is_empty(value))
|
|
nm_setting_bond_remove_option(s_bond, option);
|
|
else
|
|
nm_setting_bond_add_option(s_bond, option, value);
|
|
|
|
if (nm_streq(option, NM_SETTING_BOND_OPTION_ARP_INTERVAL))
|
|
_nm_setting_bond_remove_options_miimon(s_bond);
|
|
else if (nm_streq(option, NM_SETTING_BOND_OPTION_MIIMON))
|
|
_nm_setting_bond_remove_options_arp_interval(s_bond);
|
|
nm_setting_bond_remove_option(s_bond, NM_SETTING_BOND_OPTION_ACTIVE_SLAVE);
|
|
}
|
|
|
|
#define WIDGET_CHANGED_FUNC(widget, func, option, dflt) \
|
|
static void widget##_widget_changed(GObject *object, GParamSpec *pspec, gpointer user_data) \
|
|
{ \
|
|
NmtPageBond * bond = NMT_PAGE_BOND(user_data); \
|
|
NmtPageBondPrivate *priv = NMT_PAGE_BOND_GET_PRIVATE(bond); \
|
|
const char * v; \
|
|
\
|
|
if (priv->updating) \
|
|
return; \
|
|
\
|
|
v = func(priv->widget); \
|
|
priv->updating = TRUE; \
|
|
_bond_add_option(priv->s_bond, option, v ?: dflt); \
|
|
priv->updating = FALSE; \
|
|
}
|
|
|
|
WIDGET_CHANGED_FUNC(primary, nmt_newt_entry_get_text, NM_SETTING_BOND_OPTION_PRIMARY, NULL)
|
|
WIDGET_CHANGED_FUNC(miimon, nmt_newt_entry_get_text, NM_SETTING_BOND_OPTION_MIIMON, "0")
|
|
WIDGET_CHANGED_FUNC(updelay, nmt_newt_entry_get_text, NM_SETTING_BOND_OPTION_UPDELAY, "0")
|
|
WIDGET_CHANGED_FUNC(downdelay, nmt_newt_entry_get_text, NM_SETTING_BOND_OPTION_DOWNDELAY, "0")
|
|
WIDGET_CHANGED_FUNC(arp_interval, nmt_newt_entry_get_text, NM_SETTING_BOND_OPTION_ARP_INTERVAL, "0")
|
|
|
|
static void
|
|
mode_widget_changed(GObject *object, GParamSpec *pspec, gpointer user_data)
|
|
{
|
|
NmtPageBond * bond = NMT_PAGE_BOND(user_data);
|
|
NmtPageBondPrivate *priv = NMT_PAGE_BOND_GET_PRIVATE(bond);
|
|
const char * mode;
|
|
|
|
if (priv->updating)
|
|
return;
|
|
|
|
mode = nmt_newt_popup_get_active_id(priv->mode);
|
|
priv->updating = TRUE;
|
|
_bond_add_option(priv->s_bond, NM_SETTING_BOND_OPTION_MODE, mode);
|
|
priv->updating = FALSE;
|
|
|
|
if (NM_IN_STRSET(mode, "balance-tlb", "balance-alb")) {
|
|
nmt_newt_popup_set_active(priv->monitoring, NMT_PAGE_BOND_MONITORING_MII);
|
|
nmt_newt_component_set_sensitive(NMT_NEWT_COMPONENT(priv->monitoring), FALSE);
|
|
} else
|
|
nmt_newt_component_set_sensitive(NMT_NEWT_COMPONENT(priv->monitoring), TRUE);
|
|
|
|
if (NM_IN_STRSET(mode, "active-backup", "balance-alb", "balance-tlb")) {
|
|
nmt_newt_widget_set_visible(NMT_NEWT_WIDGET(priv->primary), TRUE);
|
|
_bond_add_option(priv->s_bond,
|
|
NM_SETTING_BOND_OPTION_PRIMARY,
|
|
nmt_newt_entry_get_text(priv->primary));
|
|
} else {
|
|
nmt_newt_widget_set_visible(NMT_NEWT_WIDGET(priv->primary), FALSE);
|
|
nm_setting_bond_remove_option(priv->s_bond, NM_SETTING_BOND_OPTION_PRIMARY);
|
|
}
|
|
}
|
|
|
|
static void
|
|
monitoring_widget_changed(GObject *object, GParamSpec *pspec, gpointer user_data)
|
|
{
|
|
NmtPageBond * bond = NMT_PAGE_BOND(user_data);
|
|
NmtPageBondPrivate *priv = NMT_PAGE_BOND_GET_PRIVATE(bond);
|
|
gboolean visible_mii;
|
|
|
|
if (priv->updating)
|
|
return;
|
|
|
|
priv->monitoring_mode = nmt_newt_popup_get_active(priv->monitoring);
|
|
visible_mii = (priv->monitoring_mode == NMT_PAGE_BOND_MONITORING_MII);
|
|
|
|
nmt_newt_widget_set_visible(NMT_NEWT_WIDGET(priv->miimon), visible_mii);
|
|
nmt_newt_widget_set_visible(NMT_NEWT_WIDGET(priv->updelay), visible_mii);
|
|
nmt_newt_widget_set_visible(NMT_NEWT_WIDGET(priv->downdelay), visible_mii);
|
|
nmt_newt_widget_set_visible(NMT_NEWT_WIDGET(priv->arp_interval), !visible_mii);
|
|
nmt_newt_widget_set_visible(NMT_NEWT_WIDGET(priv->arp_ip_target), !visible_mii);
|
|
|
|
if (visible_mii) {
|
|
miimon_widget_changed(NULL, NULL, bond);
|
|
updelay_widget_changed(NULL, NULL, bond);
|
|
downdelay_widget_changed(NULL, NULL, bond);
|
|
} else {
|
|
arp_interval_widget_changed(NULL, NULL, bond);
|
|
arp_ip_target_widget_changed(NULL, NULL, bond);
|
|
}
|
|
}
|
|
|
|
static void
|
|
arp_ip_target_widget_changed(GObject *object, GParamSpec *pspec, gpointer user_data)
|
|
{
|
|
NmtPageBond * bond = NMT_PAGE_BOND(user_data);
|
|
NmtPageBondPrivate *priv = NMT_PAGE_BOND_GET_PRIVATE(bond);
|
|
char ** ips, *target;
|
|
|
|
if (priv->updating)
|
|
return;
|
|
|
|
g_object_get(G_OBJECT(priv->arp_ip_target), "strings", &ips, NULL);
|
|
target = g_strjoinv(",", ips);
|
|
|
|
priv->updating = TRUE;
|
|
_bond_add_option(priv->s_bond, NM_SETTING_BOND_OPTION_ARP_IP_TARGET, target);
|
|
priv->updating = FALSE;
|
|
|
|
g_free(target);
|
|
g_strfreev(ips);
|
|
}
|
|
|
|
static gboolean
|
|
bond_connection_type_filter(GType connection_type, gpointer user_data)
|
|
{
|
|
NmtPageBond * bond = user_data;
|
|
NmtPageBondPrivate *priv = NMT_PAGE_BOND_GET_PRIVATE(bond);
|
|
|
|
if (priv->slave_type != NM_TYPE_SETTING_WIRED && connection_type == NM_TYPE_SETTING_INFINIBAND)
|
|
return TRUE;
|
|
if (priv->slave_type != NM_TYPE_SETTING_INFINIBAND && connection_type == NM_TYPE_SETTING_WIRED)
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
nmt_page_bond_constructed(GObject *object)
|
|
{
|
|
NmtPageBond * bond = NMT_PAGE_BOND(object);
|
|
NmtPageBondPrivate *priv = NMT_PAGE_BOND_GET_PRIVATE(bond);
|
|
NmtEditorSection * section;
|
|
NmtEditorGrid * grid;
|
|
NMSettingWired * s_wired;
|
|
NMSettingBond * s_bond;
|
|
NmtNewtWidget * widget, *label;
|
|
NMConnection * conn;
|
|
|
|
conn = nmt_editor_page_get_connection(NMT_EDITOR_PAGE(bond));
|
|
s_bond = nm_connection_get_setting_bond(conn);
|
|
if (!s_bond) {
|
|
nm_connection_add_setting(conn, nm_setting_bond_new());
|
|
s_bond = nm_connection_get_setting_bond(conn);
|
|
}
|
|
priv->s_bond = s_bond;
|
|
|
|
s_wired = nm_connection_get_setting_wired(conn);
|
|
if (!s_wired) {
|
|
nm_connection_add_setting(conn, nm_setting_wired_new());
|
|
s_wired = nm_connection_get_setting_wired(conn);
|
|
}
|
|
|
|
section = nmt_editor_section_new(_("BOND"), NULL, TRUE);
|
|
grid = nmt_editor_section_get_body(section);
|
|
|
|
widget = nmt_newt_separator_new();
|
|
nmt_editor_grid_append(grid, _("Slaves"), widget, NULL);
|
|
nmt_editor_grid_set_row_flags(grid, widget, NMT_EDITOR_GRID_ROW_LABEL_ALIGN_LEFT);
|
|
|
|
widget = nmt_slave_list_new(conn, bond_connection_type_filter, bond);
|
|
g_signal_connect(widget, "notify::connections", G_CALLBACK(slaves_changed), bond);
|
|
nmt_editor_grid_append(grid, NULL, widget, NULL);
|
|
priv->slaves = NMT_SLAVE_LIST(widget);
|
|
|
|
widget = nmt_newt_popup_new(bond_mode);
|
|
g_signal_connect(widget, "notify::active-id", G_CALLBACK(mode_widget_changed), bond);
|
|
nmt_editor_grid_append(grid, _("Mode"), widget, NULL);
|
|
priv->mode = NMT_NEWT_POPUP(widget);
|
|
|
|
widget = nmt_newt_entry_new(40, 0);
|
|
g_signal_connect(widget, "notify::text", G_CALLBACK(primary_widget_changed), bond);
|
|
nmt_editor_grid_append(grid, _("Primary"), widget, NULL);
|
|
priv->primary = NMT_NEWT_ENTRY(widget);
|
|
|
|
widget = nmt_newt_popup_new(bond_monitoring);
|
|
g_signal_connect(widget, "notify::active", G_CALLBACK(monitoring_widget_changed), bond);
|
|
nmt_editor_grid_append(grid, _("Link monitoring"), widget, NULL);
|
|
priv->monitoring = NMT_NEWT_POPUP(widget);
|
|
|
|
widget = nmt_newt_entry_numeric_new(10, 0, G_MAXINT);
|
|
g_signal_connect(widget, "notify::text", G_CALLBACK(miimon_widget_changed), bond);
|
|
label = nmt_newt_label_new(C_("milliseconds", "ms"));
|
|
nmt_editor_grid_append(grid, _("Monitoring frequency"), widget, label);
|
|
priv->miimon = NMT_NEWT_ENTRY(widget);
|
|
|
|
widget = nmt_newt_entry_numeric_new(10, 0, G_MAXINT);
|
|
g_signal_connect(widget, "notify::text", G_CALLBACK(updelay_widget_changed), bond);
|
|
label = nmt_newt_label_new(C_("milliseconds", "ms"));
|
|
nmt_editor_grid_append(grid, _("Link up delay"), widget, label);
|
|
priv->updelay = NMT_NEWT_ENTRY(widget);
|
|
|
|
widget = nmt_newt_entry_numeric_new(10, 0, G_MAXINT);
|
|
g_signal_connect(widget, "notify::text", G_CALLBACK(downdelay_widget_changed), bond);
|
|
label = nmt_newt_label_new(C_("milliseconds", "ms"));
|
|
nmt_editor_grid_append(grid, _("Link down delay"), widget, label);
|
|
priv->downdelay = NMT_NEWT_ENTRY(widget);
|
|
|
|
widget = nmt_newt_entry_numeric_new(10, 0, G_MAXINT);
|
|
g_signal_connect(widget, "notify::text", G_CALLBACK(arp_interval_widget_changed), bond);
|
|
label = nmt_newt_label_new(C_("milliseconds", "ms"));
|
|
nmt_editor_grid_append(grid, _("Monitoring frequency"), widget, label);
|
|
priv->arp_interval = NMT_NEWT_ENTRY(widget);
|
|
|
|
widget = nmt_address_list_new(NMT_ADDRESS_LIST_IP4);
|
|
g_signal_connect(widget, "notify::strings", G_CALLBACK(arp_ip_target_widget_changed), bond);
|
|
nmt_editor_grid_append(grid, _("ARP targets"), widget, NULL);
|
|
priv->arp_ip_target = NMT_ADDRESS_LIST(widget);
|
|
|
|
widget = nmt_mac_entry_new(40, ETH_ALEN, NMT_MAC_ENTRY_TYPE_CLONED);
|
|
g_object_bind_property(s_wired,
|
|
NM_SETTING_WIRED_CLONED_MAC_ADDRESS,
|
|
widget,
|
|
"mac-address",
|
|
G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
|
|
nmt_editor_grid_append(grid, _("Cloned MAC address"), widget, NULL);
|
|
|
|
g_signal_connect(s_bond,
|
|
"notify::" NM_SETTING_BOND_OPTIONS,
|
|
G_CALLBACK(bond_options_changed),
|
|
bond);
|
|
bond_options_changed(G_OBJECT(s_bond), NULL, bond);
|
|
slaves_changed(G_OBJECT(priv->slaves), NULL, bond);
|
|
|
|
nmt_editor_page_add_section(NMT_EDITOR_PAGE(bond), section);
|
|
|
|
G_OBJECT_CLASS(nmt_page_bond_parent_class)->constructed(object);
|
|
}
|
|
|
|
static void
|
|
nmt_page_bond_saved(NmtEditorPage *editor_page)
|
|
{
|
|
NmtPageBondPrivate *priv = NMT_PAGE_BOND_GET_PRIVATE(editor_page);
|
|
|
|
nmt_edit_connection_list_recommit(NMT_EDIT_CONNECTION_LIST(priv->slaves));
|
|
}
|
|
|
|
static void
|
|
nmt_page_bond_class_init(NmtPageBondClass *bond_class)
|
|
{
|
|
GObjectClass * object_class = G_OBJECT_CLASS(bond_class);
|
|
NmtEditorPageClass *editor_page_class = NMT_EDITOR_PAGE_CLASS(bond_class);
|
|
|
|
g_type_class_add_private(bond_class, sizeof(NmtPageBondPrivate));
|
|
|
|
object_class->constructed = nmt_page_bond_constructed;
|
|
editor_page_class->saved = nmt_page_bond_saved;
|
|
}
|