[gssdp] Port sniffer to GTK4



commit c251ddcd03331ecba8702658be8023fb32743a85
Author: Jens Georg <mail jensge org>
Date:   Sun Jun 20 15:29:42 2021 +0000

    Port sniffer to GTK4

 .gitlab-ci.yml                           |   4 +-
 meson.build                              |   2 +-
 tools/gssdp-device-sniffer.gresource.xml |   3 +
 tools/main-window.c                      | 125 ++++-----
 tools/main-window.ui                     | 449 +++++++++++--------------------
 tools/meson.build                        |   3 +-
 6 files changed, 235 insertions(+), 351 deletions(-)
---
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 5930c19..b0fad7e 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -61,9 +61,9 @@ check-merge-request:
 
 .gssdp.fedora@common:
   variables:
-    BASE_TAG: '2021-05-22.0'
+    BASE_TAG: '2021-06-19.0'
     FDO_UPSTREAM_REPO: GNOME/gssdp
-    FDO_DISTRIBUTION_PACKAGES: 'clang clang-analyzer gcovr git libasan libubsan python3-gobject python3-pip 
xmlto'
+    FDO_DISTRIBUTION_PACKAGES: 'clang clang-analyzer gcovr git libasan libubsan python3-gobject python3-pip 
xmlto gtk4-devel'
     FDO_DISTRIBUTION_EXEC: |
       dnf install -y 'dnf-command(builddep)' &&
       dnf builddep -y gssdp --setopt=install_weak_deps=False &&
diff --git a/meson.build b/meson.build
index e043070..2683c70 100644
--- a/meson.build
+++ b/meson.build
@@ -75,7 +75,7 @@ subdir('libgssdp')
 subdir('tests')
 
 if get_option('sniffer')
-  gtk = dependency('gtk+-3.0', version : '>= 3.12')
+  gtk = dependency('gtk4', version : '>= 4')
   subdir('tools')
 endif
 
diff --git a/tools/gssdp-device-sniffer.gresource.xml b/tools/gssdp-device-sniffer.gresource.xml
index 6a9d0a3..0b957e4 100644
--- a/tools/gssdp-device-sniffer.gresource.xml
+++ b/tools/gssdp-device-sniffer.gresource.xml
@@ -3,4 +3,7 @@
   <gresource prefix="/org/gupnp/GSSDP">
     <file preprocess="xml-stripblanks" alias="MainWindow.ui">main-window.ui</file>
   </gresource>
+  <gresource prefix="/org/gupnp">
+    <file preprocess="xml-stripblanks" alias="Logo.svg">images/gupnp-logo-short.svg</file>
+  </gresource>
 </gresources>
diff --git a/tools/main-window.c b/tools/main-window.c
index 80e6d03..36a0d67 100644
--- a/tools/main-window.c
+++ b/tools/main-window.c
@@ -12,6 +12,8 @@
 
 #include <libsoup/soup.h>
 
+#define LOGO_RESOURCE "/org/gupnp/Logo.svg"
+
 typedef enum
 {
         PACKET_STORE_COLUMN_TIME,
@@ -52,7 +54,7 @@ struct _GSSDPDeviceSnifferMainWindow {
         // Bound child widgets
         GtkWidget *packet_treeview;
         GtkWidget *packet_textview;
-        GtkWidget *capture_button_image;
+        GtkWidget *capture_button;
         GtkWidget *device_treeview;
         GtkWidget *details_scrolled;
         GMenuModel *sniffer_context_menu;
@@ -114,9 +116,7 @@ main_window_set_property (GObject *object,
                                     ? "media-playback-stop-symbolic"
                                     : "media-playback-start-symbolic";
 
-                gtk_image_set_from_icon_name (GTK_IMAGE (self->capture_button_image),
-                                              icon_name,
-                                              GTK_ICON_SIZE_BUTTON);
+                gtk_button_set_icon_name(GTK_BUTTON (self->capture_button), icon_name);
                 break;
         default:
                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -229,8 +229,8 @@ on_ssdp_message (GSSDPClient *ssdp_client,
                 return;
 
         if (gtk_search_bar_get_search_mode (GTK_SEARCH_BAR (self->searchbar))) {
-                const char *filter =
-                        gtk_entry_get_text (GTK_ENTRY (self->address_filter));
+                const char *filter = gtk_editable_get_text (
+                        GTK_EDITABLE (self->address_filter));
                 if (filter != NULL && strcmp (filter, from_ip) != 0)
                         return;
         }
@@ -453,7 +453,7 @@ gssdp_device_sniffer_main_window_class_init (
 
         gtk_widget_class_bind_template_child (widget_class,
                                               GSSDPDeviceSnifferMainWindow,
-                                              capture_button_image);
+                                              capture_button);
 
         gtk_widget_class_bind_template_child (widget_class,
                                               GSSDPDeviceSnifferMainWindow,
@@ -531,23 +531,18 @@ on_realize (GtkWidget *self, gpointer user_data)
 {
         double w;
         double h;
-#if GTK_CHECK_VERSION(3, 22, 0)
-        {
-                GdkWindow *window = gtk_widget_get_window (self);
-                GdkDisplay *display = gdk_display_get_default ();
-                GdkMonitor *monitor =
-                        gdk_display_get_monitor_at_window (display, window);
-                GdkRectangle rectangle;
-
-                gdk_monitor_get_geometry (monitor, &rectangle);
-                w = rectangle.width * 0.75;
-                h = rectangle.height * 0.75;
-        }
 
-#else
-        w = gdk_screen_width () * 0.75;
-        h = gdk_screen_height () * 0.75;
-#endif
+        GtkNative *native = gtk_widget_get_native (self);
+        GdkSurface *surface = gtk_native_get_surface (native);
+        GdkDisplayManager *mgr = gdk_display_manager_get ();
+        GdkDisplay *display = gdk_display_manager_get_default_display (mgr);
+        GdkMonitor *monitor =
+                gdk_display_get_monitor_at_surface (display, surface);
+        GdkRectangle rectangle;
+
+        gdk_monitor_get_geometry (monitor, &rectangle);
+        w = rectangle.width * 0.75;
+        h = rectangle.height * 0.75;
 
         int window_width = CLAMP ((int) w, 10, 1000);
         int window_height = CLAMP ((int) h, 10, 800);
@@ -672,7 +667,11 @@ static void
 on_about (GSimpleAction *action, GVariant *parameter, gpointer user_data)
 {
         const char *AUTHORS[] = { "Zeeshan Ali (Khattak) <zeeshanak gnome org>",
+                                  "Jens Georg <mail jensge org>",
                                   NULL };
+
+        GdkTexture *logo = gdk_texture_new_from_resource (LOGO_RESOURCE);
+
         gtk_show_about_dialog (
                 GTK_WINDOW (user_data),
                 "copyright",
@@ -688,7 +687,10 @@ on_about (GSimpleAction *action, GVariant *parameter, gpointer user_data)
                 "translator-credits",
                 "license-type",
                 GTK_LICENSE_LGPL_2_1,
+                "logo", logo,
                 NULL);
+
+        g_object_unref (logo);
 }
 
 static void
@@ -712,7 +714,7 @@ on_set_address_filter (GSimpleAction *action,
                             PACKET_STORE_COLUMN_IP,
                             &ip_filter,
                             -1);
-        gtk_entry_set_text (GTK_ENTRY (self->address_filter), ip_filter);
+        gtk_editable_set_text (GTK_EDITABLE (self->address_filter), ip_filter);
         g_free (ip_filter);
 
         gtk_search_bar_set_search_mode (GTK_SEARCH_BAR (self->searchbar), TRUE);
@@ -726,46 +728,43 @@ static GActionEntry actions[] = { { "clear-capture", on_clear_capture },
                                     on_set_address_filter } };
 
 static void
-do_popup_menu (GSSDPDeviceSnifferMainWindow *self, GdkEventButton *event)
-{
-        gtk_menu_popup_at_pointer (GTK_MENU (self->context_menu),
-                                   (event != NULL) ? (GdkEvent *) event
-                                                   : gtk_get_current_event ());
-}
-
-static gboolean
-on_popup_menu (GtkWidget *widget, gpointer user_data)
+on_button_release (GtkGesture *click,
+                   int n_press,
+                   gdouble x,
+                   gdouble y,
+                   gpointer user_data)
 {
         GSSDPDeviceSnifferMainWindow *self =
                 GSSDP_DEVICE_SNIFFER_MAIN_WINDOW (user_data);
 
-        do_popup_menu (self, NULL);
+        GdkEventSequence *sequence = gtk_gesture_single_get_current_sequence (
+                GTK_GESTURE_SINGLE (click));
 
-        return TRUE;
-}
+        GdkEvent *event = gtk_gesture_get_last_event (click, sequence);
 
-static gboolean
-on_button_release (GtkWidget *widget, GdkEventButton *event, gpointer user_data)
-{
-        GSSDPDeviceSnifferMainWindow *self =
-                GSSDP_DEVICE_SNIFFER_MAIN_WINDOW (user_data);
+        if (n_press != 1) {
+                return;
+        }
+
+        if (!gdk_event_triggers_context_menu (event)) {
+                return;
+        }
 
-        GtkTreeSelection *selection;
+        gtk_gesture_set_sequence_state (GTK_GESTURE (click), sequence,
+                                        GTK_EVENT_SEQUENCE_CLAIMED);
         GtkTreeModel *model;
         GtkTreeIter iter;
-        if (event->type != GDK_BUTTON_RELEASE || event->button != 3) {
-                return FALSE;
-        }
 
-        selection = gtk_tree_view_get_selection (
+        GtkTreeSelection *selection = gtk_tree_view_get_selection (
                 GTK_TREE_VIEW (self->packet_treeview));
+
         if (!gtk_tree_selection_get_selected (selection, &model, &iter)) {
-                return FALSE;
+                return;
         }
 
-        do_popup_menu (self, event);
-
-        return TRUE;
+        GdkRectangle rect = { x, y, 1, 1 };
+        gtk_popover_set_pointing_to (GTK_POPOVER (self->context_menu), &rect);
+        gtk_popover_popup (GTK_POPOVER (self->context_menu));
 }
 
 static void
@@ -774,9 +773,20 @@ gssdp_device_sniffer_main_window_init (GSSDPDeviceSnifferMainWindow *self)
         gtk_widget_init_template (GTK_WIDGET (self));
 
         self->context_menu =
-                gtk_menu_new_from_model (self->sniffer_context_menu);
-
-        gtk_menu_attach_to_widget(GTK_MENU (self->context_menu), self->packet_treeview, NULL);
+                gtk_popover_menu_new_from_model (self->sniffer_context_menu);
+        gtk_widget_set_parent (self->context_menu, self->packet_treeview);
+        gtk_popover_set_position (GTK_POPOVER (self->context_menu),
+                                  GTK_POS_BOTTOM);
+        gtk_popover_set_has_arrow (GTK_POPOVER (self->context_menu), FALSE);
+        gtk_widget_set_halign (self->context_menu, GTK_ALIGN_START);
+
+        GtkGesture *click = gtk_gesture_click_new ();
+        gtk_event_controller_set_name (GTK_EVENT_CONTROLLER (click),
+                                       "packet-treeview-click");
+        gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (click), 3);
+        gtk_gesture_single_set_exclusive (GTK_GESTURE_SINGLE (click), TRUE);
+        gtk_widget_add_controller (self->packet_treeview,
+                                   GTK_EVENT_CONTROLLER (click));
 
         g_signal_connect (G_OBJECT (self),
                           "realize",
@@ -790,13 +800,8 @@ gssdp_device_sniffer_main_window_init (GSSDPDeviceSnifferMainWindow *self)
                           G_CALLBACK (on_packet_selected),
                           self);
 
-        g_signal_connect (G_OBJECT (self->packet_treeview),
-                          "popup-menu",
-                          G_CALLBACK (on_popup_menu),
-                          self);
-
-        g_signal_connect (G_OBJECT (self->packet_treeview),
-                          "button-release-event",
+        g_signal_connect (G_OBJECT (click),
+                          "pressed",
                           G_CALLBACK (on_button_release),
                           self);
 
diff --git a/tools/main-window.ui b/tools/main-window.ui
index 605a04d..0929f6a 100644
--- a/tools/main-window.ui
+++ b/tools/main-window.ui
@@ -1,34 +1,22 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.22.2 -->
 <interface>
-  <requires lib="gtk+" version="3.20"/>
+  <requires lib="gtk" version="4.0"/>
   <object class="GtkListStore" id="device_store">
     <columns>
-      <!-- column-name uid -->
       <column type="gchararray"/>
-      <!-- column-name first-seen -->
       <column type="gchararray"/>
-      <!-- column-name device-type -->
       <column type="gchararray"/>
-      <!-- column-name location -->
       <column type="gchararray"/>
     </columns>
   </object>
   <object class="GtkListStore" id="packet_store">
     <columns>
-      <!-- column-name time -->
       <column type="gchararray"/>
-      <!-- column-name source-address -->
       <column type="gchararray"/>
-      <!-- column-name interface -->
       <column type="gchararray"/>
-      <!-- column-name type -->
       <column type="gchararray"/>
-      <!-- column-name information -->
       <column type="gchararray"/>
-      <!-- column-name SoupMessageHeader1 -->
       <column type="SoupMessageHeaders"/>
-      <!-- column-name GDateTime1 -->
       <column type="GDateTime"/>
     </columns>
   </object>
@@ -47,8 +35,8 @@
     </section>
   </menu>
   <template class="GSSDPDeviceSnifferMainWindow" parent="GtkApplicationWindow">
-    <property name="can_focus">False</property>
-    <property name="can_focus">False</property>
+    <property name="can_focus">0</property>
+    <property name="can_focus">0</property>
     <child>
       <menu id="sniffer_context_menu">
         <section>
@@ -61,374 +49,261 @@
     </child>
     <child type="titlebar">
       <object class="GtkHeaderBar">
-        <property name="visible">True</property>
-        <property name="can_focus">False</property>
-        <property name="show_close_button">True</property>
+        <property name="can_focus">0</property>
         <child>
           <object class="GtkBox">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
+            <property name="can_focus">0</property>
             <property name="spacing">6</property>
             <child>
               <object class="GtkButton">
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="receives_default">True</property>
+                <property name="receives_default">1</property>
                 <property name="tooltip_text" translatable="yes">Clear packet capture</property>
                 <property name="action_name">win.clear-capture</property>
-                <child>
-                  <object class="GtkImage">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="icon_name">edit-clear-all-symbolic</property>
-                  </object>
-                </child>
+                <property name="icon_name">edit-clear-all-symbolic</property>
               </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">True</property>
-                <property name="position">0</property>
-              </packing>
             </child>
             <child>
-              <object class="GtkToggleButton">
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="receives_default">True</property>
+              <object class="GtkToggleButton" id="capture_button">
+                <property name="receives_default">1</property>
                 <property name="tooltip_text" translatable="yes">Toggle packet capture</property>
-                <property name="active">True</property>
+                <property name="active">1</property>
                 <property name="action_name">win.toggle-capture</property>
-                <child>
-                  <object class="GtkImage" id="capture_button_image">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="icon_name">media-playback-stop-symbolic</property>
-                  </object>
-                </child>
+                <property name="icon_name">media-playback-stop-symbolic</property>
               </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">True</property>
-                <property name="position">1</property>
-              </packing>
             </child>
             <child>
               <object class="GtkButton">
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="receives_default">True</property>
+                <property name="receives_default">1</property>
                 <property name="tooltip_text" translatable="yes">Trigger a rescan of the network</property>
                 <property name="action_name">win.trigger-rescan</property>
-                <child>
-                  <object class="GtkImage">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="icon_name">view-refresh-symbolic</property>
-                  </object>
-                </child>
+                <property name="icon_name">view-refresh-symbolic</property>
               </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">True</property>
-                <property name="position">2</property>
-              </packing>
             </child>
           </object>
-          <packing>
-            <property name="position">1</property>
-          </packing>
         </child>
         <child type="title">
           <object class="GtkStackSwitcher">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
+            <property name="can_focus">0</property>
             <property name="halign">center</property>
-            <property name="icon_size">0</property>
             <property name="stack">stack1</property>
           </object>
         </child>
-        <child>
+        <child type="end">
           <object class="GtkToggleButton" id="searchbutton">
-            <property name="visible">True</property>
-            <property name="can_focus">True</property>
-            <property name="receives_default">True</property>
+            <property name="receives_default">1</property>
             <property name="tooltip_text" translatable="yes">Enable content filter</property>
-            <property name="active">False</property>
-            <child>
-              <object class="GtkImage">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="icon_name">system-search-symbolic</property>
-              </object>
-            </child>
+            <property name="icon_name">system-search-symbolic</property>
           </object>
-          <packing>
-            <property name="pack_type">end</property>
-            <property name="position">1</property>
-          </packing>
         </child>
-        <child>
+        <child type="end">
           <object class="GtkMenuButton" id="window-menu">
-            <property name="visible">True</property>
-            <property name="can_focus">True</property>
-            <property name="receives_default">True</property>
+            <property name="receives_default">1</property>
             <property name="menu-model">sniffer-window-menu</property>
-            <child>
-              <object class="GtkImage">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="icon_name">open-menu-symbolic</property>
-              </object>
-            </child>
+            <property name="icon-name">open-menu-symbolic</property>
           </object>
-          <packing>
-            <property name="pack_type">end</property>
-            <property name="position">1</property>
-          </packing>
         </child>
       </object>
     </child>
     <child>
       <object class="GtkStack" id="stack1">
-        <property name="visible">True</property>
-        <property name="can_focus">False</property>
+        <property name="can_focus">0</property>
         <child>
-          <object class="GtkBox" id="vbox">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
-            <property name="border_width">6</property>
-            <property name="orientation">vertical</property>
-            <property name="spacing">6</property>
-            <child>
-              <object class="GtkSearchBar" id="searchbar">
-                <property name="visible">True</property>
-                <property name="show_close_button">True</property>
-                <property name="search-mode-enabled">True</property>
+          <object class="GtkStackPage">
+            <property name="title" translatable="yes">Packets</property>
+            <property name="child">
+              <object class="GtkBox" id="vbox">
+                <property name="can_focus">0</property>
+                <property name="margin-start">6</property>
+                <property name="margin-end">6</property>
+                <property name="margin-top">6</property>
+                <property name="margin-bottom">6</property>
+                <property name="orientation">vertical</property>
+                <property name="spacing">6</property>
                 <child>
-                 <object class="GtkSearchEntry" id="address_filter">
-                   <property name="visible">True</property>
-                   <property name="max-width-chars">40</property>
-                 </object>
+                  <object class="GtkSearchBar" id="searchbar">
+                    <property name="show_close_button">1</property>
+                    <property name="search-mode-enabled">1</property>
+                    <property name="child">
+                      <object class="GtkSearchEntry" id="address_filter">
+                        <property name="max-width-chars">40</property>
+                      </object>
+                    </property>
+                  </object>
                 </child>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">True</property>
-                <property name="position">0</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkScrolledWindow" id="packet-scrolledwindow">
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="shadow_type">in</property>
                 <child>
-                  <object class="GtkTreeView" id="packet_treeview">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="model">packet_store</property>
-                    <child internal-child="selection">
-                      <object class="GtkTreeSelection"/>
-                    </child>
-                    <child>
-                      <object class="GtkTreeViewColumn">
-                        <property name="title" translatable="yes">Time</property>
+                  <object class="GtkScrolledWindow" id="packet-scrolledwindow">
+                    <property name="vexpand">1</property>
+                    <property name="child">
+                      <object class="GtkTreeView" id="packet_treeview">
+                        <property name="model">packet_store</property>
+                        <child internal-child="selection">
+                          <object class="GtkTreeSelection"/>
+                        </child>
                         <child>
-                          <object class="GtkCellRendererText"/>
-                          <attributes>
-                            <attribute name="markup">0</attribute>
-                          </attributes>
+                          <object class="GtkTreeViewColumn">
+                            <property name="title" translatable="yes">Time</property>
+                            <child>
+                              <object class="GtkCellRendererText"/>
+                              <attributes>
+                                <attribute name="markup">0</attribute>
+                              </attributes>
+                            </child>
+                          </object>
                         </child>
-                      </object>
-                    </child>
-                    <child>
-                      <object class="GtkTreeViewColumn">
-                        <property name="title" translatable="yes">Source Address</property>
                         <child>
-                          <object class="GtkCellRendererText"/>
-                          <attributes>
-                            <attribute name="markup">1</attribute>
-                          </attributes>
+                          <object class="GtkTreeViewColumn">
+                            <property name="title" translatable="yes">Source Address</property>
+                            <child>
+                              <object class="GtkCellRendererText"/>
+                              <attributes>
+                                <attribute name="markup">1</attribute>
+                              </attributes>
+                            </child>
+                          </object>
                         </child>
-                      </object>
-                    </child>
-                    <child>
-                      <object class="GtkTreeViewColumn">
-                        <property name="title" translatable="yes">Interface</property>
                         <child>
-                          <object class="GtkCellRendererText"/>
-                          <attributes>
-                            <attribute name="markup">2</attribute>
-                          </attributes>
+                          <object class="GtkTreeViewColumn">
+                            <property name="title" translatable="yes">Interface</property>
+                            <child>
+                              <object class="GtkCellRendererText"/>
+                              <attributes>
+                                <attribute name="markup">2</attribute>
+                              </attributes>
+                            </child>
+                          </object>
                         </child>
-                      </object>
-                    </child>
-                    <child>
-                      <object class="GtkTreeViewColumn">
-                        <property name="title" translatable="yes">Packet Type</property>
                         <child>
-                          <object class="GtkCellRendererText"/>
-                          <attributes>
-                            <attribute name="markup">3</attribute>
-                          </attributes>
+                          <object class="GtkTreeViewColumn">
+                            <property name="title" translatable="yes">Packet Type</property>
+                            <child>
+                              <object class="GtkCellRendererText"/>
+                              <attributes>
+                                <attribute name="markup">3</attribute>
+                              </attributes>
+                            </child>
+                          </object>
                         </child>
-                      </object>
-                    </child>
-                    <child>
-                      <object class="GtkTreeViewColumn">
-                        <property name="title" translatable="yes">Packet Information</property>
                         <child>
-                          <object class="GtkCellRendererText"/>
-                          <attributes>
-                            <attribute name="markup">4</attribute>
-                          </attributes>
+                          <object class="GtkTreeViewColumn">
+                            <property name="title" translatable="yes">Packet Information</property>
+                            <child>
+                              <object class="GtkCellRendererText"/>
+                              <attributes>
+                                <attribute name="markup">4</attribute>
+                              </attributes>
+                            </child>
+                          </object>
                         </child>
                       </object>
-                    </child>
+                    </property>
                   </object>
                 </child>
-              </object>
-              <packing>
-                <property name="expand">True</property>
-                <property name="fill">True</property>
-                <property name="position">1</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkScrolledWindow" id="details_scrolled">
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="shadow_type">in</property>
                 <child>
-                  <object class="GtkTextView" id="packet_textview">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="editable">False</property>
-                    <property name="monospace">True</property>
+                  <object class="GtkScrolledWindow" id="details_scrolled">
+                    <property name="vexpand">1</property>
+                    <property name="child">
+                      <object class="GtkTextView" id="packet_textview">
+                        <property name="editable">0</property>
+                        <property name="monospace">1</property>
+                      </object>
+                    </property>
                   </object>
                 </child>
-              </object>
-              <packing>
-                <property name="expand">True</property>
-                <property name="fill">True</property>
-                <property name="position">2</property>
-              </packing>
-            </child>
-            <child>
+            <child type="end">
               <object class="GtkBox">
                 <property name="orientation">horizontal</property>
                 <property name="spacing">6</property>
                 <property name="visible">True</property>
-                <child>
+                <child type="start">
                       <object class="GtkLabel" id="info_label">
                         <property name="label"></property>
                         <property name="visible">True</property>
                         <property name="halign">start</property>
+                        <property name="hexpand">true</property>
                         <property name="valign">center</property>
                       </object>
-                      <packing>
-                        <property name="expand">True</property>
-                        <property name="fill">True</property>
-                        <property name="position">0</property>
-                      </packing>
                   </child>
-                  <child>
+                  <child type="end">
                       <object class="GtkLabel" id="counter_label">
                         <property name="label"></property>
                         <property name="visible">True</property>
                         <property name="halign">end</property>
+                        <property name="hexpand">true</property>
                         <property name="valign">center</property>
                       </object>
-                      <packing>
-                        <property name="expand">True</property>
-                        <property name="fill">True</property>
-                         <property name="position">2</property>
-                      </packing>
                 </child>
               </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">True</property>
-                <property name="position">3</property>
-              </packing>
             </child>
 
+              </object>
+            </property>
           </object>
-          <packing>
-            <property name="name">page0</property>
-            <property name="title" translatable="yes">Packets</property>
-          </packing>
         </child>
         <child>
-          <object class="GtkScrolledWindow" id="device-details-scrolledwindow">
-            <property name="name">Bar</property>
-            <property name="visible">True</property>
-            <property name="can_focus">True</property>
-            <property name="margin_top">6</property>
-            <property name="margin_bottom">6</property>
-            <property name="shadow_type">in</property>
-            <child>
-              <object class="GtkTreeView" id="device_treeview">
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="model">device_store</property>
-                <child internal-child="selection">
-                  <object class="GtkTreeSelection"/>
-                </child>
-                <child>
-                  <object class="GtkTreeViewColumn">
-                    <property name="title" translatable="yes">Unique Identifier</property>
+          <object class="GtkStackPage">
+            <property name="title" translatable="yes">Device history</property>
+            <property name="child">
+              <object class="GtkScrolledWindow" id="device-details-scrolledwindow">
+                <property name="name">Bar</property>
+                <property name="margin_top">6</property>
+                <property name="margin_bottom">6</property>
+                <property name="child">
+                  <object class="GtkTreeView" id="device_treeview">
+                    <property name="model">device_store</property>
+                    <child internal-child="selection">
+                      <object class="GtkTreeSelection"/>
+                    </child>
                     <child>
-                      <object class="GtkCellRendererText"/>
-                      <attributes>
-                        <attribute name="text">0</attribute>
-                      </attributes>
+                      <object class="GtkTreeViewColumn">
+                        <property name="title" translatable="yes">Unique Identifier</property>
+                        <child>
+                          <object class="GtkCellRendererText"/>
+                          <attributes>
+                            <attribute name="text">0</attribute>
+                          </attributes>
+                        </child>
+                      </object>
                     </child>
-                  </object>
-                </child>
-                <child>
-                  <object class="GtkTreeViewColumn">
-                    <property name="title" translatable="yes">First Notify</property>
                     <child>
-                      <object class="GtkCellRendererText"/>
-                      <attributes>
-                        <attribute name="text">1</attribute>
-                      </attributes>
+                      <object class="GtkTreeViewColumn">
+                        <property name="title" translatable="yes">First Notify</property>
+                        <child>
+                          <object class="GtkCellRendererText"/>
+                          <attributes>
+                            <attribute name="text">1</attribute>
+                          </attributes>
+                        </child>
+                      </object>
                     </child>
-                  </object>
-                </child>
-                <child>
-                  <object class="GtkTreeViewColumn">
-                    <property name="title" translatable="yes">Device Type</property>
                     <child>
-                      <object class="GtkCellRendererText"/>
-                      <attributes>
-                        <attribute name="text">2</attribute>
-                      </attributes>
+                      <object class="GtkTreeViewColumn">
+                        <property name="title" translatable="yes">Device Type</property>
+                        <child>
+                          <object class="GtkCellRendererText"/>
+                          <attributes>
+                            <attribute name="text">2</attribute>
+                          </attributes>
+                        </child>
+                      </object>
                     </child>
-                  </object>
-                </child>
-                <child>
-                  <object class="GtkTreeViewColumn">
-                    <property name="title" translatable="yes">Location</property>
                     <child>
-                      <object class="GtkCellRendererText"/>
-                      <attributes>
-                        <attribute name="text">3</attribute>
-                      </attributes>
+                      <object class="GtkTreeViewColumn">
+                        <property name="title" translatable="yes">Location</property>
+                        <child>
+                          <object class="GtkCellRendererText"/>
+                          <attributes>
+                            <attribute name="text">3</attribute>
+                          </attributes>
+                        </child>
+                      </object>
                     </child>
                   </object>
-                </child>
+                </property>
               </object>
-            </child>
+            </property>
           </object>
-          <packing>
-            <property name="name">page1</property>
-            <property name="title" translatable="yes">Device history</property>
-            <property name="position">1</property>
-          </packing>
         </child>
       </object>
     </child>
-   </template>
+  </template>
 </interface>
diff --git a/tools/meson.build b/tools/meson.build
index 59c5e74..3de758c 100644
--- a/tools/meson.build
+++ b/tools/meson.build
@@ -1,6 +1,7 @@
 resource = gnome.compile_resources(
     'org.gupnp.GSSDP.DeviceSniffer',
-    'gssdp-device-sniffer.gresource.xml'
+    'gssdp-device-sniffer.gresource.xml',
+    source_dir: [meson.current_source_dir(), meson.source_root() / 'doc']
 )
 
 sniffer = executable(


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