[network-manager-applet] connection-editor: add support for bridges



commit feeeb91176445b7ce4015db1280699ac2de8a5fb
Author: Dan Winship <danw gnome org>
Date:   Thu Nov 1 15:46:37 2012 -0400

    connection-editor: add support for bridges

 po/POTFILES.in                               |    2 +
 src/connection-editor/Makefile.am            |    6 +
 src/connection-editor/ce-page-bridge-port.ui |  115 +++++++
 src/connection-editor/ce-page-bridge.ui      |  471 ++++++++++++++++++++++++++
 src/connection-editor/new-connection.c       |    7 +
 src/connection-editor/nm-connection-editor.c |   11 +
 src/connection-editor/nm-connection-list.c   |    9 +-
 src/connection-editor/page-bridge-port.c     |  172 ++++++++++
 src/connection-editor/page-bridge-port.h     |   58 ++++
 src/connection-editor/page-bridge.c          |  348 +++++++++++++++++++
 src/connection-editor/page-bridge.h          |   62 ++++
 src/connection-editor/page-master.c          |   13 +
 src/connection-editor/page-master.h          |    1 +
 13 files changed, 1272 insertions(+), 3 deletions(-)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 3dd00b2..5d483cc 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -40,6 +40,8 @@ src/connection-editor/nm-connection-editor.c
 src/connection-editor/nm-connection-list.c
 src/connection-editor/page-8021x-security.c
 src/connection-editor/page-bond.c
+src/connection-editor/page-bridge.c
+src/connection-editor/page-bridge-port.c
 src/connection-editor/page-dsl.c
 src/connection-editor/page-ethernet.c
 src/connection-editor/page-general.c
diff --git a/src/connection-editor/Makefile.am b/src/connection-editor/Makefile.am
index 742a7da..773a559 100644
--- a/src/connection-editor/Makefile.am
+++ b/src/connection-editor/Makefile.am
@@ -56,6 +56,10 @@ nm_connection_editor_SOURCES = \
 	page-master.c \
 	page-bond.h \
 	page-bond.c \
+	page-bridge.h \
+	page-bridge.c \
+	page-bridge-port.h \
+	page-bridge-port.c \
 	page-vlan.h \
 	page-vlan.c \
 	vpn-helpers.h \
@@ -94,6 +98,8 @@ ui_DATA = \
 	ce-page-wimax.ui \
 	ce-page-infiniband.ui \
 	ce-page-bond.ui \
+	ce-page-bridge.ui \
+	ce-page-bridge-port.ui \
 	ce-page-ip4.ui \
 	ce-ip4-routes.ui \
 	ce-page-ip6.ui \
diff --git a/src/connection-editor/ce-page-bridge-port.ui b/src/connection-editor/ce-page-bridge-port.ui
new file mode 100644
index 0000000..28871bd
--- /dev/null
+++ b/src/connection-editor/ce-page-bridge-port.ui
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <requires lib="gtk+" version="2.16"/>
+  <object class="GtkTable" id="BridgePortPage">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="border_width">12</property>
+    <property name="n_rows">3</property>
+    <property name="n_columns">2</property>
+    <property name="column_spacing">12</property>
+    <property name="row_spacing">6</property>
+    <child>
+      <object class="GtkCheckButton" id="bridge_port_hairpin_mode">
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="receives_default">False</property>
+        <property name="use_underline">True</property>
+        <property name="xalign">0</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">2</property>
+        <property name="bottom_attach">3</property>
+        <property name="y_options">GTK_FILL</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel" id="bridge_port_path_cost_label">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="xalign">0</property>
+        <property name="label" translatable="yes">Path _cost:</property>
+        <property name="use_underline">True</property>
+      </object>
+      <packing>
+        <property name="top_attach">1</property>
+        <property name="bottom_attach">2</property>
+        <property name="y_options">GTK_FILL</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel" id="bridge_port_priority_label">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="xalign">0</property>
+        <property name="label" translatable="yes">_Priority:</property>
+        <property name="use_underline">True</property>
+      </object>
+      <packing>
+        <property name="y_options">GTK_FILL</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkSpinButton" id="bridge_port_priority">
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="invisible_char">â</property>
+        <property name="invisible_char_set">True</property>
+        <property name="adjustment">bridge_port_priority_adjustment</property>
+        <property name="numeric">True</property>
+      </object>
+      <packing>
+        <property name="left_attach">1</property>
+        <property name="right_attach">2</property>
+        <property name="y_options">GTK_FILL</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkSpinButton" id="bridge_port_path_cost">
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="invisible_char">â</property>
+        <property name="invisible_char_set">True</property>
+        <property name="adjustment">bridge_port_path_cost_adjustment</property>
+        <property name="snap_to_ticks">True</property>
+        <property name="numeric">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>
+        <property name="y_options">GTK_FILL</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel" id="bridge_port_hairpin_mode_label">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="xalign">0</property>
+        <property name="label" translatable="yes">_Hairpin mode:</property>
+        <property name="use_underline">True</property>
+        <property name="mnemonic_widget">bridge_port_hairpin_mode</property>
+      </object>
+      <packing>
+        <property name="top_attach">2</property>
+        <property name="bottom_attach">3</property>
+        <property name="y_options">GTK_FILL</property>
+      </packing>
+    </child>
+  </object>
+  <object class="GtkAdjustment" id="bridge_port_path_cost_adjustment">
+    <property name="lower">1</property>
+    <property name="upper">65535</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
+  </object>
+  <object class="GtkAdjustment" id="bridge_port_priority_adjustment">
+    <property name="upper">63</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">1</property>
+  </object>
+</interface>
diff --git a/src/connection-editor/ce-page-bridge.ui b/src/connection-editor/ce-page-bridge.ui
new file mode 100644
index 0000000..bc3cd10
--- /dev/null
+++ b/src/connection-editor/ce-page-bridge.ui
@@ -0,0 +1,471 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <requires lib="gtk+" version="2.16"/>
+  <object class="GtkAdjustment" id="bridge_ageing_time_adjustment">
+    <property name="upper">4294967296</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
+  </object>
+  <object class="GtkAdjustment" id="bridge_forward_delay_adjustment">
+    <property name="upper">30</property>
+    <property name="value">15</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">100</property>
+  </object>
+  <object class="GtkAdjustment" id="bridge_hello_time_adjustment">
+    <property name="lower">1</property>
+    <property name="upper">10</property>
+    <property name="value">2</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">1</property>
+  </object>
+  <object class="GtkAdjustment" id="bridge_max_age_adjustment">
+    <property name="lower">6</property>
+    <property name="upper">40</property>
+    <property name="value">6</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">1</property>
+  </object>
+  <object class="GtkAdjustment" id="bridge_priority_adjustment">
+    <property name="upper">65535</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
+  </object>
+  <object class="GtkListStore" id="master_connections_model">
+    <columns>
+      <!-- column-name connection -->
+      <column type="NMRemoteConnection"/>
+      <!-- column-name name -->
+      <column type="gchararray"/>
+    </columns>
+  </object>
+  <object class="GtkTable" id="BridgePage">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="border_width">12</property>
+    <property name="n_rows">9</property>
+    <property name="n_columns">2</property>
+    <property name="column_spacing">12</property>
+    <property name="row_spacing">6</property>
+    <child>
+      <object class="GtkLabel" id="master_connections_label">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="xalign">0</property>
+        <property name="label" translatable="yes">Bridged _connections:</property>
+        <property name="use_underline">True</property>
+      </object>
+      <packing>
+        <property name="right_attach">2</property>
+        <property name="top_attach">1</property>
+        <property name="bottom_attach">2</property>
+        <property name="x_options">GTK_FILL</property>
+        <property name="y_options"/>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkHBox" id="hbox2">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="spacing">10</property>
+        <child>
+          <object class="GtkScrolledWindow" id="scrolledwindow1">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="shadow_type">in</property>
+            <child>
+              <object class="GtkTreeView" id="master_connections">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="model">master_connections_model</property>
+                <property name="headers_visible">False</property>
+                <child internal-child="selection">
+                  <object class="GtkTreeSelection" id="treeview-selection1"/>
+                </child>
+                <child>
+                  <object class="GtkTreeViewColumn" id="master_connection_name">
+                    <child>
+                      <object class="GtkCellRendererText" id="master_connection_renderer"/>
+                      <attributes>
+                        <attribute name="text">1</attribute>
+                      </attributes>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">True</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkButtonBox" id="buttonbox1">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="orientation">vertical</property>
+            <property name="spacing">10</property>
+            <property name="layout_style">start</property>
+            <child>
+              <object class="GtkButton" id="master_connection_add">
+                <property name="label">gtk-add</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="master_connection_edit">
+                <property name="label" translatable="yes">_Edit</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_underline">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="master_connection_delete">
+                <property name="label" translatable="yes">_Delete</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_underline">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">2</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="right_attach">2</property>
+        <property name="top_attach">2</property>
+        <property name="bottom_attach">3</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel" id="bridge_prio">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="xalign">0</property>
+        <property name="label" translatable="yes">_Priority:</property>
+        <property name="use_underline">True</property>
+      </object>
+      <packing>
+        <property name="top_attach">5</property>
+        <property name="bottom_attach">6</property>
+        <property name="y_options">GTK_FILL</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel" id="master_interface_label">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="xalign">0</property>
+        <property name="label" translatable="yes">_Interface name:</property>
+        <property name="use_underline">True</property>
+        <property name="mnemonic_widget">master_interface</property>
+      </object>
+      <packing>
+        <property name="y_options">GTK_FILL</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkEntry" id="master_interface">
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="invisible_char">â</property>
+      </object>
+      <packing>
+        <property name="left_attach">1</property>
+        <property name="right_attach">2</property>
+        <property name="y_options">GTK_FILL</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel" id="bridge_forward_delay_label">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="xalign">0</property>
+        <property name="label" translatable="yes">_Forward delay:</property>
+        <property name="use_underline">True</property>
+        <property name="mnemonic_widget">bridge_forward_delay</property>
+      </object>
+      <packing>
+        <property name="top_attach">6</property>
+        <property name="bottom_attach">7</property>
+        <property name="y_options">GTK_FILL</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel" id="bridge_hello_time_label">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="xalign">0</property>
+        <property name="label" translatable="yes">_Hello time:</property>
+        <property name="use_underline">True</property>
+        <property name="mnemonic_widget">bridge_hello_time</property>
+      </object>
+      <packing>
+        <property name="top_attach">7</property>
+        <property name="bottom_attach">8</property>
+        <property name="y_options">GTK_FILL</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkHBox" id="bridge_forward_delay_box">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="spacing">4</property>
+        <child>
+          <object class="GtkSpinButton" id="bridge_forward_delay">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="invisible_char">â</property>
+            <property name="invisible_char_set">True</property>
+            <property name="adjustment">bridge_forward_delay_adjustment</property>
+            <property name="snap_to_ticks">True</property>
+            <property name="numeric">True</property>
+          </object>
+          <packing>
+            <property name="expand">True</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="label2">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="xalign">0</property>
+            <property name="label" translatable="yes">s</property>
+          </object>
+          <packing>
+            <property name="expand">True</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="left_attach">1</property>
+        <property name="right_attach">2</property>
+        <property name="top_attach">6</property>
+        <property name="bottom_attach">7</property>
+        <property name="y_options">GTK_FILL</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkHBox" id="bridge_hello_time_box">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="spacing">4</property>
+        <child>
+          <object class="GtkSpinButton" id="bridge_hello_time">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="invisible_char">â</property>
+            <property name="invisible_char_set">True</property>
+            <property name="adjustment">bridge_hello_time_adjustment</property>
+            <property name="snap_to_ticks">True</property>
+            <property name="numeric">True</property>
+          </object>
+          <packing>
+            <property name="expand">True</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="label3">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="xalign">0</property>
+            <property name="label" translatable="yes">s</property>
+          </object>
+          <packing>
+            <property name="expand">True</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="left_attach">1</property>
+        <property name="right_attach">2</property>
+        <property name="top_attach">7</property>
+        <property name="bottom_attach">8</property>
+        <property name="y_options">GTK_FILL</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkCheckButton" id="bridge_stp_checkbox">
+        <property name="label" translatable="yes">Enable _STP (Spanning Tree Protocol)</property>
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="receives_default">False</property>
+        <property name="use_underline">True</property>
+        <property name="xalign">0</property>
+        <property name="draw_indicator">True</property>
+      </object>
+      <packing>
+        <property name="right_attach">2</property>
+        <property name="top_attach">4</property>
+        <property name="bottom_attach">5</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkSpinButton" id="bridge_priority">
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="invisible_char">â</property>
+        <property name="invisible_char_set">True</property>
+        <property name="adjustment">bridge_priority_adjustment</property>
+        <property name="numeric">True</property>
+      </object>
+      <packing>
+        <property name="left_attach">1</property>
+        <property name="right_attach">2</property>
+        <property name="top_attach">5</property>
+        <property name="bottom_attach">6</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel" id="bridge_max_age_label">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="xalign">0</property>
+        <property name="label" translatable="yes">_Max age:</property>
+        <property name="use_underline">True</property>
+        <property name="mnemonic_widget">bridge_max_age</property>
+      </object>
+      <packing>
+        <property name="top_attach">8</property>
+        <property name="bottom_attach">9</property>
+        <property name="y_options">GTK_FILL</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkHBox" id="bridge_max_age_box">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="spacing">4</property>
+        <child>
+          <object class="GtkSpinButton" id="bridge_max_age">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="invisible_char">â</property>
+            <property name="invisible_char_set">True</property>
+            <property name="adjustment">bridge_max_age_adjustment</property>
+            <property name="snap_to_ticks">True</property>
+            <property name="numeric">True</property>
+          </object>
+          <packing>
+            <property name="expand">True</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="label1">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="xalign">0</property>
+            <property name="label" translatable="yes">s</property>
+          </object>
+          <packing>
+            <property name="expand">True</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="left_attach">1</property>
+        <property name="right_attach">2</property>
+        <property name="top_attach">8</property>
+        <property name="bottom_attach">9</property>
+        <property name="y_options">GTK_FILL</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel" id="bridge_ageing_time_label">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="xalign">0</property>
+        <property name="label" translatable="yes">_Aging time:</property>
+        <property name="use_underline">True</property>
+        <property name="mnemonic_widget">bridge_ageing_time</property>
+      </object>
+      <packing>
+        <property name="top_attach">3</property>
+        <property name="bottom_attach">4</property>
+        <property name="y_options">GTK_FILL</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkHBox" id="bridge_ageing_time_box">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="spacing">4</property>
+        <child>
+          <object class="GtkSpinButton" id="bridge_ageing_time">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="invisible_char">â</property>
+            <property name="invisible_char_set">True</property>
+            <property name="adjustment">bridge_ageing_time_adjustment</property>
+            <property name="snap_to_ticks">True</property>
+            <property name="numeric">True</property>
+          </object>
+          <packing>
+            <property name="expand">True</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="label4">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="xalign">0</property>
+            <property name="label" translatable="yes">s</property>
+          </object>
+          <packing>
+            <property name="expand">True</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="left_attach">1</property>
+        <property name="right_attach">2</property>
+        <property name="top_attach">3</property>
+        <property name="bottom_attach">4</property>
+        <property name="y_options">GTK_FILL</property>
+      </packing>
+    </child>
+  </object>
+</interface>
diff --git a/src/connection-editor/new-connection.c b/src/connection-editor/new-connection.c
index 4a6e1a6..e60cfda 100644
--- a/src/connection-editor/new-connection.c
+++ b/src/connection-editor/new-connection.c
@@ -32,6 +32,7 @@
 #include "page-dsl.h"
 #include "page-infiniband.h"
 #include "page-bond.h"
+#include "page-bridge.h"
 #include "page-vlan.h"
 #include "page-vpn.h"
 #include "vpn-helpers.h"
@@ -139,6 +140,12 @@ get_connection_type_list (void)
 	data.virtual = TRUE;
 	g_array_append_val (array, data);
 
+	data.name = _("Bridge");
+	data.new_connection_func = bridge_connection_new;
+	data.setting_type = NM_TYPE_SETTING_BRIDGE;
+	data.virtual = TRUE;
+	g_array_append_val (array, data);
+
 	data.name = _("VLAN");
 	data.new_connection_func = vlan_connection_new;
 	data.setting_type = NM_TYPE_SETTING_VLAN;
diff --git a/src/connection-editor/nm-connection-editor.c b/src/connection-editor/nm-connection-editor.c
index 0b99566..816d314 100644
--- a/src/connection-editor/nm-connection-editor.c
+++ b/src/connection-editor/nm-connection-editor.c
@@ -48,6 +48,7 @@
 #include <nm-setting-wimax.h>
 #include <nm-setting-infiniband.h>
 #include <nm-setting-bond.h>
+#include <nm-setting-bridge.h>
 #include <nm-utils.h>
 
 #include <nm-remote-connection.h>
@@ -70,6 +71,8 @@
 #include "page-wimax.h"
 #include "page-infiniband.h"
 #include "page-bond.h"
+#include "page-bridge.h"
+#include "page-bridge-port.h"
 #include "page-vlan.h"
 #include "ce-polkit-button.h"
 #include "vpn-helpers.h"
@@ -843,6 +846,9 @@ nm_connection_editor_set_connection (NMConnectionEditor *editor,
 	} else if (!strcmp (connection_type, NM_SETTING_BOND_SETTING_NAME)) {
 		if (!add_page (editor, ce_page_bond_new, editor->connection, error))
 			goto out;
+	} else if (!strcmp (connection_type, NM_SETTING_BRIDGE_SETTING_NAME)) {
+		if (!add_page (editor, ce_page_bridge_new, editor->connection, error))
+			goto out;
 	} else if (!strcmp (connection_type, NM_SETTING_VLAN_SETTING_NAME)) {
 		if (!add_page (editor, ce_page_vlan_new, editor->connection, error))
 			goto out;
@@ -853,6 +859,11 @@ nm_connection_editor_set_connection (NMConnectionEditor *editor,
 	slave_type = nm_setting_connection_get_slave_type (s_con);
 	if (!g_strcmp0 (slave_type, NM_SETTING_BOND_SETTING_NAME))
 		add_ip4 = add_ip6 = FALSE;
+	else if (!g_strcmp0 (slave_type, NM_SETTING_BRIDGE_SETTING_NAME)) {
+		add_ip4 = add_ip6 = FALSE;
+		if (!add_page (editor, ce_page_bridge_port_new, editor->connection, error))
+			goto out;
+	}
 
 	if (add_ip4 && !add_page (editor, ce_page_ip4_new, editor->connection, error))
 		goto out;
diff --git a/src/connection-editor/nm-connection-list.c b/src/connection-editor/nm-connection-list.c
index 2a7b708..f445edf 100644
--- a/src/connection-editor/nm-connection-list.c
+++ b/src/connection-editor/nm-connection-list.c
@@ -570,16 +570,19 @@ tree_model_visible_func (GtkTreeModel *model,
 		return gtk_tree_model_iter_has_child  (model, iter);
 	}
 
-	/* A connection node is visible unless it is a bond slave to
-	 * another known connection.
+	/* A connection node is visible unless it is a slave to a known
+	 * bond or bridge.
 	 */
 	s_con = nm_connection_get_setting_connection (connection);
 	g_object_unref (connection);
 	g_return_val_if_fail (s_con != NULL, FALSE);
 
 	master = nm_setting_connection_get_master (s_con);
+	if (!master)
+		return TRUE;
 	slave_type = nm_setting_connection_get_slave_type (s_con);
-	if (!master || g_strcmp0 (slave_type, NM_SETTING_BOND_SETTING_NAME) != 0)
+	if (   g_strcmp0 (slave_type, NM_SETTING_BOND_SETTING_NAME) != 0
+	    && g_strcmp0 (slave_type, NM_SETTING_BRIDGE_SETTING_NAME) != 0)
 		return TRUE;
 
 	if (nm_remote_settings_get_connection_by_uuid (self->settings, master))
diff --git a/src/connection-editor/page-bridge-port.c b/src/connection-editor/page-bridge-port.c
new file mode 100644
index 0000000..a1e34d3
--- /dev/null
+++ b/src/connection-editor/page-bridge-port.c
@@ -0,0 +1,172 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager Connection editor -- Connection editor for NetworkManager
+ *
+ * Dan Williams <dcbw redhat com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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.
+ *
+ * (C) Copyright 2008 - 2011 Red Hat, Inc.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+
+#include <nm-setting-connection.h>
+#include <nm-setting-bridge-port.h>
+#include <nm-utils.h>
+
+#include "page-bridge-port.h"
+
+G_DEFINE_TYPE (CEPageBridgePort, ce_page_bridge_port, CE_TYPE_PAGE)
+
+#define CE_PAGE_BRIDGE_PORT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CE_TYPE_PAGE_BRIDGE_PORT, CEPageBridgePortPrivate))
+
+typedef struct {
+	NMSettingBridgePort *setting;
+
+	GtkSpinButton *priority;
+	GtkSpinButton *path_cost;
+	GtkToggleButton *hairpin_mode;
+
+} CEPageBridgePortPrivate;
+
+static void
+bridge_port_private_init (CEPageBridgePort *self)
+{
+	CEPageBridgePortPrivate *priv = CE_PAGE_BRIDGE_PORT_GET_PRIVATE (self);
+	GtkBuilder *builder;
+
+	builder = CE_PAGE (self)->builder;
+
+	priv->priority = GTK_SPIN_BUTTON (GTK_WIDGET (gtk_builder_get_object (builder, "bridge_port_priority")));
+	priv->path_cost = GTK_SPIN_BUTTON (GTK_WIDGET (gtk_builder_get_object (builder, "bridge_port_path_cost")));
+	priv->hairpin_mode = GTK_TOGGLE_BUTTON (GTK_WIDGET (gtk_builder_get_object (builder, "bridge_port_hairpin_mode")));
+}
+
+static void
+stuff_changed (GtkWidget *w, gpointer user_data)
+{
+	ce_page_changed (CE_PAGE (user_data));
+}
+
+static void
+populate_ui (CEPageBridgePort *self)
+{
+	CEPageBridgePortPrivate *priv = CE_PAGE_BRIDGE_PORT_GET_PRIVATE (self);
+	NMSettingBridgePort *s_port = priv->setting;
+
+	gtk_spin_button_set_value (priv->priority, (gdouble) nm_setting_bridge_port_get_priority (s_port));
+	gtk_spin_button_set_value (priv->path_cost, (gdouble) nm_setting_bridge_port_get_path_cost (s_port));
+	gtk_toggle_button_set_active (priv->hairpin_mode, nm_setting_bridge_port_get_hairpin_mode (s_port));
+}
+
+static void
+finish_setup (CEPageBridgePort *self, gpointer unused, GError *error, gpointer user_data)
+{
+	CEPageBridgePortPrivate *priv = CE_PAGE_BRIDGE_PORT_GET_PRIVATE (self);
+
+	if (error)
+		return;
+
+	populate_ui (self);
+
+	g_signal_connect (priv->priority, "value-changed", G_CALLBACK (stuff_changed), self);
+	g_signal_connect (priv->path_cost, "value-changed", G_CALLBACK (stuff_changed), self);
+	g_signal_connect (priv->hairpin_mode, "toggled", G_CALLBACK (stuff_changed), self);
+}
+
+CEPage *
+ce_page_bridge_port_new (NMConnection *connection,
+                         GtkWindow *parent_window,
+                         NMClient *client,
+                         NMRemoteSettings *settings,
+                         const char **out_secrets_setting_name,
+                         GError **error)
+{
+	CEPageBridgePort *self;
+	CEPageBridgePortPrivate *priv;
+
+	self = CE_PAGE_BRIDGE_PORT (ce_page_new (CE_TYPE_PAGE_BRIDGE_PORT,
+	                                         connection,
+	                                         parent_window,
+	                                         client,
+	                                         settings,
+	                                         UIDIR "/ce-page-bridge-port.ui",
+	                                         "BridgePortPage",
+	                                         /* Translators: a "Bridge Port" is a network
+	                                          * device that is part of a bridge.
+	                                          */
+	                                         _("Bridge Port")));
+	if (!self) {
+		g_set_error_literal (error, NMA_ERROR, NMA_ERROR_GENERIC, _("Could not load bridge port user interface."));
+		return NULL;
+	}
+
+	bridge_port_private_init (self);
+	priv = CE_PAGE_BRIDGE_PORT_GET_PRIVATE (self);
+
+	priv->setting = nm_connection_get_setting_bridge_port (connection);
+	if (!priv->setting) {
+		priv->setting = NM_SETTING_BRIDGE_PORT (nm_setting_bridge_port_new ());
+		nm_connection_add_setting (connection, NM_SETTING (priv->setting));
+	}
+
+	g_signal_connect (self, "initialized", G_CALLBACK (finish_setup), NULL);
+
+	return CE_PAGE (self);
+}
+
+static void
+ui_to_setting (CEPageBridgePort *self)
+{
+	CEPageBridgePortPrivate *priv = CE_PAGE_BRIDGE_PORT_GET_PRIVATE (self);
+
+	g_object_set (priv->setting,
+	              NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, gtk_toggle_button_get_active (priv->hairpin_mode),
+	              NM_SETTING_BRIDGE_PORT_PRIORITY, gtk_spin_button_get_value_as_int (priv->priority),
+	              NM_SETTING_BRIDGE_PORT_PATH_COST, gtk_spin_button_get_value_as_int (priv->path_cost),
+	              NULL);
+}
+
+static gboolean
+validate (CEPage *page, NMConnection *connection, GError **error)
+{
+	CEPageBridgePort *self = CE_PAGE_BRIDGE_PORT (page);
+	CEPageBridgePortPrivate *priv = CE_PAGE_BRIDGE_PORT_GET_PRIVATE (self);
+
+	ui_to_setting (self);
+	return nm_setting_verify (NM_SETTING (priv->setting), NULL, error);
+}
+
+static void
+ce_page_bridge_port_init (CEPageBridgePort *self)
+{
+}
+
+static void
+ce_page_bridge_port_class_init (CEPageBridgePortClass *bridge_port_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (bridge_port_class);
+	CEPageClass *parent_class = CE_PAGE_CLASS (bridge_port_class);
+
+	g_type_class_add_private (object_class, sizeof (CEPageBridgePortPrivate));
+
+	/* virtual methods */
+	parent_class->validate = validate;
+}
diff --git a/src/connection-editor/page-bridge-port.h b/src/connection-editor/page-bridge-port.h
new file mode 100644
index 0000000..2a35240
--- /dev/null
+++ b/src/connection-editor/page-bridge-port.h
@@ -0,0 +1,58 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager Connection editor -- Connection editor for NetworkManager
+ *
+ * Dan Williams <dcbw redhat com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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.
+ *
+ * (C) Copyright 2008 - 2012 Red Hat, Inc.
+ */
+
+#ifndef __PAGE_BRIDGE_PORT_H__
+#define __PAGE_BRIDGE_PORT_H__
+
+#include <nm-connection.h>
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "ce-page.h"
+
+#define CE_TYPE_PAGE_BRIDGE_PORT            (ce_page_bridge_port_get_type ())
+#define CE_PAGE_BRIDGE_PORT(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), CE_TYPE_PAGE_BRIDGE_PORT, CEPageBridgePort))
+#define CE_PAGE_BRIDGE_PORT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), CE_TYPE_PAGE_BRIDGE_PORT, CEPageBridgePortClass))
+#define CE_IS_PAGE_BRIDGE_PORT(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CE_TYPE_PAGE_BRIDGE_PORT))
+#define CE_IS_PAGE_BRIDGE_PORT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CE_TYPE_PAGE_BRIDGE_PORT))
+#define CE_PAGE_BRIDGE_PORT_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), CE_TYPE_PAGE_BRIDGE_PORT, CEPageBridgePortClass))
+
+typedef struct {
+	CEPage parent;
+} CEPageBridgePort;
+
+typedef struct {
+	CEPageClass parent;
+} CEPageBridgePortClass;
+
+GType ce_page_bridge_port_get_type (void);
+
+CEPage *ce_page_bridge_port_new (NMConnection *connection,
+                                 GtkWindow *parent,
+                                 NMClient *client,
+                                 NMRemoteSettings *settings,
+                                 const char **out_secrets_setting_name,
+                                 GError **error);
+
+#endif  /* __PAGE_BRIDGE_PORT_H__ */
+
diff --git a/src/connection-editor/page-bridge.c b/src/connection-editor/page-bridge.c
new file mode 100644
index 0000000..961002a
--- /dev/null
+++ b/src/connection-editor/page-bridge.c
@@ -0,0 +1,348 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager Connection editor -- Connection editor for NetworkManager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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.
+ *
+ * Copyright 2012 Red Hat, Inc.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+
+#include <nm-setting-connection.h>
+#include <nm-setting-bridge.h>
+
+#include "page-bridge.h"
+#include "nm-connection-editor.h"
+#include "new-connection.h"
+
+G_DEFINE_TYPE (CEPageBridge, ce_page_bridge, CE_TYPE_PAGE_MASTER)
+
+#define CE_PAGE_BRIDGE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CE_TYPE_PAGE_BRIDGE, CEPageBridgePrivate))
+
+typedef struct {
+	NMSettingBridge *setting;
+
+	GtkWindow *toplevel;
+
+	GtkSpinButton *ageing_time;
+	GtkCheckButton *stp;
+	GtkSpinButton *priority;
+	GtkSpinButton *forward_delay;
+	GtkSpinButton *hello_time;
+	GtkSpinButton *max_age;
+
+} CEPageBridgePrivate;
+
+static void
+bridge_private_init (CEPageBridge *self)
+{
+	CEPageBridgePrivate *priv = CE_PAGE_BRIDGE_GET_PRIVATE (self);
+	GtkBuilder *builder;
+
+	builder = CE_PAGE (self)->builder;
+
+	priv->ageing_time = GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "bridge_ageing_time"));
+	priv->stp = GTK_CHECK_BUTTON (gtk_builder_get_object (builder, "bridge_stp_checkbox"));
+	priv->priority = GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "bridge_priority"));
+	priv->forward_delay = GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "bridge_forward_delay"));
+	priv->hello_time = GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "bridge_hello_time"));
+	priv->max_age = GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "bridge_max_age"));
+
+	priv->toplevel = GTK_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (priv->stp),
+	                                                      GTK_TYPE_WINDOW));
+}
+
+static void
+stuff_changed (GtkWidget *w, gpointer user_data)
+{
+	ce_page_changed (CE_PAGE (user_data));
+}
+
+static void
+stp_toggled (GtkToggleButton *stp, gpointer user_data)
+{
+	CEPageBridge *self = user_data;
+	CEPageBridgePrivate *priv = CE_PAGE_BRIDGE_GET_PRIVATE (self);
+
+	if (gtk_toggle_button_get_active (stp)) {
+		gtk_widget_set_sensitive (GTK_WIDGET (priv->priority), TRUE);
+		gtk_widget_set_sensitive (GTK_WIDGET (priv->forward_delay), TRUE);
+		gtk_widget_set_sensitive (GTK_WIDGET (priv->hello_time), TRUE);
+		gtk_widget_set_sensitive (GTK_WIDGET (priv->max_age), TRUE);
+	} else {
+		gtk_widget_set_sensitive (GTK_WIDGET (priv->priority), FALSE);
+		gtk_widget_set_sensitive (GTK_WIDGET (priv->forward_delay), FALSE);
+		gtk_widget_set_sensitive (GTK_WIDGET (priv->hello_time), FALSE);
+		gtk_widget_set_sensitive (GTK_WIDGET (priv->max_age), FALSE);
+	}
+}
+
+static void
+populate_ui (CEPageBridge *self)
+{
+	CEPageBridgePrivate *priv = CE_PAGE_BRIDGE_GET_PRIVATE (self);
+	NMSettingBridge *s_bridge = priv->setting;
+	gboolean stp;
+	int priority, forward_delay, hello_time, max_age;
+	int ageing_time;
+
+	/* Ageing time */
+	ageing_time = nm_setting_bridge_get_ageing_time (s_bridge);
+	gtk_spin_button_set_value (priv->ageing_time, (gdouble) ageing_time);
+	g_signal_connect (priv->ageing_time, "value-changed",
+	                  G_CALLBACK (stuff_changed),
+	                  self);
+
+	/* STP */
+	g_signal_connect (priv->stp, "toggled",
+	                  G_CALLBACK (stp_toggled),
+	                  self);
+	stp = nm_setting_bridge_get_stp (s_bridge);
+	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->stp), stp);
+
+	/* Priority */
+	priority = nm_setting_bridge_get_priority (s_bridge);
+	gtk_spin_button_set_value (priv->priority, (gdouble) priority);
+	g_signal_connect (priv->priority, "value-changed",
+	                  G_CALLBACK (stuff_changed),
+	                  self);
+
+	/* Forward delay */
+	forward_delay = nm_setting_bridge_get_forward_delay (s_bridge);
+	gtk_spin_button_set_value (priv->forward_delay, (gdouble) forward_delay);
+	g_signal_connect (priv->forward_delay, "value-changed",
+	                  G_CALLBACK (stuff_changed),
+	                  self);
+
+	/* Hello time */
+	hello_time = nm_setting_bridge_get_hello_time (s_bridge);
+	gtk_spin_button_set_value (priv->hello_time, (gdouble) hello_time);
+	g_signal_connect (priv->hello_time, "value-changed",
+	                  G_CALLBACK (stuff_changed),
+	                  self);
+
+	/* Max age */
+	max_age = nm_setting_bridge_get_max_age (s_bridge);
+	gtk_spin_button_set_value (priv->max_age, (gdouble) max_age);
+	g_signal_connect (priv->max_age, "value-changed",
+	                  G_CALLBACK (stuff_changed),
+	                  self);
+}
+
+static void
+create_connection (CEPageMaster *master, NMConnection *connection)
+{
+	NMSetting *s_port;
+
+	s_port = nm_connection_get_setting (connection, NM_TYPE_SETTING_BRIDGE_PORT);
+	if (!s_port) {
+		s_port = nm_setting_bridge_port_new ();
+		nm_connection_add_setting (connection, s_port);
+	}
+}
+
+static gboolean
+connection_type_filter (GType type, gpointer user_data)
+{
+	if (type == NM_TYPE_SETTING_WIRED ||
+	    type == NM_TYPE_SETTING_WIRELESS ||
+		type == NM_TYPE_SETTING_VLAN)
+		return TRUE;
+	else
+		return FALSE;
+}
+
+static void
+add_slave (CEPageMaster *master, NewConnectionResultFunc result_func)
+{
+	CEPageBridge *self = CE_PAGE_BRIDGE (master);
+	CEPageBridgePrivate *priv = CE_PAGE_BRIDGE_GET_PRIVATE (self);
+
+	new_connection_dialog (priv->toplevel,
+	                       CE_PAGE (self)->settings,
+	                       connection_type_filter,
+	                       result_func,
+	                       master);
+}
+
+static void
+finish_setup (CEPageBridge *self, gpointer unused, GError *error, gpointer user_data)
+{
+	if (error)
+		return;
+
+	populate_ui (self);
+}
+
+CEPage *
+ce_page_bridge_new (NMConnection *connection,
+                    GtkWindow *parent_window,
+                    NMClient *client,
+                    NMRemoteSettings *settings,
+                    const char **out_secrets_setting_name,
+                    GError **error)
+{
+	CEPageBridge *self;
+	CEPageBridgePrivate *priv;
+
+	self = CE_PAGE_BRIDGE (ce_page_new (CE_TYPE_PAGE_BRIDGE,
+	                                  connection,
+	                                  parent_window,
+	                                  client,
+	                                  settings,
+	                                  UIDIR "/ce-page-bridge.ui",
+	                                  "BridgePage",
+	                                  _("Bridge")));
+	if (!self) {
+		g_set_error_literal (error, NMA_ERROR, NMA_ERROR_GENERIC,
+		                     _("Could not load bridge user interface."));
+		return NULL;
+	}
+
+	bridge_private_init (self);
+	priv = CE_PAGE_BRIDGE_GET_PRIVATE (self);
+
+	priv->setting = nm_connection_get_setting_bridge (connection);
+	if (!priv->setting) {
+		priv->setting = NM_SETTING_BRIDGE (nm_setting_bridge_new ());
+		nm_connection_add_setting (connection, NM_SETTING (priv->setting));
+	}
+
+	g_signal_connect (self, "initialized", G_CALLBACK (finish_setup), NULL);
+
+	return CE_PAGE (self);
+}
+
+static void
+ui_to_setting (CEPageBridge *self)
+{
+	CEPageBridgePrivate *priv = CE_PAGE_BRIDGE_GET_PRIVATE (self);
+	int ageing_time, priority, forward_delay, hello_time, max_age;
+	gboolean stp;
+
+	ageing_time = gtk_spin_button_get_value_as_int (priv->ageing_time);
+	stp = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->stp));
+	g_object_set (G_OBJECT (priv->setting),
+	              NM_SETTING_BRIDGE_AGEING_TIME, ageing_time,
+	              NM_SETTING_BRIDGE_STP, stp,
+	              NULL);
+
+	if (stp) {
+		priority = gtk_spin_button_get_value_as_int (priv->priority);
+		forward_delay = gtk_spin_button_get_value_as_int (priv->forward_delay);
+		hello_time = gtk_spin_button_get_value_as_int (priv->hello_time);
+		max_age = gtk_spin_button_get_value_as_int (priv->max_age);
+
+		g_object_set (G_OBJECT (priv->setting),
+		              NM_SETTING_BRIDGE_PRIORITY, priority,
+		              NM_SETTING_BRIDGE_FORWARD_DELAY, forward_delay,
+		              NM_SETTING_BRIDGE_HELLO_TIME, hello_time,
+		              NM_SETTING_BRIDGE_MAX_AGE, max_age,
+		              NULL);
+	}
+}
+
+static gboolean
+validate (CEPage *page, NMConnection *connection, GError **error)
+{
+	CEPageBridge *self = CE_PAGE_BRIDGE (page);
+	CEPageBridgePrivate *priv = CE_PAGE_BRIDGE_GET_PRIVATE (self);
+
+	if (!CE_PAGE_CLASS (ce_page_bridge_parent_class)->validate (page, connection, error))
+		return FALSE;
+
+	ui_to_setting (self);
+	return nm_setting_verify (NM_SETTING (priv->setting), NULL, error);
+}
+
+static void
+ce_page_bridge_init (CEPageBridge *self)
+{
+}
+
+static void
+ce_page_bridge_class_init (CEPageBridgeClass *bridge_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (bridge_class);
+	CEPageClass *parent_class = CE_PAGE_CLASS (bridge_class);
+	CEPageMasterClass *master_class = CE_PAGE_MASTER_CLASS (bridge_class);
+
+	g_type_class_add_private (object_class, sizeof (CEPageBridgePrivate));
+
+	/* virtual methods */
+	parent_class->validate = validate;
+	master_class->create_connection = create_connection;
+	master_class->add_slave = add_slave;
+}
+
+void
+bridge_connection_new (GtkWindow *parent,
+                     const char *detail,
+                     NMRemoteSettings *settings,
+                     PageNewConnectionResultFunc result_func,
+                     gpointer user_data)
+{
+	NMConnection *connection;
+	int bridge_num, max_bridge_num, num;
+	GSList *connections, *iter;
+	NMConnection *conn2;
+	NMSettingBridge *s_bridge;
+	const char *iface;
+	char *my_iface;
+
+	connection = ce_page_new_connection (_("Bridge connection %d"),
+	                                     NM_SETTING_BRIDGE_SETTING_NAME,
+	                                     TRUE,
+	                                     settings,
+	                                     user_data);
+	nm_connection_add_setting (connection, nm_setting_bridge_new ());
+
+	/* Find an available interface name */
+	bridge_num = max_bridge_num = 0;
+	connections = nm_remote_settings_list_connections (settings);
+	for (iter = connections; iter; iter = iter->next) {
+		conn2 = iter->data;
+
+		if (!nm_connection_is_type (conn2, NM_SETTING_BRIDGE_SETTING_NAME))
+			continue;
+		s_bridge = nm_connection_get_setting_bridge (conn2);
+		if (!s_bridge)
+			continue;
+		iface = nm_setting_bridge_get_interface_name (s_bridge);
+		if (!iface || strncmp (iface, "bridge", 4) != 0 || !g_ascii_isdigit (iface[4]))
+			continue;
+
+		num = atoi (iface + 4);
+		if (num > max_bridge_num)
+			max_bridge_num = num;
+		if (num == bridge_num)
+			bridge_num = max_bridge_num + 1;
+	}
+	g_slist_free (connections);
+
+	my_iface = g_strdup_printf ("bridge%d", bridge_num);
+	s_bridge = nm_connection_get_setting_bridge (connection);
+	g_object_set (G_OBJECT (s_bridge),
+	              NM_SETTING_BRIDGE_INTERFACE_NAME, my_iface,
+	              NULL);
+	g_free (my_iface);
+
+	(*result_func) (connection, FALSE, NULL, user_data);
+}
+
diff --git a/src/connection-editor/page-bridge.h b/src/connection-editor/page-bridge.h
new file mode 100644
index 0000000..fa6d927
--- /dev/null
+++ b/src/connection-editor/page-bridge.h
@@ -0,0 +1,62 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager Connection editor -- Connection editor for NetworkManager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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.
+ *
+ * Copyright 2012 Red Hat, Inc.
+ */
+
+#ifndef __PAGE_BRIDGE_H__
+#define __PAGE_BRIDGE_H__
+
+#include <nm-connection.h>
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "page-master.h"
+
+#define CE_TYPE_PAGE_BRIDGE            (ce_page_bridge_get_type ())
+#define CE_PAGE_BRIDGE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), CE_TYPE_PAGE_BRIDGE, CEPageBridge))
+#define CE_PAGE_BRIDGE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), CE_TYPE_PAGE_BRIDGE, CEPageBridgeClass))
+#define CE_IS_PAGE_BRIDGE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CE_TYPE_PAGE_BRIDGE))
+#define CE_IS_PAGE_BRIDGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CE_TYPE_PAGE_BRIDGE))
+#define CE_PAGE_BRIDGE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), CE_TYPE_PAGE_BRIDGE, CEPageBridgeClass))
+
+typedef struct {
+	CEPageMaster parent;
+} CEPageBridge;
+
+typedef struct {
+	CEPageMasterClass parent;
+} CEPageBridgeClass;
+
+GType ce_page_bridge_get_type (void);
+
+CEPage *ce_page_bridge_new (NMConnection *connection,
+                            GtkWindow *parent,
+                            NMClient *client,
+                            NMRemoteSettings *settings,
+                            const char **out_secrets_setting_name,
+                            GError **error);
+
+void bridge_connection_new (GtkWindow *parent,
+                            const char *detail,
+                            NMRemoteSettings *settings,
+                            PageNewConnectionResultFunc result_func,
+                            gpointer user_data);
+
+#endif  /* __PAGE_BRIDGE_H__ */
+
diff --git a/src/connection-editor/page-master.c b/src/connection-editor/page-master.c
index 41a084c..a3d59ca 100644
--- a/src/connection-editor/page-master.c
+++ b/src/connection-editor/page-master.c
@@ -47,6 +47,7 @@ typedef struct {
 } CEPageMasterPrivate;
 
 enum {
+	CREATE_CONNECTION,
 	CONNECTION_ADDED,
 	CONNECTION_REMOVED,
 
@@ -297,6 +298,8 @@ add_connection (NMConnection *connection,
 	              NULL);
 	g_free (name);
 
+	g_signal_emit (self, signals[CREATE_CONNECTION], 0, connection);
+
 	editor = nm_connection_editor_new (priv->toplevel,
 	                                   connection,
 	                                   CE_PAGE (self)->client,
@@ -534,6 +537,16 @@ ce_page_master_class_init (CEPageMasterClass *master_class)
 	parent_class->validate = validate;
 
 	/* Signals */
+	signals[CREATE_CONNECTION] = 
+		g_signal_new ("create-connection",
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_FIRST,
+		              G_STRUCT_OFFSET (CEPageMasterClass, create_connection),
+		              NULL, NULL,
+		              g_cclosure_marshal_VOID__OBJECT,
+		              G_TYPE_NONE, 1,
+		              NM_TYPE_CONNECTION);
+
 	signals[CONNECTION_ADDED] = 
 		g_signal_new ("connection-added",
 		              G_OBJECT_CLASS_TYPE (object_class),
diff --git a/src/connection-editor/page-master.h b/src/connection-editor/page-master.h
index 8d512a3..5bd0575 100644
--- a/src/connection-editor/page-master.h
+++ b/src/connection-editor/page-master.h
@@ -44,6 +44,7 @@ typedef struct {
 	CEPageClass parent;
 
 	/* signals */
+	void (*create_connection)  (CEPageMaster *self, NMConnection *connection);
 	void (*connection_added)   (CEPageMaster *self, NMConnection *connection);
 	void (*connection_removed) (CEPageMaster *self, NMConnection *connection);
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]